feat(helpdesk): add trend delta indicator per agent in team dashboard

Shows a small arrow next to the ticket count in each agent card header:
↑3 (orange) = received 3 more than resolved → backlog growing
↓2 (green) = resolved 2 more than received → backlog shrinking
Hidden when delta is 0 (stable).

Delta is computed from received_in_period (tickets created in the
selected period assigned to this agent) minus resolved_in_period.
No snapshot storage needed — derived from existing ticket data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 21:09:52 +02:00
parent 671105e359
commit f2aa45dd2c
3 changed files with 36 additions and 0 deletions

View File

@@ -1621,6 +1621,7 @@ class DebitorDetailService
'critical_tickets' => 0,
'age_hours_sum' => 0,
'resolved_in_period' => 0,
'received_in_period' => 0,
'open_ticket_details' => [],
'resolved_customers' => [],
'resolved_categories' => [],
@@ -1631,6 +1632,9 @@ class DebitorDetailService
if ($isClosed) {
$createdTs = self::parseIsoToTimestamp((string) ($ticket['Created_On'] ?? ''));
if ($createdTs !== null && $createdTs >= $periodStart) {
$agents[$normalizedUser]['received_in_period']++;
}
if ($activityTs !== null && $activityTs >= $periodStart) {
$agents[$normalizedUser]['resolved_in_period']++;
$globalResolved++;
@@ -1659,6 +1663,11 @@ class DebitorDetailService
$agents[$normalizedUser]['open_tickets']++;
$globalOpen++;
$createdTs = self::parseIsoToTimestamp((string) ($ticket['Created_On'] ?? ''));
if ($createdTs !== null && $createdTs >= $periodStart) {
$agents[$normalizedUser]['received_in_period']++;
}
if ($rawUser === '') {
$globalUnassigned++;
}
@@ -1733,6 +1742,8 @@ class DebitorDetailService
'critical_tickets' => $agent['critical_tickets'],
'avg_age_hours' => $avgAge,
'resolved_in_period' => $agent['resolved_in_period'],
'received_in_period' => $agent['received_in_period'],
'trend_delta' => $agent['received_in_period'] - $agent['resolved_in_period'],
'open_ticket_details' => $details,
'performance' => [
'top_customers' => array_map(

View File

@@ -220,6 +220,22 @@
border-radius: 0;
}
/* Team workload — trend delta indicator */
.helpdesk-team-trend-up,
.helpdesk-team-trend-down {
font-size: var(--text-xs, 0.75rem);
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.helpdesk-team-trend-up {
color: var(--app-warning, #f59e0b);
}
.helpdesk-team-trend-down {
color: var(--app-success, #198754);
}
/* Team workload — inline avatar for section titles */
.helpdesk-team-avatar-inline {
display: inline-flex;

View File

@@ -110,6 +110,15 @@ if (container) {
title.appendChild(document.createTextNode(name));
title.appendChild(h('span', 'helpdesk-team-title-count', count));
// Trend delta: ↑3 (growing) or ↓2 (shrinking)
const delta = m.trend_delta ?? 0;
if (delta !== 0) {
const arrow = delta > 0 ? '↑' : '↓';
const cls = delta > 0 ? 'helpdesk-team-trend-up' : 'helpdesk-team-trend-down';
title.appendChild(h('span', cls, arrow + Math.abs(delta)));
}
section.appendChild(title);
// Ticket table