Files
DXApp/DXApp.TemplateKitProject/Pages/Invoices/Details.cshtml
2026-06-09 11:48:41 +02:00

294 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@page
@model DXApp.TemplateKitProject.Pages.Invoices.DetailsModel
@{
ViewData["Title"] = "Rechnungsdetails";
string FormatFileSize(long bytes)
{
if (bytes < 1024) return $"{bytes} Bytes";
if (bytes < 1024 * 1024) return $"{bytes / 1024.0:N2} KB";
return $"{bytes / (1024.0 * 1024.0):N2} MB";
}
}
<h2><i class="dx-icon-doc"></i> Rechnungsdetails</h2>
<a href="/Invoices" class="btn btn-secondary mb-3"><i class="dx-icon-back"></i> Zurück zur Liste</a>
@if (!string.IsNullOrEmpty(Model.Invoice?.ResultFilePath))
{
<button class="btn btn-primary mb-3 ms-2"
onclick="openPdfViewer(@Model.Invoice.Id)">
<i class="dx-icon-pdffile"></i> Ergebnis anzeigen
</button>
}
@if (Model.Invoice is null)
{
<div class="alert alert-danger">Rechnung nicht gefunden.</div>
}
else
{
<table class="table table-sm table-bordered w-auto">
<tr><th>ID</th><td>@Model.Invoice.Id</td></tr>
<tr><th>Rechnungsnummer</th><td>@Model.Invoice.InvoiceNumber</td></tr>
<tr><th>Rechnungsdatum</th><td>@Model.Invoice.InvoiceDate.ToString("dd.MM.yyyy")</td></tr>
<tr><th>Verkäufer</th><td>@Model.Invoice.SellerName</td></tr>
<tr><th>USt-ID Verkäufer</th><td>@Model.Invoice.SellerTaxId</td></tr>
<tr><th>Käufer</th><td>@Model.Invoice.BuyerName</td></tr>
<tr><th>Währung</th><td>@Model.Invoice.CurrencyCode</td></tr>
<tr><th>Steuerbetrag</th><td>@Model.Invoice.TaxAmount.ToString("N2")</td></tr>
<tr><th>Gesamtbetrag</th><td><strong>@Model.Invoice.TotalAmount.ToString("N2")</strong></td></tr>
<tr><th>IBAN</th><td>@Model.Invoice.Iban</td></tr>
<tr><th>Quelle</th><td>@Model.Invoice.SourceType</td></tr>
<tr><th>Guideline-ID</th><td><code>@Model.Invoice.GuidelineId</code></td></tr>
<tr><th>Importiert am</th><td>@Model.Invoice.ImportedAt.ToString("dd.MM.yyyy HH:mm")</td></tr>
<tr>
<th>Result-PDF</th>
<td>
@if (!string.IsNullOrEmpty(Model.Invoice.ResultFilePath))
{
<small class="text-muted">@Model.Invoice.ResultFilePath</small>
}
else
{
<span class="text-muted"> nicht vorhanden </span>
}
</td>
</tr>
</table>
@* Anhänge-Sektion *@
@if (Model.Invoice.Attachments.Any())
{
<h4 class="mt-4"><i class="dx-icon-attach"></i> Anhänge (@Model.Invoice.Attachments.Count)</h4>
<div class="list-group">
@foreach (var attachment in Model.Invoice.Attachments)
{
var icon = "dx-icon-file";
var extension = System.IO.Path.GetExtension(attachment.OriginalFileName).ToLowerInvariant();
icon = extension switch
{
".xml" => "dx-icon-exportxlsx",
".pdf" => "dx-icon-pdffile",
".jpg" or ".jpeg" or ".png" or ".gif" => "dx-icon-image",
".txt" => "dx-icon-txtfile",
_ => "dx-icon-file"
};
<a href="javascript:void(0);"
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"
onclick="openAttachmentViewer('@attachment.OriginalFileName', '@Uri.EscapeDataString(attachment.SavedFilePath)', '@extension')">
<div>
<i class="@icon me-2"></i>
<strong>@attachment.OriginalFileName</strong>
@if (attachment.IsZugferdXml)
{
<span class="badge bg-success ms-2">ZUGFeRD-XML</span>
}
<br />
<small class="text-muted">
Größe: @FormatFileSize(attachment.FileSizeBytes) ·
Extrahiert: @attachment.ExtractedAt.ToString("dd.MM.yyyy HH:mm")
</small>
</div>
<span class="badge bg-primary">Öffnen</span>
</a>
}
</div>
}
else
{
<h4 class="mt-4"><i class="dx-icon-attach"></i> Anhänge</h4>
<div class="alert alert-info">Keine Anhänge extrahiert.</div>
}
@(Html.DevExtreme().Popup()
.ID("pdf-viewer-popup")
.Title("PDF Viewer")
.Width("90%")
.Height("90%")
.ShowCloseButton(true)
.OnHiding("onPdfPopupHiding")
.Shading(true)
.ShadingColor("rgba(0, 0, 0, 0.5)")
.ContentTemplate(new JS(@"function() {
return '<iframe id=""pdf-iframe"" style=""width:100%;height:100%;border:none;""></iframe>';
}"))
)
@(Html.DevExtreme().Popup()
.ID("attachment-viewer-popup")
.Title("Anhang")
.Width("90%")
.Height("90%")
.ShowCloseButton(true)
.OnHiding("onAttachmentPopupHiding")
.Shading(true)
.ShadingColor("rgba(0, 0, 0, 0.5)")
.ContentTemplate(new JS(@"function() {
return '<div id=""attachment-content"" style=""width:100%;height:100%;overflow:hidden;display:flex;flex-direction:column;""></div>';
}"))
)
}
<style>
/* Z-Index für PDF-Viewer Popup erhöhen - muss höher sein als layout-header (1505) */
.dx-popup-wrapper.dx-overlay-wrapper {
z-index: 10500 !important;
}
.dx-overlay-shader {
z-index: 10499 !important;
}
/* Spezifisch für unser PDF-Popup */
#pdf-viewer-popup .dx-overlay-content {
z-index: 10500 !important;
}
/* CodeMirror soll volle Höhe des Popups nutzen */
#attachment-content {
height: 100% !important;
}
#attachment-content .CodeMirror {
height: 100% !important;
font-size: 14px;
}
</style>
<script>
function openPdfViewer(invoiceId) {
var pdfUrl = window.location.origin + '/Invoices/ViewPdf?id=' + invoiceId;
var viewerUrl = '/js/pdfjs/web/viewer.html?file=' + encodeURIComponent(pdfUrl);
var popup = $('#pdf-viewer-popup').dxPopup('instance');
// Z-Index explizit setzen (höher als layout-header mit 1505)
popup.option('container', undefined); // Default container verwenden
popup.option('position', { my: 'center', at: 'center', of: window });
// onShown sicherstellen dass iframe im DOM ist
popup.option('onShown', function () {
$('#pdf-iframe').attr('src', viewerUrl);
// Z-Index nach dem Öffnen nochmal sicherstellen
$('.dx-popup-wrapper').css('z-index', '10500');
$('.dx-overlay-shader').css('z-index', '10499');
});
popup.show();
}
function onPdfPopupHiding() {
// iframe src leeren beim Schließen → verhindert dass PDF im Hintergrund weiter läuft
$('#pdf-iframe').attr('src', '');
}
function openAttachmentViewer(fileName, encodedFilePath, extension) {
var filePath = decodeURIComponent(encodedFilePath);
var popup = $('#attachment-viewer-popup').dxPopup('instance');
var $content = $('#attachment-content');
// Popup-Titel setzen
popup.option('title', fileName);
// Z-Index setzen
popup.option('container', undefined);
popup.option('position', { my: 'center', at: 'center', of: window });
// Content basierend auf Dateityp laden
popup.option('onShown', function () {
$content.html('<div class="text-center p-5"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Laden...</span></div></div>');
// Z-Index sicherstellen
$('.dx-popup-wrapper').css('z-index', '10500');
$('.dx-overlay-shader').css('z-index', '10499');
if (extension === '.pdf') {
// PDF mit PDF.js anzeigen
var pdfUrl = window.location.origin + '/Invoices/ViewAttachment?handler=Download&filePath=' + encodedFilePath;
var viewerUrl = '/js/pdfjs/web/viewer.html?file=' + encodeURIComponent(pdfUrl);
$content.html('<iframe style="width:100%;height:100%;border:none;" src="' + viewerUrl + '"></iframe>');
}
else if (extension === '.xml' || extension === '.txt') {
// Text/XML laden und mit Syntax-Highlighting anzeigen
$.get('/Invoices/ViewAttachment?filePath=' + encodedFilePath, function(data) {
if (extension === '.xml') {
// CodeMirror für XML - Container leeren
$content.html('');
// CodeMirror laden (falls noch nicht geladen)
if (typeof CodeMirror === 'undefined') {
$('<link>')
.attr('rel', 'stylesheet')
.attr('href', 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css')
.appendTo('head');
$('<link>')
.attr('rel', 'stylesheet')
.attr('href', 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/monokai.min.css')
.appendTo('head');
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js', function() {
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/xml/xml.min.js', function() {
initCodeMirror(data);
});
});
} else {
initCodeMirror(data);
}
function initCodeMirror(content) {
// CodeMirror direkt in den Container einfügen
var editor = CodeMirror($content[0], {
value: content,
mode: 'xml',
lineNumbers: true,
readOnly: true,
theme: 'monokai',
lineWrapping: true,
viewportMargin: Infinity
});
// Höhe explizit setzen nach kurzer Verzögerung
setTimeout(function() {
editor.setSize('100%', '100%');
editor.refresh();
}, 100);
}
} else {
// Plain Text
$content.html('<pre style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; height: 100%; overflow: auto; margin: 0;">' +
$('<div>').text(data).html() + '</pre>');
}
}).fail(function() {
$content.html('<div class="alert alert-danger m-3">Fehler beim Laden der Datei.</div>');
});
}
else if (extension === '.jpg' || extension === '.jpeg' || extension === '.png' || extension === '.gif') {
// Bild anzeigen
var imageUrl = window.location.origin + '/Invoices/ViewAttachment?handler=Download&filePath=' + encodedFilePath;
$content.html('<div class="text-center p-3" style="height: 100%; display: flex; align-items: center; justify-content: center;">' +
'<img src="' + imageUrl + '" alt="' + fileName + '" class="img-fluid" style="max-height: 100%; max-width: 100%; object-fit: contain;">' +
'</div>');
}
else {
// Nicht unterstützter Typ → Download anbieten
var downloadUrl = window.location.origin + '/Invoices/ViewAttachment?handler=Download&filePath=' + encodedFilePath;
$content.html('<div class="alert alert-info m-3">' +
'<h5>Dieser Dateityp kann nicht angezeigt werden.</h5>' +
'<p>Bitte laden Sie die Datei herunter:</p>' +
'<a href="' + downloadUrl + '" class="btn btn-primary" download="' + fileName + '">' +
'<i class="dx-icon-download"></i> Datei herunterladen' +
'</a></div>');
}
});
popup.show();
}
function onAttachmentPopupHiding() {
// Content leeren
$('#attachment-content').html('');
}
</script>