Add cost metrics to analytics dashboard

This commit is contained in:
2026-04-28 11:27:51 +08:00
parent 67e43b02bf
commit ab915e9292
13 changed files with 226 additions and 56 deletions

View File

@@ -2,7 +2,7 @@
import { useEffect, useState, useCallback, startTransition } from "react";
import { motion } from "motion/react";
import { Zap, Hash, Users, Cpu, TrendingUp, BarChart3 } from "lucide-react";
import { Zap, Hash, Users, Cpu, DollarSign, TrendingUp, BarChart3 } from "lucide-react";
import { StatsCard } from "@/components/StatsCard";
import { TimeRangeSelector } from "@/components/TimeRangeSelector";
import { TrendChart } from "@/components/charts/TrendChart";
@@ -14,6 +14,7 @@ import { useI18n } from "@/lib/i18n";
interface OverviewData {
total_calls: number;
total_tokens: number;
total_quota: number;
active_users: number;
active_models: number;
}
@@ -24,6 +25,7 @@ interface TrendPoint {
total_tokens: number;
prompt_tokens: number;
completion_tokens: number;
quota: number;
}
interface RankItem {
@@ -35,8 +37,8 @@ interface RankItem {
export default function DashboardPage() {
const { t } = useI18n();
const { getEffectiveRange } = useTimeRange();
const [granularity, setGranularity] = useState<"day" | "week" | "month">("day");
const [trendMetric, setTrendMetric] = useState<"total_tokens" | "calls">("total_tokens");
const [granularity, setGranularity] = useState<"hour" | "day" | "week" | "month">("day");
const [trendMetric, setTrendMetric] = useState<"total_tokens" | "calls" | "quota">("total_tokens");
const [overview, setOverview] = useState<OverviewData | null>(null);
const [trends, setTrends] = useState<TrendPoint[]>([]);
const [userRank, setUserRank] = useState<RankItem[]>([]);
@@ -61,6 +63,7 @@ export default function DashboardPage() {
useEffect(() => { fetchData(); }, [fetchData]);
const grans = [
{ key: "hour" as const, label: t("gran.hour") },
{ key: "day" as const, label: t("gran.day") },
{ key: "week" as const, label: t("gran.week") },
{ key: "month" as const, label: t("gran.month") },
@@ -76,11 +79,12 @@ export default function DashboardPage() {
</div>
{overview && (
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
<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.activeUsers")} value={overview.active_users} icon={Users} delay={0.1} />
<StatsCard title={t("dash.activeModels")} value={overview.active_models} icon={Cpu} delay={0.15} />
<StatsCard title={t("dash.totalCost")} value={overview.total_quota / 500000} 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>
)}
@@ -104,7 +108,7 @@ export default function DashboardPage() {
))}
</div>
<div className="flex gap-1 rounded-md p-0.5" style={{ background: "var(--row-hover)", border: "1px solid var(--surface-border)" }}>
{([["total_tokens", t("metric.token")], ["calls", t("metric.calls")]] as const).map(([k, l]) => (
{([["total_tokens", t("metric.token")], ["calls", t("metric.calls")], ["quota", t("metric.cost")]] as const).map(([k, l]) => (
<button key={k} onClick={() => setTrendMetric(k)}
className="px-2.5 py-1 text-xs rounded transition-colors"
style={{