All checks were successful
Build & Deploy PLDpro.Web Test to 192.168.1.100 / build-and-deploy (push) Successful in 1m15s
167 lines
6.3 KiB
Plaintext
167 lines
6.3 KiB
Plaintext
@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));
|
||
} |