localStorage: locationId, energyPercent, locationConfig
This commit is contained in:
parent
aa71616961
commit
20bb84da63
@ -1,14 +1,22 @@
|
||||
<div class="MainMenu NoUserSelect">
|
||||
<div class="MainMenuBar">
|
||||
|
||||
<div class="MainMenuItem MainMenuButton" (click)="showDrawer = !showDrawer">
|
||||
<fa-icon [icon]="faBars"></fa-icon>
|
||||
</div>
|
||||
|
||||
<div class="MainMenuItem MainMenuTitle">
|
||||
{{ menuService.title }}
|
||||
</div>
|
||||
|
||||
<div class="MainMenuItem" routerLink="/Settings">
|
||||
<fa-icon [icon]="faGears"></fa-icon>
|
||||
</div>
|
||||
|
||||
@if (!ws.connected) {
|
||||
<div class="MainMenuItem MainMenuNotConnected">NICHT VERBUNDEN</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import {Routes} from '@angular/router';
|
||||
import {LocationList} from './location/list/location-list';
|
||||
import {LocationDetail} from './location/detail/location-detail';
|
||||
import {SettingsComponent} from './settings/settings-component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{path: 'Location/:id', component: LocationDetail},
|
||||
{path: 'Location', component: LocationList},
|
||||
{path: 'Location', component: LocationDetail},
|
||||
{path: 'Settings', component: SettingsComponent},
|
||||
{path: '**', redirectTo: '/Location'},
|
||||
];
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {Router, RouterLinkActive, RouterOutlet} from '@angular/router';
|
||||
import {Router, RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router';
|
||||
import {FaIconComponent} from '@fortawesome/angular-fontawesome';
|
||||
import {faBars} from '@fortawesome/free-solid-svg-icons';
|
||||
import {faBars, faBookmark as faBookmarkSolid, faGear, faGears} from '@fortawesome/free-solid-svg-icons';
|
||||
import {MenuService} from './menu-service';
|
||||
import {Location} from './location/Location';
|
||||
import {LocationService} from './location/location-service';
|
||||
import {WebsocketService} from './common';
|
||||
import {ConfigService} from './config.service';
|
||||
import {faBookmark as faBookmarkRegular} from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet, FaIconComponent, RouterLinkActive],
|
||||
imports: [RouterOutlet, FaIconComponent, RouterLinkActive, RouterLink],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.less'
|
||||
})
|
||||
@ -23,6 +25,7 @@ export class App implements OnInit, OnDestroy {
|
||||
|
||||
constructor(
|
||||
readonly locationService: LocationService,
|
||||
readonly configService: ConfigService,
|
||||
readonly menuService: MenuService,
|
||||
readonly router: Router,
|
||||
readonly ws: WebsocketService,
|
||||
@ -45,4 +48,11 @@ export class App implements OnInit, OnDestroy {
|
||||
})
|
||||
}
|
||||
|
||||
protected readonly faBookmarkRegular = faBookmarkRegular;
|
||||
|
||||
protected readonly faBookmarkSolid = faBookmarkSolid;
|
||||
|
||||
protected readonly faGear = faGear;
|
||||
|
||||
protected readonly faGears = faGears;
|
||||
}
|
||||
|
||||
106
src/main/angular/src/app/config.service.ts
Normal file
106
src/main/angular/src/app/config.service.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ConfigService {
|
||||
|
||||
private readonly LOCATION_ID_KEY = "locationId";
|
||||
|
||||
private readonly ENERGY_PERCENT_KEY = "energyPercent";
|
||||
|
||||
private readonly ENERGY_PERCENT_FALLBACK = false;
|
||||
|
||||
private readonly LOCATION_CONFIG_KEY = "locationConfig";
|
||||
|
||||
private readonly LOCATION_CONFIG_FALLBACK = false;
|
||||
|
||||
constructor() {
|
||||
this._locationId = this.readNumberOrNull(this.LOCATION_ID_KEY);
|
||||
this._energyPercent = this.readBoolean(this.ENERGY_PERCENT_KEY, this.ENERGY_PERCENT_FALLBACK);
|
||||
this._locationConfig = this.readBoolean(this.LOCATION_CONFIG_KEY, this.LOCATION_CONFIG_FALLBACK);
|
||||
}
|
||||
|
||||
private readNumberOrNull(key: string): number | null {
|
||||
const value = this.read(key);
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
const number = parseInt(value);
|
||||
return isNaN(number) ? null : number;
|
||||
}
|
||||
|
||||
private readBoolean(key: string, fallback: boolean): boolean {
|
||||
const value = this.read(key);
|
||||
if (value === "true") {
|
||||
return true;
|
||||
}
|
||||
if (value === "false") {
|
||||
return false;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private read(key: string): string | null {
|
||||
const value = localStorage.getItem(key);
|
||||
console.log("LOAD", key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private writeBoolean(key: string, value: boolean | null): void {
|
||||
console.log("STORE", key, value);
|
||||
if (value !== null && value !== undefined) {
|
||||
localStorage.setItem(key, value + "");
|
||||
} else {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
// locationId -----------------------------------------------------------------------------------
|
||||
|
||||
private _locationId: number | null = null;
|
||||
|
||||
get locationId(): number | null {
|
||||
return this._locationId;
|
||||
}
|
||||
|
||||
set locationId(value: number | null) {
|
||||
this._locationId = value;
|
||||
if (value !== null && value !== undefined) {
|
||||
localStorage.setItem(this.LOCATION_ID_KEY, value + "");
|
||||
} else {
|
||||
localStorage.removeItem(this.LOCATION_ID_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
// energyPercent -----------------------------------------------------------------------------------
|
||||
|
||||
private _energyPercent: boolean = this.ENERGY_PERCENT_FALLBACK;
|
||||
|
||||
get energyPercent(): boolean {
|
||||
return this._energyPercent;
|
||||
}
|
||||
|
||||
set energyPercent(value: boolean) {
|
||||
this._energyPercent = value;
|
||||
this.writeBoolean(this.ENERGY_PERCENT_KEY, value);
|
||||
}
|
||||
|
||||
// locationConfig -----------------------------------------------------------------------------------
|
||||
|
||||
private _locationConfig: boolean = this.LOCATION_CONFIG_FALLBACK;
|
||||
|
||||
get locationConfig(): boolean {
|
||||
return this._locationConfig;
|
||||
}
|
||||
|
||||
set locationConfig(value: boolean) {
|
||||
this._locationConfig = value;
|
||||
if (value !== null && value !== undefined) {
|
||||
localStorage.setItem(this.LOCATION_CONFIG_KEY, value + "");
|
||||
} else {
|
||||
localStorage.removeItem(this.LOCATION_CONFIG_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -28,164 +28,167 @@
|
||||
</ng-content>
|
||||
</app-location-energy>
|
||||
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Ort
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Name
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-text [initial]="location.name" (onChange)="locationService.name(location, $event)"></app-text>
|
||||
@if (configService.locationConfig) {
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Ort
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Breitengrad
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Name
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-text [initial]="location.name" (onChange)="locationService.name(location, $event)"></app-text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-number [initial]="location.latitude" (onChange)="locationService.latitude(location, $event)" unit="°"></app-number>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Längengrad
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Breitengrad
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-number [initial]="location.latitude" (onChange)="locationService.latitude(location, $event)" unit="°"></app-number>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-number [initial]="location.longitude" (onChange)="locationService.longitude(location, $event)" unit="°"></app-number>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Längengrad
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-number [initial]="location.longitude" (onChange)="locationService.longitude(location, $event)" unit="°"></app-number>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Energie
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Bezug
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.energyPurchase" (onChange)="locationService.energyPurchase(location, $event)" [filter]="filterEnergy"></app-series-select>
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Energie
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Einspeisung
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Bezug
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.energyPurchase" (onChange)="locationService.energyPurchase(location, $event)" [filter]="filterEnergy"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.energyDeliver" (onChange)="locationService.energyDeliver(location, $event)" [filter]="filterEnergy"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Erzeugung
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Einspeisung
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.energyDeliver" (onChange)="locationService.energyDeliver(location, $event)" [filter]="filterEnergy"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.energyProduce" (onChange)="locationService.energyProduce(location, $event)" [filter]="filterEnergy"></app-series-select>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Erzeugung
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.energyProduce" (onChange)="locationService.energyProduce(location, $event)" [filter]="filterEnergy"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Leistung
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Bezug
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.powerPurchase" (onChange)="locationService.powerPurchase(location, $event)" [filter]="filterPower"></app-series-select>
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Leistung
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Einspeisung
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Bezug
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.powerPurchase" (onChange)="locationService.powerPurchase(location, $event)" [filter]="filterPower"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.powerDeliver" (onChange)="locationService.powerDeliver(location, $event)" [filter]="filterPower"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Erzeugung
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Einspeisung
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.powerDeliver" (onChange)="locationService.powerDeliver(location, $event)" [filter]="filterPower"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.powerProduce" (onChange)="locationService.powerProduce(location, $event)" [filter]="filterPower"></app-series-select>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Erzeugung
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.powerProduce" (onChange)="locationService.powerProduce(location, $event)" [filter]="filterPower"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Außen
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Temperatur
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.outsideTemperature" (onChange)="locationService.outsideTemperature(location, $event)" [filter]="filterTemperature"></app-series-select>
|
||||
<div class="Section">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Außen
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Relative Luftfeuchte
|
||||
<div class="SectionBody">
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Temperatur
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.outsideTemperature" (onChange)="locationService.outsideTemperature(location, $event)" [filter]="filterTemperature"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.outsideHumidityRelative" (onChange)="locationService.outsideHumidityRelative(location, $event)" [filter]="filterHumidityRelative"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Absolute Luftfeuchte
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Relative Luftfeuchte
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.outsideHumidityRelative" (onChange)="locationService.outsideHumidityRelative(location, $event)" [filter]="filterHumidityRelative"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.outsideHumidityAbsolute" (onChange)="locationService.outsideHumidityAbsolute(location, $event)" [filter]="filterHumidityAbsolute"></app-series-select>
|
||||
<div class="Section2">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Absolute Luftfeuchte
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
<app-series-select [initial]="location.outsideHumidityAbsolute" (onChange)="locationService.outsideHumidityAbsolute(location, $event)" [filter]="filterHumidityAbsolute"></app-series-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {Component, Inject, LOCALE_ID, OnDestroy, OnInit} from '@angular/core';
|
||||
import {LocationService} from '../location-service';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||
import {Location} from '../Location';
|
||||
import {Text} from '../../shared/text/text';
|
||||
import {Number} from '../../shared/number/number';
|
||||
@ -14,6 +14,19 @@ import {Series} from '../../series/Series';
|
||||
import {SeriesType} from '../../series/SeriesType';
|
||||
import {DateService} from '../../date.service';
|
||||
import {LocationPower} from '../power/location-power';
|
||||
import {ConfigService} from '../../config.service';
|
||||
|
||||
export function paramNumberOrNull(params: Params, key: string): number | null {
|
||||
const param = params[key];
|
||||
if (param === null || param === undefined) {
|
||||
return null;
|
||||
}
|
||||
const value = parseInt(param);
|
||||
if (isNaN(value)) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-location-detail',
|
||||
@ -58,6 +71,8 @@ export class LocationDetail implements OnInit, OnDestroy {
|
||||
readonly activatedRoute: ActivatedRoute,
|
||||
readonly menuService: MenuService,
|
||||
readonly dateService: DateService,
|
||||
readonly configService: ConfigService,
|
||||
readonly router: Router,
|
||||
@Inject(LOCALE_ID) readonly locale: string,
|
||||
) {
|
||||
this.datePipe = new DatePipe(locale);
|
||||
@ -65,7 +80,14 @@ export class LocationDetail implements OnInit, OnDestroy {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.locationService.id = null;
|
||||
this.subs.push(this.activatedRoute.params.subscribe(params => this.locationService.id = params['id'] || null));
|
||||
this.subs.push(this.activatedRoute.params.subscribe(params => {
|
||||
const id = paramNumberOrNull(params, "id");
|
||||
if (id === null && this.configService.locationId !== null) {
|
||||
this.router.navigate(["Location/" + this.configService.locationId]);
|
||||
return;
|
||||
}
|
||||
this.locationService.id = id;
|
||||
}));
|
||||
this.subs.push(this.locationService.location$.subscribe(this.onLocationChange));
|
||||
}
|
||||
|
||||
|
||||
@ -14,10 +14,12 @@
|
||||
<div class="SectionBody COLOR_FONT_PURCHASE">
|
||||
{{ purchase.toValueString(null) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_PURCHASE percent">
|
||||
{{ purchasePercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_PURCHASE percent">
|
||||
{{ purchasePercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="Section4">
|
||||
@ -27,10 +29,12 @@
|
||||
<div class="SectionBody COLOR_FONT_PRODUCE">
|
||||
{{ produce.toValueString(null) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_PRODUCE percent">
|
||||
{{ producePercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_PRODUCE percent">
|
||||
{{ producePercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="Section4">
|
||||
@ -40,14 +44,16 @@
|
||||
<div class="SectionBody COLOR_FONT_SELF">
|
||||
{{ self.toValueString(null) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ selfPercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ selfPercentProduce.toValueString(null) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ selfPercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ selfPercentProduce.toValueString(null) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="Section4">
|
||||
@ -66,14 +72,16 @@
|
||||
<div class="SectionBody COLOR_FONT_DELIVER">
|
||||
{{ deliver.toValueString(null) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ deliveryPercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ deliveryPercentProduce.toValueString(null) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ deliveryPercentConsume.toValueString(null) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ deliveryPercentProduce.toValueString(null) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {AfterViewInit, Component, Input, OnDestroy, OnInit, signal} from '@angular/core';
|
||||
import {AfterViewInit, Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {Location} from '../Location';
|
||||
import {Series} from '../../series/Series';
|
||||
import {Next} from '../../common';
|
||||
@ -8,6 +8,7 @@ import {SeriesService} from '../../series/series-service';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {Value} from '../../series/Value';
|
||||
import EnergyCharts from './charts/energy-charts';
|
||||
import {ConfigService} from '../../config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-location-energy',
|
||||
@ -20,8 +21,6 @@ import EnergyCharts from './charts/energy-charts';
|
||||
})
|
||||
export class LocationEnergy implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
protected readonly signal = signal;
|
||||
|
||||
protected readonly Interval = Interval;
|
||||
|
||||
private readonly subs: Subscription[] = [];
|
||||
@ -75,6 +74,7 @@ export class LocationEnergy implements OnInit, AfterViewInit, OnDestroy {
|
||||
constructor(
|
||||
readonly pointService: PointService,
|
||||
readonly serieService: SeriesService,
|
||||
readonly configService: ConfigService,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
<div class="List LocationList NoUserSelect">
|
||||
@for (location of list; track location.id) {
|
||||
<div class="ListItem Location" routerLink="/Location/{{location.id}}">
|
||||
{{ location.name }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@ -1,35 +0,0 @@
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {LocationService} from '../location-service';
|
||||
import {Location} from '../Location';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {MenuService} from '../../menu-service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-location-list',
|
||||
imports: [
|
||||
RouterLink
|
||||
],
|
||||
templateUrl: './location-list.html',
|
||||
styleUrl: './location-list.less',
|
||||
})
|
||||
export class LocationList implements OnInit, OnDestroy {
|
||||
|
||||
protected list: Location[] = [];
|
||||
|
||||
constructor(
|
||||
readonly locationService: LocationService,
|
||||
readonly menuService: MenuService,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.locationService.findAll(list => this.list = list);
|
||||
this.menuService.title = "Orte";
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.menuService.title = "";
|
||||
}
|
||||
|
||||
}
|
||||
@ -25,8 +25,14 @@ export class LocationService extends CrudService<Location> {
|
||||
}
|
||||
|
||||
set id(id: number | null) {
|
||||
this._id = id;
|
||||
this.fetch();
|
||||
if (this._id !== id) {
|
||||
this._id = id;
|
||||
this.fetch();
|
||||
}
|
||||
}
|
||||
|
||||
get id(): number | null {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
private readonly fetch = () => {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div class="Section3">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Aktuelle Leistung
|
||||
Aktuell
|
||||
</div>
|
||||
</div>
|
||||
<div class="SectionBody">
|
||||
@ -13,10 +13,12 @@
|
||||
<div class="SectionBody COLOR_FONT_PURCHASE">
|
||||
{{ location.powerPurchase?.value?.toValueString(dateService.now) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_PURCHASE percent">
|
||||
{{ location.powerPurchasePercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_PURCHASE percent">
|
||||
{{ location.powerPurchasePercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="Section4">
|
||||
@ -26,10 +28,12 @@
|
||||
<div class="SectionBody COLOR_FONT_PRODUCE">
|
||||
{{ location.powerProduce?.value?.toValueString(dateService.now) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_PRODUCE percent">
|
||||
{{ location.powerProducePercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_PRODUCE percent">
|
||||
{{ location.powerProducePercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="Section4">
|
||||
@ -39,14 +43,16 @@
|
||||
<div class="SectionBody COLOR_FONT_SELF">
|
||||
{{ location.powerSelf.toValueString(dateService.now) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ location.powerSelfPercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ location.powerSelfPercentProduce.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ location.powerSelfPercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_SELF percent">
|
||||
{{ location.powerSelfPercentProduce.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="Section4">
|
||||
@ -65,14 +71,16 @@
|
||||
<div class="SectionBody COLOR_FONT_DELIVER">
|
||||
{{ location.powerDeliver?.value?.toValueString(dateService.now) }}
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ location.powerDeliveryPercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ location.powerDeliveryPercentProduce.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
@if (configService.energyPercent) {
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ location.powerDeliveryPercentConsume.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Verbrauch</sub>
|
||||
</div>
|
||||
<div class="SectionBody COLOR_FONT_DELIVER percent">
|
||||
{{ location.powerDeliveryPercentProduce.toValueString(dateService.now) }}
|
||||
<sub class="subscript">Produktion</sub>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Location} from '../Location';
|
||||
import {DateService} from '../../date.service';
|
||||
import {ConfigService} from '../../config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-location-power',
|
||||
@ -15,6 +16,7 @@ export class LocationPower {
|
||||
|
||||
constructor(
|
||||
readonly dateService: DateService,
|
||||
readonly configService: ConfigService,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
<div
|
||||
class="container NoUserSelect"
|
||||
[ngClass]="classes()"
|
||||
(mouseenter)="showPen = true"
|
||||
(mouseleave)="showPen = false"
|
||||
>
|
||||
<select [(ngModel)]="model" (ngModelChange)="changed($event)">
|
||||
<option [ngValue]="null">-</option>
|
||||
@for (location of locations; track location.id) {
|
||||
<option [ngValue]="location.id">
|
||||
{{ location.name }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
@if (showPen) {
|
||||
<fa-icon [icon]="faPen"></fa-icon>
|
||||
}
|
||||
</div>
|
||||
@ -0,0 +1,25 @@
|
||||
.container {
|
||||
display: flex;
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
background-color: #0002;
|
||||
}
|
||||
|
||||
select {
|
||||
all: unset;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
background-color: red !important;
|
||||
}
|
||||
|
||||
.changed {
|
||||
background-color: yellow !important;
|
||||
}
|
||||
80
src/main/angular/src/app/location/select/location-select.ts
Normal file
80
src/main/angular/src/app/location/select/location-select.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||
import {FaIconComponent} from '@fortawesome/angular-fontawesome';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {NgClass} from '@angular/common';
|
||||
import {faPen} from '@fortawesome/free-solid-svg-icons';
|
||||
import {Location} from '../Location';
|
||||
import {LocationService} from '../location-service';
|
||||
import {DateService} from '../../date.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-location-select',
|
||||
imports: [
|
||||
FaIconComponent,
|
||||
FormsModule,
|
||||
NgClass
|
||||
],
|
||||
templateUrl: './location-select.html',
|
||||
styleUrl: './location-select.less',
|
||||
})
|
||||
export class LocationSelect implements OnInit {
|
||||
|
||||
protected readonly faPen = faPen;
|
||||
|
||||
private _initial: number | null = null;
|
||||
|
||||
@Input()
|
||||
locations!: Location[];
|
||||
|
||||
@Input()
|
||||
allowEmpty: boolean = true;
|
||||
|
||||
@Input()
|
||||
filter: (location: Location) => boolean = () => true;
|
||||
|
||||
@Output()
|
||||
readonly onChange = new EventEmitter<number | null>();
|
||||
|
||||
protected showPen: boolean = false;
|
||||
|
||||
protected model: number | null = null;
|
||||
|
||||
protected readonly Location = Location;
|
||||
|
||||
constructor(
|
||||
readonly locationService: LocationService,
|
||||
readonly dateService: DateService,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.locationService.findAll(list => this.locations = list);
|
||||
}
|
||||
|
||||
@Input()
|
||||
set initial(value: number | null) {
|
||||
this._initial = value;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
private readonly reset = (): void => {
|
||||
this.model = this._initial;
|
||||
};
|
||||
|
||||
protected classes(): {} {
|
||||
return {
|
||||
"changed": this.model !== this._initial,
|
||||
"invalid": !this.allowEmpty && this.model === null,
|
||||
};
|
||||
}
|
||||
|
||||
protected changed(id: number | null) {
|
||||
if (this.allowEmpty || id !== null) {
|
||||
this.onChange.emit(id);
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -16,10 +16,6 @@ select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.unchanged {
|
||||
background-color: lightgreen !important;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
background-color: red !important;
|
||||
}
|
||||
|
||||
@ -78,7 +78,6 @@ export class SeriesSelect implements OnInit, OnDestroy {
|
||||
|
||||
protected classes(): {} {
|
||||
return {
|
||||
"unchanged": this.model === this._initial,
|
||||
"changed": this.model !== or(this._initial, i => i.id, null),
|
||||
"invalid": !this.allowEmpty && this.model === null,
|
||||
};
|
||||
|
||||
32
src/main/angular/src/app/settings/settings-component.html
Normal file
32
src/main/angular/src/app/settings/settings-component.html
Normal file
@ -0,0 +1,32 @@
|
||||
<div class="Section3">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Favorit
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<app-location-select [initial]="configService.locationId" (onChange)="configService.locationId = $event"></app-location-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="Section3">
|
||||
<div class="SectionHeading">
|
||||
<div class="SectionHeadingText">
|
||||
Anzeige
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" #checkbox [checked]="configService.energyPercent" (change)="configService.energyPercent = checkbox.checked">
|
||||
Energie Prozentsätze
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" #checkbox [checked]="configService.locationConfig" (change)="configService.locationConfig = checkbox.checked">
|
||||
Ort Konfiguration
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
30
src/main/angular/src/app/settings/settings-component.ts
Normal file
30
src/main/angular/src/app/settings/settings-component.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {LocationSelect} from '../location/select/location-select';
|
||||
import {LocationService} from '../location/location-service';
|
||||
import {Location} from '../location/Location'
|
||||
import {ConfigService} from '../config.service';
|
||||
import {config} from 'rxjs';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-component',
|
||||
imports: [
|
||||
LocationSelect,
|
||||
FormsModule
|
||||
],
|
||||
templateUrl: './settings-component.html',
|
||||
styleUrl: './settings-component.less',
|
||||
})
|
||||
export class SettingsComponent {
|
||||
|
||||
protected location: Location | null = null;
|
||||
|
||||
constructor(
|
||||
readonly locationService: LocationService,
|
||||
readonly configService: ConfigService,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
protected readonly config = config;
|
||||
}
|
||||
@ -62,7 +62,8 @@ div {
|
||||
}
|
||||
|
||||
.Section3 {
|
||||
border: 1px solid gray;
|
||||
border: 1px solid lightgray;
|
||||
border-radius: 0.25em;
|
||||
margin: 1em 0.5em 0.5em;
|
||||
padding: 0.5em;
|
||||
overflow: visible;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user