feat(helpdesk): redesign team dashboard with agent cards and ticket details
Replace KPI tiles + table with visual agent cards showing workload at a glance. Each card has the agent name, ticket count badge (warning-colored when critical), a proportional load bar, and the actual open tickets listed underneath (number, description, age). Critical tickets are highlighted with warning color. Queue (unassigned) shown as dashed card at top. Performance tab uses compact cards with success-colored bars. Backend now returns open_ticket_details per member (sorted: critical first, then by age descending). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1593,7 +1593,7 @@ class DebitorDetailService
|
||||
$periodStart = $nowTs - ($periodDays * 86400);
|
||||
$criticalThresholdHours = 48;
|
||||
|
||||
/** @var array<string, array{display_name: string, support_user: string, open_tickets: int, critical_tickets: int, age_hours_sum: int, resolved_in_period: int}> $agents */
|
||||
/** @var array<string, array{display_name: string, support_user: string, open_tickets: int, critical_tickets: int, age_hours_sum: int, resolved_in_period: int, open_ticket_details: list<array{no: string, description: string, age_hours: int, critical: bool, customer: string}>}> $agents */
|
||||
$agents = [];
|
||||
$globalOpen = 0;
|
||||
$globalUnassigned = 0;
|
||||
@@ -1619,6 +1619,7 @@ class DebitorDetailService
|
||||
'critical_tickets' => 0,
|
||||
'age_hours_sum' => 0,
|
||||
'resolved_in_period' => 0,
|
||||
'open_ticket_details' => [],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1635,17 +1636,28 @@ class DebitorDetailService
|
||||
$globalUnassigned++;
|
||||
}
|
||||
|
||||
$ageHours = 0;
|
||||
$isCritical = false;
|
||||
if ($activityTs !== null) {
|
||||
$ageHours = intdiv(max(0, $nowTs - $activityTs), 3600);
|
||||
$agents[$normalizedUser]['age_hours_sum'] += $ageHours;
|
||||
|
||||
if ($ageHours > $criticalThresholdHours) {
|
||||
$agents[$normalizedUser]['critical_tickets']++;
|
||||
$isCritical = true;
|
||||
}
|
||||
|
||||
$globalAgeSum += $ageHours;
|
||||
$globalOpenCount++;
|
||||
}
|
||||
|
||||
$agents[$normalizedUser]['open_ticket_details'][] = [
|
||||
'no' => trim((string) ($ticket['No'] ?? '')),
|
||||
'description' => trim((string) ($ticket['Description'] ?? '')),
|
||||
'age_hours' => $ageHours,
|
||||
'critical' => $isCritical,
|
||||
'customer' => trim((string) ($ticket['Customer_No'] ?? '')),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1655,6 +1667,16 @@ class DebitorDetailService
|
||||
? (int) round($agent['age_hours_sum'] / $agent['open_tickets'])
|
||||
: 0;
|
||||
|
||||
// Sort ticket details: critical first, then by age descending
|
||||
$details = $agent['open_ticket_details'];
|
||||
usort($details, static function (array $a, array $b): int {
|
||||
if ($a['critical'] !== $b['critical']) {
|
||||
return $b['critical'] <=> $a['critical'];
|
||||
}
|
||||
|
||||
return $b['age_hours'] <=> $a['age_hours'];
|
||||
});
|
||||
|
||||
$members[] = [
|
||||
'support_user' => $agent['support_user'],
|
||||
'display_name' => $agent['display_name'],
|
||||
@@ -1662,6 +1684,7 @@ class DebitorDetailService
|
||||
'critical_tickets' => $agent['critical_tickets'],
|
||||
'avg_age_hours' => $avgAge,
|
||||
'resolved_in_period' => $agent['resolved_in_period'],
|
||||
'open_ticket_details' => $details,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user