'CSRF-Fehler', 'got'=>$_POST['csrf_token']??'', 'expected'=>$_SESSION['csrf_token']??'']); exit; } $newStatus = $_POST['status'] ?? ''; $note = trim($_POST['note'] ?? ''); $allowed = ['available', 'busy', 'break', 'offline']; if (!in_array($newStatus, $allowed, true)) { http_response_code(400); echo json_encode(['error' => 'Ungültiger Status']); exit; } try { staff_set_status($pdo, (int) $staff['id'], $newStatus, $note); staff_touch_activity($pdo, (int) $staff['id']); echo json_encode(['ok' => true, 'status' => $newStatus]); } catch (Throwable $e) { error_log('staff_availability: ' . $e->getMessage()); http_response_code(500); echo json_encode(['error' => 'Status konnte nicht gespeichert werden.']); } exit; } // ── Schichtplan (Admin-Seite) ───────────────────────────────────────────────── $admin = has_permission($staff, 'manage_availability') ? $staff : null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_csrf(); $action = $_POST['action'] ?? ''; // Admin: Status eines Mitarbeiters ändern if ($action === 'set_staff_status' && $admin) { $targetId = (int) ($_POST['staff_id'] ?? 0); $newStatus = (string) ($_POST['status'] ?? ''); $exists = $pdo->prepare('SELECT name FROM staff WHERE id = ? AND is_active = 1'); $exists->execute([$targetId]); $targetName = $exists->fetchColumn(); if (!$targetName || !in_array($newStatus, STAFF_AVAILABILITY_STATUSES, true)) { flash('error', 'Ungültiger Mitarbeiter oder Status.'); } else { staff_set_status($pdo, $targetId, $newStatus, (string) ($_POST['note'] ?? '')); audit_log($admin['id'], "Status von Mitarbeiter #$targetId auf $newStatus gesetzt"); flash('success', 'Status von ' . $targetName . ' geändert.'); } redirect('/staff/availability.php'); } // Admin: Zeit bis zum automatischen Offline einstellen if ($action === 'save_auto_offline' && $admin) { $m = max(0, min(1440, (int) ($_POST['auto_offline_minutes'] ?? 30))); set_setting('staff_auto_offline_minutes', (string) $m); audit_log($admin['id'], 'Automatisch offline nach ' . ($m > 0 ? $m . ' Minuten' : 'aus') . ' gesetzt'); flash('success', $m > 0 ? "Mitarbeiter werden nach $m Minuten ohne Aktivität automatisch auf Offline gesetzt." : 'Automatisch offline ist ausgeschaltet.'); redirect('/staff/availability.php'); } if ($action === 'save_shifts' && $admin) { $targetId = (int)($_POST['staff_id'] ?? 0); $__nameStmt = $pdo->prepare('SELECT name FROM staff WHERE id = ?'); $__nameStmt->execute([$targetId]); $editAgentName = $__nameStmt->fetchColumn() ?: "#$targetId"; if (!$targetId) { flash('error', 'Ungültiger Mitarbeiter.'); redirect('/staff/availability.php'); } // Alte Schichten löschen $pdo->prepare('DELETE FROM staff_shifts WHERE staff_id = ?')->execute([$targetId]); // Neue speichern $days = $_POST['days'] ?? []; foreach ($days as $day => $times) { if (empty($times['active'])) continue; $start = $times['start'] ?? '08:00'; $end = $times['end'] ?? '17:00'; // Keine Zeitvalidierung – Nutzer ist verantwortlich $pdo->prepare( 'INSERT INTO staff_shifts (staff_id, weekday, start_time, end_time, is_active) VALUES (?,?,?,?,1)' )->execute([$targetId, (int)$day, $start, $end]); } audit_log($admin['id'], "Schichtplan für Mitarbeiter #$targetId gespeichert"); flash('success', 'Schichtplan für ' . e($editAgentName ?? "#$targetId") . ' gespeichert.'); redirect('/staff/availability.php?edit=' . $targetId); } } // ── Daten laden ─────────────────────────────────────────────────────────────── staff_run_auto_offline($pdo); $agents = $pdo->query( "SELECT s.*, sa.status AS avail_status, sa.auto_offline AS avail_auto, sa.note AS avail_note, sa.updated_at AS avail_updated FROM staff s LEFT JOIN staff_availability sa ON sa.staff_id = s.id WHERE s.is_active = 1 ORDER BY s.name" )->fetchAll(); // Schichten für alle Mitarbeiter $allShifts = $pdo->query( 'SELECT * FROM staff_shifts WHERE is_active = 1 ORDER BY staff_id, weekday, start_time' )->fetchAll(); $shiftsByStaff = []; foreach ($allShifts as $sh) { $shiftsByStaff[$sh['staff_id']][$sh['weekday']][] = $sh; } // Für den Edit-Modus $editStaffId = (int)($_GET['edit'] ?? 0); $editShifts = $editStaffId ? ($shiftsByStaff[$editStaffId] ?? []) : []; $pageTitle = 'Verfügbarkeit & Schichten'; $activePage = 'availability'; require __DIR__ . '/_header.php'; $statusLabels = [ 'available' => ['Verfügbar', '#22c55e'], 'busy' => ['Beschäftigt', '#f59e0b'], 'break' => ['Pause', '#6366f1'], 'offline' => ['Offline', '#94a3b8'], ]; $weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']; ?>

Verfügbarkeit & Schichten

Mein Status

[$sl, $sc]): ?>

Team-Übersicht

automatisch offline
aktiv
Schichtplan

Status der Mitarbeiter ändern (Admin)

Ein von dir gesetzter Status bleibt, bis der Mitarbeiter ihn selbst ändert oder du ihn erneut änderst.

MitarbeiterStatus und Notiz
Minuten ohne Aktivität 0 = aus. Bei neuer Aktivität kommt der vorherige Status zurück.

Schichtplan:

Definiere an welchen Tagen und zu welchen Zeiten dieser Mitarbeiter verfügbar ist. Tickets werden außerhalb der Schicht nicht automatisch zugewiesen.

Tag Aktiv Von Bis
onchange="toggleDay(, this.checked)"> required> required>
Abbrechen