prepare('SELECT * FROM departments WHERE id = ?'); $stmt->execute([$deptId]); $dept = $stmt->fetch(); if (!$dept) { flash('error', 'Abteilung nicht gefunden.'); redirect('/staff/departments.php'); } $fieldTypes = [ 'text' => 'Einzeiliger Text', 'textarea' => 'Mehrzeiliger Text', 'select' => 'Dropdown-Auswahl', 'radio' => 'Radio-Auswahl (Punkte)', 'checkbox' => 'Checkbox (Ja/Nein)', 'number' => 'Zahl', 'date' => 'Datum', ]; $errors = []; // Feldpositionen: Schlüssel => [Gruppe, Beschriftung]; "@"-Schlüssel stehen in custom_fields.form_section $positions = [ '@topic_top' => ['Abschnitt 1 – Themenauswahl', 'vor der Themenauswahl'], '@topic' => ['Abschnitt 1 – Themenauswahl', 'nach der Themenauswahl'], '@contact_top' => ['Abschnitt 2 – Kontaktdaten', 'vor Name/E-Mail'], '@contact' => ['Abschnitt 2 – Kontaktdaten', 'nach Name/E-Mail'], '@details_top' => ['Abschnitt 3 – Betreff und Beschreibung', 'vor dem Betreff'], '@details_mid' => ['Abschnitt 3 – Betreff und Beschreibung', 'zwischen Betreff und Beschreibung'], '@details' => ['Abschnitt 3 – Betreff und Beschreibung', 'nach der Beschreibung'], ]; $self = '/staff/department_form.php?dept=' . $deptId; if ($_SERVER['REQUEST_METHOD'] === 'POST') { verify_csrf(); $action = $_POST['action'] ?? ''; if ($action === 'save_form') { $clip = fn(string $k, int $max) => mb_substr(trim((string) ($_POST[$k] ?? '')), 0, $max); $cfg = [ 'title' => $clip('title', 150), 'contact_title' => $clip('contact_title', 100), 'issue_title' => $clip('issue_title', 100), 'details_title' => $clip('details_title', 100), 'intro' => $clip('intro', 1000), 'subject_show' => !empty($_POST['subject_show']), 'subject_label' => $clip('subject_label', 100), 'message_label' => $clip('message_label', 100), 'message_show' => !empty($_POST['message_show']), 'subject_width' => in_array($_POST['subject_width'] ?? '', ['half', 'third', 'twothirds'], true) ? $_POST['subject_width'] : 'full', 'message_width' => in_array($_POST['message_width'] ?? '', ['half', 'third', 'twothirds'], true) ? $_POST['message_width'] : 'full', 'message_hint' => $clip('message_hint', 200), 'attachment_show' => !empty($_POST['attachment_show']), 'submit_label' => $clip('submit_label', 60), ]; $pdo->prepare('UPDATE departments SET own_form = ?, form_config = ?, updated_at = ? WHERE id = ?') ->execute([!empty($_POST['own_form']) ? 1 : 0, json_encode($cfg, JSON_UNESCAPED_UNICODE), db_now(), $deptId]); audit_log($staff['id'], 'Abteilungsformular gespeichert: ' . $dept['name']); flash('success', 'Formular gespeichert.'); redirect($self); } if ($action === 'save_field') { $fid = (int) ($_POST['id'] ?? 0); $label = trim((string) ($_POST['label'] ?? '')); $type = array_key_exists($_POST['field_type'] ?? '', $fieldTypes) ? $_POST['field_type'] : 'text'; $options = trim((string) ($_POST['options'] ?? '')); $required = !empty($_POST['is_required']) ? 1 : 0; $active = !empty($_POST['is_active']) ? 1 : 0; $sort = (int) ($_POST['sort_order'] ?? 0); $radioInline = !empty($_POST['radio_inline']) ? 1 : 0; $helpText = form_help_compose((string) ($_POST['help_text'] ?? ''), (string) ($_POST['link_url'] ?? ''), (string) ($_POST['link_word'] ?? ''), $label); $width = in_array($_POST['form_width'] ?? '', ['half', 'third', 'twothirds'], true) ? $_POST['form_width'] : null; $secPick = (string) ($_POST['form_section'] ?? ''); $section = ($secPick === '' || isset($positions[$secPick])) ? $secPick : mb_substr(trim((string) ($_POST['form_section_custom'] ?? '')), 0, 100); if ($label === '') $errors[] = 'Bitte eine Bezeichnung angeben.'; if (in_array($type, ['select', 'radio'], true) && $options === '') $errors[] = 'Bitte mindestens eine Option angeben (eine pro Zeile).'; if (!$errors) { if ($fid) { $pdo->prepare('UPDATE custom_fields SET label=?, field_type=?, options=?, is_required=?, is_active=?, sort_order=?, form_section=?, form_width=?, radio_inline=?, help_text=? WHERE id=? AND department_id=?') ->execute([$label, $type, $options ?: null, $required, $active, $sort, $section ?: null, $width, $radioInline, $helpText ?: null, $fid, $deptId]); } else { $pdo->prepare('INSERT INTO custom_fields (label, field_type, options, help_topic_id, department_id, is_required, is_active, sort_order, form_section, form_width, radio_inline, help_text, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)') ->execute([$label, $type, $options ?: null, null, $deptId, $required, $active, $sort, $section ?: null, $width, $radioInline, $helpText ?: null, db_now()]); } audit_log($staff['id'], "Abteilungsfeld gespeichert ({$dept['name']}): {$label}"); flash('success', 'Feld gespeichert.'); redirect($self); } } if ($action === 'delete_field') { $pdo->prepare('DELETE FROM custom_fields WHERE id = ? AND department_id = ?')->execute([(int) ($_POST['id'] ?? 0), $deptId]); audit_log($staff['id'], "Abteilungsfeld gelöscht ({$dept['name']})"); flash('success', 'Feld gelöscht (bereits erfasste Werte in Tickets bleiben erhalten).'); redirect($self); } } $cfg = json_decode((string) ($dept['form_config'] ?? ''), true); $cfg = is_array($cfg) ? $cfg : []; $cv = fn(string $k, string $def = '') => (string) ($cfg[$k] ?? $def); $flag = fn(string $k) => !array_key_exists($k, $cfg) || !empty($cfg[$k]); $fieldsStmt = $pdo->prepare('SELECT * FROM custom_fields WHERE department_id = ? ORDER BY sort_order, label'); $fieldsStmt->execute([$deptId]); $fields = $fieldsStmt->fetchAll(); $editField = null; if (!empty($_GET['edit'])) { foreach ($fields as $f) if ((int) $f['id'] === (int) $_GET['edit']) $editField = $f; } $pageTitle = 'Formular: ' . $dept['name']; $activePage = 'departments'; require __DIR__ . '/_header.php'; ?>

← Zurück zur Abteilung

Ticket-Formular —

Hier legst du fest, wie das Formular „Neues Ticket“ aussieht, wenn ein Kunde diese Abteilung wählt (direkt oder über ein Hilfe-Thema dieser Abteilung).

Ist das aktiv, erscheinen für diese Abteilung nur die unten festgelegten Felder. Die allgemeinen Ticket-Felder und die Felder der Hilfe-Themen werden dann nicht verwendet. Name und E-Mail-Adresse werden immer abgefragt, damit wir antworten können.

Standardfelder

Ohne Betrefffeld wird der Betreff automatisch „Anfrage “.

'Ganze Zeile', 'half' => 'Halbe Zeile', 'third' => 'Ein Drittel', 'twothirds' => 'Zwei Drittel']; ?>

Mit „Halbe Zeile“ steht der Betreff neben einem benachbarten eigenen Feld (zum Beispiel einem Zahlenfeld direkt vor oder nach dem Betreff).

Ohne Beschreibung wird der Text des Tickets aus deinen eigenen Feldern zusammengesetzt („Bezeichnung: Eingabe“).

Felder dieser Abteilung

ReihenfolgeAbschnittBezeichnungTypPflichtAktiv
Bearbeiten ·
Noch keine eigenen Felder. Rechts kannst du das erste anlegen.

trim((string) ($x['form_section'] ?? '')), $fields), fn($v) => $v !== '' && $v[0] !== '@')) as $sn): ?>

Felder mit gleichem Namen landen im selben Abschnitt.

Bei einer Checkbox steht der Text neben dem Kästchen, bei anderen Feldern unter dem Feld. Das Wort aus „Verlinkter Teil“ wird im Text zum Link auf die Adresse. Eine Checkbox als Pflichtfeld muss angehakt werden.

Aufeinanderfolgende Felder im selben Abschnitt, die zusammen in eine Zeile passen, stehen nebeneinander.