Files
deskhub/DeskHub-Webseite/staff/staff_manage.php
T
2026-10-16 19:12:21 +00:00

406 lines
23 KiB
PHP
Raw 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';
$me = require_admin_or_permission('manage_staff');
$isFullAdmin = $me['role'] === 'admin';
$canManageTeams = has_permission($me, 'manage_teams');
$pdo = get_db();
$errors = [];
$departments = $pdo->query('SELECT * FROM departments ORDER BY name')->fetchAll();
$customRoles = $pdo->query('SELECT * FROM roles ORDER BY name')->fetchAll();
$teams = $pdo->query('SELECT id, name, is_active FROM teams ORDER BY name')->fetchAll();
$permLabels = [
'reply_ticket' => 'Tickets beantworten',
'close_ticket' => 'Tickets schließen/lösen',
'delete_ticket' => 'Tickets löschen',
'transfer_ticket' => 'Tickets übertragen',
'post_note' => 'Interne Notizen schreiben',
'assign_ticket' => 'Tickets zuweisen',
'manage_canned' => 'Textbausteine verwalten',
'view_reports' => 'Berichte einsehen',
'manage_kb' => 'Wissensdatenbank verwalten',
'create_ticket' => 'Tickets im Namen von Kunden erstellen',
] + array_diff_key(admin_section_permissions(), ['manage_kb' => 1]);
/** Setzt die zusätzlichen Abteilungen (Erweiterter Zugriff) neu. */
function save_staff_access(PDO $pdo, int $id, ?int $primaryDeptId, array $post): void
{
$selected = array_unique(array_filter(array_map('intval', $post['extra_departments'] ?? [])));
$pdo->prepare('DELETE FROM staff_department WHERE staff_id = ?')->execute([$id]);
$ins = $pdo->prepare('INSERT INTO staff_department (staff_id, department_id, notify, role_id) VALUES (?,?,?,?)');
$validRoles = array_map('intval', $pdo->query('SELECT id FROM roles')->fetchAll(PDO::FETCH_COLUMN));
foreach ($selected as $dId) {
if ($dId === (int) $primaryDeptId) continue; // Hauptabteilung wird nicht doppelt gespeichert
$rid = (int) ($post['role_' . $dId] ?? 0);
$ins->execute([$id, $dId, !empty($post['notify_' . $dId]) ? 1 : 0, in_array($rid, $validRoles, true) ? $rid : null]);
}
}
/** Setzt die Team-Mitgliedschaften eines Mitarbeiters neu. */
function save_staff_teams(PDO $pdo, int $id, array $teamIds): void
{
$pdo->prepare('DELETE FROM team_members WHERE staff_id = ?')->execute([$id]);
$ins = $pdo->prepare('INSERT INTO team_members (team_id, staff_id) VALUES (?,?)');
foreach (array_unique(array_filter(array_map('intval', $teamIds))) as $tid) $ins->execute([$tid, $id]);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
$action = $_POST['action'] ?? '';
if ($action === 'create' || $action === 'update') {
$id = (int) ($_POST['id'] ?? 0);
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
// Nur echte Administratoren dürfen die Administrator-Rolle vergeben – sonst könnte sich ein
// per Co-Admin-Recht (nur manage_staff) berechtigter Agent selbst (oder andere) zum
// Vollzugriff-Admin machen. Beim Bearbeiten durch einen Co-Admin bleibt die vorhandene
// Rolle des Ziel-Kontos unverändert, statt sie stillschweigend auf "Mitarbeiter" zu setzen.
if ($isFullAdmin) {
$role = ($_POST['role'] ?? '') === 'admin' ? 'admin' : 'agent';
} elseif ($action === 'update') {
$currentRoleStmt = $pdo->prepare('SELECT role FROM staff WHERE id = ?');
$currentRoleStmt->execute([$id]);
$role = $currentRoleStmt->fetchColumn() === 'admin' ? 'admin' : 'agent';
} else {
$role = 'agent';
}
$roleId = ($_POST['role_id'] ?? '') !== '' ? (int) $_POST['role_id'] : null;
$deptId = ($_POST['department_id'] ?? '') !== '' ? (int) $_POST['department_id'] : null;
$isActive = ($_POST['status'] ?? 'active') === 'active' ? 1 : 0;
$password = $_POST['password'] ?? '';
$signature = sanitize_staff_html(trim($_POST['signature'] ?? ''));
if ($name === '') $errors[] = 'Bitte einen Namen angeben.';
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = 'Bitte eine gültige E-Mail-Adresse angeben.';
if ($action === 'create' || $password !== '') {
$pwErr = validate_password_strength($password);
if ($pwErr) $errors[] = $pwErr;
}
if ($action === 'update' && $id === (int) $me['id'] && !$isActive) $errors[] = 'Sie können Ihr eigenes Konto nicht deaktivieren.';
$dup = $pdo->prepare('SELECT COUNT(*) FROM staff WHERE LOWER(email) = LOWER(?) AND id <> ?');
$dup->execute([$email, $id]);
if ($dup->fetchColumn() > 0) $errors[] = 'Ein Mitarbeiter mit dieser E-Mail-Adresse existiert bereits.';
if (!$errors) {
if ($action === 'create') {
$pdo->prepare('INSERT INTO staff (name, email, password_hash, role, role_id, department_id, signature, is_active, created_at) VALUES (?,?,?,?,?,?,?,?,?)')
->execute([$name, $email, password_hash($password, PASSWORD_DEFAULT), $role, $roleId, $deptId, $signature ?: null, $isActive, db_now()]);
$id = (int) $pdo->lastInsertId();
audit_log($me['id'], "Mitarbeiter angelegt: {$name} ({$email})");
flash('success', 'Mitarbeiter angelegt.');
} else {
$sql = 'UPDATE staff SET name=?, email=?, role=?, role_id=?, department_id=?, signature=?, is_active=?';
$params = [$name, $email, $role, $roleId, $deptId, $signature ?: null, $isActive];
if ($password !== '') { $sql .= ', password_hash=?'; $params[] = password_hash($password, PASSWORD_DEFAULT); }
$params[] = $id;
$pdo->prepare($sql . ' WHERE id=?')->execute($params);
audit_log($me['id'], "Mitarbeiter aktualisiert: {$name} ({$email})");
flash('success', 'Änderungen gespeichert.');
}
save_staff_access($pdo, $id, $deptId, $_POST);
if ($canManageTeams) save_staff_teams($pdo, $id, (array) ($_POST['teams'] ?? []));
redirect('/staff/staff_manage.php');
}
}
// Eigenständiger Zugriffs-Speicher-Aufruf (Rückwärtskompatibilität)
if ($action === 'save_access') {
$id = (int) $_POST['id'];
$stmt = $pdo->prepare('SELECT department_id FROM staff WHERE id = ?');
$stmt->execute([$id]);
save_staff_access($pdo, $id, (int) $stmt->fetchColumn(), $_POST);
audit_log($me['id'], "Abteilungszugriff geändert für Mitarbeiter #{$id}");
flash('success', 'Abteilungszugriff gespeichert.');
redirect('/staff/staff_manage.php?edit=' . $id . '&tab=access');
}
if ($action === 'delete') {
$id = (int) $_POST['id'];
if ($id === (int) $me['id']) {
flash('error', 'Sie können Ihr eigenes Konto nicht löschen.');
} else {
$pdo->prepare('UPDATE tickets SET assigned_staff_id = NULL WHERE assigned_staff_id = ?')->execute([$id]);
$pdo->prepare('DELETE FROM staff WHERE id = ?')->execute([$id]);
audit_log($me['id'], "Mitarbeiter gelöscht: #{$id}");
flash('success', 'Mitarbeiter gelöscht.');
}
redirect('/staff/staff_manage.php');
}
}
$isNew = isset($_GET['new']);
$editId = (int) ($_GET['edit'] ?? 0);
$showForm = $isNew || $editId || ($errors && in_array($_POST['action'] ?? '', ['create', 'update'], true));
$editStaff = null;
$extraAccess = []; // department_id => ['notify' => 0/1, 'role_id' => ?int]
$memberTeams = [];
if ($editId) {
$stmt = $pdo->prepare('SELECT * FROM staff WHERE id = ?');
$stmt->execute([$editId]);
$editStaff = $stmt->fetch() ?: null;
if ($editStaff) {
$stmt = $pdo->prepare('SELECT department_id, notify, role_id FROM staff_department WHERE staff_id = ?');
$stmt->execute([$editId]);
foreach ($stmt->fetchAll() as $row) $extraAccess[(int) $row['department_id']] = ['notify' => (int) $row['notify'], 'role_id' => $row['role_id'] !== null ? (int) $row['role_id'] : null];
$stmt = $pdo->prepare('SELECT team_id FROM team_members WHERE staff_id = ?');
$stmt->execute([$editId]);
$memberTeams = array_map('intval', $stmt->fetchAll(PDO::FETCH_COLUMN));
}
}
if ($_POST && $errors) { // eingegebene Auswahl bei Fehlern erhalten
$extraAccess = [];
foreach (array_filter(array_map('intval', $_POST['extra_departments'] ?? [])) as $dId) {
$extraAccess[$dId] = ['notify' => !empty($_POST['notify_' . $dId]) ? 1 : 0, 'role_id' => ($_POST['role_' . $dId] ?? '') !== '' ? (int) $_POST['role_' . $dId] : null];
}
$memberTeams = array_map('intval', (array) ($_POST['teams'] ?? []));
}
$allStaff = $pdo->query(
'SELECT s.*, d.name AS department_name,
(SELECT COUNT(*) FROM team_members tm WHERE tm.staff_id = s.id) AS team_count
FROM staff s LEFT JOIN departments d ON d.id = s.department_id ORDER BY s.name'
)->fetchAll();
$fmt = fn(?string $dt) => $dt ? date('d.m.Y', strtotime($dt)) : '–';
$pageTitle = 'Mitarbeiter';
$activePage = 'staff';
require __DIR__ . '/_header.php';
?>
<?php foreach ($errors as $err): ?>
<div class="flash error"><?= e($err) ?></div>
<?php endforeach; ?>
<?php if ($showForm): ?>
<?php
$f = fn(string $k, $default = '') => $_POST[$k] ?? $default;
$v = fn(string $k, string $col, $default = '') => $f($k, $editStaff[$col] ?? $default);
$curStatus = $_POST ? ($_POST['status'] ?? 'active') : (($editStaff['is_active'] ?? 1) ? 'active' : 'locked');
$curRole = (string) $v('role', 'role', 'agent');
$curRoleId = (string) $v('role_id', 'role_id');
$curDept = (string) $v('department_id', 'department_id');
$startTab = in_array($_GET['tab'] ?? '', ['account', 'access', 'perms', 'teams'], true) ? $_GET['tab'] : 'account';
$rolePerms = [];
foreach ($customRoles as $r) $rolePerms[$r['id']] = json_decode($r['permissions'], true) ?: [];
$agentDefaults = default_permissions('agent');
$adminDefaults = default_permissions('admin');
?>
<h1>
<?= $editStaff ? 'Agenten verwalten' : 'Neuer Agent' ?>
<?php if ($editStaff): ?><span class="muted" style="font-size:1rem;font-weight:400">— <?= e($editStaff['name']) ?></span><?php endif; ?>
</h1>
<form method="post" class="card" style="padding:0" autocomplete="off">
<?= csrf_field() ?>
<input type="hidden" name="action" value="<?= $editStaff ? 'update' : 'create' ?>">
<?php if ($editStaff): ?><input type="hidden" name="id" value="<?= (int) $editStaff['id'] ?>"><?php endif; ?>
<div style="display:flex;gap:4px;padding:10px 12px 0;border-bottom:1px solid var(--border)">
<button type="button" class="tab-btn" data-tab="account">Konto</button>
<button type="button" class="tab-btn" data-tab="access">Zugang</button>
<button type="button" class="tab-btn" data-tab="perms">Berechtigungen</button>
<button type="button" class="tab-btn" data-tab="teams">Teams</button>
</div>
<!-- Konto -->
<div class="tab-pane" data-pane="account" style="padding:16px 20px">
<h3 style="margin-top:0">Kontoinformationen</h3>
<label for="name">Name *</label>
<input type="text" id="name" name="name" value="<?= e($v('name', 'name')) ?>" required>
<label for="email">E-Mail-Adresse *</label>
<input type="email" id="email" name="email" value="<?= e($v('email', 'email')) ?>" required>
<label>Status *</label>
<div style="display:flex;gap:18px;margin:4px 0 10px">
<label style="display:flex;align-items:center;gap:6px;margin:0"><input type="radio" name="status" value="active" style="width:auto" <?= $curStatus === 'active' ? 'checked' : '' ?>> <strong>Aktiv</strong></label>
<label style="display:flex;align-items:center;gap:6px;margin:0"><input type="radio" name="status" value="locked" style="width:auto" <?= $curStatus !== 'active' ? 'checked' : '' ?>> Gesperrt</label>
</div>
<label for="password"><?= $editStaff ? 'Neues Passwort (leer = unverändert)' : 'Passwort *' ?></label>
<input type="password" id="password" name="password" autocomplete="new-password" <?= $editStaff ? '' : 'required' ?>>
<label for="signature">Signatur (E-Mail-Fuß für eigene Antworten)</label>
<textarea id="signature" name="signature" data-richtext data-image-upload-url="/staff/upload_signature_image.php" style="min-height:90px" placeholder="z. B. Mit freundlichen Grüßen&#10;Max Mustermann"><?= e($v('signature', 'signature')) ?></textarea>
</div>
<!-- Zugang -->
<div class="tab-pane" data-pane="access" style="padding:16px 20px;display:none">
<h3 style="margin-top:0">Zugang</h3>
<p class="muted" style="margin-top:0">Wähle die Abteilungen, zu denen der Agent Zugang haben soll.</p>
<h4 style="border-bottom:1px dotted var(--border);padding-bottom:4px">Hauptabteilung <span style="color:#dc2626">*</span></h4>
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap">
<select name="department_id" id="department_id" style="max-width:320px">
<option value="">–</option>
<?php foreach ($departments as $d): ?>
<option value="<?= $d['id'] ?>" <?= $curDept === (string) $d['id'] ? 'selected' : '' ?>><?= e($d['name']) ?></option>
<?php endforeach; ?>
</select>
<span class="muted" style="font-size:.85rem">Rolle: <strong id="primary-role-label">–</strong> <span style="font-size:.78rem">(Reiter „Berechtigungen“)</span></span>
</div>
<h4 style="border-bottom:1px dotted var(--border);padding-bottom:4px;margin-top:22px">Erweiterter Zugriff</h4>
<div id="extra-rows"></div>
<div style="display:flex;align-items:center;gap:8px;margin-top:10px">
<select id="extra-add" style="max-width:260px"><option value="">— Abteilung auswählen —</option></select>
<button type="button" class="btn secondary" id="extra-add-btn">Hinzufügen</button>
</div>
</div>
<!-- Berechtigungen -->
<div class="tab-pane" data-pane="perms" style="padding:16px 20px;display:none">
<h3 style="margin-top:0">Berechtigungen</h3>
<label for="role">Kontotyp</label>
<select name="role" id="role" style="max-width:320px" <?= $isFullAdmin ? '' : 'disabled' ?>>
<option value="agent" <?= $curRole === 'agent' ? 'selected' : '' ?>>Mitarbeiter</option>
<option value="admin" <?= $curRole === 'admin' ? 'selected' : '' ?>>Administrator (alle Rechte)</option>
</select>
<?php if (!$isFullAdmin): ?>
<input type="hidden" name="role" value="<?= e($curRole) ?>">
<p class="muted" style="font-size:.78rem;margin-top:2px">Nur Administratoren können die Administrator-Rolle vergeben.</p>
<?php endif; ?>
<div id="role-id-box">
<label for="role_id">Rolle (für Mitarbeiter)</label>
<select name="role_id" id="role_id" style="max-width:320px">
<option value="">– Standard-Mitarbeiterrechte –</option>
<?php foreach ($customRoles as $cr): ?>
<option value="<?= $cr['id'] ?>" <?= $curRoleId === (string) $cr['id'] ? 'selected' : '' ?>><?= e($cr['name']) ?></option>
<?php endforeach; ?>
</select>
<p class="muted" style="font-size:.78rem">Rollen legst du unter <a href="/staff/roles.php">Rollen</a> an.</p>
</div>
<h4 style="border-bottom:1px dotted var(--border);padding-bottom:4px">Wirksame Rechte</h4>
<div id="perm-list" style="columns:2;column-gap:24px;font-size:.88rem"></div>
</div>
<!-- Teams -->
<div class="tab-pane" data-pane="teams" style="padding:16px 20px;display:none">
<h3 style="margin-top:0">Teams</h3>
<?php if (!$teams): ?>
<p class="muted">Es sind noch keine Teams angelegt. Teams legst du unter <a href="/staff/teams.php">Teams</a> an.</p>
<?php else: ?>
<p class="muted" style="margin-top:0">Der Agent ist Mitglied in folgenden Teams.<?= $canManageTeams ? '' : ' (Zum Ändern fehlt das Recht „Teams verwalten“.)' ?></p>
<?php foreach ($teams as $t): ?>
<label style="display:flex;align-items:center;gap:8px;margin:6px 0">
<input type="checkbox" name="teams[]" value="<?= $t['id'] ?>" style="width:auto" <?= in_array((int) $t['id'], $memberTeams, true) ? 'checked' : '' ?> <?= $canManageTeams ? '' : 'disabled' ?>>
<?= e($t['name']) ?><?= $t['is_active'] ? '' : ' <span class="muted">(deaktiviert)</span>' ?>
</label>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div class="btn-row" style="padding:0 20px 18px">
<button type="submit" class="btn"><?= $editStaff ? 'Änderungen speichern' : 'Agent anlegen' ?></button>
<a href="/staff/staff_manage.php" class="btn secondary">Abbrechen</a>
</div>
</form>
<style>
.tab-btn{background:none;border:1px solid transparent;border-bottom:none;padding:8px 16px;cursor:pointer;border-radius:6px 6px 0 0;color:var(--muted)}
.tab-btn.active{background:var(--card-bg,#fff);border-color:var(--border);color:inherit;font-weight:600;position:relative;top:1px}
.extra-row{display:flex;align-items:center;gap:12px;padding:6px 0;border-bottom:1px dotted var(--border)}
.extra-row .nm{flex:1}
.extra-row button{background:none;border:none;color:#dc2626;cursor:pointer;font-size:1rem}
</style>
<script>
(function () {
var btns = document.querySelectorAll('.tab-btn'), panes = document.querySelectorAll('.tab-pane');
function show(t) {
btns.forEach(function (b) { b.classList.toggle('active', b.dataset.tab === t); });
panes.forEach(function (p) { p.style.display = p.dataset.pane === t ? '' : 'none'; });
}
btns.forEach(function (b) { b.addEventListener('click', function () { show(b.dataset.tab); }); });
show(<?= json_encode($startTab) ?>);
// Erweiterter Zugriff
var depts = <?= json_encode(array_map(fn($d) => ['id' => (int) $d['id'], 'name' => $d['name']], $departments), JSON_UNESCAPED_UNICODE) ?>;
var extra = <?= json_encode((object) $extraAccess) ?>; // id -> {notify, role_id}
var roles = <?= json_encode(array_map(fn($r) => ['id' => (int) $r['id'], 'name' => $r['name']], $customRoles), JSON_UNESCAPED_UNICODE) ?>;
var rows = document.getElementById('extra-rows'), addSel = document.getElementById('extra-add'), primary = document.getElementById('department_id');
function esc(s) { var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
function render() {
var p = primary.value;
delete extra[p]; // Hauptabteilung nicht doppelt
rows.innerHTML = '';
depts.forEach(function (d) {
if (!(d.id in extra)) return;
var div = document.createElement('div'); div.className = 'extra-row';
var opts = '<option value="">Hauptrolle</option>' + roles.map(function (r) { return '<option value="' + r.id + '"' + (String(extra[d.id].role_id) === String(r.id) ? ' selected' : '') + '>' + esc(r.name) + '</option>'; }).join('');
div.innerHTML = '<span class="nm">' + esc(d.name) + '<input type="hidden" name="extra_departments[]" value="' + d.id + '"></span>' +
'<select name="role_' + d.id + '" style="max-width:200px" title="Rolle in dieser Abteilung">' + opts + '</select>' +
'<label style="display:flex;align-items:center;gap:6px;margin:0"><input type="checkbox" name="notify_' + d.id + '" style="width:auto"' + (extra[d.id].notify ? ' checked' : '') + '> Benachrichtigungen</label>' +
'<button type="button" title="Entfernen" aria-label="Entfernen">🗑</button>';
div.querySelector('input[type=checkbox]').addEventListener('change', function (e) { extra[d.id].notify = e.target.checked ? 1 : 0; });
div.querySelector('select').addEventListener('change', function (e) { extra[d.id].role_id = e.target.value === '' ? null : parseInt(e.target.value, 10); });
div.querySelector('button').addEventListener('click', function () { delete extra[d.id]; render(); });
rows.appendChild(div);
});
addSel.innerHTML = '<option value="">— Abteilung auswählen —</option>';
depts.forEach(function (d) { if (!(d.id in extra) && String(d.id) !== p) addSel.insertAdjacentHTML('beforeend', '<option value="' + d.id + '">' + esc(d.name) + '</option>'); });
}
document.getElementById('extra-add-btn').addEventListener('click', function () { if (addSel.value) { extra[addSel.value] = { notify: 1, role_id: null }; render(); } });
primary.addEventListener('change', render);
render();
// Wirksame Rechte
var labels = <?= json_encode($permLabels, JSON_UNESCAPED_UNICODE) ?>;
var roleDefs = <?= json_encode((object) $rolePerms) ?>, agentDef = <?= json_encode($agentDefaults) ?>, adminDef = <?= json_encode($adminDefaults) ?>;
var roleSel = document.getElementById('role'), roleIdSel = document.getElementById('role_id'), list = document.getElementById('perm-list');
function perms() {
if (roleSel.value === 'admin') return adminDef;
return roleIdSel.value && roleDefs[roleIdSel.value] ? roleDefs[roleIdSel.value] : agentDef;
}
function primaryRoleLabel() {
if (roleSel.value === 'admin') return 'Administrator';
var r = roles.filter(function (x) { return String(x.id) === roleIdSel.value; })[0];
return r ? r.name : 'Standard-Mitarbeiterrechte';
}
function renderPerms() {
document.getElementById('primary-role-label').textContent = primaryRoleLabel();
document.getElementById('role-id-box').style.display = roleSel.value === 'admin' ? 'none' : '';
var p = perms(); list.innerHTML = '';
Object.keys(labels).forEach(function (k) {
list.insertAdjacentHTML('beforeend', '<div style="padding:2px 0">' + (p[k] ? '✓' : '<span class="muted">✗</span>') + ' ' + esc(labels[k]) + '</div>');
});
}
roleSel.addEventListener('change', renderPerms); roleIdSel.addEventListener('change', renderPerms); renderPerms();
})();
</script>
<?php else: ?>
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px">
<h1 style="margin:0">Mitarbeiter</h1>
<a href="/staff/staff_manage.php?new=1" class="btn">Neuen Agenten hinzufügen</a>
</div>
<div class="card" style="margin-top:14px">
<table>
<thead><tr><th>Name</th><th>E-Mail</th><th>Typ</th><th>Status</th><th>Hauptabteilung</th><th style="text-align:center">Teams</th><th>Erstellt</th><th></th></tr></thead>
<tbody>
<?php foreach ($allStaff as $s): ?>
<tr>
<td><a href="/staff/staff_manage.php?edit=<?= (int) $s['id'] ?>"><?= e($s['name']) ?></a></td>
<td><?= e($s['email']) ?></td>
<td><?= $s['role'] === 'admin' ? 'Administrator' : 'Mitarbeiter' ?></td>
<td><strong><?= $s['is_active'] ? 'Aktiv' : 'Gesperrt' ?></strong></td>
<td><?= e($s['department_name'] ?? '–') ?></td>
<td style="text-align:center"><?= (int) $s['team_count'] ?></td>
<td class="muted" style="font-size:.82rem"><?= e($fmt($s['created_at'] ?? null)) ?></td>
<td style="white-space:nowrap">
<a href="/staff/staff_manage.php?edit=<?= (int) $s['id'] ?>">Bearbeiten</a> ·
<form method="post" style="display:inline" onsubmit="return confirm('Mitarbeiter wirklich löschen?');">
<?= csrf_field() ?>
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= (int) $s['id'] ?>">
<button type="submit" style="background:none;border:none;color:#dc2626;cursor:pointer;padding:0;font-size:.9rem">Löschen</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php require __DIR__ . '/_footer.php'; ?>