Persönliche Klausurlast pro Woche, Mitarbeit-Reset und Sitzplan-Strichliste
CI / build-and-test (push) Canceled after 0s

- Klausuren: neuer ExamWeekLoadService zählt eigene Klausuren je ISO-Woche
  über alle Kurse hinweg (Klassen-Kollisionen deckt bereits der externe
  Klausurplaner ab). Hinweis direkt im ExamDialog beim Datum, zusätzlich
  neue Dashboard-Karte "Klausurwochen" für die 60-Tage-Vorausschau.
- Mitarbeit: Schnelleingabe-Dialog kann eine Bewertung jetzt per Entf auf
  "nicht bewertet" zurücksetzen (bisher nur im Sitzplatz-Dialog möglich).
- Sitzplan: Strichliste "gemeldet"/"gemeldet und drangekommen" direkt auf
  der Sitzplatz-Kachel (ParticipationEntry.RaisedHandCount/CalledOnCount);
  schlägt im Sitzplatz-Dialog eine Quantitätsbewertung vor (ein Klick zum
  Übernehmen, nie automatisch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-30 02:11:20 +02:00
co-authored by Claude Sonnet 5
parent 538ad65a3a
commit da4b88c93d
19 changed files with 640 additions and 8 deletions
@@ -50,6 +50,10 @@ public partial class DashboardViewModel : ObservableObject
/// hat rein rechnerisch schon 100 %, das ist noch kein auffälliges Muster, nur eine zu kleine
/// Stichprobe. Dieselbe Konstante wie GroupOverviewViewModel.AttendanceMinSampleSize.
private const int AttendanceMinSampleSize = 8;
/// Vorausschau für die Klausurwochen-Karte (Nutzer-Feedback): weit genug, um eine sich
/// anbahnende Häufung noch rechtzeitig vor dem Anlegen weiterer Klausuren zu zeigen, aber
/// keine Vorschau auf das ganze Schuljahr.
private const int ExamLoadLookaheadDays = 60;
[ObservableProperty] private string _greeting = "";
[ObservableProperty] private string _currentDate = "";
@@ -72,6 +76,7 @@ public partial class DashboardViewModel : ObservableObject
public ObservableCollection<CalendarDayCell> CalendarDays { get; } = [];
public ObservableCollection<OpenExcuseItem> OpenExcuses { get; } = [];
public ObservableCollection<AttendanceWarningItem> AttendanceWarnings { get; } = [];
public ObservableCollection<ExamWeekLoadItem> ExamWeekLoads { get; } = [];
public ObservableCollection<SupportPlanDueItem> SupportPlanReviews { get; } = [];
public ObservableCollection<UpcomingDateItem> UpcomingDates { get; } = [];
public ObservableCollection<CorrectionProgressItem> OpenCorrections { get; } = [];
@@ -106,6 +111,7 @@ public partial class DashboardViewModel : ObservableObject
public DashboardCardOption UnplannedCard => Card("unplanned");
public DashboardCardOption AlertsCard => Card("alerts");
public DashboardCardOption AttendanceCard => Card("attendance");
public DashboardCardOption ExamLoadCard => Card("examload");
public DashboardCardOption SupportCard => Card("support");
public DashboardCardOption GroupsCard => Card("groups");
public int TodayLessonCount => TodaysLessons.Count;
@@ -209,6 +215,7 @@ public partial class DashboardViewModel : ObservableObject
LoadCalendar();
LoadOpenExcuses(groups.Values.ToList(), today);
LoadAttendanceWarnings(today);
LoadExamWeekLoads(groups, today);
LoadSupportPlanReviews(today);
LoadUpcomingDates(groups, today);
LoadOpenCorrections(groups, today);
@@ -228,6 +235,7 @@ public partial class DashboardViewModel : ObservableObject
UnplannedCard.IsEmpty = UnplannedLessons.Count == 0;
AlertsCard.IsEmpty = Alerts.Count == 0;
AttendanceCard.IsEmpty = AttendanceWarnings.Count == 0;
ExamLoadCard.IsEmpty = ExamWeekLoads.Count == 0;
SupportCard.IsEmpty = SupportPlanReviews.Count == 0;
GroupsCard.IsEmpty = CurrentGroups.Count == 0;
@@ -322,6 +330,27 @@ public partial class DashboardViewModel : ObservableObject
AttendanceWarnings.Add(item);
}
// ── Klausurwochen (Nutzer-Feedback) ───────────────────────────────────────
//
// Persönliche Klausurlast über alle Kurse hinweg — anders als die klassenbezogene
// Kollisionsprüfung, die bereits der schulische Klausurplaner übernimmt (siehe
// ExamWeekLoadService). Nur geplante, noch bevorstehende Klausuren zählen: die
// Vorausschau soll helfen, eine sich anbahnende Woche zu erkennen, bevor man eine weitere
// Klausur genau dort einträgt — bereits durchgeführte/korrigierte Klausuren werden schon
// von der Karte "Offene Korrekturen" abgedeckt.
private void LoadExamWeekLoads(IReadOnlyDictionary<Guid, LearningGroup> groups, DateOnly today)
{
ExamWeekLoads.Clear();
var lastDay = today.AddDays(ExamLoadLookaheadDays);
var upcoming = groups.Keys
.SelectMany(gid => _exams.GetByGroup(gid))
.Where(e => e.Status == ExamStatus.Planned && e.Date >= today && e.Date <= lastDay);
foreach (var week in ExamWeekLoadService.FindOverloadedWeeks(upcoming))
ExamWeekLoads.Add(new ExamWeekLoadItem(week.IsoWeek, week.WeekStart, week.WeekEnd, week.ExamCount));
}
// ── Förderplan-Wiedervorlage (5.3.2) ──────────────────────────────────────
private void LoadSupportPlanReviews(DateOnly today)
@@ -547,7 +576,7 @@ public partial class DashboardViewModel : ObservableObject
"excuses" => "Offene Entschuldigungen", "upcoming" => "Anstehende Termine",
"corrections" => "Offene Korrekturen", "unplanned" => "Ungeplante Stunden", "alerts" => "Auffälligkeiten",
"attendance" => "Fehlzeiten-Warnung", "support" => "Förderplan-Wiedervorlage",
"groups" => "Meine Lerngruppen", _ => key,
"groups" => "Meine Lerngruppen", "examload" => "Klausurwochen", _ => key,
};
private void ApplyCardLayout()
@@ -966,6 +995,13 @@ public class AttendanceWarningItem(Guid studentId, string studentName, double ab
public double AbsenceRatePercent { get; } = absenceRatePercent;
}
public class ExamWeekLoadItem(int isoWeek, DateOnly weekStart, DateOnly weekEnd, int examCount)
{
public int ExamCount { get; } = examCount;
public string Label => $"KW {isoWeek} ({weekStart:dd.MM.}{weekEnd:dd.MM.})";
public string CountDisplay => ExamCount == 1 ? "1 Klausur" : $"{ExamCount} Klausuren";
}
// ── Förderplan-Wiedervorlage (5.3.2) ──────────────────────────────────────────
public class SupportPlanDueItem