Files
deskhub/DeskHub-Webseite/staff/departments.php
T
2026-10-23 11:14:24 +00:00

265 lines
14 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';
$staff = require_admin_or_permission('manage_departments');
$pdo = get_db();
$errors = [];
$staffList = $pdo->query('SELECT id, name FROM staff WHERE is_active = 1 ORDER BY name')->fetchAll();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
$action = $_POST['action'] ?? '';
if ($action === 'create' || $action === 'update') {
$id = $action === 'update' ? (int) ($_POST['id'] ?? 0) : 0;
try {
department_save($pdo, $id, [
'name' => $_POST['name'] ?? '', 'email' => $_POST['email'] ?? '', 'is_default' => !empty($_POST['is_default']),
'is_active' => ($_POST['status'] ?? 'active') === 'active', 'manager_id' => $_POST['manager_id'] ?? null,
'sla_plan_id' => $_POST['sla_plan_id'] ?? null, 'notes' => $_POST['notes'] ?? '', 'signature' => $_POST['signature'] ?? '',
'auto_assign_mode' => $_POST['auto_assign_mode'] ?? 'none', 'auto_assign_staff_id' => $_POST['auto_assign_staff_id'] ?? null,
]);
audit_log($staff['id'], ($action === 'create' ? 'Abteilung erstellt: ' : 'Abteilung aktualisiert: ') . trim($_POST['name'] ?? ''));
flash('success', $action === 'create' ? 'Abteilung erstellt.' : 'Änderungen gespeichert.');
redirect('/staff/departments.php');
} catch (AdminModelException $e) {
$errors[] = $e->getMessage();
}
}
if ($action === 'delete') {
try {
$deleted = department_delete($pdo, (int) $_POST['id']);
audit_log($staff['id'], "Abteilung gelöscht: {$deleted}");
flash('success', 'Abteilung gelöscht.');
} catch (AdminModelException $e) {
flash('error', $e->getMessage());
}
redirect('/staff/departments.php');
}
}
$isNew = isset($_GET['new']);
$editId = (int) ($_GET['edit'] ?? 0);
$showForm = $isNew || $editId || ($errors && in_array($_POST['action'] ?? '', ['create', 'update'], true));
$editDept = null;
if ($editId) {
$stmt = $pdo->prepare('SELECT * FROM departments WHERE id = ?');
$stmt->execute([$editId]);
$editDept = $stmt->fetch() ?: null;
}
// Mitglieder = Hauptabteilung ODER zusätzlich zugewiesene Abteilung
$memberStmt = $pdo->prepare(
'SELECT s.id, s.name, s.email, s.role, s.is_active, (s.department_id = ?) AS is_primary
FROM staff s
WHERE s.department_id = ? OR s.id IN (SELECT staff_id FROM staff_department WHERE department_id = ?)
ORDER BY s.name'
);
$departments = $pdo->query(
'SELECT d.*, m.name AS manager_name,
(SELECT COUNT(*) FROM staff s WHERE s.department_id = d.id OR s.id IN (SELECT staff_id FROM staff_department sd WHERE sd.department_id = d.id)) AS member_count
FROM departments d LEFT JOIN staff m ON m.id = d.manager_id
ORDER BY d.name'
)->fetchAll();
$emailOptions = $pdo->query(
'SELECT ea.email, d.name AS department_name FROM email_addresses ea JOIN departments d ON d.id = ea.department_id ORDER BY ea.email'
)->fetchAll();
$fmt = fn(?string $dt) => $dt ? date('d.m.Y H:i', strtotime($dt)) : '–';
$pageTitle = 'Abteilungen';
$activePage = 'departments';
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, $editDept[$col] ?? $default);
$curStatus = $_POST ? ($_POST['status'] ?? 'active') : (($editDept['is_active'] ?? 1) ? 'active' : 'inactive');
$curEmail = strtolower((string) $v('email', 'email'));
$curManager = (string) $v('manager_id', 'manager_id');
$curAutoMode = (string) $v('auto_assign_mode', 'auto_assign_mode', 'none');
$curAutoStaff = (string) $v('auto_assign_staff_id', 'auto_assign_staff_id');
$isDefaultChecked = $_POST ? !empty($_POST['is_default']) : !empty($editDept['is_default']);
$members = [];
if ($editDept) {
$did = (int) $editDept['id'];
$memberStmt->execute([$did, $did, $did]);
$members = $memberStmt->fetchAll();
}
$seen = false;
?>
<h1>
<?= $editDept ? 'Abteilung aktualisieren' : 'Neue Abteilung' ?>
<?php if ($editDept): ?><span class="muted" style="font-size:1rem;font-weight:400">— <?= e($editDept['name']) ?></span><?php endif; ?>
</h1>
<form method="post" class="card" style="padding:0">
<?= csrf_field() ?>
<input type="hidden" name="action" value="<?= $editDept ? 'update' : 'create' ?>">
<?php if ($editDept): ?><input type="hidden" name="id" value="<?= (int) $editDept['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="dept">Abteilung</button>
<button type="button" class="tab-btn" data-tab="members">Mitglieder<?= $editDept ? ' (' . count($members) . ')' : '' ?></button>
<?php if ($editDept): ?><a href="/staff/department_form.php?dept=<?= (int) $editDept['id'] ?>" class="tab-btn" style="text-decoration:none">Ticket-Formular<?= !empty($editDept['own_form']) ? ' ✓' : '' ?></a><?php endif; ?>
</div>
<div class="tab-pane" data-pane="dept" style="padding:16px 20px">
<h3 style="margin-top:0">Abteilungsinformationen</h3>
<label for="name">Name *</label>
<input type="text" id="name" name="name" value="<?= e($v('name', 'name')) ?>" 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="inactive" style="width:auto" <?= $curStatus === 'inactive' ? 'checked' : '' ?>> Deaktiviert</label>
</div>
<label for="manager_id">Abteilungsleiter</label>
<select id="manager_id" name="manager_id">
<option value="">— Keine(r) —</option>
<?php foreach ($staffList as $s): ?>
<option value="<?= $s['id'] ?>" <?= $curManager === (string) $s['id'] ? 'selected' : '' ?>><?= e($s['name']) ?></option>
<?php endforeach; ?>
</select>
<label for="auto_assign_mode">Neue Tickets automatisch zuweisen</label>
<select id="auto_assign_mode" name="auto_assign_mode">
<?php foreach (department_auto_assign_modes() as $__mk => $__ml): ?>
<option value="<?= e($__mk) ?>" <?= $curAutoMode === $__mk ? 'selected' : '' ?>><?= e($__ml) ?></option>
<?php endforeach; ?>
</select>
<label for="auto_assign_staff_id" style="margin-top:8px">Mitarbeiter (nur bei „Immer an einen bestimmten Mitarbeiter“)</label>
<select id="auto_assign_staff_id" name="auto_assign_staff_id">
<option value="">— Niemand —</option>
<?php foreach ($staffList as $s): ?>
<option value="<?= $s['id'] ?>" <?= $curAutoStaff === (string) $s['id'] ? 'selected' : '' ?>><?= e($s['name']) ?></option>
<?php endforeach; ?>
</select>
<p class="muted" style="font-size:.78rem;margin-top:4px">Gilt für Tickets aus Formular, E-Mail, API (z. B. Minecraft-Plugin) und Live-Chat. Eine Ticket-Regel mit „Mitarbeiter zuweisen“ hat Vorrang. Ist der Mitarbeiter im Urlaub, geht das Ticket an seine Vertretung. „Reihum“ überspringt Mitarbeiter im Urlaub, offline oder außerhalb ihrer Schicht.</p>
<label for="sla_plan_id">SLA-Plan</label>
<select id="sla_plan_id" name="sla_plan_id">
<option value="">— Zeiten der Priorität verwenden —</option>
<?php foreach ($pdo->query('SELECT id, name, is_active FROM sla_plans ORDER BY name')->fetchAll() as $__sp): ?>
<option value="<?= $__sp['id'] ?>" <?= (string) $v('sla_plan_id', 'sla_plan_id') === (string) $__sp['id'] ? 'selected' : '' ?>><?= e($__sp['name']) ?><?= $__sp['is_active'] ? '' : ' (deaktiviert)' ?></option>
<?php endforeach; ?>
</select>
<label for="email">Abteilungs-E-Mail (optional)</label>
<select id="email" name="email">
<option value="">— Automatisch (Standardadresse der Abteilung) —</option>
<?php foreach ($emailOptions as $o): $sel = strtolower($o['email']) === $curEmail; $seen = $seen || $sel; ?>
<option value="<?= e($o['email']) ?>" <?= $sel ? 'selected' : '' ?>><?= e($o['email']) ?> (<?= e($o['department_name']) ?>)</option>
<?php endforeach; ?>
<?php if ($curEmail !== '' && !$seen): ?><option value="<?= e($curEmail) ?>" selected><?= e($curEmail) ?></option><?php endif; ?>
</select>
<p class="muted" style="font-size:.78rem;margin-top:3px">Adressen, Priorität und Postfach-Abruf pflegst du unter <a href="/staff/email_addresses.php">E-Mail-Adressen</a>.</p>
<label style="display:flex; align-items:center; gap:8px; margin-top:14px">
<input type="checkbox" name="is_default" style="width:auto" <?= $isDefaultChecked ? 'checked' : '' ?>>
Standardabteilung (für E-Mail-Tickets ohne Zuordnung)
</label>
<label for="signature">Signatur (E-Mail-Fuß für Antworten ohne Mitarbeiter-Signatur)</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;Ihr Support-Team"><?= e($v('signature', 'signature')) ?></textarea>
<h3>Administratornotizen <span class="muted" style="font-weight:400;font-size:.85rem">– Interne Notizen, sichtbar für alle Administratoren</span></h3>
<textarea id="notes" name="notes" rows="6"><?= e($v('notes', 'notes')) ?></textarea>
</div>
<div class="tab-pane" data-pane="members" style="padding:16px 20px;display:none">
<?php if (!$editDept): ?>
<p class="muted">Mitglieder können nach dem Erstellen der Abteilung unter <a href="/staff/staff_manage.php">Mitarbeiter</a> zugewiesen werden.</p>
<?php elseif (!$members): ?>
<p class="muted">Dieser Abteilung sind noch keine Mitarbeiter zugewiesen. Die Zuweisung erfolgt beim jeweiligen Mitarbeiter unter <a href="/staff/staff_manage.php">Mitarbeiter</a>.</p>
<?php else: ?>
<table>
<thead><tr><th>Name</th><th>E-Mail</th><th>Rolle</th><th>Zuordnung</th><th>Status</th></tr></thead>
<tbody>
<?php foreach ($members as $m): ?>
<tr>
<td><?= e($m['name']) ?><?= (string) $m['id'] === $curManager ? ' <span class="muted">(Leiter)</span>' : '' ?></td>
<td><?= e($m['email']) ?></td>
<td><?= $m['role'] === 'admin' ? 'Administrator' : 'Agent' ?></td>
<td><?= $m['is_primary'] ? 'Hauptabteilung' : 'Zusätzlich' ?></td>
<td><?= $m['is_active'] ? 'Aktiv' : 'Deaktiviert' ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p class="muted" style="font-size:.78rem;margin-top:10px">Zuweisungen änderst du unter <a href="/staff/staff_manage.php">Mitarbeiter</a>.</p>
<?php endif; ?>
</div>
<div class="btn-row" style="padding:0 20px 18px">
<button type="submit" class="btn"><?= $editDept ? 'Änderungen speichern' : 'Erstellen' ?></button>
<a href="/staff/departments.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}
</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('dept');
})();
</script>
<?php else: ?>
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px">
<h1 style="margin:0">Abteilungen</h1>
<a href="/staff/departments.php?new=1" class="btn">Neue Abteilung hinzufügen</a>
</div>
<div class="card" style="margin-top:14px">
<table>
<thead><tr><th>Name</th><th>Status</th><th style="text-align:center">Mitglieder</th><th>Abteilungsleiter</th><th>E-Mail</th><th>Erstellt</th><th>Zuletzt aktualisiert</th><th></th></tr></thead>
<tbody>
<?php foreach ($departments as $d): ?>
<tr>
<td><a href="/staff/departments.php?edit=<?= (int) $d['id'] ?>"><?= e($d['name']) ?></a><?= $d['is_default'] ? ' <span class="muted">(Standard)</span>' : '' ?></td>
<td><strong><?= ($d['is_active'] ?? 1) ? 'Aktiv' : 'Deaktiviert' ?></strong></td>
<td style="text-align:center"><a href="/staff/departments.php?edit=<?= (int) $d['id'] ?>"><?= (int) $d['member_count'] ?></a></td>
<td><?= e($d['manager_name'] ?? '') ?></td>
<td class="muted" style="font-size:.85rem"><?= e($d['email']) ?></td>
<td class="muted" style="font-size:.82rem"><?= e($fmt($d['created_at'] ?? null)) ?></td>
<td class="muted" style="font-size:.82rem"><?= e($fmt($d['updated_at'] ?? null)) ?></td>
<td style="white-space:nowrap">
<a href="/staff/departments.php?edit=<?= (int) $d['id'] ?>">Bearbeiten</a> ·
<a href="/staff/department_form.php?dept=<?= (int) $d['id'] ?>">Formular<?= !empty($d['own_form']) ? ' ✓' : '' ?></a> ·
<form method="post" style="display:inline" onsubmit="return confirm('Abteilung wirklich löschen?');">
<?= csrf_field() ?>
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= (int) $d['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; ?>
<?php if (!$departments): ?>
<tr><td colspan="8" class="muted">Noch keine Abteilungen angelegt.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php require __DIR__ . '/_footer.php'; ?>