265 lines
14 KiB
PHP
265 lines
14 KiB
PHP
<?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 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'; ?>
|