65 lines
3.4 KiB
PHP
65 lines
3.4 KiB
PHP
<?php
|
|
/**
|
|
* staff/live_tickets.php
|
|
*
|
|
* Leichter Abruf für die Live-Anzeige im Mitarbeiterbereich (assets/js/live-tickets.js): aktuelle Kennzahlen und Tickets, die seit der
|
|
* zuletzt gesehenen Ticket-ID neu angelegt wurden. Jeder sieht nur Tickets seiner Abteilungen.
|
|
* ?since=0 liefert nur den Ausgangsstand (keine „neuen“ Tickets), damit beim ersten Aufruf nichts aufpoppt.
|
|
*/
|
|
require_once __DIR__ . '/../includes/bootstrap.php';
|
|
$staff = current_staff();
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Cache-Control: no-store');
|
|
if (!$staff) {
|
|
http_response_code(401);
|
|
echo json_encode(['error' => 'login']);
|
|
exit;
|
|
}
|
|
// Abgelaufene Sitzung (Inaktivität) gilt auch hier als abgemeldet; dieser Abruf verlängert die Sitzung nie
|
|
$__timeout = (int) (get_setting('staff_session_timeout', '30') ?: 30);
|
|
$__last = (int) ($_SESSION['staff_last_activity'] ?? 0);
|
|
if ($__last && (time() - $__last) > $__timeout * 60) {
|
|
http_response_code(401);
|
|
echo json_encode(['error' => 'login', 'sessionExpired' => true]);
|
|
exit;
|
|
}
|
|
// Die Sitzungsdatei sofort freigeben: Der Abruf läuft alle paar Sekunden und soll andere Seitenaufrufe nicht ausbremsen
|
|
if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
|
|
|
|
$pdo = get_db();
|
|
$since = max(0, (int) ($_GET['since'] ?? 0));
|
|
[$deptFilter, $deptParams] = dept_filter_sql(staff_department_ids($staff), 't.department_id');
|
|
$count = function (string $where, array $params = []) use ($pdo, $deptFilter, $deptParams): int {
|
|
$s = $pdo->prepare("SELECT COUNT(*) FROM tickets t WHERE {$where}{$deptFilter}");
|
|
$s->execute(array_merge($params, $deptParams));
|
|
return (int) $s->fetchColumn();
|
|
};
|
|
$open = "t.status NOT IN ('resolved','closed')";
|
|
$counts = [
|
|
'open' => $count($open),
|
|
'mine' => $count("t.assigned_staff_id = ? AND {$open}", [(int) $staff['id']]),
|
|
'unassigned' => $count("t.assigned_staff_id IS NULL AND {$open}"),
|
|
'overdue' => $count("{$open} AND (t.is_overdue = 1 OR (t.sla_paused_at IS NULL AND t.resolution_due_at IS NOT NULL AND t.resolution_due_at < ?))", [db_now()]),
|
|
'unanswered' => $count("t.status = 'open'"),
|
|
];
|
|
|
|
// Neue Tickets: ohne Spam, ohne Live-Chats (die haben eigene Hinweise) und ohne zusammengeführte
|
|
$visible = "t.is_spam = 0 AND t.source <> 'chat' AND t.merged_into IS NULL";
|
|
$m = $pdo->prepare("SELECT COALESCE(MAX(t.id), 0) FROM tickets t WHERE {$visible}{$deptFilter}");
|
|
$m->execute($deptParams);
|
|
$latest = (int) $m->fetchColumn();
|
|
$tickets = [];
|
|
$more = 0;
|
|
if ($since > 0 && $latest > $since) {
|
|
$s = $pdo->prepare("SELECT t.id, t.ticket_number, t.subject, t.requester_name, d.name AS department FROM tickets t LEFT JOIN departments d ON d.id = t.department_id
|
|
WHERE t.id > ? AND {$visible}{$deptFilter} ORDER BY t.id ASC LIMIT 6");
|
|
$s->execute(array_merge([$since], $deptParams));
|
|
foreach ($s->fetchAll() as $t) {
|
|
$tickets[] = ['id' => (int) $t['id'], 'number' => (string) $t['ticket_number'], 'subject' => mb_substr((string) $t['subject'], 0, 120), 'name' => mb_substr((string) $t['requester_name'], 0, 60), 'department' => (string) ($t['department'] ?? '')];
|
|
}
|
|
$c = $pdo->prepare("SELECT COUNT(*) FROM tickets t WHERE t.id > ? AND {$visible}{$deptFilter}");
|
|
$c->execute(array_merge([$since], $deptParams));
|
|
$more = max(0, (int) $c->fetchColumn() - count($tickets));
|
|
}
|
|
echo json_encode(['latest' => $latest, 'counts' => $counts, 'tickets' => $tickets, 'more' => $more], JSON_UNESCAPED_UNICODE);
|