Files
LehrerApp/LehrerApp.Core/Services/ExamPriorityService.cs
T
adminandClaude Sonnet 5 7fbf035cbb Klausuren-Hauptseite: gruppenübergreifende Liste mit Prioritäts-Score statt Datum
Sidebar-Klausuren war bisher ein Placeholder. Neue Seite zeigt alle Klausuren des
Schuljahres sortiert nach abgeleiteter Dringlichkeit (Korrekturfortschritt statt
manuellem Status), mit Detailbereich, Parallelkurs-Umschalter und Notenspiegel.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 01:27:18 +02:00

68 lines
3.2 KiB
C#

using LehrerApp.Core.Models;
namespace LehrerApp.Core.Services;
/// Zählt den Korrekturfortschritt einer Klausur aus den vorhandenen Ergebnissen, statt einen
/// eigenen "Korrektur läuft"-Status pflegen zu müssen — ein `ExamResult` gilt als erledigt, sobald
/// entweder Punkte/Note eingetragen oder der Schüler als abwesend markiert wurde. Von
/// DashboardViewModel (Karte "Offene Korrekturen") und ExamsOverviewViewModel (Klausuren-
/// Hauptseite) gemeinsam genutzt, damit beide Stellen exakt dieselbe Zahl zeigen.
public static class ExamCorrectionCounter
{
public static (int Expected, int Evaluated) Count(Exam exam, List<GroupMembership> groupMemberships,
List<ExamResult> examResults)
{
var expected = groupMemberships.Count(m => GroupMembershipService.IsActiveOn(m, exam.Date));
var evaluated = examResults.Count(r => r.Absent || !string.IsNullOrWhiteSpace(r.Grade) || r.Points.Count > 0);
return (expected, Math.Min(evaluated, expected));
}
}
public enum ExamListStatus { Planned, AwaitingCorrection, CorrectionInProgress, CorrectionStuck, AwaitingReturn, Returned }
public readonly record struct ExamPriorityInfo(ExamListStatus Status, double Score);
/// Ordnet Klausuren für die Klausuren-Hauptseite nach einem unsichtbaren Prioritäts-Score statt
/// nach Datum: unbearbeitete/überfällige Korrekturen oben, erledigte unten. "Korrektur läuft"
/// wird bewusst nicht als eigener, manuell zu pflegender Status abgelegt (siehe
/// `ExamCorrectionCounter`) — bleibt eine Klausur trotzdem lange in Bearbeitung hängen (typischer
/// Grund: ein einzelner nie nachschreibender Schüler), fällt sie nach `StuckAfterDays` aus der
/// dringenden Zone in eine ruhige "hängt fest"-Einstufung, statt dauerhaft oben zu kleben.
public static class ExamPriorityService
{
public const int StuckAfterDays = 21;
private const int CorrectionGraceDays = 3;
public static ExamPriorityInfo Evaluate(Exam exam, int expected, int evaluated, DateOnly today)
{
if (exam.Status == ExamStatus.Returned)
return new ExamPriorityInfo(ExamListStatus.Returned, -100);
if (exam.Status == ExamStatus.Graded)
return new ExamPriorityInfo(ExamListStatus.AwaitingReturn, 300);
if (exam.Status == ExamStatus.Planned)
{
var daysUntil = exam.Date.DayNumber - today.DayNumber;
return new ExamPriorityInfo(ExamListStatus.Planned, Math.Clamp(150 - daysUntil, 20, 150));
}
// Status == Conducted: Korrekturfortschritt entscheidet über die genaue Einstufung.
var daysSince = today.DayNumber - exam.Date.DayNumber;
if (evaluated <= 0)
{
var score = daysSince <= CorrectionGraceDays ? 400 + daysSince * 10 : 600 + daysSince;
return new ExamPriorityInfo(ExamListStatus.AwaitingCorrection, score);
}
if (expected > 0 && evaluated >= expected)
return new ExamPriorityInfo(ExamListStatus.AwaitingReturn, 300);
if (daysSince > StuckAfterDays)
return new ExamPriorityInfo(ExamListStatus.CorrectionStuck, 90);
return new ExamPriorityInfo(ExamListStatus.CorrectionInProgress, 400 + daysSince * 3);
}
}