Files
awo-hamburg-intranet/module/tasks/pages/admin/task_form.php
Moritz Weinmann eb3aa75615 Add Einrichtung and Fachbereich as permission/filter types (knowledgecenter + tasks)
- Create knowledgecenter_category_einricht, _fachbereich, knowledgecenter_post_einricht,
  knowledgecenter_post_fachbereich tables; extend task_target_rule with main_einricht_id
  and main_bereich_id columns
- Middleware: load main_einricht_id/main_bereich_id from main_contact_department,
  expose $allowedEinrichts/$allowedFachbereiche globals (same pattern as existing 3 types)
- Ajax: add update_category/post_einrichts/fachbereiche functions, extend
  update_category_links() and search filter query
- Views: add einricht/fachbereich LEFT JOINs and WHERE filters in all 5 query sites
  (categories_posts_listform, category_posts_widget, post_announcement_listform,
  post_cardform userHasAccessForPost, Ajax search)
- post_cardform_settings: add Einrichtungen/Fachbereiche tagify pickers with save/load
- Tasks: add listEinrichts/listFachbereiche to repo+service, add UI selects in task_form,
  extend target-rule normalization and upsert builder, extend AssignmentResolverService
  scope loading and matchesAnyRule to include einricht/fachbereich matching

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 11:03:53 +02:00

1159 lines
67 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
declare(strict_types=1);
if (!isset($task) && !isset($rules) && !isset($error)) {
require_once dirname(dirname(__DIR__)) . '/actions/admin/task_form_action.php';
$viewData = task_cert_admin_task_form_action();
if (is_array($viewData)) {
extract($viewData, EXTR_SKIP);
}
}
$task = $task ?? null;
$rules = $rules ?? [];
$error = $error ?? null;
$lookup = $lookup ?? [];
$methodConfig = $method_config ?? [];
$targetSelection = $target_selection ?? [];
$taskId = (int) ($task['id'] ?? 0);
$savedSuccessfully = TaskCertRequest::queryInt('saved', 0) === 1;
$resetApplied = TaskCertRequest::queryInt('reset', 0) === 1;
$resetAssignments = TaskCertRequest::queryInt('reset_assignments', 0);
$resetSubmissions = TaskCertRequest::queryInt('reset_submissions', 0);
$resetCertificates = TaskCertRequest::queryInt('reset_certificates', 0);
$syncDone = TaskCertRequest::queryInt('sync_done', 0) === 1;
$syncError = TaskCertRequest::queryString('sync_error', '');
$syncMode = TaskCertRequest::queryString('sync_mode', '');
$syncApplied = TaskCertRequest::queryInt('sync_applied', 0) === 1;
$syncScope = TaskCertRequest::queryString('sync_scope', '');
$syncCycleKey = TaskCertRequest::queryString('sync_cycle_key', '');
$syncTargetCount = TaskCertRequest::queryInt('sync_target_count', 0);
$syncExistingCount = TaskCertRequest::queryInt('sync_existing_count', 0);
$syncCreateCount = TaskCertRequest::queryInt('sync_create_count', 0);
$syncUpdateCount = TaskCertRequest::queryInt('sync_update_count', 0);
$syncStaleCount = TaskCertRequest::queryInt('sync_stale_count', 0);
$syncProtectedCompletedCount = TaskCertRequest::queryInt('sync_protected_completed_count', 0);
$syncProtectedCertificateCount = TaskCertRequest::queryInt('sync_protected_certificate_count', 0);
$syncRemoveCount = TaskCertRequest::queryInt('sync_remove_count', 0);
$syncRemoveWithSubmissionsCount = TaskCertRequest::queryInt('sync_remove_with_submissions_count', 0);
$activeTab = TaskCertRequest::queryInt('tab', 0);
if ($activeTab < 0) {
$activeTab = 0;
}
$syncProtectedTotalCount = $syncProtectedCompletedCount + $syncProtectedCertificateCount;
$syncCanApply = $syncDone && $syncMode === 'dry_run';
$methodConfig = array_merge([
'enabled' => [
'knowledge_read' => 0,
'form_submit' => 0,
'quiz' => 0,
'manual_approval' => 0,
],
'knowledge_post_ids' => [],
'form_fields' => [],
'quiz_questions' => [],
], $methodConfig);
$targetSelection = array_merge([
'mandant_ids' => [],
'department_ids' => [],
'role_ids' => [],
'einricht_ids' => [],
'fachbereich_ids' => [],
'override_include_contact_ids' => [],
'override_exclude_contact_ids' => [],
'override_include_reason' => '',
'override_exclude_reason' => '',
], $targetSelection);
$reminderPolicy = $rules['reminder_policy'] ?? [
'base_mode' => 'due_date',
'first_escalation_days' => 0,
'step_days' => 7,
'max_level' => 3,
'grace_days' => 7,
'active' => 1,
];
$isReminderActive = (int) ($reminderPolicy['active'] ?? 1) === 1;
$formFields = is_array($methodConfig['form_fields']) ? $methodConfig['form_fields'] : [];
if ($formFields === []) {
$formFields = [[
'field_key' => '',
'label' => '',
'field_type' => 'text',
'is_required' => 0,
'placeholder' => '',
'options_text' => '',
]];
}
$quizQuestions = is_array($methodConfig['quiz_questions']) ? $methodConfig['quiz_questions'] : [];
if ($quizQuestions === []) {
$quizQuestions = [[
'question_text' => '',
'option_a' => '',
'option_b' => '',
'option_c' => '',
'option_d' => '',
'correct_option' => 'a',
]];
}
$lookupMandants = is_array($lookup['mandants'] ?? null) ? $lookup['mandants'] : [];
$lookupDepartments = is_array($lookup['departments'] ?? null) ? $lookup['departments'] : [];
$lookupRoles = is_array($lookup['roles'] ?? null) ? $lookup['roles'] : [];
$lookupEinrichts = is_array($lookup['einrichts'] ?? null) ? $lookup['einrichts'] : [];
$lookupFachbereiche = is_array($lookup['fachbereiche'] ?? null) ? $lookup['fachbereiche'] : [];
$lookupContacts = is_array($lookup['contacts'] ?? null) ? $lookup['contacts'] : [];
$lookupKnowledgePosts = is_array($lookup['knowledge_posts'] ?? null) ? $lookup['knowledge_posts'] : [];
$lookupTaskCategories = is_array($lookup['task_categories'] ?? null) ? $lookup['task_categories'] : [];
$hasLookupGaps = ($lookupMandants === [] || $lookupDepartments === [] || $lookupRoles === [] || $lookupContacts === []);
$hasTaskCategoryLookupGap = ($lookupTaskCategories === []);
$deadlineRuleType = (string) ($task['deadline_rule_type'] ?? 'cycle_end');
if (!in_array($deadlineRuleType, ['cycle_end', 'offset_days', 'weekday', 'monthday'], true)) {
$deadlineRuleType = 'cycle_end';
}
$deadlineOffsetDays = (int) ($task['deadline_offset_days'] ?? 0);
$deadlineWeekday = (int) ($task['deadline_weekday'] ?? 7);
if ($deadlineWeekday < 1 || $deadlineWeekday > 7) {
$deadlineWeekday = 7;
}
$deadlineMonthday = (int) ($task['deadline_monthday'] ?? 0);
$isRecurringFrequency = (($task['frequency_type'] ?? 'once') === 'recurring');
$recurrenceBasis = (string) ($task['recurrence_basis'] ?? 'calendar');
if (!in_array($recurrenceBasis, ['calendar', 'completion'], true)) {
$recurrenceBasis = 'calendar';
}
$startDateValueRaw = trim((string) ($task['start_date'] ?? ''));
if ($startDateValueRaw === '') {
$startDateValue = date('Y-m-d');
} else {
try {
$startDateValue = (new DateTimeImmutable($startDateValueRaw))->format('Y-m-d');
} catch (Throwable $throwable) {
$startDateValue = preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDateValueRaw)
? $startDateValueRaw
: date('Y-m-d');
}
}
$certificateValidityMode = (string) ($task['certificate_validity_mode'] ?? '');
if (!in_array($certificateValidityMode, ['cycle', 'days', 'permanent'], true)) {
$certificateDays = (int) ($task['certificate_validity_days'] ?? 0);
if ($certificateDays > 0) {
$certificateValidityMode = 'days';
} elseif ($isRecurringFrequency) {
$certificateValidityMode = 'cycle';
} else {
$certificateValidityMode = 'permanent';
}
}
$ensureLookupRows = static function (array $rows, array $selectedIds, string $labelKey, string $fallbackPrefix): array {
$existingIds = [];
foreach ($rows as $row) {
$rowId = (int) ($row['id'] ?? 0);
if ($rowId > 0) {
$existingIds[$rowId] = true;
}
}
foreach (array_values(array_unique(array_map('intval', $selectedIds))) as $selectedId) {
if ($selectedId <= 0 || isset($existingIds[$selectedId])) {
continue;
}
$rows[] = [
'id' => $selectedId,
$labelKey => $fallbackPrefix . ' #' . $selectedId . ' (nicht gefunden)',
];
}
return $rows;
};
$lookupMandants = $ensureLookupRows($lookupMandants, (array) ($targetSelection['mandant_ids'] ?? []), 'description', 'Mandant');
$lookupDepartments = $ensureLookupRows($lookupDepartments, (array) ($targetSelection['department_ids'] ?? []), 'description', 'Abteilung');
$lookupRoles = $ensureLookupRows($lookupRoles, (array) ($targetSelection['role_ids'] ?? []), 'description', 'Rolle');
$lookupEinrichts = $ensureLookupRows($lookupEinrichts, (array) ($targetSelection['einricht_ids'] ?? []), 'description', 'Einrichtung');
$lookupFachbereiche = $ensureLookupRows($lookupFachbereiche, (array) ($targetSelection['fachbereich_ids'] ?? []), 'description', 'Fachbereich');
$lookupKnowledgePosts = $ensureLookupRows($lookupKnowledgePosts, (array) ($methodConfig['knowledge_post_ids'] ?? []), 'title', 'Beitrag');
$lookupTaskCategories = $ensureLookupRows($lookupTaskCategories, [(int) ($task['task_category_id'] ?? 0)], 'name', 'Kategorie');
$lookupContacts = $ensureLookupRows(
$lookupContacts,
array_merge(
(array) ($targetSelection['override_include_contact_ids'] ?? []),
(array) ($targetSelection['override_exclude_contact_ids'] ?? []),
(array) ($targetSelection['responsible_contact_ids'] ?? [])
),
'name',
'Kontakt'
);
$contactLabel = static function (array $contact): string {
$name = trim((string) ($contact['name'] ?? ''));
$email = trim((string) ($contact['email'] ?? ''));
if ($name !== '' && $email !== '') {
return $name . ' (' . $email . ')';
}
if ($name !== '') {
return $name;
}
if ($email !== '') {
return $email;
}
return 'Kontakt #' . (int) ($contact['id'] ?? 0);
};
if (!function_exists('task_cert_render_styles')) {
require_once dirname(dirname(__DIR__)) . '/bootstrap.php';
}
task_cert_render_styles(['admin'], ['vendor/multiselect/MultiSelect.css']);
task_cert_render_scripts([
'vendor/multiselect/MultiSelect.js',
'js/task_cert_admin_form_wizard.js',
]);
?>
<!-- Quill auf Goldstandard-Stack (wie Wiki/Forum/Products): CDN 2.0.0-dev.3 +
quill-better-table + shared_components (resize, presets). Die alte
vendored Quill (assets/vendor/quill/) wird hier bewusst nicht mehr geladen. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/quill@2.0.0-dev.3/dist/quill.snow.css">
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.0-dev.3/dist/quill.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/quill-better-table@1.2.10/dist/quill-better-table.css">
<script src="https://cdn.jsdelivr.net/npm/quill-better-table@1.2.10/dist/quill-better-table.min.js"></script>
<link rel="stylesheet" href="/module/shared_components/quill/quill_resize.css">
<script src="/module/shared_components/quill/quill_resize.js"></script>
<script src="/module/shared_components/quill/toolbar_presets.js"></script>
<?php
task_cert_render_scripts(['js/task_cert_quill_editor.js']);
$taskCertBaseUrl = task_cert_base_url();
$taskFormViewUrl = task_cert_view_url('admin.task_form');
$taskListViewUrl = task_cert_view_url('admin.task_list');
$taskDetailViewUrl = $taskId > 0
? task_cert_view_url('admin.task_detail', ['id' => $taskId])
: '';
$taskSyncAssignmentsEndpoint = $taskCertBaseUrl . '/endpoints/admin/sync_assignments.php';
$taskSyncRedirectUrl = $taskId > 0
? task_cert_view_url('admin.task_form', ['id' => $taskId])
: $taskFormViewUrl;
?>
<div class="task-cert task-cert-admin-form" data-task-cert-admin-wizard>
<form action="<?php echo TaskCertView::e($taskCertBaseUrl . '/endpoints/admin/task_upsert.php'); ?>" method="post">
<input type="hidden" name="csrf_token" value="<?php echo TaskCertView::e($csrf_token ?? ''); ?>">
<input type="hidden" name="task_id" value="<?php echo $taskId; ?>">
<input
type="hidden"
name="redirect_to_stay"
value="<?php echo TaskCertView::e($taskFormViewUrl . '?id={task_id}&saved=1'); ?>"
data-wizard-redirect-stay
>
<input type="hidden" name="redirect_to_close" value="<?php echo TaskCertView::e($taskListViewUrl); ?>">
<div class="task-cert-form-header">
<div class="task-cert-title-wrap">
<a
href="<?php echo TaskCertView::e($taskListViewUrl); ?>"
class="task-cert-back-link"
aria-label="Zur Aufgabenliste"
title="Zur Aufgabenliste"
>&larr;</a>
<h2><?php echo $taskId > 0 ? 'Aufgabe bearbeiten' : 'Aufgabe erstellen'; ?></h2>
</div>
<div class="task-cert-form-header-actions">
<?php if ($taskId > 0): ?>
<a href="<?php echo TaskCertView::e($taskDetailViewUrl); ?>" class="btn">Aufgabenübersicht</a>
<?php endif; ?>
<button type="submit" class="btn task-cert-btn-success" name="after_save" value="stay">Speichern</button>
<button type="submit" class="btn task-cert-btn-success" name="after_save" value="close">Speichern &amp; schließen</button>
</div>
</div>
<?php if ($error): ?>
<div class="task-cert-error"><?php echo TaskCertView::e($error); ?></div>
<?php elseif ($syncError !== ''): ?>
<div class="task-cert-error"><?php echo TaskCertView::e($syncError); ?></div>
<?php elseif ($savedSuccessfully): ?>
<div class="task-cert-success">Aufgabe wurde erfolgreich gespeichert.</div>
<?php if ($resetApplied): ?>
<div class="task-cert-warning">
Bestehender Fortschritt im aktuellen Zyklus wurde zurückgesetzt.
Zuweisungen: <?php echo (int) $resetAssignments; ?>,
Einreichungen: <?php echo (int) $resetSubmissions; ?>,
Zertifikate widerrufen: <?php echo (int) $resetCertificates; ?>.
</div>
<?php endif; ?>
<?php endif; ?>
<div class="task-cert-wizard-tabs" role="tablist" aria-label="Aufgaben-Assistent">
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="0" role="tab">Stammdaten</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="1" role="tab">Zeitplan</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="2" role="tab">Zertifikat</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="3" role="tab">Bestätigungsvoraussetzungen</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="4" role="tab">Zielgruppe</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="5" role="tab">Ausnahmeregelungen</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="6" role="tab">Eskalation</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="7" role="tab">Gefahrenbereich</button>
<button type="button" class="task-cert-wizard-tab" data-wizard-tab="8" role="tab">Vorschau</button>
</div>
<section class="task-cert-wizard-step" data-wizard-step="0">
<aside class="task-cert-step-intro">
<strong>Grunddaten der Aufgabe</strong>
<span>Titel, Beschreibung und grundlegender Status.</span>
</aside>
<div class="task-cert-step-main">
<div class="task-cert-block">
<h3>Stammdaten</h3>
<div>
<label for="title">Titel</label>
<input type="text" id="title" name="title" value="<?php echo TaskCertView::e($task['title'] ?? ''); ?>" required>
</div>
<div>
<label for="description">Beschreibung</label>
<textarea id="description" name="description" rows="4"><?php echo TaskCertView::e($task['description'] ?? ''); ?></textarea>
</div>
<div>
<label for="task_category_id">Kategorie</label>
<select id="task_category_id" name="task_category_id" required>
<option value="">Bitte wählen</option>
<?php foreach ($lookupTaskCategories as $category): ?>
<?php $id = (int) ($category['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<?php
$isSelectedCategory = ((int) ($task['task_category_id'] ?? 0) === $id);
$isActiveCategory = (int) ($category['active'] ?? 1) === 1;
$isDisabledCategory = !$isActiveCategory && !$isSelectedCategory;
$optionLabel = (string) ($category['name'] ?? ('Kategorie #' . $id));
if (!$isActiveCategory) {
$optionLabel .= ' (inaktiv)';
}
?>
<option
value="<?php echo $id; ?>"
<?php echo $isSelectedCategory ? 'selected' : ''; ?>
<?php echo $isDisabledCategory ? 'disabled' : ''; ?>
>
<?php echo TaskCertView::e($optionLabel); ?>
</option>
<?php endforeach; ?>
</select>
<?php if ($hasTaskCategoryLookupGap): ?>
<div class="task-cert-warning">Kategorien konnten nicht geladen werden. Bitte DB-Struktur/Migration prüfen.</div>
<?php endif; ?>
</div>
<div>
<label for="active">Aktiv</label>
<select id="active" name="active">
<option value="1" <?php echo ((int) ($task['active'] ?? 1) === 1) ? 'selected' : ''; ?>>Ja</option>
<option value="0" <?php echo ((int) ($task['active'] ?? 1) === 0) ? 'selected' : ''; ?>>Nein</option>
</select>
</div>
<div>
<label for="responsible_contact_ids">Verantwortliche</label>
<select id="responsible_contact_ids" class="tc-multiselect" name="responsible_contact_ids[]" multiple data-placeholder="Verantwortliche auswählen">
<?php foreach ($lookupContacts as $contact): ?>
<?php $id = (int) ($contact['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<?php $label = $contactLabel($contact); ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) ($targetSelection['responsible_contact_ids'] ?? []), true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e($label); ?>
</option>
<?php endforeach; ?>
</select>
<div class="task-cert-hint">Ansprechpartner, die den Mitarbeitenden als Kontakt für diese Aufgabe angezeigt werden.</div>
</div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="1" hidden>
<aside class="task-cert-step-intro">
<strong>Zeitplan und Fälligkeit</strong>
<span>Lege Startdatum, Wiederholung und Fälligkeit in einem Schritt fest.</span>
</aside>
<div class="task-cert-step-main">
<div class="task-cert-block">
<h3>Start &amp; Wiederholung</h3>
<div>
<label for="start_date">Startdatum</label>
<input type="date" id="start_date" name="start_date" value="<?php echo TaskCertView::e($startDateValue); ?>" required>
<div class="task-cert-hint">
Die Aufgabe wird den zugewiesenen Benutzern erst am Startdatum angezeigt.
</div>
</div>
<div>
<label for="frequency_type">Frequenz</label>
<select id="frequency_type" name="frequency_type" data-frequency-toggle>
<option value="once" <?php echo (($task['frequency_type'] ?? 'once') === 'once') ? 'selected' : ''; ?>>Einmalig</option>
<option value="recurring" <?php echo (($task['frequency_type'] ?? '') === 'recurring') ? 'selected' : ''; ?>>Wiederkehrend</option>
</select>
</div>
<div data-frequency-group="recurring" <?php echo $isRecurringFrequency ? '' : 'hidden'; ?>>
<label for="recurrence_basis">Rhythmus-Basis</label>
<select id="recurrence_basis" name="recurrence_basis" <?php echo $isRecurringFrequency ? '' : 'disabled'; ?>>
<option value="calendar" <?php echo $recurrenceBasis === 'calendar' ? 'selected' : ''; ?>>Kalenderbasiert</option>
<option value="completion" <?php echo $recurrenceBasis === 'completion' ? 'selected' : ''; ?>>Erledigungsbasiert (pro Mitarbeiter)</option>
</select>
<div class="task-cert-hint">
Kalenderbasiert folgt festen Intervallen ab Startdatum. Erledigungsbasiert startet die nächste Periode erst nach Abschluss.
</div>
</div>
<div class="task-cert-recurrence-inline" data-frequency-group="recurring" <?php echo $isRecurringFrequency ? '' : 'hidden'; ?>>
<div>
<label for="recurrence_unit">Intervall-Einheit</label>
<select id="recurrence_unit" name="recurrence_unit" <?php echo $isRecurringFrequency ? '' : 'disabled'; ?>>
<option value="">-</option>
<option value="day" <?php echo (($task['recurrence_unit'] ?? '') === 'day') ? 'selected' : ''; ?>>Tag</option>
<option value="week" <?php echo (($task['recurrence_unit'] ?? '') === 'week') ? 'selected' : ''; ?>>Woche</option>
<option value="month" <?php echo (($task['recurrence_unit'] ?? '') === 'month') ? 'selected' : ''; ?>>Monat</option>
<option value="year" <?php echo (($task['recurrence_unit'] ?? '') === 'year') ? 'selected' : ''; ?>>Jahr</option>
</select>
</div>
<div>
<label for="recurrence_interval">Intervall</label>
<input type="number" id="recurrence_interval" name="recurrence_interval" min="1" value="<?php echo (int) ($task['recurrence_interval'] ?? 1); ?>" <?php echo $isRecurringFrequency ? '' : 'disabled'; ?>>
</div>
</div>
<div data-frequency-group="recurring" <?php echo $isRecurringFrequency ? '' : 'hidden'; ?>>
<label>
<input type="checkbox" name="show_cycle_period" value="1" <?php echo ((int) ($task['show_cycle_period'] ?? 0) === 1) ? 'checked' : ''; ?>>
Zeitraum in „Meine Aufgaben" anzeigen
</label>
<div class="task-cert-hint">
Zeigt den Erledigungs-Zeitraum (z.&nbsp;B. 01.06.30.06.) hinter dem Fälligkeitsdatum. Standardmäßig aus.
</div>
</div>
</div>
<div class="task-cert-block">
<h3>Fälligkeit</h3>
<div class="task-cert-deadline-mode">
<label class="task-cert-deadline-choice">
<input type="radio" name="deadline_rule_type" value="cycle_end" data-deadline-rule <?php echo $deadlineRuleType === 'cycle_end' ? 'checked' : ''; ?>>
<span class="task-cert-deadline-choice-title">Bis Zyklusende</span>
<span class="task-cert-deadline-choice-text">Fälligkeit liegt immer am Ende des aktuellen Zyklus.</span>
</label>
<label class="task-cert-deadline-choice">
<input type="radio" name="deadline_rule_type" value="offset_days" data-deadline-rule <?php echo $deadlineRuleType === 'offset_days' ? 'checked' : ''; ?>>
<span class="task-cert-deadline-choice-title">X Tage nach Startdatum</span>
<span class="task-cert-deadline-choice-text">Frist wird relativ zum Startdatum gesetzt.</span>
</label>
<label class="task-cert-deadline-choice">
<input type="radio" name="deadline_rule_type" value="weekday" data-deadline-rule <?php echo $deadlineRuleType === 'weekday' ? 'checked' : ''; ?>>
<span class="task-cert-deadline-choice-title">Fester Wochentag</span>
<span class="task-cert-deadline-choice-text">Nur bei wöchentlichen Aufgaben. Beispiel: bis Sonntag.</span>
</label>
<label class="task-cert-deadline-choice">
<input type="radio" name="deadline_rule_type" value="monthday" data-deadline-rule <?php echo $deadlineRuleType === 'monthday' ? 'checked' : ''; ?>>
<span class="task-cert-deadline-choice-title">Fester Monatstag</span>
<span class="task-cert-deadline-choice-text">Nur für monatliche/jährliche Aufgaben. Kürzere Monate werden gekappt.</span>
</label>
</div>
<div class="task-cert-deadline-group" data-deadline-group="cycle_end" hidden>
<div class="task-cert-hint">Die Frist entspricht exakt dem Ende des aktuellen Zyklus.</div>
</div>
<div class="task-cert-deadline-group" data-deadline-group="offset_days" hidden>
<label for="deadline_offset_days">Fällig nach (Tagen)</label>
<input type="number" id="deadline_offset_days" name="deadline_offset_days" min="1" value="<?php echo TaskCertView::e($deadlineOffsetDays > 0 ? (string) $deadlineOffsetDays : ''); ?>">
</div>
<div class="task-cert-deadline-group" data-deadline-group="weekday" hidden>
<label for="deadline_weekday">Wochentag</label>
<select id="deadline_weekday" name="deadline_weekday">
<option value="1" <?php echo $deadlineWeekday === 1 ? 'selected' : ''; ?>>Montag</option>
<option value="2" <?php echo $deadlineWeekday === 2 ? 'selected' : ''; ?>>Dienstag</option>
<option value="3" <?php echo $deadlineWeekday === 3 ? 'selected' : ''; ?>>Mittwoch</option>
<option value="4" <?php echo $deadlineWeekday === 4 ? 'selected' : ''; ?>>Donnerstag</option>
<option value="5" <?php echo $deadlineWeekday === 5 ? 'selected' : ''; ?>>Freitag</option>
<option value="6" <?php echo $deadlineWeekday === 6 ? 'selected' : ''; ?>>Samstag</option>
<option value="7" <?php echo $deadlineWeekday === 7 ? 'selected' : ''; ?>>Sonntag</option>
</select>
</div>
<div class="task-cert-deadline-group" data-deadline-group="monthday" hidden>
<div>
<label for="deadline_monthday">Monatstag</label>
<input type="number" id="deadline_monthday" name="deadline_monthday" min="1" max="31" value="<?php echo TaskCertView::e($deadlineMonthday > 0 ? (string) $deadlineMonthday : ''); ?>">
</div>
</div>
<div class="task-cert-hint task-cert-deadline-preview" data-deadline-preview></div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="2" hidden>
<aside class="task-cert-step-intro">
<strong>Zertifikatslogik</strong>
<span>Aktiviere Zertifikate und steuere deren Gültigkeit.</span>
</aside>
<div class="task-cert-step-main">
<div class="task-cert-block">
<h3>Zertifikat</h3>
<div>
<label for="certificate_enabled">Zertifikat aktiv</label>
<select id="certificate_enabled" name="certificate_enabled">
<option value="1" <?php echo ((int) ($task['certificate_enabled'] ?? 1) === 1) ? 'selected' : ''; ?>>Ja</option>
<option value="0" <?php echo ((int) ($task['certificate_enabled'] ?? 1) === 0) ? 'selected' : ''; ?>>Nein</option>
</select>
</div>
<div>
<label for="certificate_title">Zertifikat Titel</label>
<input type="text" id="certificate_title" name="certificate_title" value="<?php echo TaskCertView::e($task['certificate_title'] ?? ''); ?>">
</div>
<div>
<label for="certificate_validity_mode">Gültigkeitsmodus</label>
<select id="certificate_validity_mode" name="certificate_validity_mode" data-certificate-validity-mode>
<option value="cycle" <?php echo $certificateValidityMode === 'cycle' ? 'selected' : ''; ?>>Zyklusbasiert (bis zum nächsten Zyklus)</option>
<option value="days" <?php echo $certificateValidityMode === 'days' ? 'selected' : ''; ?>>Tagebasiert</option>
<option value="permanent" <?php echo $certificateValidityMode === 'permanent' ? 'selected' : ''; ?>>Dauerhaft</option>
</select>
</div>
<div data-certificate-validity-group="days" <?php echo $certificateValidityMode === 'days' ? '' : 'hidden'; ?>>
<label for="certificate_validity_days">Gültigkeit in Tagen</label>
<input type="number" id="certificate_validity_days" name="certificate_validity_days" min="1" value="<?php echo TaskCertView::e((string) ($task['certificate_validity_days'] ?? '')); ?>">
</div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="3" hidden>
<aside class="task-cert-step-intro">
<strong>Bestätigungsvoraussetzungen</strong>
<span>Alle Methoden in einem Reiter. Details werden nur bei aktivierter Methode angezeigt.</span>
</aside>
<div class="task-cert-step-main">
<div class="task-cert-block">
<h3>Methoden</h3>
<div class="task-cert-method-section">
<div class="task-cert-method-header">
<label>
<input type="checkbox" data-method-toggle="knowledge_read" name="method_enabled[knowledge_read]" value="1" <?php echo ((int) ($methodConfig['enabled']['knowledge_read'] ?? 0) === 1) ? 'checked' : ''; ?>>
Wissensbeiträge lesen
</label>
</div>
<div class="task-cert-method-details" data-method-details="knowledge_read" hidden>
<label for="knowledge_post_ids">Verknüpfte Beiträge</label>
<select id="knowledge_post_ids" class="tc-multiselect" name="knowledge_post_ids[]" multiple data-placeholder="Beiträge auswählen">
<?php foreach ($lookupKnowledgePosts as $post): ?>
<?php $postId = (int) ($post['id'] ?? 0); ?>
<?php if ($postId <= 0) { continue; } ?>
<option value="<?php echo $postId; ?>" <?php echo in_array($postId, (array) $methodConfig['knowledge_post_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e((string) ($post['title'] ?? ('Beitrag #' . $postId))); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="task-cert-method-section">
<div class="task-cert-method-header">
<label>
<input type="checkbox" data-method-toggle="form_submit" name="method_enabled[form_submit]" value="1" <?php echo ((int) ($methodConfig['enabled']['form_submit'] ?? 0) === 1) ? 'checked' : ''; ?>>
Formular ausfüllen
</label>
</div>
<div class="task-cert-method-details" data-method-details="form_submit" hidden>
<strong>Formularfelder</strong>
<?php
$prefillOptionsJson = [];
foreach (ContactPrefillColumns::MAP as $colKey => $colLabel) {
$prefillOptionsJson[] = ['value' => $colKey, 'label' => $colLabel];
}
?>
<div id="task-cert-form-fields" data-next-index="<?php echo count($formFields); ?>" data-prefill-options="<?php echo TaskCertView::e(json_encode($prefillOptionsJson, JSON_UNESCAPED_UNICODE)); ?>">
<?php foreach ($formFields as $idx => $field): ?>
<?php $fieldTypeCurrent = (string) ($field['field_type'] ?? 'text'); ?>
<?php $showOptions = in_array($fieldTypeCurrent, ['select', 'checkbox', 'radio'], true); ?>
<div class="task-cert-form-row" data-form-row>
<div class="task-cert-form-row-head">
<strong class="task-cert-form-row-title">Formularfeld</strong>
<button type="button" class="btn task-cert-btn-danger" data-remove-form-row>Entfernen</button>
</div>
<input type="hidden" name="form_fields[<?php echo (int) $idx; ?>][field_key]" value="<?php echo TaskCertView::e((string) ($field['field_key'] ?? '')); ?>">
<div class="task-cert-form-row-grid">
<div class="task-cert-form-cell">
<label>Label</label>
<input
type="text"
name="form_fields[<?php echo (int) $idx; ?>][label]"
placeholder="z. B. Kilometerstand"
value="<?php echo TaskCertView::e((string) ($field['label'] ?? '')); ?>"
>
</div>
<div class="task-cert-form-cell">
<label>Typ</label>
<select name="form_fields[<?php echo (int) $idx; ?>][field_type]" data-form-field-type>
<?php foreach (TaskCertConstants::FIELD_TYPES as $fieldType): ?>
<option value="<?php echo TaskCertView::e($fieldType); ?>" <?php echo ($fieldTypeCurrent === $fieldType) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e($fieldType); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="task-cert-form-cell task-cert-form-required">
<label>
<input type="checkbox" name="form_fields[<?php echo (int) $idx; ?>][is_required]" value="1" <?php echo ((int) ($field['is_required'] ?? 0) === 1) ? 'checked' : ''; ?>>
Pflicht
</label>
</div>
</div>
<div class="task-cert-form-row-grid task-cert-form-row-grid-secondary">
<div class="task-cert-form-cell">
<label>Placeholder</label>
<input
type="text"
name="form_fields[<?php echo (int) $idx; ?>][placeholder]"
placeholder="Optionaler Hinweistext"
value="<?php echo TaskCertView::e((string) ($field['placeholder'] ?? '')); ?>"
>
</div>
<div class="task-cert-form-cell" data-form-field-prefill <?php echo $fieldTypeCurrent !== 'text' ? 'hidden' : ''; ?>>
<label>Vorbefüllung</label>
<?php $currentPrefill = (string) ($field['prefill_column'] ?? ''); ?>
<select name="form_fields[<?php echo (int) $idx; ?>][prefill_column]">
<?php foreach (ContactPrefillColumns::MAP as $colKey => $colLabel): ?>
<option value="<?php echo TaskCertView::e($colKey); ?>" <?php echo $currentPrefill === $colKey ? 'selected' : ''; ?>>
<?php echo TaskCertView::e($colLabel); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="task-cert-form-field-options" data-form-field-options <?php echo $showOptions ? '' : 'hidden'; ?>>
<label>Optionen (Komma getrennt)</label>
<input
type="text"
name="form_fields[<?php echo (int) $idx; ?>][options_text]"
placeholder="z. B. Ja, Nein"
value="<?php echo TaskCertView::e((string) ($field['options_text'] ?? '')); ?>"
>
</div>
</div>
<?php endforeach; ?>
</div>
<button type="button" class="btn task-cert-btn-success" id="task-cert-add-form-row">Feld hinzufügen</button>
</div>
</div>
<div class="task-cert-method-section">
<div class="task-cert-method-header">
<label>
<input type="checkbox" data-method-toggle="quiz" name="method_enabled[quiz]" value="1" <?php echo ((int) ($methodConfig['enabled']['quiz'] ?? 0) === 1) ? 'checked' : ''; ?>>
Quiz
</label>
</div>
<div class="task-cert-method-details" data-method-details="quiz" hidden>
<strong>Quizfragen</strong>
<div id="task-cert-quiz-questions" data-next-index="<?php echo count($quizQuestions); ?>">
<?php foreach ($quizQuestions as $idx => $question): ?>
<div class="task-cert-quiz-row" data-quiz-row>
<div class="task-cert-quiz-question">
<label>Frage</label>
<input type="text" name="quiz_questions[<?php echo (int) $idx; ?>][question_text]" placeholder="Frage" value="<?php echo TaskCertView::e((string) ($question['question_text'] ?? '')); ?>">
</div>
<div class="task-cert-quiz-answers">
<div class="task-cert-quiz-answer">
<label>Antwort A</label>
<input type="text" name="quiz_questions[<?php echo (int) $idx; ?>][option_a]" placeholder="Antwort A" value="<?php echo TaskCertView::e((string) ($question['option_a'] ?? '')); ?>">
</div>
<div class="task-cert-quiz-answer">
<label>Antwort B</label>
<input type="text" name="quiz_questions[<?php echo (int) $idx; ?>][option_b]" placeholder="Antwort B" value="<?php echo TaskCertView::e((string) ($question['option_b'] ?? '')); ?>">
</div>
<div class="task-cert-quiz-answer">
<label>Antwort C</label>
<input type="text" name="quiz_questions[<?php echo (int) $idx; ?>][option_c]" placeholder="Antwort C" value="<?php echo TaskCertView::e((string) ($question['option_c'] ?? '')); ?>">
</div>
<div class="task-cert-quiz-answer">
<label>Antwort D</label>
<input type="text" name="quiz_questions[<?php echo (int) $idx; ?>][option_d]" placeholder="Antwort D" value="<?php echo TaskCertView::e((string) ($question['option_d'] ?? '')); ?>">
</div>
</div>
<div class="task-cert-quiz-footer">
<div class="task-cert-quiz-correct">
<label>Richtige Antwort</label>
<select name="quiz_questions[<?php echo (int) $idx; ?>][correct_option]">
<?php foreach (['a', 'b', 'c', 'd'] as $letter): ?>
<option value="<?php echo $letter; ?>" <?php echo (($question['correct_option'] ?? 'a') === $letter) ? 'selected' : ''; ?>>
Antwort <?php echo strtoupper($letter); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="task-cert-quiz-remove">
<button type="button" class="btn task-cert-btn-danger" data-remove-quiz-row>Entfernen</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<button type="button" class="btn task-cert-btn-success" id="task-cert-add-quiz-row">Frage hinzufügen</button>
</div>
</div>
<div class="task-cert-method-section">
<div class="task-cert-method-header">
<label>
<input type="checkbox" data-method-toggle="manual_approval" name="method_enabled[manual_approval]" value="1" <?php echo ((int) ($methodConfig['enabled']['manual_approval'] ?? 0) === 1) ? 'checked' : ''; ?>>
Manuelle Freigabe
</label>
</div>
<div class="task-cert-method-details" data-method-details="manual_approval" hidden>
<div class="task-cert-hint">Mitarbeiter stellen Antrag, Admin entscheidet in der Freigabe-Warteschlange.</div>
</div>
</div>
<div class="task-cert-hint">Empfehlung: Mindestens eine Methode aktivieren.</div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="4" hidden>
<aside class="task-cert-step-intro">
<strong>Zielgruppe</strong>
<span>Ordne die Aufgabe über Mandanten, Abteilungen und Rollen zu.</span>
</aside>
<div class="task-cert-step-main">
<?php if ($hasLookupGaps): ?>
<div class="task-cert-error">
Einige Auswahl-Listen sind leer. Bitte DB-Zugriff und Legacy-Tabellen prüfen (`main_mandant`, `main_department`, `main_role`, `main_contact`).
</div>
<?php endif; ?>
<div class="task-cert-block">
<h3>Zielgruppe</h3>
<div>
<label for="target_mandant_ids">Mandanten</label>
<select id="target_mandant_ids" class="tc-multiselect" name="target_mandant_ids[]" multiple data-placeholder="Mandanten auswählen">
<?php foreach ($lookupMandants as $mandant): ?>
<?php $id = (int) ($mandant['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['mandant_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e((string) ($mandant['description'] ?? ('Mandant #' . $id))); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="target_department_ids">Abteilungen</label>
<select id="target_department_ids" class="tc-multiselect" name="target_department_ids[]" multiple data-placeholder="Abteilungen auswählen">
<?php foreach ($lookupDepartments as $department): ?>
<?php $id = (int) ($department['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['department_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e((string) ($department['description'] ?? ('Abteilung #' . $id))); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="target_role_ids">Rollen</label>
<select id="target_role_ids" class="tc-multiselect" name="target_role_ids[]" multiple data-placeholder="Rollen auswählen">
<?php foreach ($lookupRoles as $role): ?>
<?php $id = (int) ($role['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['role_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e((string) ($role['description'] ?? ('Rolle #' . $id))); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="target_einricht_ids">Einrichtungen</label>
<select id="target_einricht_ids" class="tc-multiselect" name="target_einricht_ids[]" multiple data-placeholder="Einrichtungen auswählen">
<?php foreach ($lookupEinrichts as $einricht): ?>
<?php $id = (int) ($einricht['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['einricht_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e((string) ($einricht['description'] ?? ('Einrichtung #' . $id))); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="target_fachbereich_ids">Fachbereiche</label>
<select id="target_fachbereich_ids" class="tc-multiselect" name="target_fachbereich_ids[]" multiple data-placeholder="Fachbereiche auswählen">
<?php foreach ($lookupFachbereiche as $fachbereich): ?>
<?php $id = (int) ($fachbereich['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['fachbereich_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e((string) ($fachbereich['description'] ?? ('Fachbereich #' . $id))); ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="5" hidden>
<aside class="task-cert-step-intro">
<strong>Ausnahmeregelungen</strong>
<span>Einzelne Mitarbeiter explizit ein- oder ausschließen.</span>
</aside>
<div class="task-cert-step-main">
<?php if ($hasLookupGaps): ?>
<div class="task-cert-error">
Kontaktlisten konnten nicht vollständig geladen werden. Bitte Berechtigungen und Datenbasis prüfen.
</div>
<?php endif; ?>
<div class="task-cert-block">
<h3>Ausnahmeregelungen</h3>
<div>
<label for="override_include_contact_ids">Mitarbeiter zusätzlich einschließen</label>
<select id="override_include_contact_ids" class="tc-multiselect" name="override_include_contact_ids[]" multiple data-placeholder="Mitarbeiter hinzufügen">
<?php foreach ($lookupContacts as $contact): ?>
<?php $id = (int) ($contact['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<?php $label = $contactLabel($contact); ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['override_include_contact_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="override_include_reason">Grund (Include)</label>
<input type="text" id="override_include_reason" name="override_include_reason" value="<?php echo TaskCertView::e((string) ($targetSelection['override_include_reason'] ?? '')); ?>">
</div>
<div>
<label for="override_exclude_contact_ids">Mitarbeiter ausschließen</label>
<select id="override_exclude_contact_ids" class="tc-multiselect" name="override_exclude_contact_ids[]" multiple data-placeholder="Mitarbeiter ausschließen">
<?php foreach ($lookupContacts as $contact): ?>
<?php $id = (int) ($contact['id'] ?? 0); ?>
<?php if ($id <= 0) { continue; } ?>
<?php $label = $contactLabel($contact); ?>
<option value="<?php echo $id; ?>" <?php echo in_array($id, (array) $targetSelection['override_exclude_contact_ids'], true) ? 'selected' : ''; ?>>
<?php echo TaskCertView::e($label); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="override_exclude_reason">Grund (Exclude)</label>
<input type="text" id="override_exclude_reason" name="override_exclude_reason" value="<?php echo TaskCertView::e((string) ($targetSelection['override_exclude_reason'] ?? '')); ?>">
</div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="6" hidden>
<aside class="task-cert-step-intro">
<strong>Eskalation nach Fälligkeit</strong>
<span>Lege fest, wann und in welchen Stufen nach Fälligkeit eskaliert wird.</span>
</aside>
<div class="task-cert-step-main">
<div class="task-cert-block">
<div class="task-cert-escalation-toggle">
<label>
<input
type="checkbox"
id="reminder_active"
name="reminder_active"
value="1"
<?php echo $isReminderActive ? 'checked' : ''; ?>
>
Eskalation aktiv
</label>
<input type="hidden" name="reminder_base_mode" value="due_date">
</div>
<div data-reminder-settings <?php echo $isReminderActive ? '' : 'hidden'; ?>>
<h3>Eskalationsstufen</h3>
<div class="task-cert-escalation-fields">
<div>
<label for="reminder_first_escalation_days">Wartezeit</label>
<div class="task-cert-input-with-suffix">
<input type="number" id="reminder_first_escalation_days" name="reminder_first_escalation_days" min="0" value="<?php echo (int) ($reminderPolicy['first_escalation_days'] ?? 0); ?>" data-escalation-input>
<span>Tage nach Fälligkeit</span>
</div>
</div>
<div>
<label for="reminder_step_days">Stufenintervall</label>
<div class="task-cert-input-with-suffix">
<input type="number" id="reminder_step_days" name="reminder_step_days" min="1" value="<?php echo (int) ($reminderPolicy['step_days'] ?? 7); ?>" data-escalation-input>
<span>Tage pro Stufe</span>
</div>
</div>
<div>
<label for="reminder_max_level">Maximum</label>
<div class="task-cert-input-with-suffix">
<input type="number" id="reminder_max_level" name="reminder_max_level" min="1" max="5" value="<?php echo min(5, (int) ($reminderPolicy['max_level'] ?? 3)); ?>" data-escalation-input>
<span>Stufen</span>
</div>
</div>
</div>
<hr class="task-cert-escalation-divider">
<h3>Karenzzeit</h3>
<div class="task-cert-escalation-fields">
<div>
<label for="reminder_grace_days">Mindestbearbeitungszeit</label>
<div class="task-cert-input-with-suffix">
<input type="number" id="reminder_grace_days" name="reminder_grace_days" min="0" value="<?php echo (int) ($reminderPolicy['grace_days'] ?? 7); ?>" data-escalation-input>
<span>Tage</span>
</div>
</div>
</div>
<div class="task-cert-hint">
Wenn ein Mitarbeiter mitten im Zyklus zugewiesen wird, greift die Eskalation erst nach dieser Frist.
</div>
</div>
</div>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="7" hidden>
<aside class="task-cert-step-intro">
<strong>Gefahrenbereich</strong>
<span>Aktionen mit direkter Auswirkung auf bestehende Daten und Aufgabenstatus.</span>
</aside>
<div class="task-cert-step-main">
<?php if ($taskId > 0): ?>
<div class="task-cert-block task-cert-danger-block">
<h3>Aufgabe deaktivieren</h3>
<button
type="submit"
class="btn task-cert-btn-danger"
form="task-cert-delete-form"
onclick="return confirm('Aufgabe wirklich deaktivieren?');"
>Nur deaktivieren</button>
<div class="task-cert-hint">
Die Aufgabe wird auf inaktiv gesetzt. Einreichungen, Zertifikate und Historie bleiben erhalten.
</div>
</div>
<div class="task-cert-block task-cert-danger-block">
<h3>Aufgabe endgültig löschen</h3>
<div class="task-cert-warning">
Diese Aktion ist endgültig und entfernt die Aufgabe inklusive aller abhängigen Daten.
</div>
<button
type="submit"
class="btn task-cert-btn-danger"
form="task-cert-hard-delete-form"
onclick="return confirm('Aufgabe UND alle zugehörigen Daten endgültig löschen? Dieser Vorgang kann nicht rückgängig gemacht werden.');"
>Endgültig löschen</button>
<div class="task-cert-hint">
Es werden auch Zuweisungen, Einreichungen, Zertifikate, Methoden, Zielgruppenregeln und Eskalationsereignisse entfernt.
</div>
</div>
<div class="task-cert-block">
<h3>Bestandsdaten bei Änderungen</h3>
<label>
<input type="checkbox" name="reset_existing_records" value="1">
Bestehende Einreichungen im aktuellen Zyklus zurücksetzen
</label>
<div class="task-cert-hint">
Setzt den Fortschritt im aktuellen Zyklus auf offen, entfernt Einreichungen dieses Zyklus
und widerruft bereits ausgestellte Zertifikate dieses Zyklus.
Historische Zyklen bleiben unverändert.
</div>
</div>
<div class="task-cert-block">
<h3>Zuweisungsregeln anwenden</h3>
<div class="task-cert-hint">
Prüft die Zuweisungen im aktuellen Zyklus gegen Mandant/Abteilung/Rolle und Overrides.
Nutzer ohne Treffer werden entfernt, außer bei abgeschlossenen Einträgen oder vorhandenem Zertifikat.
</div>
<button
type="button"
class="btn"
onclick="document.getElementById('task-cert-sync-preview-form').submit();"
>Vorschau berechnen</button>
<?php if ($syncDone): ?>
<div class="task-cert-block task-cert-block-inset">
<h4>Vorschau-Ergebnis</h4>
<div class="task-cert-detail-grid">
<div><strong>Zyklus:</strong> <?php echo TaskCertView::e($syncCycleKey !== '' ? $syncCycleKey : '-'); ?></div>
<div><strong>Zielkontakte:</strong> <?php echo $syncTargetCount; ?></div>
<div><strong>Bestehende Zuweisungen:</strong> <?php echo $syncExistingCount; ?></div>
<div><strong>Neu:</strong> <?php echo $syncCreateCount; ?></div>
<div><strong>Aktualisiert:</strong> <?php echo $syncUpdateCount; ?></div>
<div><strong>Nicht mehr passend:</strong> <?php echo $syncStaleCount; ?></div>
<div><strong>Geschützt (Completed):</strong> <?php echo $syncProtectedCompletedCount; ?></div>
<div><strong>Geschützt (Zertifikat):</strong> <?php echo $syncProtectedCertificateCount; ?></div>
<div><strong>Geschützt gesamt:</strong> <?php echo $syncProtectedTotalCount; ?></div>
<div><strong>Zu entfernen:</strong> <?php echo $syncRemoveCount; ?></div>
<div><strong>davon mit Einreichungen:</strong> <?php echo $syncRemoveWithSubmissionsCount; ?></div>
<div><strong>Modus:</strong> <?php echo TaskCertView::e($syncApplied ? 'Angewendet' : 'Vorschau'); ?></div>
</div>
<?php if ($syncCanApply): ?>
<div class="task-cert-warning">
Beim Anwenden werden <?php echo $syncRemoveCount; ?> nicht mehr passende Zuweisungen im aktuellen Zyklus entfernt.
</div>
<button
type="button"
class="btn task-cert-btn-success"
onclick="if (confirm('Zuweisungsregeln jetzt anwenden? Es werden ' + <?php echo $syncRemoveCount; ?> + ' Zuweisungen entfernt.')) { document.getElementById('task-cert-sync-apply-form').submit(); }"
>Jetzt anwenden</button>
<?php elseif ($syncApplied): ?>
<div class="task-cert-success">
Zuweisungsregeln wurden angewendet. Neu: <?php echo $syncCreateCount; ?>, entfernt: <?php echo $syncRemoveCount; ?>, geschützt: <?php echo $syncProtectedTotalCount; ?>.
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php else: ?>
<div class="task-cert-block">
<div class="task-cert-hint">
Dieser Bereich ist verfügbar, sobald die Aufgabe einmal gespeichert wurde.
</div>
</div>
<?php endif; ?>
</div>
</section>
<section class="task-cert-wizard-step" data-wizard-step="8" hidden>
<aside class="task-cert-step-intro">
<strong>Vorschau</strong>
<span>So sieht die Detailseite für Mitarbeiter aus (zuletzt gespeicherter Stand).</span>
</aside>
<div class="task-cert-block">
<?php if ($taskId > 0): ?>
<?php $previewUrl = $taskCertBaseUrl . '/pages/admin/task_preview.php?' . http_build_query(['id' => $taskId, 'csrf_token' => (string) ($csrf_token ?? '')]); ?>
<div class="task-cert-preview-toolbar">
<button type="button" class="btn task-cert-btn-success" data-preview-reload>Aktualisieren</button>
<a href="<?php echo TaskCertView::e($previewUrl); ?>" target="_blank" rel="noopener">In neuem Tab öffnen</a>
</div>
<iframe
class="task-cert-preview-frame"
data-preview-frame
data-preview-src="<?php echo TaskCertView::e($previewUrl); ?>"
title="Vorschau der Detailseite"
></iframe>
<?php else: ?>
<div class="task-cert-hint">
Bitte zuerst speichern &ndash; danach erscheint hier die Vorschau der Detailseite.
</div>
<?php endif; ?>
</div>
</section>
</form>
<?php if ($taskId > 0): ?>
<form
id="task-cert-sync-preview-form"
action="<?php echo TaskCertView::e($taskSyncAssignmentsEndpoint); ?>"
method="post"
style="display:none;"
>
<input type="hidden" name="csrf_token" value="<?php echo TaskCertView::e($csrf_token ?? ''); ?>">
<input type="hidden" name="task_id" value="<?php echo $taskId; ?>">
<input type="hidden" name="mode" value="dry_run">
<input type="hidden" name="scope" value="current_cycle">
<input type="hidden" name="tab" value="<?php echo $activeTab; ?>" data-sync-tab>
<input type="hidden" name="redirect_to" value="<?php echo TaskCertView::e($taskSyncRedirectUrl); ?>" data-sync-redirect>
</form>
<form
id="task-cert-sync-apply-form"
action="<?php echo TaskCertView::e($taskSyncAssignmentsEndpoint); ?>"
method="post"
style="display:none;"
>
<input type="hidden" name="csrf_token" value="<?php echo TaskCertView::e($csrf_token ?? ''); ?>">
<input type="hidden" name="task_id" value="<?php echo $taskId; ?>">
<input type="hidden" name="mode" value="apply">
<input type="hidden" name="scope" value="current_cycle">
<input type="hidden" name="tab" value="<?php echo $activeTab; ?>" data-sync-tab>
<input type="hidden" name="redirect_to" value="<?php echo TaskCertView::e($taskSyncRedirectUrl); ?>" data-sync-redirect>
</form>
<form
id="task-cert-delete-form"
action="<?php echo TaskCertView::e($taskCertBaseUrl . '/endpoints/admin/task_delete.php'); ?>"
method="post"
style="display:none;"
>
<input type="hidden" name="csrf_token" value="<?php echo TaskCertView::e($csrf_token ?? ''); ?>">
<input type="hidden" name="task_id" value="<?php echo $taskId; ?>">
<input type="hidden" name="redirect_to" value="<?php echo TaskCertView::e($taskListViewUrl); ?>">
</form>
<form
id="task-cert-hard-delete-form"
action="<?php echo TaskCertView::e($taskCertBaseUrl . '/endpoints/admin/task_delete_hard.php'); ?>"
method="post"
style="display:none;"
>
<input type="hidden" name="csrf_token" value="<?php echo TaskCertView::e($csrf_token ?? ''); ?>">
<input type="hidden" name="task_id" value="<?php echo $taskId; ?>">
<input type="hidden" name="confirm_hard_delete" value="1">
<input type="hidden" name="redirect_to" value="<?php echo TaskCertView::e($taskListViewUrl); ?>">
</form>
<?php endif; ?>
</div>