Excel Export eingebaut

This commit is contained in:
MarcWieland
2026-06-25 20:22:35 +02:00
parent 2f95fa0e3e
commit b12e94128c
6 changed files with 470 additions and 0 deletions
@@ -6,6 +6,7 @@
@inject ISnackbar Snackbar
@inject AuthenticationStateProvider AuthStateProvider
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
<PageTitle>KW @_kw Wochenübersicht Timetracker</PageTitle>
@@ -34,6 +35,10 @@ else
</MudText>
</MudStack>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="0">
<MudTooltip Text="Woche als Excel exportieren">
<MudIconButton Icon="@Icons.Material.Filled.Download"
Style="color: var(--mud-palette-primary-text)" OnClick="ExportWeekExcel" />
</MudTooltip>
@if (!IsCurrentWeek)
{
<MudButton Variant="Variant.Text" Style="color: var(--mud-palette-primary-text)"
@@ -491,6 +496,10 @@ else
private async Task PrevWeek() { _monday = _monday.AddDays(-7); await LoadWeek(); }
private async Task NextWeek() { _monday = _monday.AddDays(7); await LoadWeek(); }
private async Task GoToCurrentWeek() { _monday = GetMonday(DateOnly.FromDateTime(DateTime.Today)); await LoadWeek(); }
private void ExportWeekExcel()
{
NavigationManager.NavigateTo($"api/tracker/export/week?monday={_monday:yyyy-MM-dd}", forceLoad: true);
}
private static DateOnly GetMonday(DateOnly date)
{
@@ -4,6 +4,7 @@
@inject ITimetrackerService TrackerService
@inject IHolidayService HolidayService
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager
<PageTitle>@_deCulture.DateTimeFormat.GetMonthName(_month) @_year Monatsübersicht Timetracker</PageTitle>
@@ -32,6 +33,10 @@ else
</MudText>
</MudStack>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="0">
<MudTooltip Text="Monat als Excel exportieren">
<MudIconButton Icon="@Icons.Material.Filled.Download"
Style="color: var(--mud-palette-primary-text)" OnClick="ExportMonthExcel" />
</MudTooltip>
@if (!IsCurrentMonth)
{
<MudButton Variant="Variant.Text" Style="color: var(--mud-palette-primary-text)"
@@ -268,6 +273,11 @@ else
await LoadMonth();
}
private void ExportMonthExcel()
{
NavigationManager.NavigateTo($"api/tracker/export/month?year={_year}&month={_month}", forceLoad: true);
}
private static string FormatTs(TimeSpan ts, bool sign = false)
{
var neg = ts < TimeSpan.Zero;
@@ -3,6 +3,7 @@
@attribute [Authorize]
@inject ITimetrackerService TrackerService
@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager NavigationManager
@using System.Security.Claims
@using timetracker.Shared
@@ -210,6 +211,75 @@ else
</MudCardContent>
</MudCard>
</MudItem>
@* ── Excel Export ── *@
<MudItem xs="12">
<MudCard Elevation="3" Class="rounded-xl">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6" Style="font-weight:700; color: var(--mud-palette-text-primary)">Excel-Datenexport</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary">Lade deine erfassten Arbeitszeiten in verschiedenen Zeiträumen als formatierte Excel-Datei herunter.</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudGrid Spacing="3">
@* Wochenexport *@
<MudItem xs="12" sm="4">
<MudStack Spacing="3">
<MudText Typo="Typo.subtitle2" Style="font-weight:700">Wochenexport</MudText>
<MudDatePicker Label="Woche wählen" @bind-Date="_exportWeekDate" PickerVariant="PickerVariant.Dialog" Variant="Variant.Outlined" Color="Color.Primary" />
<MudButton StartIcon="@Icons.Material.Filled.Download" Variant="Variant.Filled" Color="Color.Primary" OnClick="ExportWeek" FullWidth="true">
Woche exportieren
</MudButton>
</MudStack>
</MudItem>
@* Monatsexport *@
<MudItem xs="12" sm="4">
<MudStack Spacing="3">
<MudText Typo="Typo.subtitle2" Style="font-weight:700">Monatsexport</MudText>
<MudStack Row="true" Spacing="2">
<MudSelect T="int" Label="Monat" @bind-Value="_exportMonth" Variant="Variant.Outlined">
@for (int m = 1; m <= 12; m++)
{
var monthVal = m;
<MudSelectItem Value="@monthVal">@_deCulture.DateTimeFormat.GetMonthName(monthVal)</MudSelectItem>
}
</MudSelect>
<MudSelect T="int" Label="Jahr" @bind-Value="_exportMonthYear" Variant="Variant.Outlined">
@for (int y = DateTime.Today.Year - 5; y <= DateTime.Today.Year + 1; y++)
{
var yearVal = y;
<MudSelectItem Value="@yearVal">@yearVal</MudSelectItem>
}
</MudSelect>
</MudStack>
<MudButton StartIcon="@Icons.Material.Filled.Download" Variant="Variant.Filled" Color="Color.Primary" OnClick="ExportMonth" FullWidth="true">
Monat exportieren
</MudButton>
</MudStack>
</MudItem>
@* Jahresexport *@
<MudItem xs="12" sm="4">
<MudStack Spacing="3">
<MudText Typo="Typo.subtitle2" Style="font-weight:700">Jahresexport</MudText>
<MudSelect T="int" Label="Jahr" @bind-Value="_exportYear" Variant="Variant.Outlined">
@for (int y = DateTime.Today.Year - 5; y <= DateTime.Today.Year + 1; y++)
{
var yearVal = y;
<MudSelectItem Value="@yearVal">@yearVal</MudSelectItem>
}
</MudSelect>
<MudButton StartIcon="@Icons.Material.Filled.Download" Variant="Variant.Filled" Color="Color.Primary" OnClick="ExportYear" FullWidth="true">
Jahr exportieren
</MudButton>
</MudStack>
</MudItem>
</MudGrid>
</MudCardContent>
</MudCard>
</MudItem>
@* ── Diagnostics Panel ── *@
<MudItem xs="12">
@@ -263,6 +333,12 @@ else
private double _weekTargetHours;
private double _weekOvertimeHours;
private double _maxHoursValue = 10.0;
// Excel Export variables
private DateTime? _exportWeekDate = DateTime.Today;
private int _exportMonth = DateTime.Today.Month;
private int _exportMonthYear = DateTime.Today.Year;
private int _exportYear = DateTime.Today.Year;
// Debug variables
private int _rawDbDaysCount = 0;
@@ -373,6 +449,25 @@ else
return $"{prefix}{(int)abs.TotalHours}:{abs.Minutes:D2}";
}
private void ExportWeek()
{
if (_exportWeekDate.HasValue)
{
var date = DateOnly.FromDateTime(_exportWeekDate.Value);
NavigationManager.NavigateTo($"api/tracker/export/week?monday={date:yyyy-MM-dd}", forceLoad: true);
}
}
private void ExportMonth()
{
NavigationManager.NavigateTo($"api/tracker/export/month?year={_exportMonthYear}&month={_exportMonth}", forceLoad: true);
}
private void ExportYear()
{
NavigationManager.NavigateTo($"api/tracker/export/year?year={_exportYear}", forceLoad: true);
}
private sealed class DayStat
{
public DateOnly Date { get; set; }