@page "/management-cockpit"
@using TrafagSalesExporter.Models
@using TrafagSalesExporter.Services
@inject IManagementCockpitService CockpitService
@inject ISnackbar Snackbar
@inject IUiTextService UiText
@T("Management Cockpit", "Management Cockpit")
@T("Management Cockpit", "Management Cockpit")
@foreach (var file in _files)
{
@file.DisplayName
}
@T("Dateien laden", "Load files")
@(_analyzing ? T("Analysiere...", "Analyzing...") : T("Cockpit erzeugen", "Build cockpit"))
@T("Zentrale Roh-Auswertung", "Central raw analysis")
@T("Diese Sicht arbeitet direkt auf `CentralSalesRecords` und zeigt nur fachlich neutrale Rohkennzahlen. Kein Intercompany-Filter, keine CHF-Umrechnung, kein Budget, keine Spartenlogik.", "This view works directly on `CentralSalesRecords` and shows only neutral raw metrics. No intercompany filter, no CHF conversion, no budget, no divisional logic.")
@foreach (var year in _centralYears)
{
@year
}
@foreach (var month in Enumerable.Range(1, 12))
{
@($"{month:D2}")
}
@(_analyzingCentral ? T("Analysiere...", "Analyzing...") : T("Zentrale Auswertung laden", "Load central analysis"))
@if (_result is not null)
{
@T("Land", "Country")@_result.Summary.Land
TSC@_result.Summary.Tsc
@T("Umsatz", "Sales")@_result.Summary.SalesValueTotal.ToString("N2")
@T("Geschaetzte Marge", "Estimated margin")@($"{_result.Summary.EstimatedMarginPercent:F1}%")
@T("Management Aussagen", "Management statements")
@foreach (var finding in _result.Findings)
{
@finding.Title: @finding.Detail
}
@T("Top Kunden", "Top customers")
@foreach (var item in _result.TopCustomers)
{
@($"{item.Label}: {item.Value:N2} ({item.SharePercent:F1}%)")
}
@T("Top Produktgruppen", "Top product groups")
@foreach (var item in _result.TopProductGroups)
{
@($"{item.Label}: {item.Value:N2} ({item.SharePercent:F1}%)")
}
@T("Top Sales Owner", "Top sales owner")
@foreach (var item in _result.TopSalesEmployees)
{
@($"{item.Label}: {item.Value:N2} ({item.SharePercent:F1}%)")
}
@T("Datenqualitaet", "Data quality")
@foreach (var entry in _result.DataQualityCounts.OrderByDescending(x => x.Value))
{
@($"{entry.Key}: {entry.Value}")
}
}
@if (_centralResult is not null)
{
@T("Zeilen", "Rows")@_centralResult.Summary.RowCount.ToString("N0")
@T("Rechnungen", "Invoices")@_centralResult.Summary.InvoiceCount.ToString("N0")
@T("Standorte", "Sites")@_centralResult.Summary.SiteCount.ToString("N0")
@T("Laender", "Countries")@_centralResult.Summary.CountryCount.ToString("N0")
@T("Waehrungen", "Currencies")@_centralResult.Summary.CurrencyCount.ToString("N0")
@T("Periode", "Period")@BuildPeriodLabel(_centralResult)
@T("Hinweise", "Notes")
@foreach (var notice in _centralResult.Notices)
{
@notice
}
@T("Jahresumsatz 2025/2026", "Yearly sales 2025/2026")
@T("Jahr", "Year")
@T("Waehrung", "Currency")
@T("Umsatz", "Sales")
@T("Zeilen", "Rows")
@context.Year
@context.Currency
@context.SalesValue.ToString("N2")
@context.RowCount.ToString("N0")
@T("Monatsumsatz", "Monthly sales")
@T("Monat", "Month")
@T("Waehrung", "Currency")
@T("Umsatz", "Sales")
@T("Zeilen", "Rows")
@context.Label
@context.Currency
@context.SalesValue.ToString("N2")
@context.RowCount.ToString("N0")
@T("Tagesumsatz im ausgewaehlten Monat", "Daily sales in selected month")
@T("Tag", "Day")
@T("Waehrung", "Currency")
@T("Umsatz", "Sales")
@T("Zeilen", "Rows")
@context.Label
@context.Currency
@context.SalesValue.ToString("N2")
@context.RowCount.ToString("N0")
@T("Fuer die Tagessicht bitte zusaetzlich einen Monat waehlen.", "Please select a month as well for the daily view.")
@T("Umsatz nach Quelle", "Sales by source")
@T("Quelle", "Source")
@T("Waehrung", "Currency")
@T("Umsatz", "Sales")
@T("Rechnungen", "Invoices")
@context.Label
@context.Currency
@context.SalesValue.ToString("N2")
@context.InvoiceCount.ToString("N0")
@T("Umsatz nach Land", "Sales by country")
@T("Land", "Country")
@T("Waehrung", "Currency")
@T("Umsatz", "Sales")
@T("Rechnungen", "Invoices")
@T("Zeilen", "Rows")
@context.Label
@context.Currency
@context.SalesValue.ToString("N2")
@context.InvoiceCount.ToString("N0")
@context.RowCount.ToString("N0")
}
@code {
private List _files = [];
private List _centralYears = [];
private string? _selectedFilePath;
private ManagementCockpitResult? _result;
private ManagementCockpitCentralResult? _centralResult;
private int _selectedCentralYear;
private int? _selectedCentralMonth;
private bool _loadingFiles;
private bool _analyzing;
private bool _analyzingCentral;
protected override async Task OnInitializedAsync()
{
await ReloadFiles();
await ReloadCentralYears();
}
private async Task ReloadFiles()
{
_loadingFiles = true;
try
{
_files = await CockpitService.GetAvailableFilesAsync();
_selectedFilePath ??= _files.FirstOrDefault()?.Path;
}
finally
{
_loadingFiles = false;
}
}
private async Task ReloadCentralYears()
{
_centralYears = await CockpitService.GetAvailableCentralYearsAsync();
if (_selectedCentralYear == 0)
_selectedCentralYear = _centralYears.LastOrDefault();
}
private async Task Analyze()
{
if (string.IsNullOrWhiteSpace(_selectedFilePath))
return;
_analyzing = true;
try
{
_result = await CockpitService.AnalyzeAsync(_selectedFilePath);
}
catch (Exception ex)
{
Snackbar.Add(string.Format(T("Cockpit konnte nicht erzeugt werden: {0}", "Could not build cockpit: {0}"), ex.Message), Severity.Error);
}
finally
{
_analyzing = false;
}
}
private async Task AnalyzeCentral()
{
if (_selectedCentralYear == 0)
return;
_analyzingCentral = true;
try
{
_centralResult = await CockpitService.AnalyzeCentralAsync(_selectedCentralYear, _selectedCentralMonth);
}
catch (Exception ex)
{
Snackbar.Add(string.Format(T("Zentrale Auswertung konnte nicht erzeugt werden: {0}", "Could not build central analysis: {0}"), ex.Message), Severity.Error);
}
finally
{
_analyzingCentral = false;
}
}
private static Severity MapSeverity(string severity) => severity switch
{
"Warning" => Severity.Warning,
"Error" => Severity.Error,
_ => Severity.Info
};
private static string BuildPeriodLabel(ManagementCockpitCentralResult result)
{
if (result.Summary.PeriodStart is null || result.Summary.PeriodEnd is null)
return "-";
return $"{result.Summary.PeriodStart.Value:dd.MM.yyyy} - {result.Summary.PeriodEnd.Value:dd.MM.yyyy}";
}
}
@code {
private string T(string german, string english) => UiText.Text(german, english);
}