98 lines
6.8 KiB
PHP
98 lines
6.8 KiB
PHP
<?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'; ?>
|