Upload via GUI (364 Dateien)

This commit is contained in:
2026-11-01 11:15:52 +00:00
parent aeae758b4d
commit c1a170563d
7 changed files with 781 additions and 448 deletions
+50 -32
View File
@@ -44,7 +44,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
flash('success', 'Ticket wurde mit dem Problem verknüpft.');
} elseif ($action === 'ticket_unlink') {
$ticketId = (int) ($_POST['ticket_id'] ?? 0);
ticket_problem_unlink($pdo, $problemId, $ticketId);
if (!ticket_problem_unlink($pdo, $problemId, $ticketId)) throw new InvalidArgumentException('Dieses Ticket ist mit dem Problem nicht verknüpft.');
log_activity($pdo, $ticketId, (int) $staff['id'], 'Verknüpfung mit ' . ticket_problem_number($problemId) . ' entfernt');
audit_log($staff['id'], 'Ticket von ' . ticket_problem_number($problemId) . ' getrennt');
flash('success', 'Ticket-Verknüpfung wurde entfernt.');
@@ -65,13 +65,18 @@ $activePage = 'problems';
$pageTitle = 'Problemmanagement';
require __DIR__ . '/_header.php';
?>
<h1>Problemmanagement</h1>
<p class="muted">Bündeln Sie Tickets mit derselben Ursache. Ursache, Workaround und dauerhafte Lösung werden zentral dokumentiert.</p>
<div class="pm-head">
<div>
<h1 style="margin:0">Problemmanagement</h1>
<p class="muted" style="margin:4px 0 0">Bündeln Sie Tickets mit derselben Ursache. Ursache, Workaround und dauerhafte Lösung werden zentral dokumentiert.</p>
</div>
<?php if ($activeTab === 'create' || $problem): ?>
<a class="btn secondary" href="/staff/problems.php">← Alle Probleme</a>
<?php else: ?>
<a class="btn" href="/staff/problems.php?tab=create">+ Neues Problem</a>
<?php endif; ?>
</div>
<?php foreach ($errors as $error): ?><div class="flash error"><?= e($error) ?></div><?php endforeach; ?>
<nav class="problem-tabs" role="tablist" aria-label="Problemmanagement">
<a role="tab" aria-selected="<?= $activeTab === 'list' ? 'true' : 'false' ?>" class="<?= $activeTab === 'list' ? 'active' : '' ?>" href="/staff/problems.php?tab=list<?= $problemId ? '&amp;id=' . $problemId : '' ?>">Probleme</a>
<a role="tab" aria-selected="<?= $activeTab === 'create' ? 'true' : 'false' ?>" class="<?= $activeTab === 'create' ? 'active' : '' ?>" href="/staff/problems.php?tab=create">Neues Problem</a>
</nav>
<?php if ($activeTab === 'create'): ?>
<section class="card">
<h2 style="margin-top:0">Neues Problem erfassen</h2>
@@ -86,22 +91,36 @@ require __DIR__ . '/_header.php';
</form>
</section>
<?php else: ?>
<div style="display:grid;grid-template-columns:minmax(240px,320px) minmax(0,1fr);gap:16px;align-items:start">
<aside class="card">
<h3 style="margin-top:0">Probleme</h3>
<?php if (!$problems): ?><p class="muted">Noch keine Probleme erfasst.</p><?php endif; ?>
<?php foreach ($problems as $item): ?>
<a href="/staff/problems.php?id=<?= (int) $item['id'] ?>" style="display:block;padding:9px 4px;border-top:1px solid var(--border,#e3e9ee);text-decoration:none;<?= (int) $item['id'] === $problemId ? 'font-weight:700;color:var(--primary)' : '' ?>">
<strong><?= e(ticket_problem_number((int) $item['id'])) ?></strong> · <?= e($item['title']) ?><br>
<span class="muted" style="font-size:.78rem"><?= e($problemStatuses[$item['status']] ?? $item['status']) ?> · <?= (int) $item['ticket_count'] ?> Tickets</span>
</a>
<?php endforeach; ?>
</aside>
<?php if (!$problem): ?>
<?php $openCount = 0; foreach ($problems as $item) { if ($item['status'] !== 'resolved') $openCount++; } ?>
<section class="card" style="padding:0;overflow:hidden">
<?php if (!$problems): ?>
<div class="empty-state" style="padding:32px">Noch keine Probleme erfasst. <a href="/staff/problems.php?tab=create">Erstes Problem anlegen</a></div>
<?php else: ?>
<div class="muted" style="padding:14px 20px;border-bottom:1px solid var(--border,#e3e9ee)"><?= count($problems) ?> Probleme · <?= $openCount ?> offen</div>
<table>
<thead><tr><th>Nr.</th><th>Titel</th><th>Status</th><th>Tickets</th><th>Zuletzt geändert</th></tr></thead>
<tbody>
<?php foreach ($problems as $item):
$pColor = ['investigating' => '#dc2626', 'workaround' => '#d97706', 'monitoring' => '#2563eb', 'resolved' => '#16a34a'][$item['status']] ?? '#64748b';
$pUrl = '/staff/problems.php?id=' . (int) $item['id'];
?>
<tr>
<td style="white-space:nowrap"><a href="<?= $pUrl ?>" class="ticket-no"><?= e(ticket_problem_number((int) $item['id'])) ?></a></td>
<td><a href="<?= $pUrl ?>"><strong><?= e($item['title']) ?></strong></a>
<?php if (!empty($item['description'])): ?><div class="muted" style="font-size:.8rem;max-width:560px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"><?= e($item['description']) ?></div><?php endif; ?></td>
<td><span class="badge" style="background:<?= $pColor ?>"><?= e($problemStatuses[$item['status']] ?? $item['status']) ?></span></td>
<td><?= (int) $item['ticket_count'] ?></td>
<td class="muted" style="white-space:nowrap"><?= e(format_dt((string) ($item['updated_at'] ?? $item['created_at']))) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</section>
<?php else: ?>
<div class="pm-detail">
<main>
<?php if (!$problem): ?>
<section class="card"><h3>Problem auswählen</h3><p class="muted">Wählen Sie links ein Problem aus oder legen Sie ein neues an.</p></section>
<?php else: ?>
<section class="card">
<div style="display:flex;justify-content:space-between;align-items:start;gap:12px;flex-wrap:wrap">
<div><span class="muted"><?= e(ticket_problem_number($problemId)) ?></span><h2 style="margin:2px 0 12px"><?= e($problem['title']) ?></h2></div>
@@ -116,8 +135,9 @@ require __DIR__ . '/_header.php';
<div style="display:flex;gap:12px;align-items:end;flex-wrap:wrap;margin-top:8px"><div><label for="problem_status">Status</label><select id="problem_status" name="status"><?php foreach ($problemStatuses as $key => $label): ?><option value="<?= e($key) ?>" <?= $problem['status'] === $key ? 'selected' : '' ?>><?= e($label) ?></option><?php endforeach; ?></select></div><button class="btn" type="submit">Problem speichern</button></div>
</form>
</section>
<section class="card" style="margin-top:16px">
</main>
<aside>
<section class="card">
<h3 style="margin-top:0">Verknüpfte Tickets (<?= count($linkedTickets) ?>)</h3>
<form method="post" style="display:flex;gap:8px;flex-wrap:wrap;align-items:end;margin-bottom:12px"><?= csrf_field() ?><input type="hidden" name="action" value="ticket_link"><input type="hidden" name="problem_id" value="<?= $problemId ?>"><div style="flex:1;min-width:200px"><label for="link_ticket_number">Ticketnummer</label><input id="link_ticket_number" type="text" name="ticket_number" required placeholder="z. B. 260001"></div><button class="btn secondary" type="submit">Ticket verknüpfen</button></form>
<?php if (!$linkedTickets): ?><p class="muted">Noch keine Tickets mit diesem Problem verknüpft.</p><?php endif; ?>
@@ -128,15 +148,13 @@ require __DIR__ . '/_header.php';
</div>
<?php endforeach; ?>
</section>
<?php endif; ?>
</main>
</div>
</aside>
</div>
<?php endif; ?>
<?php endif; ?>
<style>
.problem-tabs{display:flex;gap:8px;margin:18px 0 12px;border-bottom:1px solid var(--border,#d8e0e8)}
.problem-tabs a{border-bottom:3px solid transparent;border-radius:7px 7px 0 0;background:transparent;color:var(--muted,#64748b);padding:10px 16px;font-weight:700;text-decoration:none}
.problem-tabs a.active{color:var(--text,#0f172a);border-bottom-color:var(--primary,#0f766e);background:var(--surface,#fff)}
@media(max-width:760px){.card+main{min-width:0}}
.pm-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap;margin-bottom:18px}
.pm-detail{display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,400px);gap:16px;align-items:start}
@media(max-width:900px){.pm-detail{grid-template-columns:1fr}}
</style>
<?php require __DIR__ . '/_footer.php'; ?>