fix: Anwesenheitskalender/Fehltagesliste nutzen die real deklarierte Boxgröße
CI / build-and-test (push) Waiting to run
CI / build-and-test (push) Waiting to run
Die DrawingValue-Builder gingen bisher immer von einer festen Breite (170) aus, unabhängig davon, wie breit die DRAWBOX/FLOWDRAWBOX in der jeweiligen Vorlage tatsächlich deklariert ist. Bei einer breiteren Box (oder einer in "pt" statt "mm" deklarierten Seite, wie im echten Fehlzeitenbrief-Template) blieb dadurch ein Großteil der eigentlich verfügbaren Fläche ungenutzt leer - sichtbar als "Luft" rechts und unterhalb des Kalenders im generierten PDF. CreateLetterDialogViewModel/LetterTemplateTools ermitteln jetzt die real deklarierte Boxbreite samt Maßeinheit aus dem geladenen Template (LetterPlaceholderBuilder.FindDeclaredDrawingBox) und reichen sie an die Builder durch, die ihr mm-entworfenes Raster entsprechend skalieren. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,42 +28,48 @@ public static class StudentAttendanceCalendarDrawingBuilder
|
||||
|
||||
public static DrawingValue Build(string studentName, AttendanceCalendarOptions options,
|
||||
IReadOnlyList<ClassAbsenceDaySummaryRow> absences,
|
||||
IReadOnlyList<UntisForeignClassRegisterEventDto> registerEntries)
|
||||
IReadOnlyList<UntisForeignClassRegisterEventDto> registerEntries, float contentWidth = 170,
|
||||
float millimeterScale = 1)
|
||||
{
|
||||
const float width = 170;
|
||||
var scale = options.Size switch
|
||||
{
|
||||
AttendanceCalendarSize.Small => .7f,
|
||||
AttendanceCalendarSize.Large => 1f,
|
||||
_ => .85f,
|
||||
};
|
||||
// Die Breite richtet sich nach der DRAWBOX-Deklaration im Layout-Skript (fest, unabhängig
|
||||
// von der Größenwahl) - nur Schrift/Zellenhöhe skalieren mit "Größe". Würde die Breite mit
|
||||
// skalieren, würde "Groß" (scale=1) exakt die Skript-Box ausfüllen, "Klein"/"Normal" aber
|
||||
// nur einen Teil davon - und eine größere Skalierung als 1 liefe über die Box hinaus und
|
||||
// würde am rechten Rand abgeschnitten (SVG overflow="hidden").
|
||||
var contentWidth = width;
|
||||
var cellHeight = 10 * scale;
|
||||
// War 10 - bei 3 Monaten nebeneinander größer als eine einzelne Tageskachel und zog damit
|
||||
// contentWidth/millimeterScale kommen aus der tatsächlichen DRAWBOX/FLOWDRAWBOX-Deklaration
|
||||
// der jeweiligen Vorlage (siehe LetterPlaceholderBuilder.FindDeclaredDrawingBox). Das Raster
|
||||
// ist in Millimetern entworfen; millimeterScale rechnet das in die Koordinaten-Einheit der
|
||||
// Vorlage um (1, wenn die Vorlage schon "mm" nutzt; ≈2.83 bei "pt") - ohne das würde das
|
||||
// Raster bei einer in "pt" deklarierten Vorlage nur rund ein Drittel der vorgesehenen Größe
|
||||
// erreichen. Schriftgrößen (FontSize) sind davon unabhängig immer echte Punktgrößen.
|
||||
// contentWidth ist unabhängig von der Größenwahl fest - nur Schrift/Zellenhöhe skalieren mit
|
||||
// "Größe". Würde die Breite mit skalieren, würde "Groß" (scale=1) exakt die Skript-Box
|
||||
// ausfüllen, "Klein"/"Normal" aber nur einen Teil davon - und eine größere Skalierung als 1
|
||||
// liefe über die Box hinaus und würde am rechten Rand abgeschnitten (SVG overflow="hidden").
|
||||
// Die Defaults (170/1) greifen nur, wenn die Vorlage nicht ermittelt werden kann (z.B.
|
||||
// Vorschau ohne Kontext).
|
||||
var cellHeight = 10 * scale * millimeterScale;
|
||||
// War 10mm - bei 3 Monaten nebeneinander größer als eine einzelne Tageskachel und zog damit
|
||||
// spürbar Platz von den Kacheln ab, ohne selbst als Inhalt wahrgenommen zu werden.
|
||||
var monthGapX = 6f;
|
||||
var monthGapX = 6f * millimeterScale;
|
||||
var first = options.NormalizedStartMonth;
|
||||
var monthCount = options.NormalizedMonthCount;
|
||||
var monthWidth = (contentWidth - monthGapX * (monthCount - 1)) / monthCount;
|
||||
var cellWidth = monthWidth / 7;
|
||||
// Kachel-Zwischenraum (Trennung zu Nachbarzellen) deutlich knapper als vorher (war "scale",
|
||||
// also bis zu 1mm auf jeder Seite - bei einer ~7mm breiten Zelle ein gutes Viertel reiner
|
||||
// Leerraum). Die Kachel selbst füllt dadurch ihren Rasterplatz sichtbar besser aus.
|
||||
var cellInset = scale * .4f;
|
||||
// Kachel-Zwischenraum (Trennung zu Nachbarzellen) deutlich knapper als vorher (war "scale"
|
||||
// mm, also bis zu 1mm auf jeder Seite - bei einer ~7mm breiten Zelle ein gutes Viertel
|
||||
// reiner Leerraum). Die Kachel selbst füllt dadurch ihren Rasterplatz sichtbar besser aus.
|
||||
var cellInset = scale * .4f * millimeterScale;
|
||||
var cellCornerRadius = Math.Min(cellWidth, cellHeight) * .2f;
|
||||
var commands = new List<DrawingCommand>();
|
||||
var y = 0f;
|
||||
commands.Add(new DrawStringEx(0, y, 14 * scale, contentWidth, "Anwesenheit",
|
||||
commands.Add(new DrawStringEx(0, y, 14 * scale * millimeterScale, contentWidth, "Anwesenheit",
|
||||
DrawingTextAlignment.AlignLeft, 11 * scale, Color: "#1F2937", Bold: true));
|
||||
y += 14 * scale;
|
||||
commands.Add(new DrawStringEx(0, y, 10 * scale, contentWidth, studentName,
|
||||
y += 14 * scale * millimeterScale;
|
||||
commands.Add(new DrawStringEx(0, y, 10 * scale * millimeterScale, contentWidth, studentName,
|
||||
DrawingTextAlignment.AlignLeft, 8 * scale, Color: "#6B7280"));
|
||||
y += 10 * scale + 2 * scale;
|
||||
y += 10 * scale * millimeterScale + 2 * scale * millimeterScale;
|
||||
var weekdays = new[] { "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So" };
|
||||
var gridStartY = y;
|
||||
var maxWeeks = 0;
|
||||
@@ -77,14 +83,15 @@ public static class StudentAttendanceCalendarDrawingBuilder
|
||||
maxWeeks = Math.Max(maxWeeks, weeks);
|
||||
var xOffset = monthIndex * (monthWidth + monthGapX);
|
||||
var monthY = gridStartY;
|
||||
commands.Add(new DrawStringEx(xOffset, monthY, 11 * scale, monthWidth,
|
||||
commands.Add(new DrawStringEx(xOffset, monthY, 11 * scale * millimeterScale, monthWidth,
|
||||
current.ToString("MMMM yyyy", CultureInfo.GetCultureInfo("de-DE")),
|
||||
DrawingTextAlignment.AlignLeft, 9 * scale, Color: "#374151", Bold: true));
|
||||
monthY += 11 * scale;
|
||||
monthY += 11 * scale * millimeterScale;
|
||||
for (var column = 0; column < 7; column++)
|
||||
commands.Add(new DrawStringEx(xOffset + column * cellWidth, monthY, 9 * scale, cellWidth,
|
||||
weekdays[column], DrawingTextAlignment.AlignCenter, 7 * scale, Color: "#6B7280", Bold: true));
|
||||
monthY += 9 * scale;
|
||||
commands.Add(new DrawStringEx(xOffset + column * cellWidth, monthY, 9 * scale * millimeterScale,
|
||||
cellWidth, weekdays[column], DrawingTextAlignment.AlignCenter, 7 * scale, Color: "#6B7280",
|
||||
Bold: true));
|
||||
monthY += 9 * scale * millimeterScale;
|
||||
|
||||
foreach (var day in days)
|
||||
{
|
||||
@@ -96,17 +103,18 @@ public static class StudentAttendanceCalendarDrawingBuilder
|
||||
commands.Add(new DrawRoundedRectangle(x + cellInset, cellY, cellWidth - 2 * cellInset,
|
||||
cellHeight - cellInset, cellCornerRadius, "#D1D5DB", .35f,
|
||||
day.HasSignal ? day.SignalColorHex : "#FFFFFF"));
|
||||
commands.Add(new DrawStringEx(x, cellY + scale, cellHeight - 2 * scale, cellWidth,
|
||||
commands.Add(new DrawStringEx(x, cellY + scale * millimeterScale,
|
||||
cellHeight - 2 * scale * millimeterScale, cellWidth,
|
||||
day.HasSignal ? day.SignalCode : day.DayNumber, DrawingTextAlignment.AlignCenter, 7 * scale,
|
||||
Color: day.HasSignal ? "#FFFFFF" : "#374151", Bold: day.HasSignal));
|
||||
}
|
||||
}
|
||||
y = gridStartY + 11 * scale + 9 * scale + maxWeeks * cellHeight + monthGapX;
|
||||
y = gridStartY + 11 * scale * millimeterScale + 9 * scale * millimeterScale + maxWeeks * cellHeight + monthGapX;
|
||||
|
||||
commands.Add(new DrawStringEx(0, y, 8 * scale, contentWidth,
|
||||
commands.Add(new DrawStringEx(0, y, 8 * scale * millimeterScale, contentWidth,
|
||||
"U unentschuldigt · A abwesend · V verspätet · E entschuldigt · ! Klassenbuch",
|
||||
DrawingTextAlignment.AlignLeft, 6.5f * scale, Color: "#6B7280"));
|
||||
return new DrawingValue(commands, y + 9 * scale);
|
||||
return new DrawingValue(commands, y + 9 * scale * millimeterScale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,19 +124,19 @@ public static class StudentAbsenceDayListDrawingBuilder
|
||||
public const string PlaceholderName = "Student.AbsenceDays";
|
||||
|
||||
public static DrawingValue Build(string studentName, AttendanceCalendarOptions options,
|
||||
IReadOnlyList<ClassAbsenceDaySummaryRow> absences)
|
||||
IReadOnlyList<ClassAbsenceDaySummaryRow> absences, float contentWidth = 170,
|
||||
float millimeterScale = 1)
|
||||
{
|
||||
const float width = 170;
|
||||
var scale = options.Size switch
|
||||
{
|
||||
AttendanceCalendarSize.Small => .75f,
|
||||
AttendanceCalendarSize.Large => 1f,
|
||||
_ => .88f,
|
||||
};
|
||||
// Breite bleibt an die DRAWBOX-Deklaration im Layout-Skript gebunden (siehe
|
||||
// StudentAttendanceCalendarDrawingBuilder) - nur Zeilenhöhe/Schrift skalieren mit "Größe".
|
||||
var contentWidth = width;
|
||||
var rowHeight = 12 * scale;
|
||||
// contentWidth/millimeterScale: siehe StudentAttendanceCalendarDrawingBuilder - contentWidth
|
||||
// bleibt an die tatsächliche DRAWBOX/FLOWDRAWBOX-Deklaration im Layout-Skript gebunden,
|
||||
// millimeterScale rechnet das mm-entworfene Raster in die Koordinaten-Einheit der Vorlage um.
|
||||
var rowHeight = 12 * scale * millimeterScale;
|
||||
var start = options.NormalizedStartMonth;
|
||||
var end = start.AddMonths(options.NormalizedMonthCount).AddDays(-1);
|
||||
var rows = absences
|
||||
@@ -138,33 +146,33 @@ public static class StudentAbsenceDayListDrawingBuilder
|
||||
.ToList();
|
||||
var commands = new List<DrawingCommand>();
|
||||
var y = 0f;
|
||||
commands.Add(new DrawStringEx(0, y, 14 * scale, contentWidth, "Fehltage",
|
||||
commands.Add(new DrawStringEx(0, y, 14 * scale * millimeterScale, contentWidth, "Fehltage",
|
||||
DrawingTextAlignment.AlignLeft, 11 * scale, Color: "#1F2937", Bold: true));
|
||||
y += 14 * scale;
|
||||
commands.Add(new DrawStringEx(0, y, 10 * scale, contentWidth, studentName,
|
||||
y += 14 * scale * millimeterScale;
|
||||
commands.Add(new DrawStringEx(0, y, 10 * scale * millimeterScale, contentWidth, studentName,
|
||||
DrawingTextAlignment.AlignLeft, 8 * scale, Color: "#6B7280"));
|
||||
y += 10 * scale + 2 * scale;
|
||||
y += 10 * scale * millimeterScale + 2 * scale * millimeterScale;
|
||||
// Spaltenbreiten so gewählt, dass auch die Datenzeilen (nicht nur die kurzen Kopfzeilen-
|
||||
// Labels) hineinpassen - "Datum" als Kopfzeile ist kürzer als "dd.MM.yyyy" und wurde bei
|
||||
// 31 zu schmal bemessen, wodurch das Datum am rechten Rand abgeschnitten wurde.
|
||||
const float dateColumnX = 2, dateColumnWidth = 38;
|
||||
const float extentColumnX = 44, extentColumnWidth = 66;
|
||||
const float statusColumnX = 114, statusColumnWidth = 54;
|
||||
var dateColumnX = 2 * millimeterScale; var dateColumnWidth = 38 * millimeterScale;
|
||||
var extentColumnX = 44 * millimeterScale; var extentColumnWidth = 66 * millimeterScale;
|
||||
var statusColumnX = 114 * millimeterScale; var statusColumnWidth = 54 * millimeterScale;
|
||||
commands.Add(new DrawRectangle(0, y, contentWidth, rowHeight, "#CBD5E1", .4f, "#F3F4F6"));
|
||||
commands.Add(new DrawStringEx(dateColumnX, y + scale, rowHeight - scale, dateColumnWidth, "Datum",
|
||||
DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(extentColumnX, y + scale, rowHeight - scale, extentColumnWidth, "Umfang",
|
||||
DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(statusColumnX, y + scale, rowHeight - scale, statusColumnWidth, "Status",
|
||||
DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(dateColumnX, y + scale * millimeterScale, rowHeight - scale * millimeterScale,
|
||||
dateColumnWidth, "Datum", DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(extentColumnX, y + scale * millimeterScale, rowHeight - scale * millimeterScale,
|
||||
extentColumnWidth, "Umfang", DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
commands.Add(new DrawStringEx(statusColumnX, y + scale * millimeterScale, rowHeight - scale * millimeterScale,
|
||||
statusColumnWidth, "Status", DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151", Bold: true));
|
||||
y += rowHeight;
|
||||
|
||||
if (rows.Count == 0)
|
||||
{
|
||||
commands.Add(new DrawStringEx(2, y + 2 * scale, rowHeight, contentWidth - 4,
|
||||
"Keine Fehltage im gewählten Zeitraum", DrawingTextAlignment.AlignLeft, 8 * scale,
|
||||
Color: "#6B7280", Italic: true));
|
||||
y += rowHeight + 3 * scale;
|
||||
commands.Add(new DrawStringEx(2 * millimeterScale, y + 2 * scale * millimeterScale, rowHeight,
|
||||
contentWidth - 4 * millimeterScale, "Keine Fehltage im gewählten Zeitraum",
|
||||
DrawingTextAlignment.AlignLeft, 8 * scale, Color: "#6B7280", Italic: true));
|
||||
y += rowHeight + 3 * scale * millimeterScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -184,12 +192,15 @@ public static class StudentAbsenceDayListDrawingBuilder
|
||||
: row.FriendlyStatusLabel;
|
||||
var statusColor = row.IsUnexcused ? "#C62828" : "#2E7D32";
|
||||
commands.Add(new DrawRectangle(0, y, contentWidth, rowHeight, "#E5E7EB", .3f, fill));
|
||||
commands.Add(new DrawStringEx(dateColumnX, y + scale, rowHeight - scale, dateColumnWidth,
|
||||
commands.Add(new DrawStringEx(dateColumnX, y + scale * millimeterScale,
|
||||
rowHeight - scale * millimeterScale, dateColumnWidth,
|
||||
row.Date.ToString("dd.MM.yyyy"), DrawingTextAlignment.AlignLeft, 7.5f * scale,
|
||||
Color: "#374151"));
|
||||
commands.Add(new DrawStringEx(extentColumnX, y + scale, rowHeight - scale, extentColumnWidth,
|
||||
commands.Add(new DrawStringEx(extentColumnX, y + scale * millimeterScale,
|
||||
rowHeight - scale * millimeterScale, extentColumnWidth,
|
||||
extent, DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: "#374151"));
|
||||
commands.Add(new DrawStringEx(statusColumnX, y + scale, rowHeight - scale, statusColumnWidth,
|
||||
commands.Add(new DrawStringEx(statusColumnX, y + scale * millimeterScale,
|
||||
rowHeight - scale * millimeterScale, statusColumnWidth,
|
||||
status, DrawingTextAlignment.AlignLeft, 7.5f * scale, Color: statusColor,
|
||||
Bold: row.IsUnexcused));
|
||||
y += rowHeight;
|
||||
@@ -210,7 +221,8 @@ public sealed class StudentAttendanceCalendarService(
|
||||
public DrawingValue Build(Student student, DateOnly month) =>
|
||||
Build(student, new AttendanceCalendarOptions(month, 1));
|
||||
|
||||
public DrawingValue Build(Student student, AttendanceCalendarOptions options)
|
||||
public DrawingValue Build(Student student, AttendanceCalendarOptions options, float contentWidth = 170,
|
||||
float millimeterScale = 1)
|
||||
{
|
||||
var className = settings.HomeroomClassName;
|
||||
if (string.IsNullOrWhiteSpace(className)) return new DrawingValue([], 0);
|
||||
@@ -233,10 +245,11 @@ public sealed class StudentAttendanceCalendarService(
|
||||
e.TeacherUsername, e.CategoryName, e.CategoryGroup, e.Text))
|
||||
.ToList();
|
||||
return StudentAttendanceCalendarDrawingBuilder.Build(rosterName, options,
|
||||
ClassAbsenceDaySummaryRow.GroupByStudentAndDay(absences), register);
|
||||
ClassAbsenceDaySummaryRow.GroupByStudentAndDay(absences), register, contentWidth, millimeterScale);
|
||||
}
|
||||
|
||||
public DrawingValue BuildAbsenceDayList(Student student, AttendanceCalendarOptions options)
|
||||
public DrawingValue BuildAbsenceDayList(Student student, AttendanceCalendarOptions options, float contentWidth = 170,
|
||||
float millimeterScale = 1)
|
||||
{
|
||||
var className = settings.HomeroomClassName;
|
||||
if (string.IsNullOrWhiteSpace(className)) return new DrawingValue([], 0);
|
||||
@@ -254,6 +267,6 @@ public sealed class StudentAttendanceCalendarService(
|
||||
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));
|
||||
ClassAbsenceDaySummaryRow.GroupByStudentAndDay(absences), contentWidth, millimeterScale);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user