diff --git a/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.html b/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.html index e5b79f6..21a4024 100644 --- a/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.html +++ b/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.html @@ -27,18 +27,52 @@ } @else if (userStats(); as stats) { -
-
-

Meine Zählpunkte

-

{{ stats.totalMeteringPoints }}

-
-
-

Aktive Mitgliedschaften

-

{{ stats.activeMemberships }}

-
-
-

Offene Anfragen

-

{{ stats.pendingMemberships }}

+
+
+
+

Meine Zählpunkte

+

{{ stats.totalMeteringPoints }}

+
+
+

Aktive Mitgliedschaften

+

{{ stats.activeMemberships }}

+
+
+

Offene Anfragen

+

{{ stats.pendingMemberships }}

+
+ + @if (meteringData(); as data) { + @if (data.meteringPoints.length > 0) { +
+
+

Verbrauch & Erzeugung

+
+ + + +
+
+ @if (chartOptions()) { +
+ } @else { +

Keine Daten im ausgewählten Zeitraum vorhanden.

+ } +
+ } + }
} diff --git a/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.ts b/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.ts index c6b50fe..f1958cb 100644 --- a/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.ts +++ b/eeg_frontend/src/app/pages/dashboard-overview/dashboard-overview.ts @@ -1,10 +1,12 @@ import {Component, inject, OnInit, signal} from '@angular/core'; +import {NgxEchartsDirective} from 'ngx-echarts'; import {AuthService} from '../../services/auth'; -import {AdminStats, DashboardService, UserStats} from '../../services/dashboard'; +import {AdminStats, DashboardService, MeteringDataOverview, UserStats} from '../../services/dashboard'; @Component({ selector: 'app-dashboard-overview', standalone: true, + imports: [NgxEchartsDirective], templateUrl: './dashboard-overview.html' }) export class DashboardOverview implements OnInit { @@ -17,6 +19,10 @@ export class DashboardOverview implements OnInit { isLoading = signal(true); error = signal(null); + meteringData = signal(null); + chartOptions = signal(null); + selectedDays = signal(30); + ngOnInit() { if (this.role === 'ADMIN') { this.dashboardService.getAdminStats().subscribe({ @@ -28,7 +34,11 @@ export class DashboardOverview implements OnInit { }); } else { this.dashboardService.getUserStats().subscribe({ - next: stats => { this.userStats.set(stats); this.isLoading.set(false); }, + next: stats => { + this.userStats.set(stats); + this.isLoading.set(false); + this.loadMeteringData(); + }, error: () => { this.isLoading.set(false); this.error.set('Fehler beim Laden der Statistiken.'); @@ -36,4 +46,72 @@ export class DashboardOverview implements OnInit { }); } } + + setRange(days: number) { + this.selectedDays.set(days); + this.loadMeteringData(); + } + + private loadMeteringData() { + const to = new Date(); + const from = new Date(); + from.setDate(from.getDate() - this.selectedDays()); + + const fromStr = from.toISOString(); + const toStr = to.toISOString(); + + this.dashboardService.getMeteringDataOverview(fromStr, toStr).subscribe({ + next: (data) => { + this.meteringData.set(data); + this.buildChartOptions(data); + }, + error: () => {} + }); + } + + private buildChartOptions(data: MeteringDataOverview) { + if (!data || data.timeSeries.length === 0) { + this.chartOptions.set(null); + return; + } + + const dates = data.timeSeries.map(e => { + const d = new Date(e.timestamp); + return d.toLocaleDateString('de-AT', {day: '2-digit', month: '2-digit'}); + }); + + const series = data.meteringPoints.map(mp => ({ + name: `${mp.atNumber.slice(-8)} (${mp.type})`, + type: 'bar' as const, + stack: 'total', + data: data.timeSeries.map(e => e.values[mp.atNumber] || 0), + itemStyle: {color: mp.type === 'CONSUMER' ? '#3b82f6' : '#22c55e'} + })); + + this.chartOptions.set({ + tooltip: { + trigger: 'axis', + formatter: (params: any[]) => { + const label = params[0]?.axisValue || ''; + let html = `${label}
`; + params.forEach((p: any) => { + html += `${p.marker} ${p.seriesName}: ${p.value?.toFixed(2)} kWh
`; + }); + return html; + } + }, + legend: { + data: series.map(s => s.name), + top: 0 + }, + grid: {left: '3%', right: '4%', bottom: '3%', containLabel: true}, + xAxis: { + type: 'category', + data: dates, + axisLabel: {rotate: dates.length > 15 ? 45 : 0} + }, + yAxis: {type: 'value', name: 'kWh'}, + series + }); + } } diff --git a/eeg_frontend/src/app/services/auth.ts b/eeg_frontend/src/app/services/auth.ts index ab8965d..e7af2ce 100644 --- a/eeg_frontend/src/app/services/auth.ts +++ b/eeg_frontend/src/app/services/auth.ts @@ -42,4 +42,15 @@ export class AuthService { localStorage.clear(); this.isLoggedInSubject.next(false); } + + getCurrentUserId(): string | null { + const token = localStorage.getItem('token'); + if (!token) return null; + try { + const payload = JSON.parse(atob(token.split('.')[1])); + return payload.userId || null; + } catch { + return null; + } + } } diff --git a/eeg_frontend/src/app/services/dashboard.ts b/eeg_frontend/src/app/services/dashboard.ts index 8243de9..9be8661 100644 --- a/eeg_frontend/src/app/services/dashboard.ts +++ b/eeg_frontend/src/app/services/dashboard.ts @@ -1,5 +1,5 @@ import {inject, Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; +import {HttpClient, HttpParams} from '@angular/common/http'; import {Observable} from 'rxjs'; import {environment} from '../../environments/environment'; @@ -16,6 +16,23 @@ export interface UserStats { pendingMemberships: number; } +export interface MeteringPointSummary { + id: string; + atNumber: string; + type: string; + totalKwh: number; +} + +export interface TimeSeriesEntry { + timestamp: string; + values: { [atNumber: string]: number }; +} + +export interface MeteringDataOverview { + meteringPoints: MeteringPointSummary[]; + timeSeries: TimeSeriesEntry[]; +} + @Injectable({providedIn: 'root'}) export class DashboardService { private http = inject(HttpClient); @@ -28,4 +45,11 @@ export class DashboardService { getUserStats(): Observable { return this.http.get(`${this.apiUrl}/user`); } + + getMeteringDataOverview(from: string, to: string): Observable { + const params = new HttpParams() + .set('from', from) + .set('to', to); + return this.http.get(`${this.apiUrl}/user/metering-data/overview`, {params}); + } }