Files
omsorg/mitarbeiter-app/pages/admin-dienstplan.php
T
2026-06-13 20:03:22 +02:00

163 lines
5.4 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
require_once __DIR__ . '/../lib/auth.php';
require_once __DIR__ . '/../lib/db.php';
require_once __DIR__ . '/../lib/layout.php';
require_admin();
// Fetch all active users
$users = db()->query(
'SELECT id, name FROM users WHERE active = 1 ORDER BY name ASC'
)->fetchAll();
$now = new DateTimeImmutable('today');
$year = isset($_GET['year']) ? (int)$_GET['year'] : (int)$now->format('Y');
$month = isset($_GET['month']) ? (int)$_GET['month'] : (int)$now->format('n');
$year = max(2020, min(2099, $year));
$month = max(1, min(12, $month));
// Resolve selected user
$selected_id = isset($_GET['user_id']) ? (int)$_GET['user_id'] : 0;
$selected_user = null;
foreach ($users as $u) {
if ((int)$u['id'] === $selected_id) { $selected_user = $u; break; }
}
if (!$selected_user && !empty($users)) {
$selected_user = $users[0];
$selected_id = (int)$selected_user['id'];
}
$first = new DateTimeImmutable(sprintf('%04d-%02d-01', $year, $month));
$month_start = $first->format('Y-m-d');
$month_end = $first->modify('last day of this month')->format('Y-m-d');
$days = (int)$first->format('t');
$prev = $first->modify('-1 month');
$next = $first->modify('+1 month');
$prev_url = '?user_id=' . $selected_id . '&year=' . $prev->format('Y') . '&month=' . $prev->format('n');
$next_url = '?user_id=' . $selected_id . '&year=' . $next->format('Y') . '&month=' . $next->format('n');
// Load shifts
$schichten = [];
if ($selected_id) {
$stmt = db()->prepare(
'SELECT date, schicht FROM dienstplan WHERE user_id = ? AND date >= ? AND date <= ?'
);
$stmt->execute([$selected_id, $month_start, $month_end]);
foreach ($stmt->fetchAll() as $row) {
$schichten[$row['date']] = $row['schicht'];
}
}
// Load overlays
$overlays = [];
if ($selected_id) {
$stmt = db()->prepare("
SELECT von, bis, 'urlaub' AS typ
FROM requests_urlaubsantrag
WHERE user_id = ? AND status = 'accepted' AND bis >= ? AND von <= ?
UNION ALL
SELECT von, bis, 'abwesenheit' AS typ
FROM requests_abwesenheitsantrag
WHERE user_id = ? AND status = 'accepted' AND bis >= ? AND von <= ?
");
$stmt->execute([$selected_id, $month_start, $month_end, $selected_id, $month_start, $month_end]);
foreach ($stmt->fetchAll() as $row) {
$cursor = new DateTimeImmutable($row['von']);
$end = new DateTimeImmutable($row['bis']);
while ($cursor <= $end) {
$key = $cursor->format('Y-m-d');
if ($key >= $month_start && $key <= $month_end) {
$overlays[$key] = $row['typ'];
}
$cursor = $cursor->modify('+1 day');
}
}
}
$today_str = $now->format('Y-m-d');
$schicht_labels = ['frueh' => 'Früh', 'spaet' => 'Spät', 'nacht' => 'Nacht'];
$weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
$months_de = ['', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'];
layout_start('Dienstpläne', 'admin-dienstplan');
?>
<h1 class="main-title">Dienstpläne</h1>
<div class="dp-user-select-wrap">
<form method="get">
<input type="hidden" name="year" value="<?= $year ?>">
<input type="hidden" name="month" value="<?= $month ?>">
<label class="form-label" for="user_id">Mitarbeiter</label>
<select name="user_id" id="user_id" onchange="this.form.submit()">
<?php foreach ($users as $u): ?>
<option value="<?= (int)$u['id'] ?>" <?= (int)$u['id'] === $selected_id ? 'selected' : '' ?>>
<?= e($u['name']) ?>
</option>
<?php endforeach; ?>
</select>
</form>
</div>
<?php if ($selected_user): ?>
<div class="dp-nav">
<div style="display:flex;gap:10px;align-items:center">
<a href="<?= e($prev_url) ?>" class="dp-nav-btn">&larr;</a>
<h2 class="dp-nav-title"><?= e($months_de[$month] . ' ' . $year) ?></h2>
<a href="<?= e($next_url) ?>" class="dp-nav-btn">&rarr;</a>
</div>
<span style="color:var(--muted);font-size:.9rem"><?= e($selected_user['name']) ?></span>
</div>
<div class="dp-grid">
<?php foreach ($weekdays as $wd): ?>
<div class="dp-weekday"><?= e($wd) ?></div>
<?php endforeach; ?>
<?php
$lead = (int)$first->format('N') - 1;
for ($i = 0; $i < $lead; $i++): ?>
<div class="dp-cell dp-cell-empty"></div>
<?php endfor; ?>
<?php for ($d = 1; $d <= $days; $d++):
$date_key = sprintf('%04d-%02d-%02d', $year, $month, $d);
$is_today = ($date_key === $today_str);
$overlay = $overlays[$date_key] ?? null;
$schicht = $schichten[$date_key] ?? null;
$cell_cls = 'dp-cell' . ($is_today ? ' dp-cell-today' : '');
?>
<div class="<?= $cell_cls ?>">
<span class="dp-day-num"><?= $d ?></span>
<?php if ($overlay): ?>
<span class="dp-badge dp-overlay-<?= e($overlay) ?>">
<?= $overlay === 'urlaub' ? 'Urlaub' : 'Abwesenheit' ?>
</span>
<?php endif; ?>
<?php if ($schicht): ?>
<span class="dp-badge dp-badge-<?= e($schicht) ?>">
<?= e($schicht_labels[$schicht]) ?>
</span>
<?php elseif (!$overlay): ?>
<span class="dp-free"></span>
<?php endif; ?>
</div>
<?php endfor; ?>
<?php
$total = $lead + $days;
$trail = (7 - ($total % 7)) % 7;
for ($i = 0; $i < $trail; $i++): ?>
<div class="dp-cell dp-cell-empty"></div>
<?php endfor; ?>
</div>
<?php else: ?>
<p style="color:var(--muted)">Keine aktiven Mitarbeiter vorhanden.</p>
<?php endif; ?>
<?php
layout_end();