Files
2026-11-04 07:55:30 +00:00

98 lines
6.8 KiB
PHP
Raw Permalink 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__ . '/../includes/bootstrap.php';
require_once __DIR__ . '/_ui.php';
$staff = require_staff_login();
$pdo = get_db();
$staffId = (int) $staff['id'];
$key = (string) ($_GET['p'] ?? 'week');
if (!isset(my_week_periods()[$key])) $key = 'week';
$range = my_week_range($key);
$now = my_week_stats($pdo, $staffId, $range['from'], $range['to']);
$before = my_week_stats($pdo, $staffId, $range['prev_from'], $range['prev_to']);
$live = my_week_now($pdo, $staffId);
$perDay = my_week_per_day($pdo, $staffId, $range['from'], $range['to']);
$maxDay = max(1, ...array_values($perDay ?: [0]));
$csatOn = csat_enabled();
$cards = [
['Gelöste Tickets', (string) $now['resolved'], my_week_delta((float) $now['resolved'], (float) $before['resolved']), 'Tickets, die dir zugewiesen waren und in diesem Zeitraum gelöst oder geschlossen wurden'],
['Gesendete Antworten', (string) $now['replies'], my_week_delta((float) $now['replies'], (float) $before['replies']), 'Öffentliche Antworten an Kunden (ohne interne Notizen)'],
['Ø Zeit bis zur ersten Antwort', my_week_fmt_duration($now['first_response_seconds']),
my_week_delta($now['first_response_seconds'] !== null ? $now['first_response_seconds'] / 60 : null, $before['first_response_seconds'] !== null ? $before['first_response_seconds'] / 60 : null, true, ' Min'),
'Nur Tickets, bei denen du als Erste/r öffentlich geantwortet hast' . ($now['first_response_count'] ? ' (' . $now['first_response_count'] . ' Tickets)' : '') . '; in Arbeitszeit, wenn Geschäftszeiten eingerichtet sind'],
['Pünktlich gelöst', $now['on_time'] !== null ? $now['on_time'] . ' %' : '–', my_week_delta($now['on_time'] !== null ? (float) $now['on_time'] : null, $before['on_time'] !== null ? (float) $before['on_time'] : null, false, ' %-Punkte'), 'Anteil der gelösten Tickets, die vor Ablauf der Lösungsfrist fertig waren'],
];
if ($csatOn) {
$cards[] = ['Zufriedenheit', $now['csat_avg'] !== null ? number_format($now['csat_avg'], 1, ',', '') . ' ★' : '–',
my_week_delta($now['csat_avg'], $before['csat_avg'], false, ' ★'),
$now['csat_count'] ? $now['csat_count'] . ' Bewertung' . ($now['csat_count'] === 1 ? '' : 'en') . ', davon ' . $now['csat_positive'] . ' % mit 4 oder 5 Sternen' : 'Noch keine Bewertungen in diesem Zeitraum'];
}
$oldest = $pdo->prepare("SELECT ticket_number, subject, created_at, resolution_due_at, status FROM tickets WHERE assigned_staff_id = ? AND is_spam = 0 AND status NOT IN ('resolved','closed') ORDER BY created_at ASC LIMIT 5");
$oldest->execute([$staffId]);
$oldest = $oldest->fetchAll();
$pageTitle = 'Meine Woche';
$activePage = 'my_week';
require __DIR__ . '/_header.php';
?>
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap">
<h1 style="margin:0">Meine Woche</h1>
<div style="display:flex;gap:6px;flex-wrap:wrap">
<?php foreach (my_week_periods() as $k => $l): ?>
<a href="?p=<?= e($k) ?>" class="btn <?= $k === $key ? '' : 'secondary' ?>" style="padding:5px 14px;font-size:.84rem"><?= e($l) ?></a>
<?php endforeach; ?>
</div>
</div>
<p class="muted">Nur für dich sichtbar: <strong><?= e($range['label']) ?></strong> (<?= e(format_dt($range['from'])) ?> bis <?= e(format_dt($range['to'])) ?>), verglichen mit dem gleich langen Zeitraum davor.</p>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;margin:16px 0">
<?php foreach ($cards as [$label, $value, $delta, $hint]): ?>
<div class="card" style="margin:0" title="<?= e($hint) ?>">
<div class="muted" style="font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em"><?= e($label) ?></div>
<div style="font-size:2rem;font-weight:800;margin:6px 0 2px"><?= e($value) ?></div>
<div style="font-size:.8rem;color:<?= $delta['trend'] > 0 ? '#15803d' : ($delta['trend'] < 0 ? '#b91c1c' : 'var(--muted)') ?>"><?= e($delta['text']) ?></div>
<div class="muted" style="font-size:.74rem;margin-top:8px"><?= e($hint) ?></div>
</div>
<?php endforeach; ?>
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:14px">
<div class="card" style="margin:0">
<h3 style="margin-top:0">Gelöst pro Tag</h3>
<div style="display:flex;align-items:flex-end;gap:6px;height:130px">
<?php foreach ($perDay as $day => $n): ?>
<div style="flex:1;min-width:0;text-align:center" title="<?= e(date('d.m.Y', strtotime($day))) ?>: <?= $n ?>">
<div style="font-size:.74rem;height:16px"><?= $n ?: '' ?></div>
<div style="height:<?= (int) round(90 * $n / $maxDay) ?>px;min-height:<?= $n ? 3 : 1 ?>px;background:<?= $n ? 'var(--primary,#0f6f6a)' : 'var(--border,#e2e8f0)' ?>;border-radius:4px 4px 0 0"></div>
<div class="muted" style="font-size:.68rem;margin-top:3px"><?= e(count($perDay) > 10 ? date('d.', strtotime($day)) : ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'][(int) date('w', strtotime($day))]) ?></div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="card" style="margin:0">
<h3 style="margin-top:0">Gerade bei dir</h3>
<div style="display:flex;gap:18px;flex-wrap:wrap;margin-bottom:10px">
<div><div style="font-size:1.6rem;font-weight:800"><?= $live['open'] ?></div><div class="muted" style="font-size:.78rem">offen</div></div>
<div><div style="font-size:1.6rem;font-weight:800"><?= $live['waiting'] ?></div><div class="muted" style="font-size:.78rem">warten auf deine Antwort</div></div>
<div><div style="font-size:1.6rem;font-weight:800;color:<?= $live['overdue'] ? '#b91c1c' : 'inherit' ?>"><?= $live['overdue'] ?></div><div class="muted" style="font-size:.78rem">überfällig</div></div>
</div>
<?php if ($oldest): ?>
<div style="font-size:.8rem;font-weight:700;margin-bottom:4px">Deine ältesten offenen Tickets</div>
<?php foreach ($oldest as $t): $late = $t['resolution_due_at'] && $t['resolution_due_at'] < db_now(); ?>
<div style="padding:5px 0;border-top:1px solid var(--border-soft);font-size:.86rem">
<a href="/staff/ticket_view.php?n=<?= urlencode($t['ticket_number']) ?>"><strong>#<?= e($t['ticket_number']) ?></strong> · <?= e(mb_strimwidth((string) $t['subject'], 0, 60, '…')) ?></a>
<span class="muted" style="font-size:.76rem">seit <?= e(date('d.m.Y', strtotime($t['created_at']))) ?><?= $late ? ' · <span style="color:#b91c1c">überfällig</span>' : '' ?></span>
</div>
<?php endforeach; ?>
<?php else: ?>
<p class="muted" style="margin:0">Keine offenen Tickets. 🎉</p>
<?php endif; ?>
</div>
</div>
<?php if (!$csatOn): ?><p class="muted" style="font-size:.82rem;margin-top:14px">Die Zufriedenheitsabfrage ist ausgeschaltet; deshalb gibt es hier keine Bewertungen. Ein Administrator schaltet sie unter Einstellungen → Allgemein ein.</p><?php endif; ?>
<?php require __DIR__ . '/_footer.php'; ?>