feat: implementiert PDF-Generierung mit Hintergrundbild und Dokumentation

This commit is contained in:
Adam Gaiswinkler
2026-02-18 22:43:26 +01:00
parent 1bff5ebbbd
commit e7ee313472
7 changed files with 538 additions and 11 deletions

View File

@@ -76,13 +76,13 @@ else
@foreach (var line in (_item.Description?.Replace("\t", " ").Split('\n') ?? Array.Empty<string>()))
{
<div class="hof-description-line">@line</div>
}
}
</div>
</div>
<div class="d-flex flex-wrap gap-3 mt-5 no-print">
<button type="button" class="btn btn-primary btn-lg px-4 shadow-sm" @onclick="PrintPage">
<i class="oi oi-print me-2"></i> Als PDF speichern
<button type="button" class="btn btn-primary btn-lg px-4 shadow-sm" @onclick="ShowPdfPreview">
<i class="oi oi-eye me-2"></i> PDF Vorschau
</button>
@if (!string.IsNullOrEmpty(_item.Link))
@@ -134,6 +134,28 @@ else
</div>
</div>
}
@if (_showPdfModal)
{
<div class="modal fade show" style="display: block; background: rgba(0,0,0,0.6); z-index: 1050;" tabindex="-1">
<div class="modal-dialog modal-xl modal-dialog-centered" style="max-width: 90vw; height: 90vh;">
<div class="modal-content" style="height: 90vh;">
<div class="modal-header">
<h5 class="modal-title"><i class="oi oi-document me-2"></i> PDF Vorschau</h5>
<button type="button" class="btn-close" @onclick="ClosePdfPreview"></button>
</div>
<div class="modal-body p-0" style="flex: 1; overflow: hidden;">
<iframe src="@_pdfPreviewUrl" style="width: 100%; height: 100%; border: none;"></iframe>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @onclick="ClosePdfPreview">Schließen</button>
<button type="button" class="btn btn-primary" @onclick="DownloadPdf">
<i class="oi oi-data-transfer-download me-2"></i> Herunterladen
</button>
</div>
</div>
</div>
</div>
}
}
<style>
@@ -214,6 +236,8 @@ else
private bool _showReportModal = false;
private string _reportReason = "";
private bool _showPdfModal = false;
private string _pdfPreviewUrl = "";
protected override async Task OnInitializedAsync()
{
@@ -239,9 +263,22 @@ else
}
}
private async Task PrintPage()
private void ShowPdfPreview()
{
await JSRuntime.InvokeVoidAsync("window.print");
_pdfPreviewUrl = $"/api/HallOfFamePdf?moduleid={ModuleState.ModuleId}";
_showPdfModal = true;
}
private void ClosePdfPreview()
{
_showPdfModal = false;
_pdfPreviewUrl = "";
}
private async Task DownloadPdf()
{
var url = $"/api/HallOfFamePdf?moduleid={ModuleState.ModuleId}&download=true";
await JSRuntime.InvokeVoidAsync("eval", $"var a = document.createElement('a'); a.href = '{url}'; a.download = 'HallOfFame.pdf'; document.body.appendChild(a); a.click(); document.body.removeChild(a);");
}
private void ShowReportModal()

View File

@@ -79,10 +79,18 @@
</div>
</div>
<div class="mt-4">
<button type="button" class="btn btn-secondary me-2" @onclick="@(() => Save("Draft"))" disabled="@_uploading">Als Entwurf speichern</button>
<button type="button" class="btn btn-primary" @onclick="@(() => Save("Published"))" disabled="@_uploading">Veröffentlichen</button>
<NavLink class="btn btn-link ms-2" href="@NavigateUrl()">Abbrechen</NavLink>
<div class="mt-4 d-flex justify-content-between align-items-center">
<div>
<button type="button" class="btn btn-secondary me-2" @onclick="@(() => Save("Draft"))" disabled="@_uploading">Als Entwurf speichern</button>
<button type="button" class="btn btn-primary" @onclick="@(() => Save("Published"))" disabled="@_uploading">Veröffentlichen</button>
<NavLink class="btn btn-link ms-2" href="@NavigateUrl()">Abbrechen</NavLink>
</div>
@if (PageState.Action == "Edit")
{
<button type="button" class="btn btn-outline-danger" @onclick="DeleteEntry" disabled="@_uploading">
<i class="oi oi-trash me-1"></i> Eintrag löschen
</button>
}
</div>
<br /><br />
@@ -265,4 +273,18 @@
AddModuleMessage(Localizer["Message.SaveError"], MessageType.Error);
}
}
private async Task DeleteEntry()
{
try
{
await HallOfFameService.DeleteHallOfFameAsync(_id, ModuleState.ModuleId);
NavigationManager.NavigateTo(NavigateUrl());
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting HallOfFame {Error}", ex.Message);
AddModuleMessage("Fehler beim Löschen des Eintrags.", MessageType.Error);
}
}
}

View File

@@ -163,7 +163,8 @@ else
{
try
{
_HallOfFames = await HallOfFameService.GetHallOfFamesAsync(ModuleState.ModuleId);
var allEntries = await HallOfFameService.GetHallOfFamesAsync(ModuleState.ModuleId);
_HallOfFames = allEntries.Where(i => i.Status == "Published").ToList();
if (PageState.User != null)
{