Files
deskhub/DeskHub-Webseite/ticket_print.php
T
2026-11-04 07:55:51 +00:00

131 lines
5.9 KiB
PHP
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.
<?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>
<?= site_icon_links() ?>
</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 = message_is_html($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>