feat: Fehlzeiten Tabelle für Templates
This commit is contained in:
@@ -91,6 +91,87 @@ public static class StudentAttendanceCalendarDrawingBuilder
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Chronologische, portable Fehlzeitenliste für Elternbriefvorlagen.</summary>
|
||||
public static class StudentAbsenceDayListDrawingBuilder
|
||||
{
|
||||
public const string PlaceholderName = "Student.AbsenceDays";
|
||||
|
||||
public static DrawingValue Build(string studentName, AttendanceCalendarOptions options,
|
||||
IReadOnlyList<ClassAbsenceDaySummaryRow> absences)
|
||||
{
|
||||
const float width = 170;
|
||||
var scale = options.Size switch
|
||||
{
|
||||
AttendanceCalendarSize.Small => .75f,
|
||||
AttendanceCalendarSize.Large => 1f,
|
||||
_ => .88f,
|
||||
};
|
||||
var contentWidth = width * scale;
|
||||
var rowHeight = 9 * scale;
|
||||
var start = options.NormalizedStartMonth;
|
||||
var end = start.AddMonths(options.NormalizedMonthCount).AddDays(-1);
|
||||
var rows = absences
|
||||
.Where(a => a.Date >= start && a.Date <= end &&
|
||||
UntisNameMatching.NamesMatch(a.StudentName, studentName))
|
||||
.OrderBy(a => a.Date)
|
||||
.ToList();
|
||||
var commands = new List<DrawingCommand>
|
||||
{
|
||||
new DrawStringEx(0, 0, 7 * scale, contentWidth, "Fehltage",
|
||||
DrawingTextAlignment.AlignLeft, 11 * scale, Color: "#1F2937", Bold: true),
|
||||
new DrawStringEx(0, 7 * scale, 6 * scale, contentWidth, studentName,
|
||||
DrawingTextAlignment.AlignLeft, 8 * scale, Color: "#6B7280"),
|
||||
};
|
||||
var y = 16 * scale;
|
||||
commands.Add(new DrawRectangle(0, y, contentWidth, rowHeight, "#CBD5E1", .4f, "#F3F4F6"));
|
||||
commands.Add(new DrawStringEx(2 * scale, y + scale, rowHeight - 2 * scale, 31 * scale, "Datum",
|
||||
DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(36 * scale, y + scale, rowHeight - 2 * scale, 75 * scale, "Umfang",
|
||||
DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(113 * scale, y + scale, rowHeight - 2 * scale, 55 * scale, "Status",
|
||||
DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
y += rowHeight;
|
||||
|
||||
if (rows.Count == 0)
|
||||
{
|
||||
commands.Add(new DrawStringEx(2 * scale, y + 2 * scale, rowHeight, contentWidth - 4 * scale,
|
||||
"Keine Fehltage im gewählten Zeitraum", DrawingTextAlignment.AlignLeft, 8 * scale,
|
||||
Color: "#6B7280", Italic: true));
|
||||
y += rowHeight + 3 * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var index = 0; index < rows.Count; index++)
|
||||
{
|
||||
var row = rows[index];
|
||||
var fill = index % 2 == 0 ? "#FFFFFF" : "#F9FAFB";
|
||||
var extent = row.CountsAsFullDay
|
||||
? "Ganzer Fehltag"
|
||||
: row.TotalAbsentPeriods > 0
|
||||
? $"Fehlzeit · {row.TotalAbsentPeriods} Std."
|
||||
: $"Fehlzeit · {row.TotalAbsentMinutes} Min.";
|
||||
var status = row.IsUnexcused
|
||||
? "Unentschuldigt"
|
||||
: row.FriendlyStatusLabel.Contains("Entschuldigt", StringComparison.OrdinalIgnoreCase)
|
||||
? "Entschuldigt"
|
||||
: row.FriendlyStatusLabel;
|
||||
var statusColor = row.IsUnexcused ? "#C62828" : "#2E7D32";
|
||||
commands.Add(new DrawRectangle(0, y, contentWidth, rowHeight, "#E5E7EB", .3f, fill));
|
||||
commands.Add(new DrawStringEx(2 * scale, y + scale, rowHeight - 2 * scale, 31 * scale,
|
||||
row.Date.ToString("dd.MM.yyyy"), DrawingTextAlignment.AlignLeft, 7.5f * scale,
|
||||
Color: "#374151"));
|
||||
commands.Add(new DrawStringEx(36 * scale, y + scale, rowHeight - 2 * scale, 75 * scale,
|
||||
extent, DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151"));
|
||||
commands.Add(new DrawStringEx(113 * scale, y + scale, rowHeight - 2 * scale, 55 * scale,
|
||||
status, DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: statusColor,
|
||||
Bold: row.IsUnexcused));
|
||||
y += rowHeight;
|
||||
}
|
||||
}
|
||||
return new DrawingValue(commands, y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Liest ausschließlich den lokalen WebUntis-Cache. Das Öffnen oder Rendern eines
|
||||
/// Elternbriefs löst dadurch keinen unerwarteten Netzwerkabruf aus.</summary>
|
||||
public sealed class StudentAttendanceCalendarService(
|
||||
@@ -126,4 +207,24 @@ public sealed class StudentAttendanceCalendarService(
|
||||
return StudentAttendanceCalendarDrawingBuilder.Build(rosterName, options,
|
||||
ClassAbsenceDaySummaryRow.GroupByStudentAndDay(absences), register);
|
||||
}
|
||||
|
||||
public DrawingValue BuildAbsenceDayList(Student student, AttendanceCalendarOptions options)
|
||||
{
|
||||
var className = settings.HomeroomClassName;
|
||||
if (string.IsNullOrWhiteSpace(className)) return new DrawingValue([], 0);
|
||||
|
||||
var first = options.NormalizedStartMonth;
|
||||
var last = first.AddMonths(options.NormalizedMonthCount).AddDays(-1);
|
||||
var rosterName = rosterCache.GetByClass(className)
|
||||
.FirstOrDefault(r => UntisNameMatching.NamesMatch(r.DisplayName, student.FullName))?.DisplayName
|
||||
?? student.FullName;
|
||||
var start = first.Year * 10000 + first.Month * 100 + first.Day;
|
||||
var end = last.Year * 10000 + last.Month * 100 + last.Day;
|
||||
var absences = absenceCache.GetByClassAndRange(className, start, end)
|
||||
.Select(e => new UntisClassAbsenceEntryDto(e.StudentName, e.ExternKey, e.ClassName, e.Date,
|
||||
e.AbsentPeriods, e.AbsentMinutes, e.TeacherUsernames, e.Subject, e.AbsenceReason, e.Note,
|
||||
e.EntryId, e.HandledOn, e.Counts, e.ExcuseNote, e.PeriodNumber, e.Status, e.CountsAsFullDay));
|
||||
return StudentAbsenceDayListDrawingBuilder.Build(rosterName, options,
|
||||
ClassAbsenceDaySummaryRow.GroupByStudentAndDay(absences));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user