Modulare Startseite: Kartenraster, eigene Anordnung je Benutzer, Auswertungen

Die Uebersicht war fest verdrahtet und fuer alle gleich. Jetzt besteht sie aus
Karten in einem 12-Spalten-Raster, die sich ziehen, in der Groesse aendern und
einrasten lassen (react-grid-layout). "Anordnen" schaltet das frei, gespeichert
wird ausdruecklich - Probieren bleibt folgenlos.

Anordnung:
- Neue Tabelle dashboard_layouts; user_id = NULL ist die Admin-Vorgabe.
- Jeder Benutzer hat seine eigene Anordnung. Admins speichern eine Vorgabe fuer
  alle und koennen sie ueber die Einstellung dashboard_enforced verbindlich
  machen; dann lehnt das Backend das Speichern eigener Anordnungen ab.
- "Auf Vorgabe zuruecksetzen" verwirft die persoenliche Anordnung.

15 Karten (Verzeichnis web/src/dashboard/cards.jsx, neue Karte = ein Eintrag):
Schnellzugriff, Status, Artikelzahl, Artikeleinheiten, Bald ablaufend,
Abgelaufen, Einkaufsliste, letzte Bewegungen sowie sechs Auswertungen
(Ablauf-Ring, Kategorien-Ring, Kategorien nach Zustand, Bestandsverlauf,
Verlauf eines Artikels, Ein-/Auslagerungen).

Diagramme als eigene SVG-Komponenten statt Diagramm-Paket:
- Zustandsfarben (ok/bald/abgelaufen) sind Statusangaben aus den Tokens und
  stehen nie ohne Beschriftung; Kategorien nutzen eine gepruefte Farbreihe in
  fester Ordnung, ab sieben Kategorien wird zu "Andere" gebuendelt.
- Eine Werteachse, duenne Marken, zurueckhaltendes Gitter, Fadenkreuz mit
  Kurzinfo. Hell und Dunkel haben eigene Farbstufen.

Mengen durchgehend in Artikeleinheiten (Glaeser, Packungen, Stueck): Gramm und
Stueck lassen sich nicht addieren, Gebinde schon. Der bisher dreifach
vorhandene Helfer liegt jetzt einmal in services/conversion.py::article_unit.

Der Verlauf wird rueckwaerts vom heutigen Bestand aus den Bewegungen
rekonstruiert. Bekannte Ungenauigkeit, im Code und in der Roadmap vermerkt:
Die Umrechnung nutzt die heutige Packungsgroesse.

Geprueft: "npm run build" laeuft durch. Die neuen pytest-Tests
(backend/tests/test_dashboard.py) konnten hier nicht laufen - auf diesem
Rechner ist kein Python installiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-23 09:48:16 +02:00
parent 4448718d8d
commit 84ce596446
17 changed files with 1940 additions and 115 deletions

View File

@@ -386,3 +386,56 @@ class MovementOut(BaseModel):
class SettingOut(BaseModel):
key: str
value: str
# ---- Startseite ----
class DashboardLayoutIn(BaseModel):
"""Anordnung der Karten. Die Felder entsprechen react-grid-layout."""
layout: list[dict]
class DashboardLayoutOut(BaseModel):
layout: list[dict]
# Woher die Anordnung stammt: eigene, Admin-Vorgabe oder eingebaut.
source: str
# Ist die Vorgabe verbindlich, darf der Benutzer nicht umbauen.
enforced: bool
has_default: bool
class DashboardStats(BaseModel):
products_in_stock: int # Artikel mit Bestand > 0
article_units: float # Summe der Artikeleinheiten
expiring_soon: int # Chargen innerhalb der Warnfrist (nicht abgelaufen)
expired: int # bereits abgelaufene Chargen
shopping_items: int # Produkte + Gruppen unter Mindestbestand
products_total: int
class ExpirySplit(BaseModel):
"""Artikeleinheiten je Ablaufzustand Grundlage für Ring und Säulen."""
ok: float
soon: float
expired: float
no_date: float # Chargen ohne MHD zählen separat, nicht als "ok"
class CategoryShare(BaseModel):
category_id: int | None
name: str
article_units: float
ok: float
soon: float
expired: float
no_date: float
class TimelinePoint(BaseModel):
date: date
article_units: float
class ActivityPoint(BaseModel):
date: date
checked_in: int
checked_out: int