mirror of
https://github.com/complexcaresolutions/dak.c2s.git
synced 2026-03-17 18:23:42 +00:00
- Backend: GET /reports/{id}/data endpoint returns stored report JSON
- Frontend: ReportViewer component renders all 5 Excel sheets as tabs
(KW gesamt, Fachgebiete, Gutachten, Therapieänderungen, ICD onko)
- ReportsPage: clickable rows with inline expansion to view reports
- Empty KW rows filtered, summary row at bottom, German labels
- Download button still available alongside inline view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
202 lines
6 KiB
Markdown
202 lines
6 KiB
Markdown
# Report Viewer (Inline-Expansion) Implementation Plan
|
|
|
|
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** Berichte in der Berichteseite als Inline-Expansion mit 5 Tabs (wie Excel-Sheets) anzeigen, statt nur als Download.
|
|
|
|
**Architecture:** Neuer Backend-Endpoint `GET /reports/{id}/data` liefert gespeichertes `report_data`-JSON. Frontend rendert mit Inline-Expansion und 5-Tab-Viewer-Komponente. Daten bereits in DB vorhanden, kein Neuberechnen nötig.
|
|
|
|
**Tech Stack:** FastAPI, SQLAlchemy, React 19, TanStack Query v5, shadcn/ui (Tabs, Table), Tailwind CSS 4
|
|
|
|
---
|
|
|
|
### Task 1: Backend — `GET /reports/{id}/data` Endpoint
|
|
|
|
**Files:**
|
|
- Modify: `backend/app/api/reports.py` (nach dem `/download/{report_id}` Endpoint, ca. Zeile 211)
|
|
|
|
**Step 1: Endpoint implementieren**
|
|
|
|
In `backend/app/api/reports.py` nach dem `download_report`-Endpoint einfügen:
|
|
|
|
```python
|
|
@router.get("/{report_id}/data")
|
|
def get_report_data(
|
|
report_id: int,
|
|
db: Session = Depends(get_db),
|
|
user: User = Depends(get_current_user),
|
|
):
|
|
"""Return the stored report_data JSON for a given report.
|
|
|
|
Accessible to both admin and dak_mitarbeiter users.
|
|
"""
|
|
report = db.query(WeeklyReport).filter(WeeklyReport.id == report_id).first()
|
|
if not report:
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, "Report not found")
|
|
if not report.report_data:
|
|
raise HTTPException(status.HTTP_404_NOT_FOUND, "Report data not available")
|
|
return report.report_data
|
|
```
|
|
|
|
**WICHTIG:** Dieser Endpoint MUSS vor dem bestehenden `@router.delete("/delete")` und `@router.get("/list")` stehen — aber er hat den Pfad `/{report_id}/data` mit einem Path-Parameter. Da FastAPI Routen in der Reihenfolge prüft, und `/list` und `/delete` statisch sind (und vor `/{report_id}` definiert sind), gibt es kein Routing-Konflikt. Einfach nach `download_report` (Zeile ~211) einfügen.
|
|
|
|
**Step 2: Testen**
|
|
|
|
Manuell (oder cURL): `curl -H "Authorization: Bearer <token>" http://localhost:8000/api/reports/1/data`
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add backend/app/api/reports.py
|
|
git commit -m "feat: add GET /reports/{id}/data endpoint for report viewer"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 2: Frontend — `useReportData` Hook
|
|
|
|
**Files:**
|
|
- Modify: `frontend/src/hooks/useReports.ts`
|
|
|
|
**Step 1: Hook hinzufügen**
|
|
|
|
Am Ende von `frontend/src/hooks/useReports.ts` einfügen:
|
|
|
|
```typescript
|
|
export function useReportData(reportId: number | null) {
|
|
return useQuery({
|
|
queryKey: ['report-data', reportId],
|
|
queryFn: () =>
|
|
api.get<Record<string, unknown>>(`/reports/${reportId}/data`).then(r => r.data),
|
|
enabled: reportId !== null,
|
|
})
|
|
}
|
|
```
|
|
|
|
**Step 2: Build prüfen**
|
|
|
|
```bash
|
|
cd frontend && pnpm build
|
|
```
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add frontend/src/hooks/useReports.ts
|
|
git commit -m "feat: add useReportData hook for fetching report JSON"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 3: Frontend — ReportViewer-Komponente
|
|
|
|
**Files:**
|
|
- Create: `frontend/src/components/ReportViewer.tsx`
|
|
|
|
**Step 1: Komponente erstellen**
|
|
|
|
Die Komponente empfängt `data: Record<string, unknown>` (das `report_data`-JSON) und rendert 5 Tabs.
|
|
|
|
Datenstruktur (aus `report_service.py`):
|
|
- `data.sheet1` → `{ summary: {...}, weekly: [{kw, erstberatungen, unterlagen, ablehnungen, keine_rm, gutachten}, ...] }`
|
|
- `data.sheet2` → `{ weekly: [{kw, onko: {anzahl, gutachten, keine_rm}, kardio: {...}, ...}, ...] }`
|
|
- `data.sheet3` → `{ weekly: [{kw, gesamt: {gutachten, alternative, bestaetigung}, onko: {...}, ...}, ...] }`
|
|
- `data.sheet4` → `{ weekly: [{kw, gutachten, ta_ja, ta_nein, diagnosekorrektur, unterversorgung, uebertherapie}, ...] }`
|
|
- `data.sheet5` → `{ icd_codes: [{icd, count}, ...] }`
|
|
|
|
Implementiere die Komponente mit:
|
|
- shadcn/ui `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`
|
|
- shadcn/ui `Table`, `TableHeader`, `TableRow`, `TableHead`, `TableBody`, `TableCell`
|
|
- Leere KW-Zeilen (alle Werte 0) ausfiltern
|
|
- Summenzeile am Ende (fett)
|
|
- Deutsche Spalten-Header
|
|
- Fallgruppen-Labels: `{ onko: 'Onkologie', kardio: 'Kardiologie', intensiv: 'Intensivmedizin', galle: 'Gallenblase', sd: 'Schilddrüse' }`
|
|
|
|
Sheet 2 und 3 haben verschachtelte Spalten (pro Fallgruppe). Nutze grouped headers mit `colSpan`.
|
|
|
|
**Step 2: Build prüfen**
|
|
|
|
```bash
|
|
pnpm build
|
|
```
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add frontend/src/components/ReportViewer.tsx
|
|
git commit -m "feat: add ReportViewer component with 5-tab sheet display"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 4: Frontend — ReportsPage mit Inline-Expansion
|
|
|
|
**Files:**
|
|
- Modify: `frontend/src/pages/ReportsPage.tsx`
|
|
|
|
**Step 1: Expansion-State und Klick-Handler**
|
|
|
|
Änderungen:
|
|
1. Import `useReportData` und `ReportViewer`
|
|
2. Neuer State: `const [expandedId, setExpandedId] = useState<number | null>(null)`
|
|
3. `useReportData(expandedId)` aufrufen
|
|
4. Tabellenzeile klickbar machen: `onClick={() => setExpandedId(expandedId === r.id ? null : r.id)}`
|
|
5. Cursor-Pointer auf der Zeile: `className="cursor-pointer hover:bg-muted/50"`
|
|
6. Nach jeder `<TableRow>` eine bedingte Expansion-Zeile:
|
|
|
|
```tsx
|
|
{expandedId === r.id && (
|
|
<TableRow>
|
|
<TableCell colSpan={isAdmin ? 6 : 5} className="p-0">
|
|
{reportDataLoading ? (
|
|
<div className="p-6"><Skeleton className="h-64 w-full" /></div>
|
|
) : reportData ? (
|
|
<div className="p-4 border-t bg-muted/20">
|
|
<ReportViewer data={reportData} />
|
|
</div>
|
|
) : (
|
|
<div className="p-6 text-center text-muted-foreground">
|
|
Keine Berichtsdaten verfügbar.
|
|
</div>
|
|
)}
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
```
|
|
|
|
**Step 2: Build und Tests prüfen**
|
|
|
|
```bash
|
|
pnpm build && pnpm test
|
|
```
|
|
|
|
**Step 3: Commit**
|
|
|
|
```bash
|
|
git add frontend/src/pages/ReportsPage.tsx
|
|
git commit -m "feat: add inline report viewer expansion to ReportsPage"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 5: Verifikation und finaler Commit
|
|
|
|
**Step 1: Build**
|
|
|
|
```bash
|
|
cd /home/frontend/dak_c2s/frontend && pnpm build
|
|
```
|
|
|
|
**Step 2: Tests**
|
|
|
|
```bash
|
|
pnpm test
|
|
```
|
|
|
|
Alle 128+ Tests müssen bestehen.
|
|
|
|
**Step 3: Finaler Commit (falls noch unstaged changes)**
|
|
|
|
```bash
|
|
git add -A && git commit -m "feat: complete report viewer inline expansion"
|
|
```
|