From 80b74d1dedb8c3d69bea938ca1d2630320e480cf Mon Sep 17 00:00:00 2001 From: Trond Schertel Date: Fri, 29 May 2026 16:10:20 +0200 Subject: [PATCH] Excel-Import --- Components/Pages/Home.razor | 4 +- Components/Pages/WorkspaceDetail.razor | 114 +++++++++++++++++++++++++ Services/WorkspaceService.cs | 41 +++++++++ ZahlenAnalyse.Web.csproj | 2 + 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 Components/Pages/WorkspaceDetail.razor diff --git a/Components/Pages/Home.razor b/Components/Pages/Home.razor index 6b633c7..9c179e4 100644 --- a/Components/Pages/Home.razor +++ b/Components/Pages/Home.razor @@ -55,7 +55,9 @@ - + diff --git a/Components/Pages/WorkspaceDetail.razor b/Components/Pages/WorkspaceDetail.razor new file mode 100644 index 0000000..62ddc89 --- /dev/null +++ b/Components/Pages/WorkspaceDetail.razor @@ -0,0 +1,114 @@ +@page "/workspace/{*WorkspaceId}" +@using ZahlenAnalyse.Web.Models +@using ZahlenAnalyse.Web.Services +@inject WorkspaceService DbService +@inject ISnackbar Snackbar +@inject NavigationManager NavManager + + + @if (_workspace == null) + { + + } + else + { + @_workspace.Name + + + + + Daten importieren + Lade eine Excel-Datei hoch, um Fakten in diesen Workspace zu importieren. + + + + + Excel hochladen + + + + + + + + + Dimensionen + + @foreach (var dim in _workspace.Dimensions) + { + @dim.Name + } + + + + + + + Letzte Importe / Einträge + + + Datum + Betrag + Details + + + @context.Date.ToShortDateString() + @context.Amount.ToString("N2") € + @string.Join(" | ", context.Dimensions.Values) + + + + + + } + + +@code { + [Parameter] public string WorkspaceId { get; set; } = string.Empty; + private Workspace? _workspace; + private List _recentFakten = new(); + + protected override async Task OnInitializedAsync() + { + _workspace = await DbService.GetWorkspaceAsync(WorkspaceId); + if (_workspace != null) + { + _recentFakten = await DbService.GetFaktenForWorkspaceAsync(WorkspaceId); + _recentFakten = _recentFakten.Take(5).ToList(); + } + } + + private async Task UploadFile(Microsoft.AspNetCore.Components.Forms.IBrowserFile e) + { + var file = e; + if (file == null) return; + + try + { + // 1. Datenstrom vom Browser öffnen + using var browserStream = file.OpenReadStream(maxAllowedSize: 1024 * 1024 * 10); // 10MB + + // 2. Den Stream komplett in den "Eimer" (Arbeitsspeicher) laden + using var memoryStream = new MemoryStream(); + await browserStream.CopyToAsync(memoryStream); + + // 3. WICHTIG: Den Lese-Zeiger im Eimer wieder nach ganz oben setzen! + memoryStream.Position = 0; + + // 4. Den fertigen MemoryStream an den Service übergeben + await DbService.ImportFromExcelAsync(WorkspaceId, memoryStream); + + Snackbar.Add("Import erfolgreich!", Severity.Success); + + // Die Tabelle mit den neuen Daten aktualisieren + _recentFakten = (await DbService.GetFaktenForWorkspaceAsync(WorkspaceId)).Take(5).ToList(); + } + catch (Exception ex) + { + Snackbar.Add($"Fehler beim Import: {ex.Message}", Severity.Error); + } + } +} \ No newline at end of file diff --git a/Services/WorkspaceService.cs b/Services/WorkspaceService.cs index 65b2541..fd3c996 100644 --- a/Services/WorkspaceService.cs +++ b/Services/WorkspaceService.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Components.Authorization; using Raven.Client.Documents; using ZahlenAnalyse.Web.Models; +using ExcelDataReader; +using System.Data; namespace ZahlenAnalyse.Web.Services; @@ -118,4 +120,43 @@ public class WorkspaceService .OrderByDescending(f => f.Date) .ToListAsync(); } + + public async Task ImportFromExcelAsync(string workspaceId, Stream fileStream) +{ + // Encoding für deutsche Excel-Dateien + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); + + using var reader = ExcelReaderFactory.CreateReader(fileStream); + var result = reader.AsDataSet(new ExcelDataSetConfiguration() { + ConfigureDataTable = (_) => new ExcelDataTableConfiguration() { UseHeaderRow = true } + }); + + var dataTable = result.Tables[0]; + + using var session = _store.OpenAsyncSession(); + + foreach (DataRow row in dataTable.Rows) + { + var fakt = new AnalysisFakt + { + WorkspaceId = workspaceId, + Date = Convert.ToDateTime(row["Datum"]), + Amount = Convert.ToDecimal(row["Betrag"]), + // Hier mappen wir dynamisch die Dimensionen + Dimensions = new Dictionary() + }; + + // Wir gehen davon aus, dass deine Excel-Spaltennamen + // den Dimensions-Namen entsprechen + foreach (var col in dataTable.Columns.Cast().Skip(2)) // Datum/Betrag überspringen + { + fakt.Dimensions[col.ColumnName] = row[col.ColumnName].ToString() ?? ""; + } + + await EnrichWithAuditDataAsync(fakt); + await session.StoreAsync(fakt); + } + + await session.SaveChangesAsync(); +} } \ No newline at end of file diff --git a/ZahlenAnalyse.Web.csproj b/ZahlenAnalyse.Web.csproj index d776c60..c2a883c 100644 --- a/ZahlenAnalyse.Web.csproj +++ b/ZahlenAnalyse.Web.csproj @@ -9,6 +9,8 @@ + +