Add shared export infrastructure
This commit is contained in:
@@ -3,9 +3,9 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Core.Services;
|
||||
using LehrerApp.Desktop.Services;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
@@ -195,27 +195,27 @@ public partial class ExamEvaluationDialogViewModel : ObservableObject
|
||||
|
||||
public string ExportCsv()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"Klausur;{_exam.Title}");
|
||||
sb.AppendLine($"Datum;{_exam.Date:dd.MM.yyyy}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("Notenspiegel");
|
||||
sb.AppendLine("Note;Anzahl;Anteil");
|
||||
var csv = new CsvBuilder()
|
||||
.AddRow("Klausur", _exam.Title)
|
||||
.AddRow("Datum", _exam.Date.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture))
|
||||
.AddBlankRow()
|
||||
.AddRow("Notenspiegel")
|
||||
.AddRow("Note", "Anzahl", "Anteil");
|
||||
foreach (var g in GradeDistribution)
|
||||
sb.AppendLine($"{g.Grade};{g.Count};{Percent(g.Count, GradedCount)}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine($"Durchschnitt;{AverageDisplay}");
|
||||
sb.AppendLine($"Median;{MedianDisplay}");
|
||||
if (!string.IsNullOrEmpty(BelowThresholdLabel1)) sb.AppendLine($"{BelowThresholdLabel1};{BelowThresholdDisplay1}");
|
||||
if (!string.IsNullOrEmpty(BelowThresholdLabel2)) sb.AppendLine($"{BelowThresholdLabel2};{BelowThresholdDisplay2}");
|
||||
sb.AppendLine($"Bewertet;{GradedCount}");
|
||||
sb.AppendLine($"Abwesend;{AbsentCount}");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("Aufgabenanalyse");
|
||||
sb.AppendLine("Aufgabe;Ø Erfüllungsgrad;Auffällig schwach");
|
||||
csv.AddRow(g.Grade, g.Count, Percent(g.Count, GradedCount));
|
||||
csv.AddBlankRow()
|
||||
.AddRow("Durchschnitt", AverageDisplay)
|
||||
.AddRow("Median", MedianDisplay);
|
||||
if (!string.IsNullOrEmpty(BelowThresholdLabel1)) csv.AddRow(BelowThresholdLabel1, BelowThresholdDisplay1);
|
||||
if (!string.IsNullOrEmpty(BelowThresholdLabel2)) csv.AddRow(BelowThresholdLabel2, BelowThresholdDisplay2);
|
||||
csv.AddRow("Bewertet", GradedCount)
|
||||
.AddRow("Abwesend", AbsentCount)
|
||||
.AddBlankRow()
|
||||
.AddRow("Aufgabenanalyse")
|
||||
.AddRow("Aufgabe", "Ø Erfüllungsgrad", "Auffällig schwach");
|
||||
foreach (var t in TaskAnalysis)
|
||||
sb.AppendLine($"{t.Label};{t.AvgPercentDisplay};{(t.IsWeak ? "ja" : "")}");
|
||||
return sb.ToString();
|
||||
csv.AddRow(t.Label, t.AvgPercentDisplay, t.IsWeak ? "ja" : "");
|
||||
return csv.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Core.Services;
|
||||
using LehrerApp.Desktop.Services;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
@@ -197,12 +197,13 @@ public partial class ReportGradeDialogViewModel : ObservableObject
|
||||
|
||||
public string ExportCsv()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"Zeugnisnoten;{_groupLabel};{SelectedPeriod.Label}");
|
||||
sb.AppendLine("Schüler;Berechnet;Übersteuert;Begründung;Endnote;Gesperrt");
|
||||
var csv = new CsvBuilder()
|
||||
.AddRow("Zeugnisnoten", _groupLabel, SelectedPeriod.Label)
|
||||
.AddRow("Schüler", "Berechnet", "Übersteuert", "Begründung", "Endnote", "Gesperrt");
|
||||
foreach (var r in Rows)
|
||||
sb.AppendLine($"{r.Name};{r.CalculatedValue};{r.OverrideValue};{r.OverrideReason};{r.FinalDisplay};{(r.IsLocked ? "ja" : "")}");
|
||||
return sb.ToString();
|
||||
csv.AddRow(r.Name, r.CalculatedValue, r.OverrideValue, r.OverrideReason,
|
||||
r.FinalDisplay, r.IsLocked ? "ja" : "");
|
||||
return csv.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Core.Services;
|
||||
using LehrerApp.Desktop.Services;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
|
||||
@@ -519,6 +520,7 @@ public class TimeEntryListItem(TimeEntry model, string? taskTitle)
|
||||
public class CategoryTimeSummary(string category, int minutes, double barFraction)
|
||||
{
|
||||
public string Category { get; } = category;
|
||||
public int Minutes { get; } = minutes;
|
||||
public string MinutesDisplay { get; } = $"{minutes} min";
|
||||
public double BarFraction { get; } = barFraction;
|
||||
}
|
||||
@@ -619,6 +621,20 @@ public partial class WorkloadEvaluationViewModel : ObservableObject
|
||||
public ObservableCollection<GroupTimeSummary> GroupSummaries { get; } = [];
|
||||
public string TotalMinutesDisplay { get; private set; } = "0 min";
|
||||
public string RequiredVsActualDisplay { get; private set; } = "";
|
||||
public string ExportSuggestedFileName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PeriodMode == SchoolYearMode)
|
||||
return $"Arbeitszeitauswertung_Schuljahr_{SelectedYear}-{SelectedYear + 1}.csv";
|
||||
var month = MonthOptions.IndexOf(SelectedMonth) + 1;
|
||||
return $"Arbeitszeitauswertung_{SelectedYear}-{month:00}.csv";
|
||||
}
|
||||
}
|
||||
|
||||
private DateOnly _periodFrom;
|
||||
private DateOnly _periodTo;
|
||||
private int _totalMinutes;
|
||||
|
||||
public WorkloadEvaluationViewModel(ITimeEntryRepository entries, IGroupRepository groups,
|
||||
WorkloadSettingsService workloadSettings, SchoolYearService schoolYear)
|
||||
@@ -671,6 +687,8 @@ public partial class WorkloadEvaluationViewModel : ObservableObject
|
||||
private void Refresh()
|
||||
{
|
||||
var (from, to) = CurrentPeriod();
|
||||
_periodFrom = from;
|
||||
_periodTo = to;
|
||||
var periodEntries = _entries.GetByDateRange(from, to);
|
||||
var groupNames = _groups.GetAll(includeInactive: true).ToDictionary(g => g.Id, g => g.Name);
|
||||
|
||||
@@ -698,6 +716,7 @@ public partial class WorkloadEvaluationViewModel : ObservableObject
|
||||
}
|
||||
|
||||
var totalMinutes = periodEntries.Sum(e => e.DurationMinutes);
|
||||
_totalMinutes = totalMinutes;
|
||||
TotalMinutesDisplay = $"{totalMinutes} min ({(totalMinutes / 60.0).ToString("0.#", CultureInfo.InvariantCulture)} h)";
|
||||
|
||||
// Pflichtstunden-Abgleich (6.3.2): auf die Anzahl Wochen im Zeitraum hochgerechnet.
|
||||
@@ -721,12 +740,52 @@ public partial class WorkloadEvaluationViewModel : ObservableObject
|
||||
|
||||
OnPropertyChanged(nameof(TotalMinutesDisplay));
|
||||
OnPropertyChanged(nameof(RequiredVsActualDisplay));
|
||||
OnPropertyChanged(nameof(ExportSuggestedFileName));
|
||||
}
|
||||
|
||||
public string ExportCsv()
|
||||
{
|
||||
var germanCulture = CultureInfo.GetCultureInfo("de-DE");
|
||||
var csv = new CsvBuilder()
|
||||
.AddRow("Arbeitszeitauswertung")
|
||||
.AddRow("Zeitraum", _periodFrom.ToString("dd.MM.yyyy", germanCulture),
|
||||
_periodTo.ToString("dd.MM.yyyy", germanCulture))
|
||||
.AddRow("Gesamtzeit (Minuten)", _totalMinutes)
|
||||
.AddRow("Gesamtzeit (Stunden)", (_totalMinutes / 60.0).ToString("0.##", germanCulture));
|
||||
|
||||
if (_workloadSettings.RequiredWeeklyHours > 0)
|
||||
{
|
||||
var weeks = (_periodTo.DayNumber - _periodFrom.DayNumber + 1) / 7.0;
|
||||
var requiredHours = _workloadSettings.RequiredWeeklyHours * weeks;
|
||||
var actualHours = _totalMinutes / 60.0;
|
||||
csv.AddRow("Pflichtstunden pro Woche",
|
||||
_workloadSettings.RequiredWeeklyHours.ToString("0.##", germanCulture))
|
||||
.AddRow("Sollzeit (Stunden)", requiredHours.ToString("0.##", germanCulture))
|
||||
.AddRow("Abweichung (Stunden)", (actualHours - requiredHours).ToString("0.##", germanCulture));
|
||||
}
|
||||
|
||||
csv.AddBlankRow()
|
||||
.AddRow("Nach Kategorie")
|
||||
.AddRow("Kategorie", "Minuten", "Stunden");
|
||||
foreach (var summary in CategorySummaries)
|
||||
csv.AddRow(summary.Category, summary.Minutes,
|
||||
(summary.Minutes / 60.0).ToString("0.##", germanCulture));
|
||||
|
||||
csv.AddBlankRow()
|
||||
.AddRow("Nach Gruppe")
|
||||
.AddRow("Gruppe", "Minuten", "Stunden");
|
||||
foreach (var summary in GroupSummaries)
|
||||
csv.AddRow(summary.GroupName, summary.Minutes,
|
||||
(summary.Minutes / 60.0).ToString("0.##", germanCulture));
|
||||
|
||||
return csv.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class GroupTimeSummary(string groupName, int minutes, double barFraction)
|
||||
{
|
||||
public string GroupName { get; } = groupName;
|
||||
public int Minutes { get; } = minutes;
|
||||
public string MinutesDisplay { get; } = $"{minutes} min";
|
||||
public double BarFraction { get; } = barFraction;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user