Abwesenheitskalender erweitert
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
require_once __DIR__ . '/inc/vacation_absence.inc.php';
|
||||
|
||||
$user = check_user();
|
||||
if (!is_admin_user()) {
|
||||
die('Zugriff verweigert. Nur Chefs dürfen den Leitungskalender sehen.');
|
||||
}
|
||||
|
||||
$schemaWarning = '';
|
||||
try {
|
||||
vacationAbsenceEnsureSchema($pdo);
|
||||
} catch (Throwable $e) {
|
||||
$schemaWarning = 'Das Abwesenheitsschema konnte nicht automatisch aktualisiert werden: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
function adminAbsenceStatusLabel(?string $status): string
|
||||
{
|
||||
$status = trim((string)$status);
|
||||
if ($status === '' || $status === 'beantragt') {
|
||||
return 'Beantragt';
|
||||
}
|
||||
if ($status === 'genehmigt') {
|
||||
return 'Genehmigt';
|
||||
}
|
||||
if ($status === 'abgelehnt') {
|
||||
return 'Abgelehnt';
|
||||
}
|
||||
return ucfirst($status);
|
||||
}
|
||||
|
||||
function adminAbsenceColor(string $reason, string $status): string
|
||||
{
|
||||
$reason = vacationAbsenceNormalizeReason($reason);
|
||||
$status = trim(strtolower($status));
|
||||
|
||||
$palette = [
|
||||
'urlaub' => '#2f855a',
|
||||
'krankheit_mit_atest' => '#c53030',
|
||||
'krankheit_ohne_atest' => '#9b2c2c',
|
||||
'berufsschule' => '#dd6b20',
|
||||
'weiterbildung' => '#6b46c1',
|
||||
'persoenliche_gruende' => '#4a5568',
|
||||
'sonstiges' => '#718096',
|
||||
];
|
||||
|
||||
$color = $palette[$reason] ?? '#2d3748';
|
||||
if ($status === 'beantragt') {
|
||||
return $color;
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
function adminAbsenceEventTitle(array $row): string
|
||||
{
|
||||
$employee = trim(($row['vorname'] ?? '') . ' ' . ($row['nachname'] ?? ''));
|
||||
$reasonLabel = vacationAbsenceReasonLabel($row['absence_reason'] ?? 'urlaub');
|
||||
$statusLabel = adminAbsenceStatusLabel($row['status'] ?? '');
|
||||
if ($employee === '') {
|
||||
return $reasonLabel . ' (' . $statusLabel . ')';
|
||||
}
|
||||
|
||||
if ($statusLabel !== 'Genehmigt') {
|
||||
return $employee . ' · ' . $reasonLabel . ' (' . $statusLabel . ')';
|
||||
}
|
||||
|
||||
return $employee . ' · ' . $reasonLabel;
|
||||
}
|
||||
|
||||
$events = [];
|
||||
|
||||
$vacStmt = $pdo->prepare("
|
||||
SELECT
|
||||
v.id,
|
||||
v.user_id,
|
||||
v.start_date,
|
||||
v.end_date,
|
||||
v.days,
|
||||
v.status,
|
||||
v.comment_user,
|
||||
v.absence_reason,
|
||||
u.vorname,
|
||||
u.nachname,
|
||||
u.email
|
||||
FROM vacations v
|
||||
JOIN users u ON u.id = v.user_id
|
||||
WHERE LOWER(TRIM(COALESCE(v.status, ''))) != 'abgelehnt'
|
||||
ORDER BY v.start_date ASC, v.end_date ASC, u.nachname ASC, u.vorname ASC
|
||||
");
|
||||
$vacStmt->execute();
|
||||
$vacations = $vacStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($vacations as $row) {
|
||||
$endInclusive = (new DateTime($row['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||
$reason = vacationAbsenceNormalizeReason($row['absence_reason'] ?? 'urlaub');
|
||||
$status = trim((string)($row['status'] ?? ''));
|
||||
$statusLabel = adminAbsenceStatusLabel($status);
|
||||
|
||||
$events[] = [
|
||||
'id' => 'vac_' . $row['id'],
|
||||
'title' => adminAbsenceEventTitle($row),
|
||||
'start' => $row['start_date'],
|
||||
'end' => $endInclusive,
|
||||
'allDay' => true,
|
||||
'backgroundColor' => adminAbsenceColor($reason, $status),
|
||||
'borderColor' => adminAbsenceColor($reason, $status),
|
||||
'extendedProps' => [
|
||||
'type' => 'absence',
|
||||
'user_id' => $row['user_id'],
|
||||
'employee_name' => trim(($row['vorname'] ?? '') . ' ' . ($row['nachname'] ?? '')),
|
||||
'email' => $row['email'] ?? '',
|
||||
'status' => $status,
|
||||
'status_label' => $statusLabel,
|
||||
'reason' => $reason,
|
||||
'reason_label' => vacationAbsenceReasonLabel($reason),
|
||||
'days' => (int)($row['days'] ?? 0),
|
||||
'comment' => $row['comment_user'] ?? '',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$companyStmt = $pdo->prepare("
|
||||
SELECT id, start_date, end_date, description
|
||||
FROM company_holidays
|
||||
ORDER BY start_date ASC, end_date ASC
|
||||
");
|
||||
$companyStmt->execute();
|
||||
$companyHolidays = $companyStmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($companyHolidays as $row) {
|
||||
$endInclusive = (new DateTime($row['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||
$events[] = [
|
||||
'id' => 'com_' . $row['id'],
|
||||
'title' => $row['description'] ?: 'Betriebsurlaub',
|
||||
'start' => $row['start_date'],
|
||||
'end' => $endInclusive,
|
||||
'allDay' => true,
|
||||
'backgroundColor' => '#005f73',
|
||||
'borderColor' => '#005f73',
|
||||
'extendedProps' => [
|
||||
'type' => 'company',
|
||||
'description' => $row['description'] ?: 'Betriebsurlaub',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
include 'header.php';
|
||||
?>
|
||||
|
||||
<div class="container">
|
||||
<h2>Leitungskalender</h2>
|
||||
|
||||
<?php if (!empty($schemaWarning)): ?>
|
||||
<div class="alert alert-warning"><?php echo htmlspecialchars($schemaWarning); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Hinweis:</strong> Dieser Kalender zeigt alle Abwesenheiten aller Personen sowie Betriebsurlaub.
|
||||
</div>
|
||||
|
||||
<div id="calendar"></div>
|
||||
<br>
|
||||
<div class="d-flex flex-wrap" style="gap: 0.5rem;">
|
||||
<span class="badge badge-success">Urlaub</span>
|
||||
<span class="badge badge-danger">Krankheit mit Attest</span>
|
||||
<span class="badge badge-dark">Krankheit ohne Attest</span>
|
||||
<span class="badge badge-warning">Berufsschule</span>
|
||||
<span class="badge badge-primary">Weiterbildung</span>
|
||||
<span class="badge badge-secondary">Persönliche Gründe</span>
|
||||
<span class="badge badge-light">Sonstiges</span>
|
||||
<span class="badge badge-info">Betriebsurlaub</span>
|
||||
</div>
|
||||
<br>
|
||||
<div id="eventDetails" style="display:none;">
|
||||
<h4>Details</h4>
|
||||
<div id="detailsContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
|
||||
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
var events = <?php echo json_encode($events, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
|
||||
function formatAllDayRange(start, end) {
|
||||
var startDate = new Date(start);
|
||||
var endDate = end ? new Date(end) : null;
|
||||
var startLabel = startDate.toLocaleDateString('de-DE');
|
||||
if (!endDate) {
|
||||
return startLabel;
|
||||
}
|
||||
|
||||
var inclusiveEnd = new Date(endDate.getTime() - 24 * 60 * 60 * 1000);
|
||||
return startLabel + ' - ' + inclusiveEnd.toLocaleDateString('de-DE');
|
||||
}
|
||||
|
||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: 'dayGridMonth',
|
||||
firstDay: 1,
|
||||
height: 700,
|
||||
events: events,
|
||||
eventClick: function(info) {
|
||||
var ev = info.event;
|
||||
var props = ev.extendedProps || {};
|
||||
var html = '<strong>' + ev.title + '</strong><br>' + formatAllDayRange(ev.start, ev.end) + '<br>';
|
||||
|
||||
if (props.type === 'absence') {
|
||||
html += 'Mitarbeiter: ' + (props.employee_name || '') + '<br>';
|
||||
html += 'Grund: ' + (props.reason_label || '') + '<br>';
|
||||
html += 'Status: ' + (props.status_label || '') + '<br>';
|
||||
html += 'Tage: ' + (props.days || 0) + '<br>';
|
||||
if (props.comment) {
|
||||
html += 'Kommentar: ' + props.comment + '<br>';
|
||||
}
|
||||
} else if (props.type === 'company') {
|
||||
html += 'Beschreibung: ' + (props.description || 'Betriebsurlaub') + '<br>';
|
||||
}
|
||||
|
||||
document.getElementById('detailsContent').innerHTML = html;
|
||||
document.getElementById('eventDetails').style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
Reference in New Issue
Block a user