Excel-Import
This commit is contained in:
@@ -55,7 +55,9 @@
|
||||
</MudText>
|
||||
</CardHeaderContent>
|
||||
<CardHeaderActions>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Settings" Color="Color.Default" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Settings"
|
||||
Color="Color.Default"
|
||||
Href="@($"/workspace/{ws.Id}")" />
|
||||
</CardHeaderActions>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
@page "/workspace/{*WorkspaceId}"
|
||||
@using ZahlenAnalyse.Web.Models
|
||||
@using ZahlenAnalyse.Web.Services
|
||||
@inject WorkspaceService DbService
|
||||
@inject ISnackbar Snackbar
|
||||
@inject NavigationManager NavManager
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="mt-8 mb-8">
|
||||
@if (_workspace == null)
|
||||
{
|
||||
<MudProgressCircular Indeterminate="true" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.h3" Class="mb-6">@_workspace.Name</MudText>
|
||||
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-6" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-4">Daten importieren</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mb-4">Lade eine Excel-Datei hoch, um Fakten in diesen Workspace zu importieren.</MudText>
|
||||
|
||||
<MudFileUpload T="IBrowserFile" FilesChanged="@(e => UploadFile(e))" Accept=".xlsx">
|
||||
<CustomContent>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.CloudUpload"
|
||||
OnClick="@context.OpenFilePickerAsync">
|
||||
Excel hochladen
|
||||
</MudButton>
|
||||
</CustomContent>
|
||||
</MudFileUpload>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-6" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-4">Dimensionen</MudText>
|
||||
<MudStack Row="true" Wrap="Wrap.Wrap">
|
||||
@foreach (var dim in _workspace.Dimensions)
|
||||
{
|
||||
<MudChip T="string" Variant="Variant.Outlined" Color="Color.Info">@dim.Name</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12">
|
||||
<MudPaper Class="pa-6" Elevation="1">
|
||||
<MudText Typo="Typo.h6" Class="mb-4">Letzte Importe / Einträge</MudText>
|
||||
<MudTable Items="_recentFakten" Hover="true" Breakpoint="Breakpoint.Sm">
|
||||
<HeaderContent>
|
||||
<MudTh>Datum</MudTh>
|
||||
<MudTh>Betrag</MudTh>
|
||||
<MudTh>Details</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Date.ToShortDateString()</MudTd>
|
||||
<MudTd>@context.Amount.ToString("N2") €</MudTd>
|
||||
<MudTd>@string.Join(" | ", context.Dimensions.Values)</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
</MudContainer>
|
||||
|
||||
@code {
|
||||
[Parameter] public string WorkspaceId { get; set; } = string.Empty;
|
||||
private Workspace? _workspace;
|
||||
private List<AnalysisFakt> _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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<string, string>()
|
||||
};
|
||||
|
||||
// Wir gehen davon aus, dass deine Excel-Spaltennamen
|
||||
// den Dimensions-Namen entsprechen
|
||||
foreach (var col in dataTable.Columns.Cast<DataColumn>().Skip(2)) // Datum/Betrag überspringen
|
||||
{
|
||||
fakt.Dimensions[col.ColumnName] = row[col.ColumnName].ToString() ?? "";
|
||||
}
|
||||
|
||||
await EnrichWithAuditDataAsync(fakt);
|
||||
await session.StoreAsync(fakt);
|
||||
}
|
||||
|
||||
await session.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetEnv" Version="3.2.0" />
|
||||
<PackageReference Include="ExcelDataReader" Version="3.8.0" />
|
||||
<PackageReference Include="ExcelDataReader.DataSet" Version="3.8.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="10.0.8" />
|
||||
<PackageReference Include="MudBlazor" Version="9.5.0" />
|
||||
<PackageReference Include="RavenDB.Client" Version="7.2.2" />
|
||||
|
||||
Reference in New Issue
Block a user