Files
CC-Switch/src/components/usage/ProviderStatsTable.tsx
T
Dex Miller 87b80c66b2 feat(usage): enhance dashboard with auto-refresh control and robust formatting (#942)
* style: format code and apply clippy lint fixes

* feat(usage): enhance dashboard with auto-refresh control and robust formatting

- Add configurable auto-refresh interval toggle (off/5s/10s/30s/60s) to usage dashboard
- Extract shared format utilities (fmtUsd, fmtInt, parseFiniteNumber, getLocaleFromLanguage)
- Refactor request log time filtering to rolling vs fixed mode with validation
- Use stable serializable query keys instead of filter objects
- Handle NaN/Infinity safely in number formatting across all usage components
- Use RFC 3339 date format in backend trend data
2026-02-06 22:00:33 +08:00

91 lines
2.8 KiB
TypeScript

import { useTranslation } from "react-i18next";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useProviderStats } from "@/lib/query/usage";
import { fmtUsd } from "./format";
interface ProviderStatsTableProps {
refreshIntervalMs: number;
}
export function ProviderStatsTable({
refreshIntervalMs,
}: ProviderStatsTableProps) {
const { t } = useTranslation();
const { data: stats, isLoading } = useProviderStats({
refetchInterval: refreshIntervalMs > 0 ? refreshIntervalMs : false,
});
if (isLoading) {
return <div className="h-[400px] animate-pulse rounded bg-gray-100" />;
}
return (
<div className="rounded-lg border border-border/50 bg-card/40 backdrop-blur-sm overflow-hidden">
<Table>
<TableHeader>
<TableRow>
<TableHead>{t("usage.provider", "Provider")}</TableHead>
<TableHead className="text-right">
{t("usage.requests", "请求数")}
</TableHead>
<TableHead className="text-right">
{t("usage.tokens", "Tokens")}
</TableHead>
<TableHead className="text-right">
{t("usage.cost", "成本")}
</TableHead>
<TableHead className="text-right">
{t("usage.successRate", "成功率")}
</TableHead>
<TableHead className="text-right">
{t("usage.avgLatency", "平均延迟")}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{stats?.length === 0 ? (
<TableRow>
<TableCell
colSpan={6}
className="text-center text-muted-foreground"
>
{t("usage.noData", "暂无数据")}
</TableCell>
</TableRow>
) : (
stats?.map((stat) => (
<TableRow key={stat.providerId}>
<TableCell className="font-medium">
{stat.providerName}
</TableCell>
<TableCell className="text-right">
{stat.requestCount.toLocaleString()}
</TableCell>
<TableCell className="text-right">
{stat.totalTokens.toLocaleString()}
</TableCell>
<TableCell className="text-right">
{fmtUsd(stat.totalCost, 4)}
</TableCell>
<TableCell className="text-right">
{stat.successRate.toFixed(1)}%
</TableCell>
<TableCell className="text-right">
{stat.avgLatencyMs}ms
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
);
}