Upload via GUI (258 Dateien)
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* ticket_print.php
|
||||
* Druckansicht für Kunden – ohne Navigation.
|
||||
*/
|
||||
require_once __DIR__ . '/includes/bootstrap.php';
|
||||
|
||||
$pdo = get_db();
|
||||
$number = $_GET['n'] ?? '';
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
'SELECT t.*, p.name AS priority_name, d.name AS department_name
|
||||
FROM tickets t
|
||||
JOIN priorities p ON p.id = t.priority_id
|
||||
JOIN departments d ON d.id = t.department_id
|
||||
WHERE t.ticket_number = ?'
|
||||
);
|
||||
$stmt->execute([$number]);
|
||||
$ticket = $stmt->fetch();
|
||||
|
||||
if (!$ticket) { http_response_code(404); die('Ticket nicht gefunden.'); }
|
||||
|
||||
// Zugangsprüfung: eingeloggter Kunde oder Gast-Zugang
|
||||
$user = current_user();
|
||||
$allowed = ($user && $ticket['user_id'] == $user['id'])
|
||||
|| !empty($_SESSION['guest_ticket_access'][$ticket['ticket_number']]);
|
||||
|
||||
if (!$allowed) {
|
||||
redirect('/ticket_lookup.php?n=' . urlencode($number));
|
||||
}
|
||||
|
||||
// Nur öffentliche Nachrichten
|
||||
$thread = $pdo->prepare(
|
||||
'SELECT tt.*, s.name AS staff_name, u.name AS user_name
|
||||
FROM ticket_threads tt
|
||||
LEFT JOIN staff s ON s.id = tt.staff_id
|
||||
LEFT JOIN users u ON u.id = tt.user_id
|
||||
WHERE tt.ticket_id = ? AND tt.is_internal_note = 0
|
||||
ORDER BY tt.created_at ASC'
|
||||
);
|
||||
$thread->execute([$ticket['id']]);
|
||||
$messages = $thread->fetchAll();
|
||||
|
||||
$attStmt = $pdo->prepare('SELECT * FROM ticket_attachments WHERE thread_id = ?');
|
||||
$siteName = get_setting('display_name', config()['site']['name'] ?? 'DeskHub');
|
||||
[$statusLabel] = status_label($ticket['status']);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Ticket #<?= e($ticket['ticket_number']) ?></title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 11pt; color: #1e293b; background: #fff; padding: 20mm; }
|
||||
.print-header { display: flex; justify-content: space-between; align-items: flex-start; padding-bottom: 12px; border-bottom: 2px solid #0f6f6a; margin-bottom: 16px; }
|
||||
.print-header .logo { font-size: 18pt; font-weight: 800; color: #0f6f6a; }
|
||||
.print-header .meta { text-align: right; font-size: 9pt; color: #64748b; }
|
||||
.ticket-title { font-size: 15pt; font-weight: 700; margin-bottom: 12px; }
|
||||
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 24px; margin-bottom: 20px; padding: 10px 14px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; }
|
||||
.info-row { display: flex; gap: 8px; font-size: 9.5pt; }
|
||||
.info-label { font-weight: 600; color: #64748b; min-width: 90px; }
|
||||
.section-title { font-size: 10pt; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: #64748b; margin: 16px 0 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px; }
|
||||
.message { border: 1px solid #e2e8f0; border-radius: 6px; margin-bottom: 10px; break-inside: avoid; }
|
||||
.message-header { display: flex; justify-content: space-between; padding: 7px 12px; background: #f8fafc; border-bottom: 1px solid #e2e8f0; font-size: 9pt; font-weight: 600; }
|
||||
.message-header.staff { background: #e6f4f3; }
|
||||
.message-body { padding: 10px 12px; font-size: 10pt; line-height: 1.6; }
|
||||
.attachments { padding: 5px 12px 7px; border-top: 1px solid #e2e8f0; font-size: 9pt; color: #64748b; }
|
||||
.print-footer { margin-top: 20px; padding-top: 8px; border-top: 1px solid #e2e8f0; font-size: 8.5pt; color: #94a3b8; display: flex; justify-content: space-between; }
|
||||
@media print { .no-print { display: none !important; } @page { margin: 15mm; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="no-print" style="position:fixed;top:16px;right:16px;display:flex;gap:8px">
|
||||
<button onclick="window.print()" style="padding:8px 16px;background:#0f6f6a;color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:.85rem">🖨 Drucken</button>
|
||||
<a href="/ticket_view.php?n=<?= urlencode($number) ?>" style="padding:8px 14px;border:1px solid #e2e8f0;border-radius:6px;text-decoration:none;color:#64748b;font-size:.85rem;background:#fff">← Zurück</a>
|
||||
</div>
|
||||
|
||||
<div class="print-header">
|
||||
<div class="logo"><?= e($siteName) ?></div>
|
||||
<div class="meta">Gedruckt: <?= date('d.m.Y H:i') ?></div>
|
||||
</div>
|
||||
|
||||
<div class="ticket-title"><?= e($ticket['subject']) ?></div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-row"><span class="info-label">Ticket-Nr.:</span><span>#<?= e($ticket['ticket_number']) ?></span></div>
|
||||
<div class="info-row"><span class="info-label">Status:</span><span><?= e($statusLabel) ?></span></div>
|
||||
<div class="info-row"><span class="info-label">Abteilung:</span><span><?= e($ticket['department_name']) ?></span></div>
|
||||
<div class="info-row"><span class="info-label">Erstellt:</span><span><?= date('d.m.Y H:i', strtotime($ticket['created_at'])) ?></span></div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Nachrichtenverlauf</div>
|
||||
|
||||
<?php foreach ($messages as $msg):
|
||||
$isStaff = $msg['author_type'] === 'staff';
|
||||
$author = $isStaff ? ($msg['staff_name'] ?? 'Support') : ($msg['user_name'] ?? $ticket['requester_name']);
|
||||
$body = $msg['message'] ?? '';
|
||||
$isHtml = preg_match('/<[a-zA-Z][^>]*>/i', $body);
|
||||
$attStmt->execute([$msg['id']]);
|
||||
$atts = $attStmt->fetchAll();
|
||||
?>
|
||||
<div class="message">
|
||||
<div class="message-header <?= $isStaff ? 'staff' : '' ?>">
|
||||
<span><?= e($author) ?><?= $isStaff ? ' (Support)' : '' ?></span>
|
||||
<span style="color:#64748b"><?= date('d.m.Y H:i', strtotime($msg['created_at'])) ?></span>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<?php if ($isHtml): ?>
|
||||
<?= sanitize_staff_html($body) ?>
|
||||
<?php else: ?>
|
||||
<?php foreach (preg_split('/\n{2,}/', trim($body)) as $p): $p = trim($p); if ($p): ?>
|
||||
<p style="margin:0 0 8px"><?= nl2br(e($p)) ?></p>
|
||||
<?php endif; endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ($atts): ?>
|
||||
<div class="attachments">📎 <?= implode(', ', array_map(fn($a) => e($a['original_name']), $atts)) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="print-footer">
|
||||
<span><?= e($siteName) ?> – Ticket #<?= e($ticket['ticket_number']) ?></span>
|
||||
<span><?= date('d.m.Y') ?></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user