Files
PLDpro.Web/Components/Pages/DmsDashboard.razor
Erik cae77ef1e3
All checks were successful
Build & Deploy PLDpro.Web Test to 192.168.1.100 / build-and-deploy (push) Successful in 1m15s
DMS Layout mit Fehlern
2026-02-09 21:50:24 +01:00

167 lines
6.3 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@page "/dms"
@using MudBlazor
@using Pldpro.Web.UI.Models
@inject Pldpro.Web.UI.Services.IDocumentClient Client
@inject NavigationManager Nav
<PageTitle>DMS</PageTitle>
<MudStack Spacing="3">
<!-- Kopfzeile: Titel, Bucket-Auswahl und Aktionen -->
<MudStack Row="true" AlignItems=AlignItems.Center Spacing="2">
<MudText Typo="Typo.h4">Dokumenten-Management</MudText>
<MudSpacer />
<MudSelect T="string" @bind-Value="_bucket" Label="Bucket" Dense="true" Style="min-width:240px">
@foreach (var b in _buckets)
{
<MudSelectItem Value="@b">@b</MudSelectItem>
}
</MudSelect>
<MudButton Variant="Variant.Outlined" OnClick="Reload" StartIcon="@Icons.Material.Filled.Refresh">
Aktualisieren
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Primary"
OnClick="@(() => Nav.NavigateTo("/dms/upload"))"
StartIcon="@Icons.Material.Filled.CloudUpload">
Upload
</MudButton>
<MudButton Variant="Variant.Outlined"
OnClick="@(() => Nav.NavigateTo("/dms/list"))"
StartIcon="@Icons.Material.Filled.List">
Zur Liste
</MudButton>
</MudStack>
<!-- Kennzahlen -->
<MudGrid>
<MudItem xs="12" md="3">
<MudPaper Class="pa-4">
<MudText Typo="Typo.subtitle1">Gesamt</MudText>
<MudText Typo="Typo.h5">@_total.ToString("N0")</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" md="3">
<MudPaper Class="pa-4">
<MudText Typo="Typo.subtitle1">Eingegangen</MudText>
<MudText Typo="Typo.h5">@_eingegangen.ToString("N0")</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" md="3">
<MudPaper Class="pa-4">
<MudText Typo="Typo.subtitle1">Freigegeben</MudText>
<MudText Typo="Typo.h5">@_freigegeben.ToString("N0")</MudText>
</MudPaper>
</MudItem>
<MudItem xs="12" md="3">
<MudPaper Class="pa-4">
<MudText Typo="Typo.subtitle1">Bezahlt</MudText>
<MudText Typo="Typo.h5">@_bezahlt.ToString("N0")</MudText>
</MudPaper>
</MudItem>
</MudGrid>
<!-- Zuletzt hinzugefügt + Filter -->
<MudPaper Class="pa-4">
<MudStack Row="true" AlignItems=AlignItems.Center Spacing="2">
<MudText Typo="Typo.h6">Zuletzt hinzugefügt</MudText>
<MudSpacer />
<MudTextField @bind-Value="_query"
Placeholder="Suche (optional)"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
Immediate="true" />
<MudTextField @bind-Value="_prefix" Placeholder="Pfad-Prefix (optional, z.B. rechnungen/2026)" />
<MudButton Variant="Variant.Outlined" OnClick="Reload" StartIcon="@Icons.Material.Filled.Search">
Filtern
</MudButton>
</MudStack>
<MudTable Items="_latest" Dense="true" Hover="true" Class="mt-3">
<HeaderContent>
<MudTh>Datei</MudTh>
<MudTh>Pfad</MudTh>
<MudTh>Größe</MudTh>
<MudTh>Geändert</MudTh>
<MudTh></MudTh>
</HeaderContent>
<RowTemplate>
<MudTd>@context.FileName</MudTd>
<MudTd>@context.PathPrefix</MudTd>
<MudTd>@(context.Size?.ToString("N0"))</MudTd>
<MudTd>@context.LastModified</MudTd>
<MudTd Align="TableCellAlign.Right">
<MudTooltip Text="Details">
<MudIconButton Icon="@Icons.Material.Filled.Description"
OnClick="@(() => Nav.NavigateTo($"/dms/detail/{Uri.EscapeDataString(context.Bucket)}/{EncodeKeyForPath(context.Key)}"))" />
</MudTooltip>
<MudTooltip Text="Download">
<MudIconButton Icon="@Icons.Material.Filled.Download"
OnClick="@(() => Download(context))" />
</MudTooltip>
</MudTd>
</RowTemplate>
</MudTable>
</MudPaper>
</MudStack>
@code {
private List<string> _buckets = new();
private string? _bucket;
private string? _query;
private string? _prefix;
private int _total;
private int _eingegangen;
private int _freigegeben;
private int _bezahlt;
private List<DocumentListItem> _latest = new();
protected override async Task OnInitializedAsync()
{
_buckets = (await Client.ListBucketsAsync()).ToList();
_bucket = _buckets.FirstOrDefault();
await Reload();
}
private async Task Reload()
{
if (string.IsNullOrWhiteSpace(_bucket))
{
_total = _eingegangen = _freigegeben = _bezahlt = 0;
_latest = new();
StateHasChanged();
return;
}
// Kennzahlen: einmal komplette Liste (für kleine Datenmengen ok)
var (allItems, total) = await Client.SearchAsync(_bucket!, _query, _prefix, 0, int.MaxValue);
_total = total;
// Aktuell sind Status nur UI-intern; wenn später persistiert, hier echte Counts laden.
_eingegangen = allItems.Count(i => i.Status == DocumentStatus.Eingegangen);
_freigegeben = allItems.Count(i => i.Status == DocumentStatus.Freigegeben);
_bezahlt = allItems.Count(i => i.Status == DocumentStatus.Bezahlt);
// Letzte 10
var (latest, _) = await Client.SearchAsync(_bucket!, _query, _prefix, 0, 10);
_latest = latest
.OrderByDescending(i => i.LastModified ?? DateTime.MinValue)
.Take(10)
.ToList();
StateHasChanged();
}
private void Download(DocumentListItem item)
{
var url = Client.GetDownloadUrl(item.Bucket, item.Key);
Nav.NavigateTo(url, forceLoad: true);
}
private static string EncodeKeyForPath(string key)
=> string.Join("/", (key ?? string.Empty)
.Split('/', StringSplitOptions.RemoveEmptyEntries)
.Select(Uri.EscapeDataString));
}