52 lines
2.8 KiB
TypeScript
52 lines
2.8 KiB
TypeScript
"use client";
|
||
|
||
import { useEffect, useState } from "react";
|
||
import { getUsageSummary } from "@/lib/admin";
|
||
import { StatusCard } from "@/components/ui";
|
||
|
||
type Summary = {
|
||
quota: { used: number; reserved: number; adjustment: number };
|
||
ledger_total: number;
|
||
tasks: { total: number; by_status: Record<string, number>; failed: number };
|
||
};
|
||
|
||
export function OverviewPanel() {
|
||
const [data, setData] = useState<Summary | null>(null);
|
||
const [error, setError] = useState("");
|
||
|
||
useEffect(() => {
|
||
getUsageSummary()
|
||
.then(setData)
|
||
.catch((e) => setError(e instanceof Error ? e.message : "无法加载概览"));
|
||
}, []);
|
||
|
||
if (error) return <div className="rounded-xl border border-danger/30 bg-danger/10 p-4 text-sm text-danger">{error}</div>;
|
||
if (!data) return <StatusCard title="正在加载概览" description="正在汇总额度与任务。" tone="info" />;
|
||
|
||
const statusLabels: Record<string, string> = { queued: "排队", running: "进行中", succeeded: "成功", failed: "失败" };
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<div className="grid gap-5 md:grid-cols-3">
|
||
<StatusCard title="累计使用" description={`${data.quota.used.toLocaleString()} 字符`} tone="success" />
|
||
<StatusCard title="冻结中" description={`${data.quota.reserved.toLocaleString()} 字符`} tone="warning" />
|
||
<StatusCard title="手动调整" description={`${data.quota.adjustment.toLocaleString()} 字符`} tone="info" />
|
||
</div>
|
||
<div className="grid gap-5 md:grid-cols-3">
|
||
<StatusCard title="任务总数" description={`${data.tasks.total}`} />
|
||
<StatusCard title={statusLabels.succeeded} description={`${data.tasks.by_status.succeeded ?? 0} 个`} tone="success" />
|
||
<StatusCard title="失败任务" description={`${data.tasks.failed} 个`} tone="warning" />
|
||
</div>
|
||
<div className="rounded-2xl border border-line bg-panel/50 p-5">
|
||
<p className="text-xs font-semibold uppercase tracking-[0.18em] text-subtle">额度对账</p>
|
||
<dl className="mt-3 grid gap-3 text-sm sm:grid-cols-3">
|
||
<div className="flex justify-between gap-4 border-b border-line pb-3 sm:border-0 sm:pb-0"><dt className="text-muted">额度账本合计</dt><dd className="text-copy">{data.ledger_total.toLocaleString()}</dd></div>
|
||
<div className="flex justify-between gap-4 sm:justify-start"><dt className="text-muted">quota_accounts.used</dt><dd className="text-copy">{data.quota.used.toLocaleString()}</dd></div>
|
||
<div className="flex justify-between gap-4 sm:justify-start"><dt className="text-muted">计入调整</dt><dd className="text-copy">{data.quota.adjustment.toLocaleString()}</dd></div>
|
||
</dl>
|
||
<p className="mt-3 text-xs leading-5 text-subtle">版本构建号会随部署更新;所有数字来自数据库流水,不包含未入账的中途值。</p>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|