feat: trend dots on stat cards, team workload panel, stat model improvement

- Dashboard stat cards now show lt-dot trend indicators (up/warn/idle) based on
  created_today vs closed_today flow — no extra DB query needed
- Add collapsible Team Workload panel showing assignee open ticket counts with
  progress bars (green/cyan/red by load), avatar, and name
- StatsModel.getTicketsByAssignee() now returns proper objects with user_id,
  display_name, open_count (was name-keyed flat array); limit raised to 8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 12:04:41 -04:00
parent fca4896e0d
commit 0d8edc9d34
3 changed files with 107 additions and 11 deletions
+11 -6
View File
@@ -25,16 +25,17 @@ class StatsModel {
/**
* Get tickets by assignee (top 5)
*/
public function getTicketsByAssignee(int $limit = 5): array {
public function getTicketsByAssignee(int $limit = 8): array {
$sql = "SELECT
u.user_id,
u.display_name,
u.username,
COUNT(t.ticket_id) as ticket_count
COUNT(t.ticket_id) as open_count
FROM tickets t
LEFT JOIN users u ON t.assigned_to = u.user_id
WHERE t.status != 'Closed'
WHERE t.status != 'Closed' AND t.assigned_to IS NOT NULL
GROUP BY t.assigned_to
ORDER BY ticket_count DESC
ORDER BY open_count DESC
LIMIT ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param('i', $limit);
@@ -42,8 +43,12 @@ class StatsModel {
$result = $stmt->get_result();
$data = [];
while ($row = $result->fetch_assoc()) {
$name = $row['display_name'] ?: $row['username'];
$data[$name] = (int)$row['ticket_count'];
$data[] = [
'user_id' => (int)$row['user_id'],
'display_name' => $row['display_name'] ?: $row['username'],
'username' => $row['username'],
'open_count' => (int)$row['open_count'],
];
}
$stmt->close();
return $data;