Backend: - ConsumptionDashboardService: aggregates consumption and community feed-in data with daily/hourly granularity based on date range - Coverage calculation: min(consumption, communityFeedIn) per interval - Ownership check on dashboard endpoint - 6 new aggregate queries in MeteringDataRepository - findActiveMeteringPointIdsByCommunityId in MembershipRepository - 6 unit tests for ConsumptionDashboardService Frontend: - Apache ECharts via ngx-echarts for chart visualization - ConsumptionDashboardComponent with metering point selector, date range picker, quick-range buttons (7/30/90 days) - Chart: blue bars (consumption), green bars (covered), orange line (community feed-in), tooltip with coverage percentage - Summary cards: total consumption, coverage %, feed-in, covered kWh - Warning when user has no community membership - Route /dashboard/consumption (MEMBER only) Tests: 143/143 passing
53 lines
1.3 KiB
TypeScript
53 lines
1.3 KiB
TypeScript
import { inject, Injectable } from '@angular/core';
|
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
import { Observable } from 'rxjs';
|
|
import { environment } from '../../environments/environment';
|
|
|
|
export interface IntervalData {
|
|
timestamp: string;
|
|
consumptionKwh: number;
|
|
communityFeedInKwh: number;
|
|
coveredKwh: number;
|
|
coveragePercent: number;
|
|
}
|
|
|
|
export interface Summary {
|
|
totalConsumptionKwh: number;
|
|
totalCoveredKwh: number;
|
|
totalCommunityFeedInKwh: number;
|
|
averageCoveragePercent: number;
|
|
}
|
|
|
|
export interface ConsumptionDashboardResponse {
|
|
meteringPointId: string;
|
|
atNumber: string;
|
|
energyCommunityId: string | null;
|
|
communityName: string | null;
|
|
from: string;
|
|
to: string;
|
|
granularity: 'DAILY' | 'HOURLY';
|
|
data: IntervalData[];
|
|
summary: Summary;
|
|
}
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class ConsumptionService {
|
|
private http = inject(HttpClient);
|
|
private apiUrl = `${environment.apiUrl}/api/community/consumption`;
|
|
|
|
getDashboard(
|
|
meteringPointId: string,
|
|
from: string,
|
|
to: string
|
|
): Observable<ConsumptionDashboardResponse> {
|
|
const params = new HttpParams()
|
|
.set('from', from)
|
|
.set('to', to);
|
|
|
|
return this.http.get<ConsumptionDashboardResponse>(
|
|
`${this.apiUrl}/${meteringPointId}/dashboard`,
|
|
{ params }
|
|
);
|
|
}
|
|
}
|