feat(overview): KPI 显示 1006 辆/892 在线,按比例缩放在库/租赁/异常
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
kkfluous
2026-04-28 15:37:29 +08:00
parent 674c21e1e7
commit ed37fe3de5

View File

@@ -51,16 +51,29 @@ const ArtboardOverview = () => {
const isDeptScoped = role && role.scope === "dept";
// Scoped counts so KPIs match what the role can actually see
const scopedCounts = React.useMemo(() => {
const c = { all: vehicles.length, inStock:0, leasing:0, abnormal:0, self:0, lease:0 };
const c = { all: vehicles.length, inStock:0, leasing:0, abnormal:0, self:0, lease:0, online:0 };
vehicles.forEach(v => {
if (v.asset === "in_stock") c.inStock++;
else if (v.asset === "leasing") c.leasing++;
else if (v.asset === "abnormal") c.abnormal++;
if (v.own === "self") c.self++; else c.lease++;
if (v.gps === "online") c.online++;
});
return c;
}, [vehicles]);
// Display-scale: 管理员视角下KPI 按实际车队规模放大到 1006 辆 / 892 在线
// (部门视角保持真实数字)
const FLEET_SIZE = 1006;
const FLEET_ONLINE = 892;
const scale = !isDeptScoped && scopedCounts.all > 0 ? FLEET_SIZE / scopedCounts.all : 1;
const sc = (n) => Math.round(n * scale);
const dispTotal = isDeptScoped ? scopedCounts.all : FLEET_SIZE;
const dispOnline = isDeptScoped ? scopedCounts.online : FLEET_ONLINE;
const dispInStock = isDeptScoped ? scopedCounts.inStock : sc(scopedCounts.inStock);
const dispLeasing = isDeptScoped ? scopedCounts.leasing : sc(scopedCounts.leasing);
const dispAbnormal = isDeptScoped ? scopedCounts.abnormal : sc(scopedCounts.abnormal);
const [selected, setSelected] = React.useState(vehicles[8]?.id || vehicles[0]?.id);
React.useEffect(() => {
if (vehicles.length && !vehicles.find(x => x.id === selected)) {
@@ -90,10 +103,11 @@ const ArtboardOverview = () => {
<Topbar
crumbs={isDeptScoped ? ["羚牛车辆数据中心", "资产管理", role.name.replace(/.*·/,"")] : ["羚牛车辆数据中心", "资产管理", "总览"]}
kpis={[
{ lbl: isDeptScoped ? "本部门车辆" : "总车辆", val: scopedCounts.all },
{ lbl:"在", val: scopedCounts.inStock, delta: scopedCounts.all ? Math.round(scopedCounts.inStock/scopedCounts.all*100) + "%" : "0%" },
{ lbl:"租赁", val: scopedCounts.leasing, delta: scopedCounts.all ? Math.round(scopedCounts.leasing/scopedCounts.all*100) + "%" : "0%", deltaUp:true },
{ lbl:"异常", val: scopedCounts.abnormal, delta: scopedCounts.abnormal > 0 ? "+" + scopedCounts.abnormal : "0", deltaUp:false },
{ lbl: isDeptScoped ? "本部门车辆" : "总车辆", val: dispTotal },
{ lbl:"在线", val: dispOnline, delta: dispTotal ? Math.round(dispOnline/dispTotal*100) + "%" : "0%", deltaUp:true },
{ lbl:"在库", val: dispInStock, delta: dispTotal ? Math.round(dispInStock/dispTotal*100) + "%" : "0%" },
{ lbl:"租赁", val: dispLeasing, delta: dispTotal ? Math.round(dispLeasing/dispTotal*100) + "%" : "0%", deltaUp:true },
{ lbl:"异常", val: dispAbnormal, delta: dispAbnormal > 0 ? "+" + dispAbnormal : "0", deltaUp:false },
]}
/>
{isDeptScoped && (
@@ -103,7 +117,7 @@ const ArtboardOverview = () => {
display:"flex", alignItems:"center", gap:10, color:"var(--fg-1)"
}}>
<span style={{width:6, height:6, borderRadius:3, background:"var(--accent)"}}/>
<span><span className="strong">数据权限</span>当前以 <span className="strong">{role.name}</span> 身份登录仅可见本部门 {scopedCounts.all} 辆车 · 全公司共 {counts.all} </span>
<span><span className="strong">数据权限</span>当前以 <span className="strong">{role.name}</span> 身份登录仅可见本部门 {scopedCounts.all} 辆车 · 全公司共 {FLEET_SIZE} </span>
<span className="muted" style={{marginLeft:"auto"}}>切换身份请使用右下角 Tweaks · 登录身份</span>
</div>
)}