Upload via GUI (258 Dateien)

This commit is contained in:
2026-10-16 19:12:21 +00:00
parent 6cced3beda
commit de06066052
50 changed files with 10411 additions and 0 deletions
+172
View File
@@ -0,0 +1,172 @@
<?php
require_once __DIR__ . '/../includes/bootstrap.php';
$admin = require_admin();
$pdo = get_db();
$errors = [];
$fieldTypes = [
'text' => 'Einzeiliger Text',
'textarea' => 'Mehrzeiliger Text',
'select' => 'Dropdown-Auswahl',
'checkbox' => 'Checkbox (Ja/Nein)',
'number' => 'Zahl',
'date' => 'Datum',
];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
$action = $_POST['action'] ?? '';
if ($action === 'create' || $action === 'update') {
$label = trim($_POST['label'] ?? '');
$type = array_key_exists($_POST['field_type'] ?? '', $fieldTypes) ? $_POST['field_type'] : 'text';
$optionsRaw = trim($_POST['options'] ?? '');
$helpTopicId = ($_POST['help_topic_id'] ?? '') !== '' ? (int) $_POST['help_topic_id'] : null;
$isRequired = !empty($_POST['is_required']) ? 1 : 0;
$isActive = !empty($_POST['is_active']) ? 1 : 0;
$sort = (int) ($_POST['sort_order'] ?? 0);
if ($label === '') $errors[] = 'Bitte eine Bezeichnung angeben.';
if ($type === 'select' && $optionsRaw === '') $errors[] = 'Bitte mindestens eine Option angeben (eine pro Zeile).';
if (!$errors) {
if ($action === 'create') {
$pdo->prepare('INSERT INTO custom_fields (label, field_type, options, help_topic_id, is_required, is_active, sort_order, created_at) VALUES (?,?,?,?,?,?,?,?)')
->execute([$label, $type, $optionsRaw ?: null, $helpTopicId, $isRequired, $isActive, $sort, db_now()]);
audit_log($admin['id'], "Ticket-Feld erstellt: {$label}");
flash('success', 'Feld erstellt.');
} else {
$id = (int) $_POST['id'];
$pdo->prepare('UPDATE custom_fields SET label=?, field_type=?, options=?, help_topic_id=?, is_required=?, is_active=?, sort_order=? WHERE id=?')
->execute([$label, $type, $optionsRaw ?: null, $helpTopicId, $isRequired, $isActive, $sort, $id]);
audit_log($admin['id'], "Ticket-Feld aktualisiert: {$label}");
flash('success', 'Feld aktualisiert.');
}
redirect('/staff/custom_fields.php');
}
}
if ($action === 'delete') {
$id = (int) $_POST['id'];
$labelStmt = $pdo->prepare('SELECT label FROM custom_fields WHERE id = ?');
$labelStmt->execute([$id]);
$delLabel = $labelStmt->fetchColumn();
$pdo->prepare('DELETE FROM custom_fields WHERE id = ?')->execute([$id]);
audit_log($admin['id'], "Ticket-Feld gelöscht: {$delLabel}");
flash('success', 'Feld gelöscht (bereits erfasste Werte bleiben in bestehenden Tickets sichtbar).');
redirect('/staff/custom_fields.php');
}
}
$fields = $pdo->query(
'SELECT cf.*, ht.name AS help_topic_name FROM custom_fields cf
LEFT JOIN help_topics ht ON ht.id = cf.help_topic_id
ORDER BY cf.sort_order, cf.label'
)->fetchAll();
$helpTopics = $pdo->query('SELECT * FROM help_topics ORDER BY name')->fetchAll();
$editId = $_GET['edit'] ?? null;
$editField = null;
if ($editId) {
$stmt = $pdo->prepare('SELECT * FROM custom_fields WHERE id = ?');
$stmt->execute([$editId]);
$editField = $stmt->fetch();
}
$pageTitle = 'Ticket-Felder';
$activePage = 'custom_fields';
require __DIR__ . '/_header.php';
?>
<h1>Individuelle Ticket-Felder</h1>
<p class="muted">Diese Felder erscheinen zusätzlich zu Name, E-Mail, Betreff und Beschreibung auf dem Formular „Neues Ticket erstellen“. Die eingegebenen Werte werden im Ticket angezeigt.</p>
<?php foreach ($errors as $err): ?>
<div class="flash error"><?= e($err) ?></div>
<?php endforeach; ?>
<div style="display:flex; gap:24px; align-items:flex-start">
<div style="flex:2">
<div class="card">
<table>
<thead><tr><th>Bezeichnung</th><th>Typ</th><th>Hilfe-Thema</th><th>Pflichtfeld</th><th>Aktiv</th><th></th></tr></thead>
<tbody>
<?php foreach ($fields as $f): ?>
<tr>
<td><?= e($f['label']) ?></td>
<td><?= e($fieldTypes[$f['field_type']] ?? $f['field_type']) ?></td>
<td class="muted"><?= $f['help_topic_name'] ? e($f['help_topic_name']) : 'Alle Themen' ?></td>
<td><?= $f['is_required'] ? '✓' : '–' ?></td>
<td><?= $f['is_active'] ? '✓' : '–' ?></td>
<td>
<a href="/staff/custom_fields.php?edit=<?= $f['id'] ?>">Bearbeiten</a> ·
<form method="post" style="display:inline" onsubmit="return confirm('Feld wirklich löschen? Bereits erfasste Werte in bestehenden Tickets bleiben erhalten.');">
<?= csrf_field() ?>
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $f['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 (!$fields): ?>
<tr><td colspan="6" class="muted">Noch keine individuellen Felder angelegt.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<div style="flex:1; min-width:300px">
<div class="card">
<h3><?= $editField ? 'Feld bearbeiten' : 'Neues Feld' ?></h3>
<form method="post">
<?= csrf_field() ?>
<input type="hidden" name="action" value="<?= $editField ? 'update' : 'create' ?>">
<?php if ($editField): ?><input type="hidden" name="id" value="<?= $editField['id'] ?>"><?php endif; ?>
<label for="label">Bezeichnung</label>
<input type="text" id="label" name="label" value="<?= e($editField['label'] ?? '') ?>" placeholder="z. B. Vertragsnummer" required>
<label for="field_type">Feldtyp</label>
<select name="field_type" id="field_type" onchange="document.getElementById('options-row').style.display = this.value==='select' ? 'block' : 'none'">
<?php foreach ($fieldTypes as $val => $lbl): ?>
<option value="<?= $val ?>" <?= ($editField['field_type'] ?? 'text') === $val ? 'selected' : '' ?>><?= e($lbl) ?></option>
<?php endforeach; ?>
</select>
<div id="options-row" style="display:<?= ($editField['field_type'] ?? '') === 'select' ? 'block' : 'none' ?>">
<label for="options">Optionen (eine pro Zeile)</label>
<textarea id="options" name="options" placeholder="Option 1&#10;Option 2&#10;Option 3"><?= e($editField['options'] ?? '') ?></textarea>
</div>
<label for="help_topic_id">Gilt für Hilfe-Thema</label>
<select name="help_topic_id" id="help_topic_id">
<option value="">Alle Themen (oder Formular ohne Themenauswahl)</option>
<?php foreach ($helpTopics as $t): ?>
<option value="<?= $t['id'] ?>" <?= (string) ($editField['help_topic_id'] ?? ($_GET['topic'] ?? '')) === (string) $t['id'] ? 'selected' : '' ?>><?= e($t['name']) ?></option>
<?php endforeach; ?>
</select>
<p class="muted" style="font-size:.78rem">Auf „Alle Themen“ belassen, damit das Feld unabhängig vom gewählten Anliegen erscheint.</p>
<label for="sort_order">Sortierung</label>
<input type="text" id="sort_order" name="sort_order" value="<?= e((string) ($editField['sort_order'] ?? '0')) ?>">
<label style="display:flex; align-items:center; gap:8px; margin-top:14px">
<input type="checkbox" name="is_required" style="width:auto" <?= !empty($editField['is_required']) ? 'checked' : '' ?>>
Pflichtfeld
</label>
<label style="display:flex; align-items:center; gap:8px; margin-top:8px">
<input type="checkbox" name="is_active" style="width:auto" <?= ($editField['is_active'] ?? 1) ? 'checked' : '' ?>>
Aktiv (auf dem Ticket-Formular sichtbar)
</label>
<div class="btn-row">
<button type="submit" class="btn"><?= $editField ? 'Speichern' : 'Erstellen' ?></button>
<?php if ($editField): ?><a href="/staff/custom_fields.php" class="btn secondary">Abbrechen</a><?php endif; ?>
</div>
</form>
</div>
</div>
</div>
<?php require __DIR__ . '/_footer.php'; ?>