121 lines
3.6 KiB
PHP
121 lines
3.6 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../includes/bootstrap.php';
|
|
$staff = require_admin_or_permission('view_time_entries');
|
|
$pdo = get_db();
|
|
|
|
$filterStaff = $_GET['staff_id'] ?? '';
|
|
$filterFrom = $_GET['from'] ?? date('Y-m-01');
|
|
$filterTo = $_GET['to'] ?? date('Y-m-d');
|
|
|
|
$allStaff = $pdo->query('SELECT id, name FROM staff WHERE is_active=1 ORDER BY name')->fetchAll();
|
|
|
|
$where = ['te.logged_at BETWEEN ? AND ?'];
|
|
$params = [$filterFrom . ' 00:00:00', $filterTo . ' 23:59:59'];
|
|
|
|
if ($filterStaff !== '') {
|
|
$where[] = 'te.staff_id = ?';
|
|
$params[] = $filterStaff;
|
|
}
|
|
|
|
$stmt = $pdo->prepare(
|
|
"SELECT te.*, s.name AS staff_name, t.ticket_number, t.subject
|
|
FROM ticket_time_entries te
|
|
JOIN staff s ON s.id = te.staff_id
|
|
JOIN tickets t ON t.id = te.ticket_id
|
|
WHERE " . implode(' AND ', $where) . "
|
|
ORDER BY te.logged_at DESC
|
|
LIMIT 500"
|
|
);
|
|
$stmt->execute($params);
|
|
$entries = $stmt->fetchAll();
|
|
|
|
// Summen je Mitarbeiter
|
|
$byStaff = [];
|
|
foreach ($entries as $e) {
|
|
$byStaff[$e['staff_name']] = ($byStaff[$e['staff_name']] ?? 0) + (int)$e['minutes'];
|
|
}
|
|
|
|
$totalMinutes = array_sum(array_column($entries, 'minutes'));
|
|
|
|
$pageTitle = 'Zeiterfassung';
|
|
$activePage = 'time_entries';
|
|
require __DIR__ . '/_header.php';
|
|
|
|
function fmt_minutes(int $m): string {
|
|
return floor($m / 60) . 'h ' . ($m % 60) . 'min';
|
|
}
|
|
?>
|
|
|
|
<div class="topbar">
|
|
<h1>⏱ Zeiterfassung</h1>
|
|
</div>
|
|
|
|
<form method="get" class="filters card" style="margin-bottom:16px">
|
|
<div>
|
|
<label>Von</label>
|
|
<input type="date" name="from" value="<?= e($filterFrom) ?>">
|
|
</div>
|
|
<div>
|
|
<label>Bis</label>
|
|
<input type="date" name="to" value="<?= e($filterTo) ?>">
|
|
</div>
|
|
<div>
|
|
<label>Mitarbeiter</label>
|
|
<select name="staff_id">
|
|
<option value="">Alle</option>
|
|
<?php foreach ($allStaff as $s): ?>
|
|
<option value="<?= $s['id'] ?>" <?= $filterStaff == $s['id'] ? 'selected' : '' ?>><?= e($s['name']) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div><button type="submit" class="btn secondary">Filtern</button></div>
|
|
</form>
|
|
|
|
<?php if ($byStaff): ?>
|
|
<div class="stat-grid" style="margin-bottom:20px">
|
|
<?php foreach ($byStaff as $name => $mins): ?>
|
|
<div class="stat-card">
|
|
<div class="num" style="font-size:1.4rem"><?= fmt_minutes($mins) ?></div>
|
|
<div class="lbl"><?= e($name) ?></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<div class="stat-card" style="border-color:var(--primary)">
|
|
<div class="num" style="font-size:1.4rem; color:var(--primary)"><?= fmt_minutes($totalMinutes) ?></div>
|
|
<div class="lbl">Gesamt</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="card">
|
|
<?php if (!$entries): ?>
|
|
<div class="empty-state">Keine Zeiteinträge im gewählten Zeitraum.</div>
|
|
<?php else: ?>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Datum</th>
|
|
<th>Mitarbeiter</th>
|
|
<th>Ticket</th>
|
|
<th>Betreff</th>
|
|
<th>Zeit</th>
|
|
<th>Notiz</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($entries as $e): ?>
|
|
<tr>
|
|
<td class="muted"><?= format_dt($e['logged_at']) ?></td>
|
|
<td><?= e($e['staff_name']) ?></td>
|
|
<td><a href="/staff/ticket_view.php?n=<?= urlencode($e['ticket_number']) ?>" class="ticket-no">#<?= e($e['ticket_number']) ?></a></td>
|
|
<td><?= e($e['subject']) ?></td>
|
|
<td style="white-space:nowrap; font-weight:600"><?= fmt_minutes((int)$e['minutes']) ?></td>
|
|
<td class="muted"><?= e($e['note'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?php require __DIR__ . '/_footer.php'; ?>
|