Files
ai-agent/web/app/dashboard/_components/team-load-panel.tsx
T

113 lines
4.3 KiB
TypeScript
Raw Normal View History

2026-04-09 10:01:23 +08:00
"use client"
import { Badge } from "@/components/ui/badge"
2026-05-25 12:06:15 +08:00
import { useI18n } from "@/i18n/provider"
2026-04-09 10:01:23 +08:00
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import type { DashboardOverview } from "@/lib/api/dashboard"
type TeamLoadPanelProps = {
agentStats: DashboardOverview["agentStats"]
}
function getLoadTone(loadRate: number) {
if (loadRate >= 85) {
return "bg-red-500"
}
if (loadRate >= 60) {
return "bg-amber-500"
}
return "bg-emerald-500"
}
export function TeamLoadPanel({ agentStats }: TeamLoadPanelProps) {
2026-05-25 12:06:15 +08:00
const t = useI18n()
2026-04-09 10:01:23 +08:00
return (
<Card className="rounded-md shadow-none">
2026-04-09 10:01:23 +08:00
<CardHeader>
2026-05-25 12:06:15 +08:00
<CardTitle>{t("dashboardHome.teamLoad")}</CardTitle>
2026-04-09 10:01:23 +08:00
<CardDescription>
2026-05-25 12:06:15 +08:00
{t("dashboardHome.teamLoadDescription", {
online: agentStats.onlineAgents,
busy: agentStats.busyAgents,
offline: agentStats.offlineAgents,
})}
2026-04-09 10:01:23 +08:00
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{agentStats.teamLoads.length === 0 ? (
<div className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
2026-05-25 12:06:15 +08:00
{t("dashboardHome.noTeamData")}
2026-04-09 10:01:23 +08:00
</div>
) : (
agentStats.teamLoads.map((item) => (
<div key={item.teamId} className="rounded-md border p-4">
2026-04-09 10:01:23 +08:00
<div className="flex flex-wrap items-center justify-between gap-3">
<div>
<div className="flex items-center gap-2">
<div className="font-medium">{item.teamName}</div>
{item.hasScheduleNow ? (
2026-05-25 12:06:15 +08:00
<Badge variant="secondary">{t("dashboardHome.scheduled")}</Badge>
2026-04-09 10:01:23 +08:00
) : (
2026-05-25 12:06:15 +08:00
<Badge variant="outline">{t("dashboardHome.notScheduled")}</Badge>
2026-04-09 10:01:23 +08:00
)}
</div>
<div className="mt-1 text-sm text-muted-foreground">
2026-05-25 12:06:15 +08:00
{t("dashboardHome.teamStats", {
total: item.totalAgents,
online: item.onlineAgents,
busy: item.busyAgents,
offline: item.offlineAgents,
})}
2026-04-09 10:01:23 +08:00
</div>
</div>
<div className="text-right">
<div className="text-2xl font-semibold">{item.loadRate.toFixed(1)}%</div>
<div className="text-xs text-muted-foreground">
2026-05-25 12:06:15 +08:00
{t("dashboardHome.load", {
processing: item.processingConversations,
capacity: item.maxConcurrentCapacity || 0,
})}
2026-04-09 10:01:23 +08:00
</div>
</div>
</div>
<div className="mt-4 h-2 rounded-full bg-muted">
<div
className={`h-2 rounded-full ${getLoadTone(item.loadRate)}`}
style={{ width: `${Math.min(item.loadRate, 100)}%` }}
/>
</div>
<div className="mt-4 grid gap-3 text-sm md:grid-cols-2 xl:grid-cols-4">
<div className="rounded-md bg-muted/35 px-3 py-2">
2026-05-25 12:06:15 +08:00
<div className="text-muted-foreground">{t("dashboardHome.waiting")}</div>
2026-04-09 10:01:23 +08:00
<div className="mt-1 text-lg font-semibold">{item.waitingConversations}</div>
</div>
<div className="rounded-md bg-muted/35 px-3 py-2">
2026-05-25 12:06:15 +08:00
<div className="text-muted-foreground">{t("dashboardHome.processing")}</div>
2026-04-09 10:01:23 +08:00
<div className="mt-1 text-lg font-semibold">{item.processingConversations}</div>
</div>
<div className="rounded-md bg-muted/35 px-3 py-2">
2026-05-25 12:06:15 +08:00
<div className="text-muted-foreground">{t("dashboardHome.capacity")}</div>
2026-04-09 10:01:23 +08:00
<div className="mt-1 text-lg font-semibold">{item.maxConcurrentCapacity}</div>
</div>
<div className="rounded-md bg-muted/35 px-3 py-2">
2026-05-25 12:06:15 +08:00
<div className="text-muted-foreground">{t("dashboardHome.busyAgents")}</div>
2026-04-09 10:01:23 +08:00
<div className="mt-1 text-lg font-semibold">{item.busyAgents}</div>
</div>
</div>
</div>
))
)}
</CardContent>
</Card>
)
}