- Notenschlüssel-Editor im ExamDialog: Stufen (Note/Prozentgrenze) bearbeitbar, Vorbelegung passend zum GradingSystem der Gruppe, Live-Anzeige der absoluten Punktegrenze je Stufe, Validierung (lückenlos, keine Dopplungen) über GradingService.ValidateGradingKey. - Neues Modell GradingKeyTemplate + Repository: Notenschlüssel als Vorlage speichern/anwenden, direkt aus dem ExamDialog heraus. - Einstellungen: Fächer / Kompetenzen / Notenschlüssel-Vorlagen sind jetzt eigene Tabs statt einer gemeinsam wachsenden Liste. Vorlagen zeigen nur noch eine kompakte Zeile; die Stufen-Bearbeitung läuft über ein Popup-Fenster (GradingKeyTemplateDialog). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
68 lines
2.9 KiB
C#
68 lines
2.9 KiB
C#
using LehrerApp.Core.Models;
|
|
|
|
namespace LehrerApp.Core.Services;
|
|
|
|
public class GradingService
|
|
{
|
|
public string CalculateGrade(double achieved, double maximum, List<GradingKeyEntry> key)
|
|
{
|
|
if (maximum <= 0) return "-";
|
|
var percent = achieved / maximum * 100.0;
|
|
return key.OrderByDescending(k => k.MinPercent)
|
|
.FirstOrDefault(k => percent >= k.MinPercent)
|
|
?.Grade ?? key.OrderBy(k => k.MinPercent).First().Grade;
|
|
}
|
|
public static List<GradingKeyEntry> DefaultKey1To6() =>
|
|
[
|
|
new() { Grade = "1", MinPercent = 87.5 },
|
|
new() { Grade = "2", MinPercent = 75.0 },
|
|
new() { Grade = "3", MinPercent = 62.5 },
|
|
new() { Grade = "4", MinPercent = 50.0 },
|
|
new() { Grade = "5", MinPercent = 25.0 },
|
|
new() { Grade = "6", MinPercent = 0.0 },
|
|
];
|
|
public static List<GradingKeyEntry> DefaultKey0To15() =>
|
|
[
|
|
new() { Grade = "15", MinPercent = 95.0 },
|
|
new() { Grade = "14", MinPercent = 90.0 },
|
|
new() { Grade = "13", MinPercent = 85.0 },
|
|
new() { Grade = "12", MinPercent = 80.0 },
|
|
new() { Grade = "11", MinPercent = 75.0 },
|
|
new() { Grade = "10", MinPercent = 70.0 },
|
|
new() { Grade = "9", MinPercent = 65.0 },
|
|
new() { Grade = "8", MinPercent = 60.0 },
|
|
new() { Grade = "7", MinPercent = 55.0 },
|
|
new() { Grade = "6", MinPercent = 50.0 },
|
|
new() { Grade = "5", MinPercent = 45.0 },
|
|
new() { Grade = "4", MinPercent = 40.0 },
|
|
new() { Grade = "3", MinPercent = 33.0 },
|
|
new() { Grade = "2", MinPercent = 27.0 },
|
|
new() { Grade = "1", MinPercent = 20.0 },
|
|
new() { Grade = "0", MinPercent = 0.0 },
|
|
];
|
|
public string? ValidateGradingKey(List<GradingKeyEntry> entries)
|
|
{
|
|
if (entries.Count < 2) return "Der Notenschlüssel braucht mindestens zwei Stufen.";
|
|
if (entries.Any(e => string.IsNullOrWhiteSpace(e.Grade)))
|
|
return "Jede Stufe braucht eine Bezeichnung.";
|
|
if (entries.Any(e => e.MinPercent < 0 || e.MinPercent > 100))
|
|
return "Prozentgrenzen müssen zwischen 0 und 100 liegen.";
|
|
var sorted = entries.OrderByDescending(e => e.MinPercent).ToList();
|
|
if (sorted.Select(e => e.MinPercent).Distinct().Count() != sorted.Count)
|
|
return "Prozentgrenzen dürfen sich nicht doppeln.";
|
|
if (sorted.Last().MinPercent != 0)
|
|
return "Die unterste Stufe muss bei 0 % liegen (lückenlose Abdeckung).";
|
|
return null;
|
|
}
|
|
|
|
public double WeightedAverage(List<(string Grade, double Weight)> grades)
|
|
{
|
|
var numeric = grades
|
|
.Select(g => (Value: int.TryParse(g.Grade, out var n) ? (int?)n : null, g.Weight))
|
|
.Where(g => g.Value.HasValue).ToList();
|
|
if (numeric.Count == 0) return 0;
|
|
var total = numeric.Sum(g => g.Weight);
|
|
return total == 0 ? 0 : numeric.Sum(g => g.Value!.Value * g.Weight) / total;
|
|
}
|
|
}
|