diff --git a/frontend/src/pages/home/HomePage/HomePage.module.css b/frontend/src/pages/home/HomePage/HomePage.module.css new file mode 100644 index 0000000..4b3a4e2 --- /dev/null +++ b/frontend/src/pages/home/HomePage/HomePage.module.css @@ -0,0 +1,193 @@ +/* REQ-USR-003: 主页 scoped 样式。语义色用 var(--color-*);网格线/底色经 token。 */ + +.home { + display: grid; + grid-template-columns: 1fr 280px; + gap: 10px; + padding: 10px; + min-height: 100%; +} + +.mainCol { + display: flex; + flex-direction: column; + gap: 10px; + min-width: 0; +} + +.panel { + background: var(--color-form-bg-edit); + border: 1px solid var(--color-border); + border-radius: 2px; +} + +/* ===== KPI head bar ===== */ +.kpiHead { + padding: 14px 18px; + display: flex; + align-items: center; + gap: 24px; + flex-wrap: wrap; +} +.kpiHeadTitle { + font-size: 15px; + font-weight: 500; + color: var(--color-text); + margin-right: 6px; +} +.kpiStat { + color: var(--color-text-secondary); +} +.kpiStat b { + color: var(--color-error); + font-weight: 500; + margin-left: 6px; + font-size: 14px; +} +.kpiStatBlue b { + color: var(--color-primary); +} +.kpiSep { + color: var(--color-border); +} +.aiBtn { + margin-left: auto; +} + +/* ===== three-col layout ===== */ +.threeCol { + display: grid; + grid-template-columns: 280px 1fr; + gap: 10px; + min-height: 0; +} +.leftNav { + background: var(--color-form-bg-edit); + border: 1px solid var(--color-border); + overflow: auto; + max-height: 70vh; +} +.center { + display: flex; + flex-direction: column; + gap: 10px; + min-width: 0; +} + +/* ===== role / process tree ===== */ +.tree { + padding: 6px 0; +} +.treeGroup { + padding: 8px 14px; + color: var(--color-text); + font-size: 13px; + font-weight: 500; + display: flex; + align-items: center; + gap: 6px; +} +.treeItem { + padding: 6px 14px 6px 36px; + display: flex; + align-items: center; + gap: 8px; + color: var(--color-text); + cursor: pointer; + font-size: 13px; + border: none; + background: transparent; + width: 100%; + text-align: left; +} +.treeItem:hover { + background: var(--color-table-row-bg-hover); +} +.treeItemActive { + background: var(--color-table-row-bg-selected); + color: var(--color-text); +} + +/* ===== KPI merged grid (复刻原型 kpi-body) ===== */ +.kpiBoard { + display: grid; + grid-template-columns: 200px 90px 1fr 1fr 90px 90px 130px; + border-top: 1px solid var(--color-border); + overflow: auto; +} +.kpiBoard > div { + border-right: 1px solid var(--color-border); + border-bottom: 1px solid var(--color-border); + padding: 10px 12px; + font-size: 13px; + min-height: 38px; + display: flex; + align-items: center; +} +.kpiHeadCell { + background: var(--color-table-header-bg); + font-weight: 500; + color: var(--color-table-header-fg); + padding: 9px 12px; +} +.kpiNavType { + justify-content: center; +} +.kpiCellCenter { + justify-content: center; +} +.kpiLink { + color: var(--color-primary); + cursor: pointer; +} +.kpiLink:hover { + text-decoration: underline; +} +.kpiNum { + justify-content: center; +} +.kpiNumRed { + color: var(--color-error); + font-weight: 600; +} +.kpiSubProc { + writing-mode: vertical-rl; + text-orientation: upright; + color: var(--color-text); + font-weight: 500; + justify-content: center; +} +.kpiRowAlt { + background: var(--color-form-bg-readonly); +} +.kpiEmpty { + padding: 32px 0; + display: flex; + justify-content: center; +} + +/* ===== common ops ===== */ +.commonOps { + padding: 14px 18px; + height: fit-content; +} +.commonOpsTitle { + font-size: 14px; + color: var(--color-text); + margin-bottom: 14px; + font-weight: 500; +} +.commonOpsLink { + display: block; + color: var(--color-primary); + padding: 8px 0; + font-size: 13px; + border: none; + background: transparent; + cursor: pointer; + text-align: left; + width: 100%; +} +.commonOpsLink:hover { + text-decoration: underline; +} diff --git a/frontend/src/pages/home/HomePage/KpiBoard.tsx b/frontend/src/pages/home/HomePage/KpiBoard.tsx new file mode 100644 index 0000000..09d27bf --- /dev/null +++ b/frontend/src/pages/home/HomePage/KpiBoard.tsx @@ -0,0 +1,131 @@ +// 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 ( +
与 svg