Notenverwaltung (Kapitel 2) und Mitarbeits-Assistent
Notenübersicht der Gruppe (Matrix, Gesamt-Spalte, Sortierung, Halbjahresfilter), Einzelnoten-Pflege samt Sammelerfassung, Gewichtungsschema mit Voreinstellung je Gruppentyp, Zeugnisnoten-Berechnung mit Übersteuern/Festschreiben/Export und Notenentwicklung im Schülerdetail. Dazu Anwesenheits-/Hausaufgaben-Tracking je Mitarbeit-Sitzung, ein neuer Mitarbeits-Assistent (Zeitleiste mit Abschnitten, automatischer Notenvorschlag, Zusammenzug zur Halbjahresnote) und eine Dashboard-Kachel für offene Entschuldigungen. Außerdem: verbliebene englische Begriffe in Auswahlfeldern und Buttons auf Deutsch umgestellt.
This commit is contained in:
@@ -17,8 +17,13 @@ public partial class DashboardViewModel : ObservableObject
|
||||
private readonly ILessonRepository _lessons;
|
||||
private readonly IExamRepository _exams;
|
||||
private readonly IWorkTaskRepository _tasks;
|
||||
private readonly IParticipationSessionRepository _participationSessions;
|
||||
private readonly IParticipationRepository _participationEntries;
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly SchoolYearService _sy;
|
||||
|
||||
private const int OpenExcuseMaxAgeDays = 21;
|
||||
|
||||
[ObservableProperty] private string _greeting = "";
|
||||
[ObservableProperty] private string _currentDate = "";
|
||||
[ObservableProperty] private string _currentSchoolYear = "";
|
||||
@@ -30,15 +35,19 @@ public partial class DashboardViewModel : ObservableObject
|
||||
public ObservableCollection<TaskItem> OpenTasks { get; } = [];
|
||||
public ObservableCollection<GroupChip> CurrentGroups { get; } = [];
|
||||
public ObservableCollection<CalendarDayCell> CalendarDays { get; } = [];
|
||||
public ObservableCollection<OpenExcuseItem> OpenExcuses { get; } = [];
|
||||
public static string[] CalendarWeekdayHeaders { get; } = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
|
||||
|
||||
// Navigation-Callback – wird von App.axaml.cs verdrahtet
|
||||
public Action<Guid>? OnNavigateToGroup { get; set; }
|
||||
|
||||
public DashboardViewModel(IGroupRepository groups, ISubjectRepository subjects, ILessonRepository lessons,
|
||||
IExamRepository exams, IWorkTaskRepository tasks, SchoolYearService sy)
|
||||
IExamRepository exams, IWorkTaskRepository tasks, IParticipationSessionRepository participationSessions,
|
||||
IParticipationRepository participationEntries, IStudentRepository students, SchoolYearService sy)
|
||||
{
|
||||
_groups = groups; _subjects = subjects; _lessons = lessons; _exams = exams; _tasks = tasks; _sy = sy;
|
||||
_groups = groups; _subjects = subjects; _lessons = lessons; _exams = exams; _tasks = tasks;
|
||||
_participationSessions = participationSessions; _participationEntries = participationEntries;
|
||||
_students = students; _sy = sy;
|
||||
Load();
|
||||
}
|
||||
|
||||
@@ -80,6 +89,41 @@ public partial class DashboardViewModel : ObservableObject
|
||||
|
||||
CalendarMonth = FirstOfMonth(now);
|
||||
LoadCalendar();
|
||||
LoadOpenExcuses(groups.Values.ToList(), today);
|
||||
}
|
||||
|
||||
private void LoadOpenExcuses(List<LearningGroup> groups, DateOnly today)
|
||||
{
|
||||
OpenExcuses.Clear();
|
||||
var cutoff = today.AddDays(-OpenExcuseMaxAgeDays);
|
||||
|
||||
var items = new List<OpenExcuseItem>();
|
||||
foreach (var g in groups)
|
||||
{
|
||||
foreach (var session in _participationSessions.GetByGroup(g.Id).Where(s => s.Date >= cutoff && s.Date <= today))
|
||||
{
|
||||
foreach (var entry in _participationEntries.GetBySession(session.Id)
|
||||
.Where(e => e.Attendance == AttendanceStatus.ExcusePending))
|
||||
{
|
||||
var student = _students.GetById(entry.StudentId);
|
||||
if (student is null) continue;
|
||||
var item = new OpenExcuseItem(session.Id, entry.StudentId, student.FullName, g.Name, session.Date);
|
||||
item.OnResolve = ResolveExcuse;
|
||||
items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var item in items.OrderBy(i => i.Date))
|
||||
OpenExcuses.Add(item);
|
||||
}
|
||||
|
||||
private void ResolveExcuse(OpenExcuseItem item, AttendanceStatus status)
|
||||
{
|
||||
var entry = _participationEntries.GetBySessionAndStudent(item.SessionId, item.StudentId);
|
||||
if (entry is null) return;
|
||||
entry.Attendance = status;
|
||||
_participationEntries.Save(entry);
|
||||
OpenExcuses.Remove(item);
|
||||
}
|
||||
|
||||
private void LoadCalendar()
|
||||
@@ -172,6 +216,33 @@ public class LessonItem { public string GroupName { get; set; } = ""; public str
|
||||
public class TaskItem { public string Title { get; set; } = ""; public string DueDate { get; set; } = ""; public bool IsOverdue { get; set; } }
|
||||
public class GroupChip { public Guid GroupId { get; set; } public string Name { get; set; } = ""; public string Subject { get; set; } = ""; }
|
||||
|
||||
// ── Offene Entschuldigungen (aus Mitarbeit-Fehltagen) ────────────────────────
|
||||
|
||||
public partial class OpenExcuseItem : ObservableObject
|
||||
{
|
||||
public Guid SessionId { get; }
|
||||
public Guid StudentId { get; }
|
||||
public string StudentName { get; }
|
||||
public string GroupName { get; }
|
||||
public DateOnly Date { get; }
|
||||
public string DateDisplay { get; }
|
||||
|
||||
public Action<OpenExcuseItem, AttendanceStatus>? OnResolve { get; set; }
|
||||
|
||||
public OpenExcuseItem(Guid sessionId, Guid studentId, string studentName, string groupName, DateOnly date)
|
||||
{
|
||||
SessionId = sessionId;
|
||||
StudentId = studentId;
|
||||
StudentName = studentName;
|
||||
GroupName = groupName;
|
||||
Date = date;
|
||||
DateDisplay = date.ToString("dd.MM.yyyy");
|
||||
}
|
||||
|
||||
[RelayCommand] private void MarkExcused() => OnResolve?.Invoke(this, AttendanceStatus.Excused);
|
||||
[RelayCommand] private void MarkUnexcused() => OnResolve?.Invoke(this, AttendanceStatus.Unexcused);
|
||||
}
|
||||
|
||||
public class CalendarDayCell
|
||||
{
|
||||
public int DayNumber { get; }
|
||||
|
||||
Reference in New Issue
Block a user