52 lines
2.0 KiB
TypeScript
52 lines
2.0 KiB
TypeScript
import { useEffect, useState } from "react";
|
||
import { api, type DashboardSummary } from "./api";
|
||
import { L, confidenceLabel, scenarioLabel, statusLabel } from "./labels";
|
||
|
||
export default function Dashboard() {
|
||
const [data, setData] = useState<DashboardSummary | null>(null);
|
||
const [err, setErr] = useState<string>("");
|
||
|
||
useEffect(() => {
|
||
api.summary().then(setData).catch((e) => setErr(String(e)));
|
||
}, []);
|
||
|
||
if (err) return <div className="error">加载失败:{err}(请确认后端已启动)</div>;
|
||
if (!data) return <div className="status">加载中…</div>;
|
||
|
||
const wan = (data.total_amount_involved / 10000).toFixed(1);
|
||
return (
|
||
<div>
|
||
<div className="cards">
|
||
<div className="card"><div className="k">线索总数</div><div className="v">{data.total}</div></div>
|
||
<div className="card"><div className="k">高置信</div><div className="v" style={{ color: "var(--high)" }}>{data.by_confidence.high ?? 0}</div></div>
|
||
<div className="card"><div className="k">涉及金额(万元)</div><div className="v">{wan}</div></div>
|
||
<div className="card"><div className="k">场景数</div><div className="v">{Object.keys(data.by_scenario).length}</div></div>
|
||
</div>
|
||
<div className="panel">
|
||
<h3>按状态分布</h3>
|
||
<div className="row">
|
||
{Object.entries(data.by_status).map(([k, v]) => (
|
||
<span key={k} className="tag">{L(statusLabel, k)}: {v}</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="panel">
|
||
<h3>按场景分布</h3>
|
||
<div className="row">
|
||
{Object.entries(data.by_scenario).map(([k, v]) => (
|
||
<span key={k} className="tag">{k} {L(scenarioLabel, k)}: {v}</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="panel">
|
||
<h3>按置信度分布</h3>
|
||
<div className="row">
|
||
{Object.entries(data.by_confidence).map(([k, v]) => (
|
||
<span key={k} className="tag">{L(confidenceLabel, k)}: {v}</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|