| @@ -298,12 +298,12 @@ Serverseitige Logik: `ReportController` ermittelt via `TimeEntryRepository::find | |||
| ## Statistiken | |||
| Arbeitszeit-Statistik als gestapeltes Balkendiagramm (Chart.js), erreichbar über den Statistik-Button im Report-Header. Tab-Navigation zwischen „Zeiten" und „Statistiken". | |||
| Arbeitszeit-Statistik als gestapeltes Balkendiagramm (Chart.js) + drei Donut-Charts (Kunden, Projekte, Leistungen), erreichbar über den Statistik-Button im Report-Header. Tab-Navigation zwischen „Zeiten" und „Statistiken". | |||
| ### Architektur | |||
| - **Backend**: `ReportController::statistics()` (Seite) + `ReportController::statisticsData()` (API) | |||
| - **Frontend**: `assets/scripts/statistics.js` (eigener Webpack-Entry), nutzt Chart.js (tree-shaked: nur `BarController`, `BarElement`, `CategoryScale`, `LinearScale`, `Tooltip`) | |||
| - **Frontend**: `assets/scripts/statistics.js` (eigener Webpack-Entry), nutzt Chart.js (tree-shaked: `BarController`, `BarElement`, `DoughnutController`, `ArcElement`, `CategoryScale`, `LinearScale`, `Tooltip`) | |||
| - **Styles**: `assets/styles/sections/_statistics.scss` | |||
| - **Template**: `templates/report/statistics.html.twig` | |||
| @@ -313,23 +313,30 @@ Arbeitszeit-Statistik als gestapeltes Balkendiagramm (Chart.js), erreichbar übe | |||
| |--------------------|--------|-------------------------------------------------------| | |||
| | `/api/statistics` | GET | Aggregierte Zeitdaten: `?range={12months|6months|4weeks}&userId={id}` | | |||
| Rückgabe enthält zwei Bereiche: | |||
| - **Balkendiagramm**: `labels`, `billable`, `nonBillable`, `billableRevenue`, `nonBillableRevenue`, `groupBy` | |||
| - **Verteilung**: `distribution.clients`, `distribution.projects`, `distribution.services` — jeweils Arrays mit `{name, hours, revenue}` | |||
| ### Daten-Aggregation | |||
| `TimeEntryRepository::getStatisticsData()` aggregiert Zeiteinträge in Buckets: | |||
| **Balkendiagramm** — `TimeEntryRepository::getStatisticsData()` aggregiert Zeiteinträge in Buckets: | |||
| - **12months**: Monats-Buckets (`Y-m`), letztes Jahr | |||
| - **6months**: Wochen-Buckets (`o-W`), letztes halbes Jahr | |||
| - **4weeks**: Tages-Buckets (`Y-m-d`), letzte 4 Wochen | |||
| Rückgabe: `labels`, `billable`, `nonBillable`, `billableRevenue`, `nonBillableRevenue`, `groupBy`. Billable/Non-Billable Trennung via `Service.billable`. Revenue-Berechnung nutzt die Stundensatz-Kaskade. | |||
| Billable/Non-Billable Trennung via `Service.billable`. Revenue-Berechnung nutzt die Stundensatz-Kaskade. | |||
| **Donut-Charts** — `TimeEntryRepository::getDistributionData()` aggregiert für denselben Zeitraum/User nach Kunden, Projekten und Leistungen (jeweils `SUM(duration)` und `SUM(rate * duration / 60)`). Einträge < 5% werden clientseitig zu „Rest" zusammengefasst. | |||
| ### Frontend-Features | |||
| - **Metrik-Umschalter**: Stunden oder Umsatz (clientseitig, kein neuer API-Call) | |||
| - **Metrik-Umschalter**: Stunden oder Umsatz — gilt für Bar-Chart und Donuts (clientseitig, kein neuer API-Call) | |||
| - **User-Filter**: Admins/Members können nach einzelnem User filtern oder alle sehen (Account-Name als „Alle") | |||
| - **Tracker**: sieht nur eigene Daten (serverseitig erzwungen) | |||
| - **Tages-Ansicht**: Alternierende Wochen-Bänder als visuelle Hilfe (Custom Chart.js Plugin `weekBands`) | |||
| - **Tooltip**: Zeigt formatierte Stunden (`h:mm`) oder Umsatz (`€`) je nach Metrik | |||
| - **Brand-Farbe**: Billable-Balken nutzen `--color-primary`, Non-Billable grau | |||
| - **Donut-Charts**: Drei nebeneinander (3-Spalten-Grid, responsive 1-Spalte), eigene Legende mit Farb-Dot, Name, Wert und Prozent. 8-Farben-Palette, „Rest" in Grau | |||
| ## TenantConnectionMiddleware | |||