120 lines
5.8 KiB
PHP
120 lines
5.8 KiB
PHP
<?php
|
|
/**
|
|
* Gespeicherte Ansichten (Warteschlangen) für die Ticketliste.
|
|
*
|
|
* Gespeichert werden neutrale Filter-Schlüssel, die Web, Desktop-App und Android-App gleichermaßen
|
|
* verstehen: q, status, assigned, departmentId, priorityId, sla, tab, quick, spam, tagId.
|
|
* Eine Ansicht gehört einem Mitarbeiter; "geteilte" Ansichten sehen alle Mitarbeiter.
|
|
*/
|
|
|
|
const QUEUE_FILTER_KEYS = ['q', 'status', 'assigned', 'departmentId', 'priorityId', 'sla', 'tab', 'quick', 'spam', 'tagId'];
|
|
|
|
/** Übersetzt die GET-Parameter der Weboberfläche in neutrale Filter (leere Werte entfallen). */
|
|
function queue_filters_from_web(array $get): array
|
|
{
|
|
$map = ['q' => 'q', 'status' => 'status', 'assigned' => 'assigned', 'department_id' => 'departmentId', 'priority_id' => 'priorityId',
|
|
'sla' => 'sla', 'tab' => 'tab', 'quick' => 'quick', 'spam' => 'spam', 'tag_id' => 'tagId'];
|
|
$out = [];
|
|
foreach ($map as $webKey => $key) {
|
|
$v = isset($get[$webKey]) && is_scalar($get[$webKey]) ? trim((string) $get[$webKey]) : '';
|
|
if ($v !== '') $out[$key] = mb_substr($v, 0, 200);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/** Wandelt neutrale Filter zurück in GET-Parameter der Weboberfläche. */
|
|
function queue_filters_to_web(array $filters): array
|
|
{
|
|
$map = ['q' => 'q', 'status' => 'status', 'assigned' => 'assigned', 'departmentId' => 'department_id', 'priorityId' => 'priority_id',
|
|
'sla' => 'sla', 'tab' => 'tab', 'quick' => 'quick', 'spam' => 'spam', 'tagId' => 'tag_id'];
|
|
$out = [];
|
|
foreach ($map as $key => $webKey) {
|
|
if (isset($filters[$key]) && $filters[$key] !== '') $out[$webKey] = (string) $filters[$key];
|
|
}
|
|
// Apps speichern mehrere Status als Liste; die Weboberfläche kennt dafür die Reiter
|
|
if (isset($out['status']) && str_contains($out['status'], ',')) {
|
|
$out['tab'] = str_contains($out['status'], 'resolved') ? ($out['tab'] ?? 'all') : ($out['tab'] ?? 'open');
|
|
unset($out['status']);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/** Übersetzt neutrale Filter in die Abfrageparameter der Mobile-API (tickets.php): status, assigned, sla, q, departmentId, priorityId. */
|
|
function queue_filters_to_api(array $filters): array
|
|
{
|
|
$out = [];
|
|
foreach (['q', 'assigned', 'sla', 'departmentId', 'priorityId'] as $k) {
|
|
if (isset($filters[$k]) && $filters[$k] !== '') $out[$k] = $filters[$k];
|
|
}
|
|
$status = $filters['status'] ?? '';
|
|
if ($status === '') {
|
|
$status = match ($filters['tab'] ?? '') {
|
|
'on_hold' => 'on_hold', 'resolved' => 'resolved', 'closed' => 'closed',
|
|
'all' => 'open,pending,answered,on_hold,resolved,closed',
|
|
default => 'open,pending,answered',
|
|
};
|
|
}
|
|
$out['status'] = $status;
|
|
switch ($filters['quick'] ?? '') {
|
|
case 'me': $out['assigned'] = 'me'; break;
|
|
case 'unassigned': $out['assigned'] = 'unassigned'; break;
|
|
case 'overdue': $out['sla'] = 'overdue'; break;
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/** Bereinigt beliebige Eingaben auf die erlaubten Filter-Schlüssel. */
|
|
function queue_clean_filters($filters): array
|
|
{
|
|
$out = [];
|
|
if (is_array($filters)) { // ältere Ansichten nutzten 'department'/'priority'
|
|
if (isset($filters['department']) && !isset($filters['departmentId'])) $filters['departmentId'] = $filters['department'];
|
|
if (isset($filters['priority']) && !isset($filters['priorityId'])) $filters['priorityId'] = $filters['priority'];
|
|
}
|
|
foreach (QUEUE_FILTER_KEYS as $key) {
|
|
if (is_array($filters) && isset($filters[$key]) && is_scalar($filters[$key]) && trim((string) $filters[$key]) !== '') {
|
|
$out[$key] = mb_substr(trim((string) $filters[$key]), 0, 200);
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/** Eigene und geteilte Ansichten, eigene zuerst. Jede Zeile bekommt 'filters' (Array) und 'mine' (bool). */
|
|
function queues_for(PDO $pdo, int $staffId): array
|
|
{
|
|
$stmt = $pdo->prepare(
|
|
'SELECT q.*, s.name AS owner_name FROM saved_queues q LEFT JOIN staff s ON s.id = q.staff_id
|
|
WHERE q.staff_id = ? OR q.is_shared = 1 ORDER BY (q.staff_id = ?) DESC, q.sort_order, q.name'
|
|
);
|
|
$stmt->execute([$staffId, $staffId]);
|
|
$rows = $stmt->fetchAll();
|
|
foreach ($rows as &$r) {
|
|
$r['filters'] = queue_clean_filters(json_decode((string) $r['filters'], true));
|
|
$r['mine'] = (int) $r['staff_id'] === $staffId;
|
|
}
|
|
return $rows;
|
|
}
|
|
|
|
/** Legt eine Ansicht an. Gibt die ID zurück. */
|
|
function queue_create(PDO $pdo, int $staffId, string $name, array $filters, bool $shared): int
|
|
{
|
|
$name = trim($name);
|
|
if ($name === '') throw new AdminModelException('Bitte einen Namen für die Ansicht angeben.', 'NAME_REQUIRED');
|
|
if (mb_strlen($name) > 80) throw new AdminModelException('Der Name ist zu lang (höchstens 80 Zeichen).', 'NAME_TOO_LONG');
|
|
$dup = $pdo->prepare('SELECT COUNT(*) FROM saved_queues WHERE staff_id = ? AND LOWER(name) = LOWER(?)');
|
|
$dup->execute([$staffId, $name]);
|
|
if ((int) $dup->fetchColumn() > 0) throw new AdminModelException('Du hast bereits eine Ansicht mit diesem Namen.', 'NAME_TAKEN');
|
|
$max = $pdo->prepare('SELECT COALESCE(MAX(sort_order), 0) + 1 FROM saved_queues WHERE staff_id = ?');
|
|
$max->execute([$staffId]);
|
|
$now = db_now();
|
|
$pdo->prepare('INSERT INTO saved_queues (staff_id, name, filters, is_shared, sort_order, created_at, updated_at) VALUES (?,?,?,?,?,?,?)')
|
|
->execute([$staffId, $name, json_encode(queue_clean_filters($filters), JSON_UNESCAPED_UNICODE), $shared ? 1 : 0, (int) $max->fetchColumn(), $now, $now]);
|
|
return (int) $pdo->lastInsertId();
|
|
}
|
|
|
|
/** Darf der Mitarbeiter die Ansicht ändern/löschen? Eigene Ansichten immer; fremde nur Administratoren. */
|
|
function queue_can_edit(array $queueRow, array $staff): bool
|
|
{
|
|
return (int) $queueRow['staff_id'] === (int) $staff['id'] || $staff['role'] === 'admin';
|
|
}
|