Schülerdokumentation: Einträge, Fehlzeitenbilanz, Datenschutz (Kapitel 5)

Dokumentationseinträge mit Typwahl (Gespräch, Vorkommnis, Förderplan,
Fehlzeit, Elternanruf, Elternbrief), vertrauliche Einträge nur nach
Bestätigung sichtbar, weiche Löschung mit Nachvollziehbarkeit. Fehlzeiten
als Auswertung des bestehenden Anwesenheits-Trackings statt zweiter
Erfassung, mit Schwellenwert-Warnung im Schülerdetail und Dashboard.
Förderplan-Wiedervorlage als Dashboard-Karte. Datenschutz: Löschfristen
mit manueller Bereinigung und DSGVO-Art.-15-Datenauskunft als Export.

Auf Nutzer-Feedback hin ergänzt: Elternanruf mit begleitendem
Gesprächsprotokoll-Dialog (Punkte abhaken, Eindrücke festhalten),
Elternbrief mit Versand-/Rückmeldungs-Tracking, Datei-Anhänge über
LiteDBs Dateispeicher, frei vergebbare Labels zur Nachverfolgung mit
Dringlichkeits-Farbcodierung, sowie eine sichtbare Farblegende für das
bestehende Notenentwicklungs-Diagramm. Dabei einen Absturz behoben:
leere Textfelder lieferten über das Binding null statt "", was beim
Speichern eine NullReferenceException auslöste.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 17:49:03 +02:00
co-authored by Claude Sonnet 5
parent 629b8d1bf0
commit d987b93315
36 changed files with 2395 additions and 62 deletions
@@ -0,0 +1,235 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:LehrerApp.Desktop.ViewModels.Students"
x:Class="LehrerApp.Desktop.Views.Students.DocumentationDialog"
x:DataType="vm:DocumentationDialogViewModel"
Title="{Binding DialogTitle}"
Width="480" SizeToContent="Height" MinHeight="360"
CanResize="True" WindowStartupLocation="CenterOwner">
<Grid RowDefinitions="*,Auto" Margin="24">
<ScrollViewer Grid.Row="0">
<StackPanel Spacing="12">
<TextBlock Text="{Binding DialogTitle}" Classes="dialogtitle"/>
<Grid ColumnDefinitions="*,12,140">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Titel *" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding Title}"/>
<TextBlock Text="{Binding TitleError}" Foreground="Red" FontSize="11"
IsVisible="{Binding TitleError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Datum *" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding DateText}" PlaceholderText="TT.MM.JJJJ"/>
<TextBlock Text="{Binding DateTextError}" Foreground="Red" FontSize="11"
IsVisible="{Binding DateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
</Grid>
<StackPanel Spacing="4">
<TextBlock Text="Typ *" FontSize="12" Opacity="0.7"/>
<ComboBox ItemsSource="{Binding TypeOptions}" SelectedItem="{Binding TypeName}"
HorizontalAlignment="Stretch"/>
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Text="Beschreibung" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding Content}" AcceptsReturn="True" Height="80" TextWrapping="Wrap"/>
</StackPanel>
<!-- Gespräch: Teilnehmer (5.1.2) -->
<StackPanel Spacing="6" IsVisible="{Binding IsConversation}">
<TextBlock Text="Teilnehmer" FontSize="12" Opacity="0.7"/>
<ItemsControl ItemsSource="{Binding Participants}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="*,Auto" Margin="0,2">
<TextBlock Grid.Column="0" Text="{Binding}" VerticalAlignment="Center" FontSize="13"/>
<Button Grid.Column="1" Content="×" Padding="7,2" FontSize="13"
Command="{Binding $parent[ItemsControl].((vm:DocumentationDialogViewModel)DataContext).RemoveParticipantCommand}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid ColumnDefinitions="*,8,Auto">
<TextBox Grid.Column="0" Text="{Binding NewParticipant}" PlaceholderText="Name"/>
<Button Grid.Column="2" Content="" Command="{Binding AddParticipantCommand}"/>
</Grid>
</StackPanel>
<!-- Fehlzeit: Aktenvermerk (5.1.1) -->
<StackPanel Spacing="8" IsVisible="{Binding IsAbsence}">
<TextBlock Text="Freier Aktenvermerk zu einer Abwesenheit (z.B. Krankschreibung eingereicht). Ersetzt nicht die Anwesenheits-Erfassung in der Mitarbeit-Ansicht und fließt nicht in die Fehlzeitenbilanz ein."
FontSize="11" Opacity="0.55" TextWrapping="Wrap"/>
<Grid ColumnDefinitions="120,12,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Stunden" FontSize="12" Opacity="0.7"/>
<NumericUpDown Value="{Binding LessonCount}" Minimum="0" FormatString="0"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4" VerticalAlignment="Bottom">
<CheckBox Content="Entschuldigt" IsChecked="{Binding AbsenceExcused}"/>
</StackPanel>
</Grid>
<StackPanel Spacing="4">
<TextBlock Text="Grund" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding AbsenceReason}"/>
</StackPanel>
</StackPanel>
<!-- Förderplan (5.3.1) -->
<StackPanel Spacing="8" IsVisible="{Binding IsSupportPlan}">
<TextBlock Text="Maßnahmen" FontSize="12" Opacity="0.7"/>
<ItemsControl ItemsSource="{Binding Measures}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="*,Auto" Margin="0,2">
<TextBlock Grid.Column="0" Text="{Binding}" VerticalAlignment="Center" FontSize="13"/>
<Button Grid.Column="1" Content="×" Padding="7,2" FontSize="13"
Command="{Binding $parent[ItemsControl].((vm:DocumentationDialogViewModel)DataContext).RemoveMeasureCommand}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid ColumnDefinitions="*,8,Auto">
<TextBox Grid.Column="0" Text="{Binding NewMeasure}" PlaceholderText="Maßnahme"/>
<Button Grid.Column="2" Content="" Command="{Binding AddMeasureCommand}"/>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Überprüfung am" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding ReviewDateText}" PlaceholderText="TT.MM.JJJJ"/>
<TextBlock Text="{Binding ReviewDateTextError}" Foreground="Red" FontSize="11"
IsVisible="{Binding ReviewDateTextError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Status" FontSize="12" Opacity="0.7"/>
<ComboBox ItemsSource="{Binding SupportStatusOptions}" SelectedItem="{Binding SupportStatusName}"
HorizontalAlignment="Stretch"/>
</StackPanel>
</Grid>
</StackPanel>
<!-- Elternanruf: Planung (Abhaken/Protokoll läuft separat über "Gespräch begleiten") -->
<StackPanel Spacing="6" IsVisible="{Binding IsParentCall}">
<TextBlock Text="Gesprächspunkte planen. Abgehakt und protokolliert wird während des Anrufs über den Button 'Gespräch begleiten' in der Übersicht."
FontSize="11" Opacity="0.55" TextWrapping="Wrap"/>
<ItemsControl ItemsSource="{Binding CallPoints}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="*,Auto" Margin="0,2">
<TextBlock Grid.Column="0" Text="{Binding}" VerticalAlignment="Center" FontSize="13"/>
<Button Grid.Column="1" Content="×" Padding="7,2" FontSize="13"
Command="{Binding $parent[ItemsControl].((vm:DocumentationDialogViewModel)DataContext).RemoveCallPointCommand}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid ColumnDefinitions="*,8,Auto">
<TextBox Grid.Column="0" Text="{Binding NewCallPoint}" PlaceholderText="Gesprächspunkt"/>
<Button Grid.Column="2" Content="" Command="{Binding AddCallPointCommand}"/>
</Grid>
</StackPanel>
<!-- Elternbrief (5.1) -->
<StackPanel Spacing="8" IsVisible="{Binding IsParentLetter}">
<StackPanel Spacing="4">
<TextBlock Text="Entwurf / Inhalt" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding LetterDraftContent}" AcceptsReturn="True" Height="70" TextWrapping="Wrap"/>
</StackPanel>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Versendet am" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding LetterSentDateText}" PlaceholderText="TT.MM.JJJJ"/>
<TextBlock Text="{Binding LetterSentDateError}" Foreground="Red" FontSize="11"
IsVisible="{Binding LetterSentDateError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4" VerticalAlignment="Bottom">
<CheckBox Content="Rückmeldung erhalten" IsChecked="{Binding LetterResponseReceived}"/>
</StackPanel>
</Grid>
<Grid ColumnDefinitions="*,12,*">
<StackPanel Grid.Column="0" Spacing="4">
<TextBlock Text="Rückmeldung am" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding LetterResponseDateText}" PlaceholderText="TT.MM.JJJJ"/>
<TextBlock Text="{Binding LetterResponseDateError}" Foreground="Red" FontSize="11"
IsVisible="{Binding LetterResponseDateError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="4">
<TextBlock Text="Rückmeldung (Notiz)" FontSize="12" Opacity="0.7"/>
<TextBox Text="{Binding LetterResponseNote}"/>
</StackPanel>
</Grid>
</StackPanel>
<!-- Anhänge (alle Typen) -->
<StackPanel Spacing="6">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="Anhänge" FontSize="12" Opacity="0.7" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content=" Datei" FontSize="12" Padding="8,4" Click="OnAddAttachment"/>
</Grid>
<ItemsControl ItemsSource="{Binding Attachments}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="vm:AttachmentItem">
<Grid ColumnDefinitions="*,Auto,Auto,Auto" Margin="0,2">
<TextBlock Grid.Column="0" Text="{Binding FileName}" VerticalAlignment="Center" FontSize="13"
TextTrimming="CharacterEllipsis"/>
<TextBlock Grid.Column="1" Text="{Binding SizeDisplay}" VerticalAlignment="Center"
FontSize="11" Opacity="0.5" Margin="6,0"/>
<Button Grid.Column="2" Content="Speichern" FontSize="11" Padding="7,2" Margin="0,0,4,0"
Click="OnOpenAttachment" Tag="{Binding}"/>
<Button Grid.Column="3" Content="×" FontSize="13" Padding="7,2"
Command="{Binding $parent[ItemsControl].((vm:DocumentationDialogViewModel)DataContext).RemoveAttachmentCommand}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Text="{Binding AttachmentError}" Foreground="Red" FontSize="11"
IsVisible="{Binding AttachmentError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
</StackPanel>
<!-- Labels zur Nachverfolgung (alle Typen) -->
<StackPanel Spacing="6">
<TextBlock Text="Labels" FontSize="12" Opacity="0.7"/>
<ItemsControl ItemsSource="{Binding Tags}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel ItemSpacing="6" LineSpacing="6"/></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{DynamicResource SystemControlBackgroundBaseMediumBrush}"
CornerRadius="10" Padding="8,3">
<StackPanel Orientation="Horizontal" Spacing="5">
<TextBlock Text="{Binding}" FontSize="11"/>
<Button Content="×" FontSize="11" Padding="0" Background="Transparent"
Command="{Binding $parent[ItemsControl].((vm:DocumentationDialogViewModel)DataContext).RemoveTagCommand}"
CommandParameter="{Binding}"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid ColumnDefinitions="*,8,Auto">
<AutoCompleteBox Grid.Column="0" Text="{Binding NewTag}"
ItemsSource="{Binding TagSuggestions}"
FilterMode="Contains" MinimumPrefixLength="0"
PlaceholderText="Label (z.B. Kritisch, Nacharbeiten)"/>
<Button Grid.Column="2" Content="" Command="{Binding AddTagCommand}"/>
</Grid>
</StackPanel>
<CheckBox Content="Vertraulich" IsChecked="{Binding IsConfidential}"
ToolTip.Tip="Blendet den Inhalt in der Übersicht standardmäßig aus; erst nach Klick auf 'Anzeigen' sichtbar."/>
</StackPanel>
</ScrollViewer>
<Grid Grid.Row="1" ColumnDefinitions="*,8,*" Margin="0,20,0,0">
<Button Grid.Column="0" Content="Abbrechen" HorizontalAlignment="Stretch" Click="OnCancel"/>
<Button Grid.Column="2" Content="Speichern" HorizontalAlignment="Stretch" Click="OnSave"/>
</Grid>
</Grid>
</Window>