QR-Scanner: Kamera-Fallbacks und Foto-Upload; weitere Aenderungen

This commit is contained in:
spaethf committed 2026-09-29 18:08:01 +02:00
1 parent 7a0406eaa2
commit e2aef67099
13 files changed
+965 -58

No files matched your search

@@ -4,6 +4,8 @@
@inject ILocationCodeService LocationCodeService
@inject ITireStackService TireStackService
@inject UserSessionService UserSession
@inject IStorageRowPdfService RowPdfService
@inject IJSRuntime JS
<PageTitle>Lagerplätze - Reifen Späth Lagerverwaltung</PageTitle>
@@ -52,7 +54,7 @@ else
</button>
<button class="stat-chip available @(statusFilter == StatusAvailable ? "active" : "")"
@onclick="FilterByStatusAvailable" title="Nur freie Plätze anzeigen">
<span class="chip-value">@allLocations.Count(l => !l.IsOccupied)</span> Frei
<span class="chip-value">@allLocations.Count(l => !l.IsOccupied && l.IsAvailable)</span> Frei
</button>
<button class="stat-chip occupied @(statusFilter == StatusOccupied ? "active" : "")"
@onclick="FilterByStatusOccupied" title="Nur belegte Plätze anzeigen">
@@ -132,11 +134,24 @@ else
var occupiedCount = rowGroup.Count(l => l.IsOccupied);
var totalCount = rowGroup.Count();
<div class="row-section @(isCollapsed ? "collapsed" : "")">
<button type="button" class="row-header" @onclick="() => ToggleRow(rowKey)">
<span class="row-chevron">@(isCollapsed ? "▶" : "▼")</span>
<h3 class="row-title">Reihe @rowGroup.Key</h3>
<span class="row-summary">@occupiedCount / @totalCount belegt</span>
</button>
<div class="row-header-wrap">
<button type="button" class="row-header" @onclick="() => ToggleRow(rowKey)">
<span class="row-chevron">@(isCollapsed ? "▶" : "▼")</span>
<h3 class="row-title">Reihe @rowGroup.Key</h3>
<span class="row-summary">@occupiedCount / @totalCount belegt</span>
</button>
<button type="button" class="btn btn-outline btn-sm row-print-btn"
title="Reihe als PDF drucken"
disabled="@(printingRowKey != null)"
@onclick="() => PrintRow(areaGroup.Key, rowGroup.Key)"
@onclick:stopPropagation>
@(printingRowKey == rowKey ? "⏳" : "🖨") PDF
</button>
</div>
@if (printErrorRowKey == rowKey && printError != null)
{
<div class="row-print-error" role="alert">@printError</div>
}
@if (!isCollapsed)
{
@foreach (var posGroup in rowGroup.GroupBy(l => l.Position).OrderBy(g => (int)g.Key))
@@ -155,11 +170,21 @@ else
@if (location.IsOccupied && storedTireStack != null)
{
<div class="card-content">
<span class="customer-name">
<span class="customer-name" title="@(storedTireStack.Customer?.FullName ?? storedTireStack.CatalogItem?.Name ?? "Lager")">
@(storedTireStack.Customer?.FullName ?? storedTireStack.CatalogItem?.Name ?? "Lager")
</span>
@if (storedTireStack.Vehicle != null)
{
<span class="vehicle-line" title="@storedTireStack.Vehicle.ShortName">
<span class="vehicle-model">🚗 @storedTireStack.Vehicle.ShortName</span>
</span>
}
<span class="tire-info">
@(storedTireStack.Season == TireSeason.Sommer ? "☀️" : storedTireStack.Season == TireSeason.Winter ? "❄️" : "🔄")
<span class="season-icon">@(storedTireStack.Season == TireSeason.Sommer ? "☀️" : storedTireStack.Season == TireSeason.Winter ? "❄️" : "🔄")</span>
@if (!string.IsNullOrEmpty(storedTireStack.TireSize))
{
<span class="tire-size-compact">@storedTireStack.TireSize</span>
}
</span>
</div>
}
@@ -231,7 +256,7 @@ else
<span class="customer">@storedTireStack.Customer.FullName</span>
@if (storedTireStack.Vehicle != null)
{
<span class="vehicle-info">@storedTireStack.Vehicle.ShortName</span>
<span class="vehicle-info">🚗 @storedTireStack.Vehicle.ShortName</span>
}
}
else
@@ -761,6 +786,40 @@ else
}
}
private string? printingRowKey;
private string? printErrorRowKey;
private string? printError;
private async Task PrintRow(AreaType area, int row)
{
var rowKey = $"{area}-{row}";
if (printingRowKey != null) return;
printingRowKey = rowKey;
printError = null;
printErrorRowKey = null;
try
{
var rowLocations = allLocations
.Where(l => l.Area == area && l.Row == row)
.ToList();
var pdf = RowPdfService.GenerateRowPdf(area, row, rowLocations);
var fileName = $"Lagerplan_{area.GetDisplayName()}_Reihe{row}_{DateTime.Now:yyyyMMdd-HHmm}.pdf";
await JS.InvokeVoidAsync("appInterop.downloadFile", fileName, Convert.ToBase64String(pdf), "application/pdf");
}
catch (Exception ex)
{
printErrorRowKey = rowKey;
printError = $"PDF konnte nicht erstellt werden: {ex.Message}";
}
finally
{
printingRowKey = null;
}
}
// Batch creation
private AreaType batchArea = AreaType.Lager;
private int batchRow = 1;