Schüler hinzufügen, Kompetenzen
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LehrerApp.Desktop.ViewModels.Settings;
|
||||
|
||||
// ── Haupt-ViewModel ───────────────────────────────────────────────────────────
|
||||
|
||||
public partial class SettingsViewModel : ObservableObject
|
||||
{
|
||||
private readonly ISubjectRepository _subjects;
|
||||
private readonly ICompetencyDomainRepository _domainRepo;
|
||||
|
||||
// ── Fächer ────────────────────────────────────────────────────────────────
|
||||
|
||||
[ObservableProperty] private string _newName = "";
|
||||
[ObservableProperty] private string _newShort = "";
|
||||
[ObservableProperty] private string _validationMessage = "";
|
||||
|
||||
public ObservableCollection<SubjectListItem> Subjects { get; } = [];
|
||||
|
||||
// ── Kompetenzkatalog ──────────────────────────────────────────────────────
|
||||
|
||||
[ObservableProperty] private SubjectListItem? _catalogSubject;
|
||||
[ObservableProperty] private int _catalogGradeLevel = 10;
|
||||
[ObservableProperty] private string _newDomainName = "";
|
||||
[ObservableProperty] private string _newDomainCode = "";
|
||||
[ObservableProperty] private string _catalogValidation = "";
|
||||
|
||||
public ObservableCollection<DomainEditItem> Domains { get; } = [];
|
||||
|
||||
// ── Konstruktor ───────────────────────────────────────────────────────────
|
||||
|
||||
public SettingsViewModel(ISubjectRepository subjects, ICompetencyDomainRepository domainRepo)
|
||||
{
|
||||
_subjects = subjects;
|
||||
_domainRepo = domainRepo;
|
||||
LoadSubjects();
|
||||
}
|
||||
|
||||
// ── Fächer: Laden / Hinzufügen / Löschen ─────────────────────────────────
|
||||
|
||||
public void LoadSubjects()
|
||||
{
|
||||
Subjects.Clear();
|
||||
foreach (var s in _subjects.GetAll())
|
||||
Subjects.Add(new SubjectListItem(s));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void AddSubject()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NewName)) { ValidationMessage = "Name erforderlich."; return; }
|
||||
_subjects.Save(new Subject { Name = NewName.Trim(), ShortName = NewShort.Trim() });
|
||||
NewName = ""; NewShort = ""; ValidationMessage = "";
|
||||
LoadSubjects();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void DeleteSubject(SubjectListItem? item)
|
||||
{
|
||||
if (item is null) return;
|
||||
_subjects.Delete(item.Id);
|
||||
if (CatalogSubject?.Id == item.Id) CatalogSubject = null;
|
||||
LoadSubjects();
|
||||
}
|
||||
|
||||
// ── Katalog: Laden ────────────────────────────────────────────────────────
|
||||
|
||||
partial void OnCatalogSubjectChanged(SubjectListItem? value) => LoadCatalog();
|
||||
partial void OnCatalogGradeLevelChanged(int value) => LoadCatalog();
|
||||
|
||||
private void LoadCatalog()
|
||||
{
|
||||
Domains.Clear();
|
||||
CatalogValidation = "";
|
||||
if (CatalogSubject is null) return;
|
||||
foreach (var d in _domainRepo.GetBySubjectAndGrade(CatalogSubject.Id, CatalogGradeLevel))
|
||||
Domains.Add(new DomainEditItem(d, _domainRepo));
|
||||
}
|
||||
|
||||
// ── Katalog: Bereich hinzufügen / löschen ────────────────────────────────
|
||||
|
||||
[RelayCommand]
|
||||
private void AddDomain()
|
||||
{
|
||||
if (CatalogSubject is null) { CatalogValidation = "Bitte zuerst ein Fach auswählen."; return; }
|
||||
if (string.IsNullOrWhiteSpace(NewDomainName)) { CatalogValidation = "Bereichsname erforderlich."; return; }
|
||||
|
||||
var domain = new CompetencyDomain
|
||||
{
|
||||
SubjectId = CatalogSubject.Id,
|
||||
GradeLevel = CatalogGradeLevel,
|
||||
Name = NewDomainName.Trim(),
|
||||
Code = NewDomainCode.Trim(),
|
||||
SortOrder = Domains.Count,
|
||||
};
|
||||
_domainRepo.Save(domain);
|
||||
Domains.Add(new DomainEditItem(domain, _domainRepo));
|
||||
NewDomainName = ""; NewDomainCode = ""; CatalogValidation = "";
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void DeleteDomain(DomainEditItem? item)
|
||||
{
|
||||
if (item is null) return;
|
||||
_domainRepo.Delete(item.Id);
|
||||
Domains.Remove(item);
|
||||
}
|
||||
|
||||
// ── JSON Import / Export ──────────────────────────────────────────────────
|
||||
|
||||
public void ImportCatalog(string json)
|
||||
{
|
||||
if (CatalogSubject is null) { CatalogValidation = "Bitte zuerst ein Fach auswählen."; return; }
|
||||
try
|
||||
{
|
||||
var opts = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||
var dto = JsonSerializer.Deserialize<CatalogDto>(json, opts);
|
||||
if (dto?.Domains is null) { CatalogValidation = "Ungültiges JSON-Format."; return; }
|
||||
|
||||
_domainRepo.DeleteBySubjectAndGrade(CatalogSubject.Id, CatalogGradeLevel);
|
||||
|
||||
for (int i = 0; i < dto.Domains.Count; i++)
|
||||
{
|
||||
var d = dto.Domains[i];
|
||||
var domain = new CompetencyDomain
|
||||
{
|
||||
SubjectId = CatalogSubject.Id,
|
||||
GradeLevel = CatalogGradeLevel,
|
||||
Name = d.Name ?? "",
|
||||
Code = d.Code ?? "",
|
||||
SortOrder = i,
|
||||
Items = (d.Competencies ?? [])
|
||||
.Select((c, j) => new CompetencyItem
|
||||
{
|
||||
Code = c.Code ?? "",
|
||||
Description = c.Description ?? "",
|
||||
SortOrder = j,
|
||||
}).ToList(),
|
||||
};
|
||||
_domainRepo.Save(domain);
|
||||
}
|
||||
CatalogValidation = "";
|
||||
LoadCatalog();
|
||||
}
|
||||
catch
|
||||
{
|
||||
CatalogValidation = "Import fehlgeschlagen – bitte JSON-Format prüfen.";
|
||||
}
|
||||
}
|
||||
|
||||
public string ExportCatalog()
|
||||
{
|
||||
var dto = new CatalogDto
|
||||
{
|
||||
Subject = CatalogSubject?.Name ?? "",
|
||||
GradeLevel = CatalogGradeLevel,
|
||||
Domains = Domains.Select(d => new DomainDto
|
||||
{
|
||||
Name = d.Name,
|
||||
Code = d.Code,
|
||||
Competencies = d.Items.Select(i => new CompetencyDto
|
||||
{
|
||||
Code = i.Code,
|
||||
Description = i.Description,
|
||||
}).ToList(),
|
||||
}).ToList(),
|
||||
};
|
||||
return JsonSerializer.Serialize(dto, new JsonSerializerOptions { WriteIndented = true });
|
||||
}
|
||||
}
|
||||
|
||||
// ── DomainEditItem ────────────────────────────────────────────────────────────
|
||||
|
||||
public partial class DomainEditItem : ObservableObject
|
||||
{
|
||||
private readonly CompetencyDomain _domain;
|
||||
private readonly ICompetencyDomainRepository _repo;
|
||||
|
||||
public Guid Id { get; }
|
||||
public string Name { get; }
|
||||
public string Code { get; }
|
||||
public string DisplayName { get; }
|
||||
|
||||
[ObservableProperty] private string _newItemCode = "";
|
||||
[ObservableProperty] private string _newItemDesc = "";
|
||||
|
||||
public ObservableCollection<CompetencyItemVm> Items { get; } = [];
|
||||
|
||||
public DomainEditItem(CompetencyDomain domain, ICompetencyDomainRepository repo)
|
||||
{
|
||||
_domain = domain;
|
||||
_repo = repo;
|
||||
Id = domain.Id;
|
||||
Name = domain.Name;
|
||||
Code = domain.Code;
|
||||
DisplayName = string.IsNullOrEmpty(domain.Code)
|
||||
? domain.Name
|
||||
: $"{domain.Name} ({domain.Code})";
|
||||
|
||||
foreach (var item in domain.Items.OrderBy(i => i.SortOrder))
|
||||
Items.Add(new CompetencyItemVm(item, DeleteItem));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void AddItem()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NewItemDesc)) return;
|
||||
var item = new CompetencyItem
|
||||
{
|
||||
Code = NewItemCode.Trim(),
|
||||
Description = NewItemDesc.Trim(),
|
||||
SortOrder = _domain.Items.Count,
|
||||
};
|
||||
_domain.Items.Add(item);
|
||||
_repo.Save(_domain);
|
||||
Items.Add(new CompetencyItemVm(item, DeleteItem));
|
||||
NewItemCode = ""; NewItemDesc = "";
|
||||
}
|
||||
|
||||
private void DeleteItem(CompetencyItemVm vm)
|
||||
{
|
||||
_domain.Items.RemoveAll(i => i.Id == vm.ItemId);
|
||||
_repo.Save(_domain);
|
||||
Items.Remove(vm);
|
||||
}
|
||||
}
|
||||
|
||||
// ── CompetencyItemVm ──────────────────────────────────────────────────────────
|
||||
|
||||
public class CompetencyItemVm
|
||||
{
|
||||
public Guid ItemId { get; }
|
||||
public string Code { get; }
|
||||
public string Description { get; }
|
||||
public string Display { get; }
|
||||
public IRelayCommand DeleteCommand { get; }
|
||||
|
||||
public CompetencyItemVm(CompetencyItem item, Action<CompetencyItemVm> onDelete)
|
||||
{
|
||||
ItemId = item.Id;
|
||||
Code = item.Code;
|
||||
Description = item.Description;
|
||||
Display = string.IsNullOrEmpty(item.Code)
|
||||
? item.Description
|
||||
: $"[{item.Code}] {item.Description}";
|
||||
DeleteCommand = new RelayCommand(() => onDelete(this));
|
||||
}
|
||||
}
|
||||
|
||||
// ── Hilfklassen ───────────────────────────────────────────────────────────────
|
||||
|
||||
public class SubjectListItem(Subject s)
|
||||
{
|
||||
public Guid Id { get; } = s.Id;
|
||||
public string Name { get; } = s.Name;
|
||||
public string ShortName { get; } = s.ShortName;
|
||||
}
|
||||
|
||||
// ── JSON DTOs ─────────────────────────────────────────────────────────────────
|
||||
|
||||
internal class CatalogDto
|
||||
{
|
||||
[JsonPropertyName("subject")] public string? Subject { get; set; }
|
||||
[JsonPropertyName("gradeLevel")] public int GradeLevel { get; set; }
|
||||
[JsonPropertyName("domains")] public List<DomainDto>? Domains { get; set; }
|
||||
}
|
||||
|
||||
internal class DomainDto
|
||||
{
|
||||
[JsonPropertyName("name")] public string? Name { get; set; }
|
||||
[JsonPropertyName("code")] public string? Code { get; set; }
|
||||
[JsonPropertyName("competencies")] public List<CompetencyDto>? Competencies { get; set; }
|
||||
}
|
||||
|
||||
internal class CompetencyDto
|
||||
{
|
||||
[JsonPropertyName("code")] public string? Code { get; set; }
|
||||
[JsonPropertyName("description")] public string? Description { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user