feat: Pädagogische Klassen-Aufgaben, Prioritäten/Checklisten, Dashboard-Schnellzugriffe

Neue Aufgabenart über bestehende Felder (WorkTask.Kind=Reminder + GroupId) statt Vererbung,
mit Priorität (TaskPriority) und optionaler Abhak-Liste (ChecklistItems, wahlweise Kurs-
Roster oder Freitext). Kurs-Dashboard zeigt jetzt eine "Anstehende Aufgaben"-Karte samt
direktem Anlege-Button; derselbe Anlege-Einstieg wurde auch ins Hauptdashboard und (als
Schnellüberblick samt fehlender Übersicht/Mitarbeit-Buttons) in die Gruppenliste gezogen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 22:24:38 +02:00
co-authored by Claude Sonnet 5
parent e7c3fdd4ec
commit e65a729f97
25 changed files with 878 additions and 39 deletions
+73
View File
@@ -1436,6 +1436,79 @@ CSV-Exports der Auswertung (6.3.3) über die gemeinsame Export-Infrastruktur aus
nur tatsächlich erfasste `TimeEntry`-Zeilen auswertet, keine `WorkTask`-Metadaten. In der
Aufgabenliste und im Dashboard-Widget "Offene Aufgaben" durch ein 🔔-Symbol gekennzeichnet.
**Nachtrag — Pädagogische Klassen-Aufgaben (Nutzer-Feedback):** Wunsch nach einer zweiten,
"weniger arbeitszeitrelevant als pädagogisch" gedachten Art von Todo-Item (Beispiele:
"Ansage an die Klasse", "Etwas zum Stichtag einsammeln/austeilen"), gleichberechtigt im
Hauptdashboard **und** im jeweiligen Kurs-Dashboard, farblich nach Frist/Priorität absetzbar,
mit optionaler Abhak-Liste.
Nutzervorschlag war eine eigene `TodoItem`-Basisklasse mit `JobTodo`/`KlassenTodo`-Ableitungen
(Vererbung). Dagegen entschieden: In dieser Codebasis mappt jedes Modell 1:1 auf eine eigene
benannte LiteDB-Collection (`LiteDbContext.cs`, keine `BsonMapper.Entity<T>()`-Discriminator-
Registrierung irgendwo im Projekt) — eine polymorphe Collection wäre der erste Fall dieser Art.
Zusätzlich verwendet die Papierkorb-Wiederherstellung (14.3, `LiteDbContext.MoveToTrash`/
`RestoreFromTrash<T>`) einfaches generisches `JsonSerializer.Serialize<T>`/`Deserialize<T>` ohne
Typ-Diskriminierung — polymorphes Round-Tripping bräuchte dort zusätzliche Handhabung. Stattdessen
wird die "Klassen-Aufgabe" rein über bereits vorhandene Felder abgebildet: `WorkTask.Kind ==
TaskKind.Reminder` (6.1.6, dessen Doku-Kommentar bereits "Ansage an die Klasse" als Beispiel
nennt) kombiniert mit dem längst nullable `WorkTask.GroupId`. Kein neues Modell, keine neue
Collection, kein neuer Dialog nötig — `AddEditWorkTaskDialog` konnte eine solche Aufgabe schon
vorher anlegen.
Neu auf `WorkTask`: `Priority` (`TaskPriority`: Low/Normal/High, Default Normal) und
`ChecklistItems` (`List<ChecklistItem>`, je Eintrag `Label`/`IsDone`/optionale `StudentId`).
Nutzervorschlag war "JSON als DB-String", um keine neue Tabelle zu brauchen und den bestehenden
Sync-Unterbau mitzunutzen — LiteDB verschachtelt C#-Listen/Objekte aber bereits nativ in einem
BSON-Dokument, ein JSON-String-Encoding wäre in einer Dokumenten-DB ein Umweg. Da
`WorkTaskRepository.Save` bei jedem Speichern das komplette `WorkTask`-Dokument über
`db.OnChange` an den Sync-Event-Publisher weiterreicht, syncen neue verschachtelte Felder
automatisch mit, ganz ohne Sync-Layer-Änderung — erreicht damit dasselbe Ziel wie der
JSON-String-Vorschlag, nur ohne Encoding-Zwischenschritt.
`ChecklistItems` vereinheitlicht die zwei vom Nutzer genannten Alternativen (Namensliste aller
Kurs-Schüler *oder* freie Teil-Punkte zum Abhaken) in einem Listentyp: `StudentId` ist gesetzt,
wenn ein Eintrag über "Aus Kursliste befüllen" aus der aktiven Kursmitgliedschaft erzeugt wurde
(`WorkTaskListView.LoadActiveRoster`, dieselbe `GroupMembershipService.IsActiveOn`-Prüfung wie
überall sonst), sonst bleibt es leer für frei eingetippte Punkte — beides im selben
`AddEditWorkTaskDialog`-Editor (Checkbox je Zeile, Entfernen-Button, Freitext-Eingabe).
Farbcodierung: `TaskPriorityDisplay` (Label/ColorHex/Options, gleiches Muster wie
`TaskCategoryDisplay`/`TaskRecurrenceDisplay`) — in der Aufgabenliste als linker Farbbalken nur
bei `High` sichtbar (Normal/Low sollen nicht zusätzlich "schreien"), im Hauptdashboard-Widget
"Offene Aufgaben" ebenso; Fälligkeitsfarbe (überfällig = rot) läuft weiterhin über den
bestehenden `Classes.overdue`-Stil.
Neue Karte "Anstehende Aufgaben" im Kurs-Dashboard (`GroupOverviewViewModel.GroupTasks`, über
neues `IWorkTaskRepository.GetByGroup`) — gleiches Karten-Muster wie die übrigen
Übersicht-Karten (`Has…`-Flag, `ObservableCollection`). Der "Zu den Aufgaben"-Link springt anders
als die übrigen Karten-Links nicht auf einen Tab *innerhalb* der Kurs-Detailansicht (die gibt es
für "Aufgaben" nicht), sondern in den eigenständigen Top-Level-Bereich "Arbeitszeit"
(`NavItem.Workload`) — neue `MainWindowViewModel.NavigateToWorkload()`, verdrahtet in
`GroupDetailView.axaml.cs` über `App.Services`, gleiches Delegate-Muster wie
`LessonViewerDialog`/`TeachingModeWindow` (View-Code-Behind statt ViewModel-zu-ViewModel-Referenz).
**Nachtrag — Direkter Anlege-Einstieg + Schnellüberblick in der Gruppenliste (Folge-Feedback):**
Die "Anstehende Aufgaben"-Karte im Kurs-Dashboard und die "Offene Aufgaben"-Kachel im
Hauptdashboard waren zunächst rein lesend — Anlegen ging nur über den Umweg
"Arbeitszeit". Beide Stellen haben jetzt einen ""-Button, der denselben
`AddEditWorkTaskDialog` öffnet wie die Aufgabenliste selbst (im Kurs-Dashboard mit der
aktuellen Gruppe vorbelegt). Damit das nicht zu drei fast identischen Kopien der
Gruppenlisten-/Kursliste-Ladelogik führt, wurde die Dialog-Öffnung in
`WorkTaskDialogHelper.ShowDialog` (`LehrerApp.Desktop/Views/Workload/`) extrahiert und wird von
`WorkTaskListView`, `GroupDetailView` (`GroupOverviewViewModel.OnAddGroupTask`) und
`DashboardView` (`DashboardViewModel.OnAddTask`) gemeinsam genutzt — gleiches
View-Code-Behind-Delegate-Muster wie überall sonst in dieser Schicht.
Bei der Gelegenheit auch das Auswahl-Panel der Gruppenliste (`GroupListView`) nachgezogen: Beim
Anwählen eines Kurses erschien bisher nur eine reine Sprung-Buttonliste ("BEREICHE") ohne jede
Kennzahl, und der Button für Tab 0 (Übersicht/Kurs-Dashboard, die oben gebaute Karten-Ansicht)
sowie Tab 3 (Mitarbeit) fehlten dort komplett — beide Tabs waren aus diesem Panel gar nicht
erreichbar. Ergänzt: ein "SCHNELLÜBERBLICK"-Block oberhalb der Buttonliste
(`GroupListViewModel.LoadQuickInfo`) mit nächster geplanter Stunde, nächster Klausur und den
(max. 3) nächsten offenen Aufgaben dieser Gruppe — bewusst dieselbe kompakte Auswertung wie die
obersten Karten des Kurs-Dashboards, hier nur ohne eigenen Tab-Wechsel. Sowie die beiden
fehlenden Buttons "📊 Übersicht" (Tab 0) und "✋ Mitarbeit" (Tab 3).
### 6.2 Zeiterfassung
- [x] **6.2.1** Timer starten/stoppen mit Zuordnung zu Aufgabe oder Kategorie —
`TimeTrackingViewModel`. Bewusst ohne live mitlaufende Sekundenanzeige (keine