Files
2026-10-23 17:50:17 +00:00

374 lines
24 KiB
PHP
Raw Permalink 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
require_once __DIR__ . '/../includes/bootstrap.php';
require_once __DIR__ . '/../includes/assistant.php';
$admin = require_admin_or_permission('manage_assistant');
$pdo = get_db();
$errors = [];
$testQuestion = '';
$testResult = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
$action = $_POST['action'] ?? '';
if ($action === 'save_settings') {
$dept = (int) ($_POST['assistant_department_id'] ?? 0);
$prio = (int) ($_POST['assistant_priority_id'] ?? 0);
$mode = ($_POST['assistant_mode'] ?? 'offline_only') === 'always' ? 'always' : 'offline_only';
if ($dept > 0) { $c = $pdo->prepare('SELECT COUNT(*) FROM departments WHERE id = ? AND is_active = 1'); $c->execute([$dept]); if (!(int) $c->fetchColumn()) $dept = 0; }
if ($prio > 0) { $c = $pdo->prepare('SELECT COUNT(*) FROM priorities WHERE id = ?'); $c->execute([$prio]); if (!(int) $c->fetchColumn()) $prio = 0; }
set_setting('assistant_enabled', !empty($_POST['assistant_enabled']) ? '1' : '0');
set_setting('assistant_mode', $mode);
set_setting('assistant_name', mb_substr(trim(strip_tags((string) ($_POST['assistant_name'] ?? ''))), 0, 60));
set_setting('assistant_greeting', mb_substr(trim(strip_tags((string) ($_POST['assistant_greeting'] ?? ''))), 0, 500));
set_setting('assistant_no_answer', mb_substr(trim(strip_tags((string) ($_POST['assistant_no_answer'] ?? ''))), 0, 500));
set_setting('assistant_department_id', (string) $dept);
set_setting('assistant_priority_id', (string) $prio);
set_setting('assistant_log_days', (string) max(0, min(3650, (int) ($_POST['assistant_log_days'] ?? 90))));
audit_log($admin['id'], 'Einstellungen des digitalen Assistenten geändert');
flash('success', 'Einstellungen gespeichert.');
redirect('/staff/assistant.php');
}
if ($action === 'save_answer') {
$id = (int) ($_POST['id'] ?? 0);
$title = trim(mb_substr((string) ($_POST['title'] ?? ''), 0, 255));
$keywords = trim(mb_substr((string) ($_POST['keywords'] ?? ''), 0, 1000));
$answer = trim(mb_substr((string) ($_POST['answer'] ?? ''), 0, 4000));
$active = !empty($_POST['is_active']) ? 1 : 0;
if ($title === '' || $answer === '') {
$errors[] = 'Bitte eine Frage (Titel) und die Antwort angeben.';
} else {
$now = db_now();
if ($id > 0) {
$pdo->prepare('UPDATE assistant_answers SET title=?, keywords=?, answer=?, is_active=?, updated_at=? WHERE id=?')->execute([$title, $keywords ?: null, $answer, $active, $now, $id]);
audit_log($admin['id'], "Antwort des digitalen Assistenten geändert: {$title}");
flash('success', 'Antwort gespeichert.');
} else {
$pdo->prepare('INSERT INTO assistant_answers (title, keywords, answer, is_active, created_at, updated_at) VALUES (?,?,?,?,?,?)')->execute([$title, $keywords ?: null, $answer, $active, $now, $now]);
audit_log($admin['id'], "Antwort des digitalen Assistenten angelegt: {$title}");
flash('success', 'Antwort angelegt.');
}
redirect('/staff/assistant.php?tab=answers');
}
}
if ($action === 'delete_answer') {
$id = (int) ($_POST['id'] ?? 0);
$t = $pdo->prepare('SELECT title FROM assistant_answers WHERE id = ?');
$t->execute([$id]);
$title = $t->fetchColumn();
if ($title !== false) {
$pdo->prepare('DELETE FROM assistant_answers WHERE id = ?')->execute([$id]);
audit_log($admin['id'], "Antwort des digitalen Assistenten gelöscht: {$title}");
flash('success', 'Antwort gelöscht.');
}
redirect('/staff/assistant.php?tab=answers');
}
if ($action === 'save_synonyms') {
$text = mb_substr(trim(strip_tags((string) ($_POST['assistant_synonyms'] ?? ''))), 0, 5000);
set_setting('assistant_synonyms', $text);
audit_log($admin['id'], 'Gleichbedeutende Wörter des digitalen Assistenten geändert');
flash('success', 'Gleichbedeutende Wörter gespeichert (' . count(assistant_custom_synonyms($text)) . ' Gruppen).');
redirect('/staff/assistant.php');
}
if ($action === 'clear_log') {
try {
$n = $pdo->exec('DELETE FROM assistant_log');
audit_log($admin['id'], 'Fragen-Log des digitalen Assistenten geleert');
flash('success', 'Fragen-Log geleert (' . (int) $n . ' Einträge).');
} catch (Throwable $e) {
flash('error', 'Das Log konnte nicht geleert werden. Bitte die Datenbank aktualisieren.');
}
redirect('/staff/assistant.php?tab=log');
}
if ($action === 'test') {
$testQuestion = trim(mb_substr((string) ($_POST['question'] ?? ''), 0, 300));
$testResult = $testQuestion !== '' ? (assistant_search($pdo, $testQuestion, false) ?: false) : null;
}
}
$answers = [];
$dbOutdated = false;
try {
$answers = $pdo->query('SELECT * FROM assistant_answers ORDER BY title')->fetchAll();
} catch (Throwable $e) {
$dbOutdated = true;
}
$edit = null;
if (!empty($_GET['edit'])) {
foreach ($answers as $a) if ((int) $a['id'] === (int) $_GET['edit']) $edit = $a;
}
$showForm = isset($_GET['new']) || $edit || $errors;
$tab = in_array($_GET['tab'] ?? '', ['settings', 'answers', 'log'], true) ? $_GET['tab'] : 'settings';
if (isset($_GET['edit']) || isset($_GET['new']) || $errors || ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'save_answer')) $tab = 'answers';
if (isset($_GET['lr']) || isset($_GET['lp']) || isset($_GET['lq']) || isset($_GET['lpage'])) $tab = 'log';
$prefillTitle = (!$edit && empty($_POST) && isset($_GET['title'])) ? mb_substr(trim((string) $_GET['title']), 0, 255) : '';
$logFilter = [
'result' => (string) ($_GET['lr'] ?? ''),
'period' => in_array($_GET['lp'] ?? '', ['today', '7', '30', 'all'], true) ? $_GET['lp'] : '30',
'q' => trim((string) ($_GET['lq'] ?? '')),
];
$logResults = assistant_log_filters();
$logPage = ['rows' => [], 'total' => 0, 'pages' => 1, 'page' => 1];
$logStats = array_fill_keys(array_keys($logResults), 0);
$logTop = [];
$logOutdated = false;
try {
$logPage = assistant_log_list($pdo, $logFilter, (int) ($_GET['lpage'] ?? 1));
$logStats = assistant_log_stats($pdo, $logFilter['period']);
$logTop = assistant_log_unanswered($pdo, $logFilter['period']);
} catch (Throwable $e) {
$logOutdated = true;
}
$logQuery = static fn(array $over = []) => '/staff/assistant.php?' . http_build_query(array_filter(array_merge(['tab' => 'log', 'lr' => $logFilter['result'], 'lp' => $logFilter['period'], 'lq' => $logFilter['q']], $over), static fn($v) => $v !== '' && $v !== null));
$departments = $pdo->query('SELECT id, name FROM departments WHERE is_active = 1 ORDER BY name')->fetchAll();
$priorities = $pdo->query('SELECT id, name FROM priorities ORDER BY sort_order')->fetchAll();
$texts = assistant_texts();
$enabled = assistant_enabled();
$activeNow = assistant_active($pdo);
$liveChatOn = get_setting('live_chat_enabled', '0') === '1';
$kbOn = get_setting('kb_enabled', '1') === '1';
$pageTitle = 'Digitaler Assistent';
$activePage = 'assistant';
require __DIR__ . '/_header.php';
?>
<h1>Digitaler Assistent</h1>
<?php foreach ($errors as $err): ?><div class="flash error"><?= e($err) ?></div><?php endforeach; ?>
<?php if ($dbOutdated): ?>
<div class="flash warning">Die Datenbank ist noch nicht auf dem neuesten Stand. Bitte unter System-Update auf „Datenbank aktualisieren“ klicken.</div>
<?php endif; ?>
<?php
$tabs = ['settings' => 'Einstellungen', 'answers' => 'Zusätzliche Antworten' . ($answers ? ' (' . count($answers) . ')' : ''), 'log' => 'Fragen-Log'];
?>
<div style="display:flex;gap:4px;flex-wrap:wrap;border-bottom:1px solid var(--border);margin-bottom:20px">
<?php foreach ($tabs as $key => $label): ?>
<a href="/staff/assistant.php?tab=<?= e($key) ?>" style="padding:9px 16px;text-decoration:none;color:inherit;border-bottom:2px solid <?= $tab === $key ? 'var(--primary,#2563eb)' : 'transparent' ?>;font-weight:<?= $tab === $key ? '600' : '400' ?>;margin-bottom:-1px"><?= e($label) ?></a>
<?php endforeach; ?>
</div>
<?php if ($tab === 'settings'): ?>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(380px,1fr));gap:20px;align-items:start">
<div class="card">
<h3>Einstellungen</h3>
<p class="muted" style="font-size:.85rem;margin-bottom:12px">
Der Assistent beantwortet Fragen von Kunden aus der Wissensdatenbank und aus den Antworten unten. Findet er nichts, fragt er, ob er ein Ticket
erstellen soll, und erfragt dafür alles Nötige. Es wird kein externer KI-Dienst verwendet, Fragen bleiben auf diesem Server.
</p>
<p style="margin:0 0 12px;font-size:.88rem">
Zustand jetzt:
<?php if (!$enabled): ?><strong style="color:#b45309">ausgeschaltet</strong>
<?php elseif ($activeNow): ?><strong style="color:#15803d">aktiv</strong> <span class="muted">(Kunden sehen den Assistenten)</span>
<?php else: ?><strong style="color:#64748b">bereit, aber gerade nicht sichtbar</strong> <span class="muted">(Live-Chat ist besetzt<?= get_setting('helpdesk_status', 'online') === 'offline' ? ' bzw. das Supportcenter ist im Wartungsmodus' : '' ?>)</span><?php endif; ?>
</p>
<form method="post">
<?= csrf_field() ?>
<input type="hidden" name="action" value="save_settings">
<label style="display:flex;align-items:center;gap:8px;margin:0"><input type="checkbox" name="assistant_enabled" value="1" style="width:auto" <?= $enabled ? 'checked' : '' ?>> Digitalen Assistenten einschalten</label>
<label for="assistant_mode" style="margin-top:12px">Wann ist er aktiv?</label>
<select id="assistant_mode" name="assistant_mode">
<option value="offline_only" <?= get_setting('assistant_mode', 'offline_only') !== 'always' ? 'selected' : '' ?>>Nur wenn der Live-Chat ausgeschaltet oder niemand erreichbar ist (Standard)</option>
<option value="always" <?= get_setting('assistant_mode', 'offline_only') === 'always' ? 'selected' : '' ?>>Immer (zum Testen)</option>
</select>
<p class="muted" style="font-size:.78rem;margin-top:4px">Live-Chat ist derzeit <strong><?= $liveChatOn ? 'eingeschaltet' : 'ausgeschaltet' ?></strong> (Einstellungen → Allgemein). Wissensdatenbank im Kundenportal: <strong><?= $kbOn ? 'an' : 'aus (dann nutzt der Assistent nur die Antworten unten)' ?></strong>.</p>
<label for="assistant_name" style="margin-top:12px">Name des Assistenten</label>
<input type="text" id="assistant_name" name="assistant_name" maxlength="60" value="<?= e(get_setting('assistant_name', '')) ?>" placeholder="Digitaler Assistent">
<label for="assistant_greeting" style="margin-top:12px">Begrüßung</label>
<textarea id="assistant_greeting" name="assistant_greeting" rows="3" maxlength="500" placeholder="<?= e($texts['greeting']) ?>"><?= e(get_setting('assistant_greeting', '')) ?></textarea>
<label for="assistant_no_answer" style="margin-top:12px">Text, wenn er keine Antwort findet</label>
<textarea id="assistant_no_answer" name="assistant_no_answer" rows="2" maxlength="500" placeholder="<?= e($texts['no_answer']) ?>"><?= e(get_setting('assistant_no_answer', '')) ?></textarea>
<label for="assistant_department_id" style="margin-top:12px">Abteilung für Tickets des Assistenten</label>
<select id="assistant_department_id" name="assistant_department_id">
<option value="0">— Standardabteilung (bzw. Abteilung des gewählten Themas) —</option>
<?php foreach ($departments as $d): ?><option value="<?= (int) $d['id'] ?>" <?= (int) get_setting('assistant_department_id', '0') === (int) $d['id'] ? 'selected' : '' ?>><?= e($d['name']) ?></option><?php endforeach; ?>
</select>
<label for="assistant_priority_id" style="margin-top:12px">Priorität für Tickets des Assistenten</label>
<select id="assistant_priority_id" name="assistant_priority_id">
<option value="0">— Standard —</option>
<?php foreach ($priorities as $p): ?><option value="<?= (int) $p['id'] ?>" <?= (int) get_setting('assistant_priority_id', '0') === (int) $p['id'] ? 'selected' : '' ?>><?= e($p['name']) ?></option><?php endforeach; ?>
</select>
<label for="assistant_log_days" style="margin-top:12px">Fragen-Log: Aufbewahrung in Tagen (0 = nichts speichern)</label>
<input type="number" id="assistant_log_days" name="assistant_log_days" min="0" max="3650" value="<?= (int) assistant_log_days() ?>" style="max-width:140px">
<p class="muted" style="font-size:.78rem;margin-top:4px">Die Tickets tragen den Tag „Assistent“ und durchlaufen deine Ticket-Regeln und die automatische Zuweisung der Abteilung. Wählt der Kunde ein Hilfethema, bestimmt dieses Abteilung und Priorität.</p>
<div class="btn-row"><button type="submit" class="btn">Speichern</button></div>
</form>
</div>
<div class="card">
<h3>Frage ausprobieren</h3>
<p class="muted" style="font-size:.85rem;margin-bottom:10px">Zeigt, was der Assistent auf eine Kundenfrage antworten würde (ohne Zähler und ohne Ticket).</p>
<form method="post" style="display:flex;gap:8px;flex-wrap:wrap">
<?= csrf_field() ?>
<input type="hidden" name="action" value="test">
<input type="text" name="question" value="<?= e($testQuestion) ?>" placeholder="z. B. Wie setze ich mein Passwort zurück?" maxlength="300" style="flex:1;min-width:220px">
<button type="submit" class="btn secondary">Testen</button>
</form>
<?php if ($testResult): ?>
<div style="margin-top:12px;padding:10px 12px;border:1px solid var(--border);border-radius:8px;background:var(--surface)">
<div class="muted" style="font-size:.76rem"><?= $testResult['source'] === 'custom' ? 'Zusätzliche Antwort' : 'Wissensdatenbank' ?>: <?= e($testResult['title']) ?></div>
<div style="white-space:pre-wrap;margin-top:6px;font-size:.88rem"><?= e($testResult['text']) ?></div>
<?php foreach ($testResult['others'] as $o): ?><div class="muted" style="font-size:.78rem;margin-top:4px">Weiterer Treffer: <?= e($o['title']) ?></div><?php endforeach; ?>
</div>
<?php elseif ($testResult === false): ?>
<div style="margin-top:12px" class="muted">Keine passende Antwort: Der Assistent würde anbieten, ein Ticket zu erstellen. Lege dafür unten eine Antwort an oder ergänze die Wissensdatenbank.</div>
<?php endif; ?>
</div>
<div class="card">
<h3>Gleichbedeutende Wörter</h3>
<p class="muted" style="font-size:.85rem;margin-bottom:10px">Wörter, die Kunden und Artikel unterschiedlich nennen, aber dasselbe meinen. Eine Gruppe je Zeile, durch Komma getrennt, zum Beispiel <em>Zugang, Einladung, beitreten</em>. Der Assistent behandelt sie dann gleich. Einige Gruppen sind schon eingebaut, deine ergänzen oder überschreiben sie.</p>
<form method="post">
<?= csrf_field() ?>
<input type="hidden" name="action" value="save_synonyms">
<textarea name="assistant_synonyms" rows="6" maxlength="5000" placeholder="Zugang, Einladung, beitreten&#10;Geld zurück, Erstattung, Rückzahlung"><?= e(get_setting('assistant_synonyms', '')) ?></textarea>
<div class="btn-row"><button type="submit" class="btn">Speichern</button></div>
</form>
</div>
</div>
<?php endif; ?>
<?php if ($tab === 'answers'): ?>
<div class="card">
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px">
<h3 style="margin:0">Zusätzliche Antworten</h3>
<?php if (!$showForm): ?><a href="/staff/assistant.php?new=1" class="btn" style="margin-left:auto">+ Antwort hinzufügen</a><?php endif; ?>
</div>
<p class="muted" style="font-size:.85rem;margin-bottom:12px">Diese Antworten gelten zusätzlich zur Wissensdatenbank und haben Vorrang. Der Assistent findet sie über die Wörter in der Frage und in den Stichwörtern.</p>
<?php if ($showForm && !$dbOutdated): ?>
<form method="post" id="antwort-form" style="margin-bottom:18px;padding:14px;border:1px solid var(--border);border-radius:8px">
<?= csrf_field() ?>
<input type="hidden" name="action" value="save_answer">
<input type="hidden" name="id" value="<?= (int) ($edit['id'] ?? ($_POST['id'] ?? 0)) ?>">
<label for="title">Frage / Thema *</label>
<input type="text" id="title" name="title" maxlength="255" required value="<?= e($_POST['title'] ?? ($edit['title'] ?? $prefillTitle)) ?>" placeholder="z. B. Wie lange dauert der Versand?">
<label for="keywords" style="margin-top:10px">Stichwörter (optional, durch Komma getrennt)</label>
<input type="text" id="keywords" name="keywords" maxlength="1000" value="<?= e($_POST['keywords'] ?? ($edit['keywords'] ?? '')) ?>" placeholder="z. B. Lieferzeit, Paket, Lieferung, Sendung">
<label for="answer" style="margin-top:10px">Antwort *</label>
<textarea id="answer" name="answer" rows="5" maxlength="4000" required placeholder="Reiner Text. Adressen mit https:// werden anklickbar."><?= e($_POST['answer'] ?? ($edit['answer'] ?? '')) ?></textarea>
<label style="display:flex;align-items:center;gap:8px;margin-top:10px"><input type="checkbox" name="is_active" value="1" style="width:auto" <?= (!$edit && empty($_POST)) || !empty($edit['is_active']) || !empty($_POST['is_active']) ? 'checked' : '' ?>> Aktiv</label>
<div class="btn-row" style="gap:8px"><button type="submit" class="btn">Speichern</button><a href="/staff/assistant.php?tab=answers" class="btn secondary">Abbrechen</a></div>
</form>
<?php endif; ?>
<?php if (!$answers): ?>
<p class="muted">Noch keine zusätzlichen Antworten.</p>
<?php else: ?>
<table>
<thead><tr><th>Frage / Thema</th><th>Stichwörter</th><th>Genutzt</th><th>Status</th><th></th></tr></thead>
<tbody>
<?php foreach ($answers as $a): ?>
<tr>
<td><a href="/staff/assistant.php?edit=<?= (int) $a['id'] ?>"><?= e($a['title']) ?></a><br><span class="muted" style="font-size:.78rem"><?= e(mb_strimwidth((string) $a['answer'], 0, 90, '…')) ?></span></td>
<td class="muted"><?= e((string) ($a['keywords'] ?? '')) ?></td>
<td><?= (int) $a['hits'] ?>×</td>
<td><?= $a['is_active'] ? 'Aktiv' : '<span class="muted">Aus</span>' ?></td>
<td style="white-space:nowrap">
<a href="/staff/assistant.php?edit=<?= (int) $a['id'] ?>">Bearbeiten</a> ·
<form method="post" style="display:inline" onsubmit="return confirm('Diese Antwort löschen?')">
<?= csrf_field() ?><input type="hidden" name="action" value="delete_answer"><input type="hidden" name="id" value="<?= (int) $a['id'] ?>">
<button type="submit" class="link" style="background:none;border:0;color:var(--danger);cursor:pointer;padding:0">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if ($tab === 'log'): ?>
<div class="card" id="fragen-log">
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px">
<h3 style="margin:0">Fragen-Log</h3>
<?php if (!$logOutdated && array_sum($logStats) > 0): ?>
<form method="post" style="margin-left:auto" onsubmit="return confirm('Das gesamte Fragen-Log löschen?')">
<?= csrf_field() ?><input type="hidden" name="action" value="clear_log">
<button type="submit" class="btn secondary">Log leeren</button>
</form>
<?php endif; ?>
</div>
<?php if ($logOutdated): ?>
<p class="muted">Das Log ist noch nicht verfügbar. Bitte unter System-Update auf „Datenbank aktualisieren“ klicken.</p>
<?php else: ?>
<p class="muted" style="font-size:.85rem;margin-bottom:12px">Hier siehst du, was Kunden den Assistenten gefragt haben und ob er eine Antwort gefunden hat. Es werden nur Frage und Ergebnis gespeichert (kein Name, keine E-Mail-Adresse). Fragen ohne Antwort zeigen, was du noch hinterlegen solltest.</p>
<div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:14px">
<?php foreach ($logResults as $key => $label): ?>
<a href="<?= e($logQuery(['lr' => $logFilter['result'] === $key ? '' : $key, 'lpage' => ''])) ?>" style="text-decoration:none;color:inherit;padding:8px 12px;border:1px solid <?= $logFilter['result'] === $key ? 'var(--primary,#2563eb)' : 'var(--border)' ?>;border-radius:8px;min-width:120px">
<div style="font-size:1.2rem;font-weight:600"><?= (int) $logStats[$key] ?></div>
<div class="muted" style="font-size:.76rem"><?= e($label) ?></div>
</a>
<?php endforeach; ?>
</div>
<form method="get" action="/staff/assistant.php" style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:14px">
<input type="hidden" name="tab" value="log">
<select name="lr" style="width:auto">
<option value="">Alle Ergebnisse</option>
<?php foreach ($logResults as $key => $label): ?><option value="<?= e($key) ?>" <?= $logFilter['result'] === $key ? 'selected' : '' ?>><?= e($label) ?></option><?php endforeach; ?>
</select>
<select name="lp" style="width:auto">
<?php foreach (['today' => 'Heute', '7' => 'Letzte 7 Tage', '30' => 'Letzte 30 Tage', 'all' => 'Gesamter Zeitraum'] as $k => $l): ?><option value="<?= e($k) ?>" <?= $logFilter['period'] === (string) $k ? 'selected' : '' ?>><?= e($l) ?></option><?php endforeach; ?>
</select>
<input type="text" name="lq" value="<?= e($logFilter['q']) ?>" placeholder="Suchen…" maxlength="100" style="flex:1;min-width:160px">
<button type="submit" class="btn secondary">Filtern</button>
<?php if ($logFilter['result'] !== '' || $logFilter['q'] !== '' || $logFilter['period'] !== '30'): ?><a href="/staff/assistant.php?tab=log" class="btn secondary">Zurücksetzen</a><?php endif; ?>
</form>
<?php if ($logTop): ?>
<div style="margin-bottom:16px;padding:10px 12px;border:1px solid var(--border);border-radius:8px">
<strong style="font-size:.88rem">Häufige Fragen ohne Antwort</strong>
<ul style="margin:6px 0 0;padding-left:18px;font-size:.88rem">
<?php foreach ($logTop as $t): ?>
<li><?= e($t['question']) ?> <span class="muted">(<?= (int) $t['n'] ?>×)</span> · <a href="/staff/assistant.php?new=1&amp;title=<?= e(rawurlencode($t['question'])) ?>">Antwort dazu anlegen</a></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php if (!$logPage['rows']): ?>
<p class="muted">Keine Fragen für diese Auswahl.</p>
<?php else: ?>
<table>
<thead><tr><th>Zeit</th><th>Frage</th><th>Ergebnis</th><th>Antwort / Ticket</th><th></th></tr></thead>
<tbody>
<?php foreach ($logPage['rows'] as $r): ?>
<tr>
<td class="muted" style="white-space:nowrap"><?= e(date('d.m.Y H:i', strtotime((string) $r['created_at']))) ?></td>
<td><?= e($r['question']) ?></td>
<td><?= e($logResults[$r['result']] ?? $r['result']) ?><?= $r['helpful'] === null ? '' : ($r['helpful'] ? ' 👍' : ' 👎') ?></td>
<td class="muted"><?= $r['ticket_number'] ? e('#' . $r['ticket_number']) : e((string) ($r['matched_title'] ?? '')) ?></td>
<td style="white-space:nowrap"><?php if ($r['result'] === 'none'): ?><a href="/staff/assistant.php?new=1&amp;title=<?= e(rawurlencode($r['question'])) ?>">Antwort anlegen</a><?php endif; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="muted" style="display:flex;gap:12px;align-items:center;margin-top:10px;font-size:.85rem">
<span><?= (int) $logPage['total'] ?> Einträge</span>
<?php if ($logPage['pages'] > 1): ?>
<span style="margin-left:auto">
<?php if ($logPage['page'] > 1): ?><a href="<?= e($logQuery(['lpage' => $logPage['page'] - 1])) ?>">← Neuere</a><?php endif; ?>
Seite <?= (int) $logPage['page'] ?> von <?= (int) $logPage['pages'] ?>
<?php if ($logPage['page'] < $logPage['pages']): ?><a href="<?= e($logQuery(['lpage' => $logPage['page'] + 1])) ?>">Ältere →</a><?php endif; ?>
</span>
<?php endif; ?>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endif; ?>
<?php require __DIR__ . '/_footer.php'; ?>