feat: harden analytics dashboard

This commit is contained in:
2026-05-27 15:19:31 +08:00
parent 5e0ca6a504
commit 356039d9cf
34 changed files with 1424 additions and 879 deletions

View File

@@ -8,6 +8,7 @@ import { TimeRangeSelector } from "@/components/TimeRangeSelector";
import { TrendChart } from "@/components/charts/TrendChart";
import { RankingBar } from "@/components/charts/RankingBar";
import { buildQuery } from "@/lib/utils";
import { quotaToUsd } from "@/lib/metrics";
import { useTimeRange } from "@/lib/time-range-context";
import { useI18n } from "@/lib/i18n";
@@ -82,19 +83,19 @@ export default function DashboardPage() {
<div className="grid grid-cols-2 gap-4 md:grid-cols-5">
<StatsCard title={t("dash.totalCalls")} value={overview.total_calls} icon={Hash} delay={0} />
<StatsCard title={t("dash.tokenUsage")} value={overview.total_tokens} format="tokens" icon={Zap} delay={0.05} />
<StatsCard title={t("dash.totalCost")} value={overview.total_quota / 500000} format="usd" icon={DollarSign} delay={0.1} />
<StatsCard title={t("dash.totalCost")} value={quotaToUsd(overview.total_quota)} format="usd" icon={DollarSign} delay={0.1} />
<StatsCard title={t("dash.activeUsers")} value={overview.active_users} icon={Users} delay={0.15} />
<StatsCard title={t("dash.activeModels")} value={overview.active_models} icon={Cpu} delay={0.2} />
</div>
)}
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ delay: 0.15 }} className="glass p-5">
<div className="mb-4 flex items-center justify-between">
<div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="flex items-center gap-2">
<TrendingUp className="h-4 w-4" style={{ color: "var(--accent)", opacity: 0.6 }} />
<h2 className="text-sm font-semibold" style={{ color: "var(--text-primary)" }}>{t("dash.trend")}</h2>
</div>
<div className="flex gap-3">
<div className="flex max-w-full flex-wrap gap-2 sm:gap-3">
<div className="flex gap-1 rounded-md p-0.5" style={{ background: "var(--row-hover)", border: "1px solid var(--surface-border)" }}>
{grans.map(g => (
<button key={g.key} onClick={() => setGranularity(g.key)}