// artboard-overview.jsx — Asset-management overview // Filter by: 资产状态 / 部门 / 归属 // Card shows: 车牌 + VIN + 城市 + 部门 + 客户 + 资产状态 // Detail shows: 资产档案 + 业务关系 + 实时车况 + 保养预警 (no driver) const AssetStatusChip = ({ status }) => { const map = { in_stock: { label: "在库", bg: "var(--accent-soft)", fg: "var(--accent)", dot: "ok" }, leasing: { label: "租赁" , bg: "rgba(46,140,140,0.15)",fg: "var(--info)", dot: "info" }, abnormal: { label: "异常", bg: "var(--danger-soft)", fg: "var(--danger)", dot: "danger" }, }; const m = map[status] || map.in_stock; return ( {m.label} ); }; const OwnChip = ({ own }) => ( {own === "self" ? "自有" : "外租"} ); const DeptDot = ({ dept }) => { const d = (window.DEPARTMENTS || []).find(x => x.id === dept); if (!d) return null; return ( {d.name} ); }; const ArtboardOverview = () => { const allVehicles = (window.VEHICLES || []); const { role } = (typeof window.useCurrentRole === "function") ? window.useCurrentRole() : { role: null }; // Apply role-based scope before user-facing filters const vehicles = React.useMemo(() => { if (!role || role.scope === "all" || role.scope === "ops" || role.scope === "finance") return allVehicles; if (role.scope === "dept") return allVehicles.filter(v => v.dept === role.deptId); return allVehicles; }, [role, allVehicles]); const counts = (window.COUNTS || {}); const deps = (window.DEPARTMENTS || []); 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 }; 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++; }); return c; }, [vehicles]); const [selected, setSelected] = React.useState(vehicles[8]?.id || vehicles[0]?.id); React.useEffect(() => { if (vehicles.length && !vehicles.find(x => x.id === selected)) { setSelected(vehicles[0].id); } }, [vehicles, selected]); const [filterAsset, setFilterAsset] = React.useState("all"); // all | in_stock | leasing | abnormal const [filterDept, setFilterDept] = React.useState("all"); const [filterOwn, setFilterOwn] = React.useState("all"); const [search, setSearch] = React.useState(""); const filtered = vehicles.filter(v => { if (filterAsset !== "all" && v.asset !== filterAsset) return false; if (filterDept !== "all" && v.dept !== filterDept) return false; if (filterOwn !== "all" && v.own !== filterOwn) return false; if (search && !v.plate.includes(search) && !v.vin.includes(search)) return false; return true; }); const v = vehicles.find(x => x.id === selected) || vehicles[0]; if (!v) return null; return (