Beide Module wurden aus einem anderen Kundenprojekt kopiert und bereinigt: Knowledgecenter: - Bild-Cache (1.985 Dateien) geleert, Ordnerstruktur mit .gitkeep behalten - Files-Gallery-Lizenzschlüssel entfernt (config.php) - Kundenspezifische Kategorien gelöscht: Teil I/II/III QM-Struktur, nummerierte QM-Kapitel, Gremien (Präsidium/Finanzausschuss/Landesausschuss), Sitzungsservice-Serie, Protokoll-Abteilungen, Testeinträge - 56 generische Kategorien bleiben (Downloads, Onboarding, Personalthemen …) Tasks: - Alle Betriebsdaten gelöscht (114 Tasks, 914 Submissions, 579 Assignments) - Task-Definitionen und Verlinkungen geleert - Kategoriestruktur bleibt (Allgemein, IT, Personal, Buchhaltung …) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
285 lines
12 KiB
PHP
285 lines
12 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
if (!isset($assignments) && !isset($error)) {
|
||
require_once dirname(dirname(__DIR__)) . '/actions/user/my_tasks_action.php';
|
||
$viewData = task_cert_user_my_tasks_action();
|
||
if (is_array($viewData)) {
|
||
extract($viewData, EXTR_SKIP);
|
||
}
|
||
}
|
||
|
||
$error = $error ?? null;
|
||
$assignments = $assignments ?? [];
|
||
$statusLabels = TaskCertConstants::assignmentStatusLabels();
|
||
$completedStatuses = TaskCertConstants::COMPLETED_STATUSES;
|
||
|
||
if (!function_exists('task_cert_render_styles')) {
|
||
require_once dirname(dirname(__DIR__)) . '/bootstrap.php';
|
||
}
|
||
task_cert_render_styles(['user']);
|
||
$taskDetailUrl = task_cert_view_url('user.task_detail');
|
||
$myTasksUrl = task_cert_view_url('user.my_tasks');
|
||
$now = new DateTimeImmutable('now');
|
||
|
||
$statusFilter = TaskCertRequest::queryString('status', '');
|
||
if ($statusFilter !== '' && !array_key_exists($statusFilter, $statusLabels)) {
|
||
$statusFilter = '';
|
||
}
|
||
|
||
if ($statusFilter !== '') {
|
||
$assignments = array_values(array_filter($assignments, static function (array $a) use ($statusFilter): bool {
|
||
return ($a['status'] ?? '') === $statusFilter;
|
||
}));
|
||
}
|
||
|
||
// Active & completed assignments: alle Zyklen separat anzeigen.
|
||
// Aktive: älteste zuerst (überfällige Rückstände oben).
|
||
// Abgeschlossene: neueste zuerst (unter <details> im UI eingeklappt).
|
||
$byTaskId = [];
|
||
foreach ($assignments as $a) {
|
||
$byTaskId[(int) ($a['task_id'] ?? 0)][] = $a;
|
||
}
|
||
|
||
$assignments = [];
|
||
foreach ($byTaskId as $taskAssignments) {
|
||
$active = [];
|
||
$completed = [];
|
||
foreach ($taskAssignments as $a) {
|
||
if (in_array($a['status'] ?? '', $completedStatuses, true)) {
|
||
$completed[] = $a;
|
||
} else {
|
||
$active[] = $a;
|
||
}
|
||
}
|
||
|
||
if ($active !== []) {
|
||
usort($active, static function (array $a, array $b): int {
|
||
$aDue = strtotime((string) ($a['due_at'] ?? '9999-12-31'));
|
||
$bDue = strtotime((string) ($b['due_at'] ?? '9999-12-31'));
|
||
return $aDue <=> $bDue;
|
||
});
|
||
foreach ($active as $a) {
|
||
$assignments[] = $a;
|
||
}
|
||
}
|
||
|
||
if ($completed !== []) {
|
||
usort($completed, static function (array $a, array $b): int {
|
||
return strtotime((string) ($b['completed_at'] ?? '0')) - strtotime((string) ($a['completed_at'] ?? '0'));
|
||
});
|
||
foreach ($completed as $a) {
|
||
$assignments[] = $a;
|
||
}
|
||
}
|
||
}
|
||
|
||
$formatDateShort = static function ($value): string {
|
||
$value = trim((string) $value);
|
||
if ($value === '') {
|
||
return '';
|
||
}
|
||
|
||
try {
|
||
return (new DateTimeImmutable($value))->format('d.m.Y');
|
||
} catch (Throwable $throwable) {
|
||
return $value;
|
||
}
|
||
};
|
||
|
||
$getCardMeta = static function (array $assignment) use ($formatDateShort): string {
|
||
$parts = [];
|
||
|
||
$dueAt = trim((string) ($assignment['due_at'] ?? ''));
|
||
if ($dueAt !== '') {
|
||
$parts[] = 'Fällig bis ' . $formatDateShort($dueAt);
|
||
} else {
|
||
$parts[] = 'Kein Fälligkeitsdatum';
|
||
}
|
||
|
||
// Zyklus-Zeitraum nur anzeigen, wenn die Aufgabe wiederkehrend ist
|
||
// (bei 'once' irrelevant). So versteht der User bei Rückständen,
|
||
// welcher Zyklus welcher Karte zugeordnet ist.
|
||
$cycleKey = (string) ($assignment['cycle_key'] ?? '');
|
||
$cycleStart = trim((string) ($assignment['cycle_start_at'] ?? ''));
|
||
$cycleEnd = trim((string) ($assignment['cycle_end_at'] ?? ''));
|
||
$showCyclePeriod = (int) ($assignment['show_cycle_period'] ?? 0) === 1;
|
||
if ($showCyclePeriod && $cycleKey !== '' && $cycleKey !== 'once' && $cycleStart !== '' && $cycleEnd !== '') {
|
||
$parts[] = 'Zeitraum ' . $formatDateShort($cycleStart) . '–' . $formatDateShort($cycleEnd);
|
||
}
|
||
|
||
return implode(' · ', $parts);
|
||
};
|
||
|
||
$isAssignmentOverdueByDate = static function (array $assignment, DateTimeImmutable $now): bool {
|
||
$status = (string) ($assignment['status'] ?? '');
|
||
if ($status === 'completed') {
|
||
return false;
|
||
}
|
||
|
||
$dueAt = trim((string) ($assignment['due_at'] ?? ''));
|
||
if ($dueAt === '') {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
return (new DateTimeImmutable($dueAt)) < $now;
|
||
} catch (Throwable $throwable) {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
$groupedAssignments = [];
|
||
$categoryOrder = [];
|
||
foreach ($assignments as $assignment) {
|
||
$categoryName = trim((string) ($assignment['task_category_name'] ?? ''));
|
||
if ($categoryName === '') {
|
||
$categoryName = 'Allgemein';
|
||
}
|
||
|
||
if (!array_key_exists($categoryName, $groupedAssignments)) {
|
||
$groupedAssignments[$categoryName] = [];
|
||
$categoryOrder[] = $categoryName;
|
||
}
|
||
|
||
$groupedAssignments[$categoryName][] = $assignment;
|
||
}
|
||
?>
|
||
<div class="task-cert task-cert-user-my-tasks">
|
||
<?php if ($error): ?>
|
||
<div class="task-cert-error"><?php echo TaskCertView::e($error); ?></div>
|
||
<?php endif; ?>
|
||
|
||
<form method="get" action="<?php echo TaskCertView::e($myTasksUrl); ?>" class="task-cert-user-filter-bar">
|
||
<label for="task-cert-user-status-filter" class="task-cert-sr-only">Status filtern</label>
|
||
<select name="status" id="task-cert-user-status-filter" aria-label="Status filtern" onchange="this.form.submit()">
|
||
<option value="">Alle Status</option>
|
||
<?php foreach ($statusLabels as $key => $label): ?>
|
||
<option value="<?php echo TaskCertView::e($key); ?>" <?php echo $statusFilter === $key ? 'selected' : ''; ?>>
|
||
<?php echo TaskCertView::e($label); ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
<?php if ($statusFilter !== ''): ?>
|
||
<a href="<?php echo TaskCertView::e($myTasksUrl); ?>" class="task-cert-user-filter-reset">Zurücksetzen</a>
|
||
<?php endif; ?>
|
||
</form>
|
||
|
||
<?php if ($assignments === []): ?>
|
||
<div class="task-cert-block">
|
||
<?php if ($statusFilter !== ''): ?>
|
||
Keine Aufgaben mit Status „<?php echo TaskCertView::e($statusLabels[$statusFilter] ?? $statusFilter); ?>“ vorhanden.
|
||
<?php else: ?>
|
||
Aktuell sind keine Aufgaben vorhanden.
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php else: ?>
|
||
<?php foreach ($categoryOrder as $categoryName): ?>
|
||
<?php
|
||
$categoryAssignments = $groupedAssignments[$categoryName] ?? [];
|
||
if ($categoryAssignments === []) { continue; }
|
||
|
||
$activeAssignments = [];
|
||
$completedAssignments = [];
|
||
foreach ($categoryAssignments as $a) {
|
||
if (in_array($a['status'] ?? '', $completedStatuses, true)) {
|
||
$completedAssignments[] = $a;
|
||
} else {
|
||
$activeAssignments[] = $a;
|
||
}
|
||
}
|
||
|
||
usort($completedAssignments, static function (array $a, array $b): int {
|
||
return strtotime((string) ($b['completed_at'] ?? '0')) - strtotime((string) ($a['completed_at'] ?? '0'));
|
||
});
|
||
|
||
$activeCount = count($activeAssignments);
|
||
$completedCount = count($completedAssignments);
|
||
?>
|
||
|
||
<section class="task-cert-user-category-group">
|
||
<header class="task-cert-user-category-head">
|
||
<h3><?php echo TaskCertView::e($categoryName); ?></h3>
|
||
<span><?php echo $activeCount; ?> offen<?php echo $completedCount > 0 ? ', ' . $completedCount . ' abgeschlossen' : ''; ?></span>
|
||
</header>
|
||
|
||
<?php if ($activeAssignments !== []): ?>
|
||
<div class="task-cert-user-task-cards">
|
||
<?php foreach ($activeAssignments as $assignment): ?>
|
||
<?php
|
||
$status = (string) ($assignment['status'] ?? '');
|
||
$title = (string) ($assignment['title'] ?? 'Aufgabe');
|
||
$metaText = $getCardMeta($assignment);
|
||
$isOverdueByDate = $isAssignmentOverdueByDate($assignment, $now);
|
||
$isEscalated = (int) ($assignment['escalation_level'] ?? 0) > 0;
|
||
$cardClasses = [
|
||
'task-cert-user-task-card',
|
||
'status-' . $status,
|
||
];
|
||
if ($isOverdueByDate) {
|
||
$cardClasses[] = 'is-overdue-date';
|
||
}
|
||
if ($isEscalated) {
|
||
$cardClasses[] = 'is-escalated';
|
||
}
|
||
?>
|
||
<a
|
||
href="<?php echo TaskCertView::e($taskDetailUrl . '?assignment_id=' . (int) $assignment['id']); ?>"
|
||
class="<?php echo TaskCertView::e(implode(' ', $cardClasses)); ?>"
|
||
>
|
||
<div class="task-cert-user-task-card-head">
|
||
<strong><?php echo TaskCertView::e($title); ?></strong>
|
||
<span class="task-cert-user-status-badge status-<?php echo TaskCertView::e($status); ?>">
|
||
<?php echo TaskCertView::e($statusLabels[$status] ?? $status); ?>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="task-cert-user-task-card-meta">
|
||
<?php echo TaskCertView::e($metaText); ?>
|
||
</div>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($completedAssignments !== []): ?>
|
||
<details class="task-cert-user-completed-group">
|
||
<summary>
|
||
<?php echo $completedCount; ?> abgeschlossene Aufgabe<?php echo $completedCount === 1 ? '' : 'n'; ?> anzeigen
|
||
</summary>
|
||
<div class="task-cert-user-task-cards">
|
||
<?php foreach ($completedAssignments as $assignment): ?>
|
||
<?php
|
||
$status = (string) ($assignment['status'] ?? '');
|
||
$title = (string) ($assignment['title'] ?? 'Aufgabe');
|
||
$metaText = $getCardMeta($assignment);
|
||
$cardClasses = ['task-cert-user-task-card', 'status-' . $status];
|
||
?>
|
||
<a
|
||
href="<?php echo TaskCertView::e($taskDetailUrl . '?assignment_id=' . (int) $assignment['id']); ?>"
|
||
class="<?php echo TaskCertView::e(implode(' ', $cardClasses)); ?>"
|
||
>
|
||
<div class="task-cert-user-task-card-head">
|
||
<strong><?php echo TaskCertView::e($title); ?></strong>
|
||
<span class="task-cert-user-status-badge status-<?php echo TaskCertView::e($status); ?>">
|
||
<?php echo TaskCertView::e($statusLabels[$status] ?? $status); ?>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="task-cert-user-task-card-meta">
|
||
<?php echo TaskCertView::e($metaText); ?>
|
||
</div>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</details>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($activeAssignments === [] && $completedAssignments === []): ?>
|
||
<div class="task-cert-block">Keine Aufgaben in dieser Kategorie.</div>
|
||
<?php endif; ?>
|
||
</section>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</div>
|