import { useEffect, useState } from "react"; import { api, ApiError } from "../api"; import type { AdminStats } from "../types"; import { BarChart3, Package, CheckCircle2, Tag, FolderTree, Inbox } from "lucide-react"; const STATUS_LABEL: Record = { active: "在用", merged: "已合并", deprecated: "已停用", }; function Card({ icon, label, value, hint, }: { icon: React.ReactNode; label: string; value: string | number; hint?: string; }) { return (
{icon} {label}
{value}
{hint &&
{hint}
}
); } export default function StatsPage() { const [stats, setStats] = useState(null); const [error, setError] = useState(""); useEffect(() => { api .stats() .then(setStats) .catch((e) => setError(e instanceof ApiError ? e.message : "加载失败")); }, []); return (

数据概览

{error && (
{error}
)} {!stats ? (
加载中…
) : ( <>
} label="商品总数" value={stats.products.toLocaleString()} /> } label="合格档案" value={stats.qualified.toLocaleString()} hint={`质量分 ≥ ${stats.min_score} 且在用`} /> } label="平均质量分" value={Math.round(stats.avg_quality * 100)} hint="满分 100" /> } label="品牌数" value={stats.brands.toLocaleString()} /> } label="分类数" value={stats.categories.toLocaleString()} /> } label="待审核投稿" value={stats.pending_submissions.toLocaleString()} />

按状态分布

{Object.keys(stats.by_status).length === 0 ? (
暂无数据
) : ( Object.entries(stats.by_status).map(([st, n]) => { const pct = stats.products > 0 ? (n / stats.products) * 100 : 0; return (
{STATUS_LABEL[st] || st}
{n}
); }) )}
)}
); }