From 8cbd4475d7ae6a49f9b09754215d472ceabc6f11 Mon Sep 17 00:00:00 2001 From: Sebastian Hedtrich Date: Tue, 11 Aug 2026 23:16:52 +0200 Subject: [PATCH] =?UTF-8?q?Klausur:=20Fach=20aus=20Lerngruppe=20=C3=BCbern?= =?UTF-8?q?ehmen,=20R=C3=BCckgabedatum=20erfassen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fach kommt jetzt aus der Lerngruppe statt manuell pro Klausur eingegeben zu werden: Fach-Feld im Anlegen-Dialog der Lerngruppe ist nicht mehr auf Typ "Kurs" beschränkt, da eine Gruppe genau ein Fach unterrichtet (bei zwei Fächern legt man zwei Gruppen an). Im Klausur-Dialog ist das Fach dadurch nur noch read-only Kontext statt eines redundanten Eingabefelds. - Neues Feld Exam.ReturnedAt: wird beim Statuswechsel auf "Zurück- gegeben" automatisch mit dem heutigen Datum belegt (und beim Zurücknehmen des Status wieder geleert), ist im Klausur-Dialog aber auch manuell nachträglich korrigierbar. Sichtbar als eigene Spalte im Klausuren-Tab. Co-Authored-By: Claude Sonnet 5 --- LehrerApp.Core/Models/Exam.cs | 1 + .../ViewModels/Groups/ExamViewModels.cs | 24 +++++++++++++++---- .../ViewModels/Groups/GroupViewModels.cs | 8 ++++++- .../Views/Groups/AddGroupDialog.axaml | 5 ++-- .../Views/Groups/ExamDialog.axaml | 13 ++++++---- .../Views/Groups/GroupDetailView.axaml | 1 + 6 files changed, 40 insertions(+), 12 deletions(-) diff --git a/LehrerApp.Core/Models/Exam.cs b/LehrerApp.Core/Models/Exam.cs index df6a77f..918d643 100644 --- a/LehrerApp.Core/Models/Exam.cs +++ b/LehrerApp.Core/Models/Exam.cs @@ -11,6 +11,7 @@ public class Exam public List Tasks { get; set; } = []; public List GradingKey { get; set; } = []; public ExamStatus Status { get; set; } = ExamStatus.Planned; + public DateOnly? ReturnedAt { get; set; } public string? Notes { get; set; } public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; diff --git a/LehrerApp.Desktop/ViewModels/Groups/ExamViewModels.cs b/LehrerApp.Desktop/ViewModels/Groups/ExamViewModels.cs index 58aaf48..2fc06ea 100644 --- a/LehrerApp.Desktop/ViewModels/Groups/ExamViewModels.cs +++ b/LehrerApp.Desktop/ViewModels/Groups/ExamViewModels.cs @@ -19,12 +19,13 @@ public partial class ExamDialogViewModel : ObservableObject private readonly int _gradeLevel; private readonly Exam? _editingExam; private readonly List _gradingKey; + private readonly string _subjectName; [ObservableProperty] private string _title = ""; [ObservableProperty] private string _dateText = DateOnly.FromDateTime(DateTime.Today).ToString("dd.MM.yyyy"); - [ObservableProperty] private string _subject = ""; [ObservableProperty] private int? _examNumber; [ObservableProperty] private string _notes = ""; + [ObservableProperty] private string _returnedAtText = ""; [ObservableProperty] private string _validationMessage = ""; [ObservableProperty] private double _totalPoints; [ObservableProperty] private bool _hasCompetencyCatalog; @@ -40,6 +41,10 @@ public partial class ExamDialogViewModel : ObservableObject public string DialogTitle => _editingExam is null ? "Neue Klausur anlegen" : "Klausur bearbeiten"; public string SaveButtonText => _editingExam is null ? "Anlegen" : "Speichern"; + /// Fach kommt von der Lerngruppe, nicht editierbar (jede Gruppe unterrichtet ein Fach). + public string SubjectDisplay => string.IsNullOrWhiteSpace(_subjectName) + ? "Kein Fach hinterlegt (siehe Lerngruppe)" : $"Fach: {_subjectName}"; + public ExamDialogViewModel(IExamRepository exams, ICompetencyDomainRepository competencyDomains, Guid groupId, Guid? subjectId, int gradeLevel, GradingSystem gradingSystem, string defaultSubjectName, Exam? editingExam, Exam? duplicateSource) @@ -47,6 +52,7 @@ public partial class ExamDialogViewModel : ObservableObject _exams = exams; _competencyDomains = competencyDomains; _groupId = groupId; _subjectId = subjectId; _gradeLevel = gradeLevel; _editingExam = editingExam; + _subjectName = defaultSubjectName; HasCompetencyCatalog = subjectId.HasValue && _competencyDomains.GetBySubjectAndGrade(subjectId.Value, gradeLevel).Count > 0; @@ -59,9 +65,9 @@ public partial class ExamDialogViewModel : ObservableObject DateText = isDuplicate ? DateOnly.FromDateTime(DateTime.Today).ToString("dd.MM.yyyy") : source.Date.ToString("dd.MM.yyyy"); - Subject = source.Subject; ExamNumber = source.ExamNumber; Notes = source.Notes ?? ""; + ReturnedAtText = isDuplicate ? "" : source.ReturnedAt?.ToString("dd.MM.yyyy") ?? ""; _gradingKey = source.GradingKey .Select(k => new GradingKeyEntry { Grade = k.Grade, MinPercent = k.MinPercent }).ToList(); foreach (var t in source.Tasks.OrderBy(t => t.Nr)) @@ -70,7 +76,6 @@ public partial class ExamDialogViewModel : ObservableObject } else { - Subject = defaultSubjectName; _gradingKey = gradingSystem == GradingSystem.Grades1To6 ? GradingService.DefaultKey1To6() : GradingService.DefaultKey0To15(); } @@ -164,13 +169,24 @@ public partial class ExamDialogViewModel : ObservableObject ValidationMessage = "Datum im Format TT.MM.JJJJ eingeben."; return; } + DateOnly? returnedAt = null; + if (!string.IsNullOrWhiteSpace(ReturnedAtText)) + { + if (!DateOnly.TryParseExact(ReturnedAtText, "dd.MM.yyyy", null, DateTimeStyles.None, out var r)) + { + ValidationMessage = "Rückgabedatum im Format TT.MM.JJJJ eingeben."; + return; + } + returnedAt = r; + } Result = _editingExam ?? new Exam { GroupId = _groupId }; Result.Title = Title.Trim(); Result.Date = date; - Result.Subject = Subject.Trim(); + Result.Subject = _subjectName.Trim(); Result.ExamNumber = ExamNumber; Result.Notes = string.IsNullOrWhiteSpace(Notes) ? null : Notes.Trim(); + Result.ReturnedAt = returnedAt; Result.Tasks = Tasks.Select(t => t.ToModel()).ToList(); Result.GradingKey = _gradingKey; _exams.Save(Result); diff --git a/LehrerApp.Desktop/ViewModels/Groups/GroupViewModels.cs b/LehrerApp.Desktop/ViewModels/Groups/GroupViewModels.cs index f4c2bf9..c766ef9 100644 --- a/LehrerApp.Desktop/ViewModels/Groups/GroupViewModels.cs +++ b/LehrerApp.Desktop/ViewModels/Groups/GroupViewModels.cs @@ -317,6 +317,10 @@ public partial class GroupDetailViewModel : ObservableObject var exam = _exams.GetById(SelectedExam.Id); if (exam is null) return; exam.Status = status; + if (status == ExamStatus.Returned) + exam.ReturnedAt ??= DateOnly.FromDateTime(DateTime.Today); + else + exam.ReturnedAt = null; _exams.Save(exam); var id = exam.Id; ReloadExams(); @@ -373,10 +377,12 @@ public class ExamSummary public ExamStatus Status { get; } public string StatusLabel { get; } public string StatusColorHex { get; } + public string ReturnedAtDisplay { get; } public ExamSummary(Core.Models.Exam e) { Id = e.Id; Title = e.Title; Date = e.Date.ToString("dd.MM.yyyy"); Status = e.Status; + ReturnedAtDisplay = e.ReturnedAt?.ToString("dd.MM.yyyy") ?? ""; StatusLabel = e.Status switch { ExamStatus.Planned => "Geplant", @@ -569,7 +575,7 @@ public partial class AddGroupDialogViewModel : ObservableObject if (string.IsNullOrWhiteSpace(Name)) { ValidationMessage = "Bezeichnung erforderlich."; return; } if (GradeLevel is < 1 or > 13) { ValidationMessage = "Klassenstufe 1–13."; return; } - string? subjectName = IsKurs && !string.IsNullOrWhiteSpace(Subject) ? Subject.Trim() : null; + string? subjectName = !string.IsNullOrWhiteSpace(Subject) ? Subject.Trim() : null; Guid? subjectId = null; if (subjectName is not null) diff --git a/LehrerApp.Desktop/Views/Groups/AddGroupDialog.axaml b/LehrerApp.Desktop/Views/Groups/AddGroupDialog.axaml index 45c93a1..df3caa1 100644 --- a/LehrerApp.Desktop/Views/Groups/AddGroupDialog.axaml +++ b/LehrerApp.Desktop/Views/Groups/AddGroupDialog.axaml @@ -25,8 +25,9 @@ - - + + - + + + + @@ -23,14 +26,14 @@ - - - - + + + + diff --git a/LehrerApp.Desktop/Views/Groups/GroupDetailView.axaml b/LehrerApp.Desktop/Views/Groups/GroupDetailView.axaml index aba298c..be3ec3d 100644 --- a/LehrerApp.Desktop/Views/Groups/GroupDetailView.axaml +++ b/LehrerApp.Desktop/Views/Groups/GroupDetailView.axaml @@ -107,6 +107,7 @@ +