// REQ-USR-003: KPI 合并网格(D5:CSS Grid gridRow span 复刻原型 kpi-body 合并)。 // 「导航类型」整列一格跨全部行;「角色」「子流程」按 roleSpan/subSpan 合并;空数据 → Empty。 import { Empty } from 'antd'; import type { KpiRow } from './dashboardData'; import { KPI_HEADERS } from './dashboardData'; import styles from './HomePage.module.css'; interface KpiBoardProps { rows: KpiRow[]; /** KPI 待处理事项/描述为纯展示(蓝色链接样式),点击不跳转;保留占位以示意无导航。 */ onNavigate?: (target: string) => void; } export default function KpiBoard({ rows }: KpiBoardProps) { if (!rows.length) { return (
); } const total = rows.length; // 表头行 = 第 1 行;数据行从第 2 行起 const cells: React.ReactNode[] = []; // 表头 7 列 KPI_HEADERS.forEach((h, i) => { cells.push(
{h}
, ); }); // 导航类型:整列一格,跨全部数据行(复刻原型 navCell '按角色') cells.push(
按角色
, ); rows.forEach((row, idx) => { const curRow = idx + 2; const alt = idx % 2 === 1 ? styles.kpiRowAlt : ''; // 角色(带 rowSpan) if (row.role) { const span = row.roleSpan ?? 1; cells.push(
{row.role}
, ); } // KPI 待处理事项(蓝色链接样式,纯展示) cells.push(
{row.item}
, ); // KPI 内容描述(蓝色链接样式,纯展示) cells.push(
{row.desc}
, ); // 今日未处理 cells.push(
{row.today}
, ); // 未清总数 cells.push(
{row.total}
, ); // 子流程(带 rowSpan) if (row.sub && row.subSpan) { cells.push(
{row.sub}
, ); } }); return (
{cells}
); }