diff --git a/.trellis/spec/hyb-oa/frontend-react-vite-design.md b/.trellis/spec/hyb-oa/frontend-react-vite-design.md index 235d19f7..b865395d 100644 --- a/.trellis/spec/hyb-oa/frontend-react-vite-design.md +++ b/.trellis/spec/hyb-oa/frontend-react-vite-design.md @@ -44,6 +44,12 @@ classes in `client/src/index.css`: secondary actions. - `ops-table-focus` for the primary desktop table container. - `ops-inline-alert` for temporary mode hints such as batch operation notices. +- `PrimaryTable` already applies `ops-table-focus` by default; page code may + add responsive visibility classes such as `hidden md:block`, but should not + recreate a separate table frame. +- Finance/admin status summaries should prefer the shared `finance-status-strip` + and `finance-metric-card` classes unless the task introduces a new reusable + metric component. **Why**: This keeps high-frequency PC pages dense and predictable without recreating page-local Tailwind command bars. It also lets `frontend-design` @@ -67,7 +73,7 @@ change the visual treatment once while preserving component contracts. -... +... ``` **Tests Required**: diff --git a/.trellis/tasks/05-28-pc-frontend-layout-unification/check.jsonl b/.trellis/tasks/05-28-pc-frontend-layout-unification/check.jsonl new file mode 100644 index 00000000..f6122b32 --- /dev/null +++ b/.trellis/tasks/05-28-pc-frontend-layout-unification/check.jsonl @@ -0,0 +1,4 @@ +{"file": ".trellis/spec/hyb-oa/project-governance.md", "reason": "Validate Trellis workflow, scope and no production side effects"} +{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Validate frontend design contracts, tests and UI governance"} +{"file": ".trellis/tasks/archive/2026-05/05-27-oa-product-flow-test-policy-audit/research/overall-audit-matrices.md", "reason": "Validate implementation remains aligned with governance review roadmap"} +{"file": ".trellis/tasks/archive/2026-05/05-27-oa-frontend-layout-page-fit-review/research/page-layout-and-fit-review.md", "reason": "Validate page taxonomy and design direction are followed"} diff --git a/.trellis/tasks/05-28-pc-frontend-layout-unification/implement.jsonl b/.trellis/tasks/05-28-pc-frontend-layout-unification/implement.jsonl new file mode 100644 index 00000000..ec8684d7 --- /dev/null +++ b/.trellis/tasks/05-28-pc-frontend-layout-unification/implement.jsonl @@ -0,0 +1,4 @@ +{"file": ".trellis/spec/hyb-oa/project-governance.md", "reason": "Trellis task, approval and commit boundaries for implementation"} +{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Primary frontend design and verification rules for PC OA pages"} +{"file": ".trellis/tasks/archive/2026-05/05-27-oa-product-flow-test-policy-audit/research/overall-audit-matrices.md", "reason": "Governance review conclusions and execution roadmap"} +{"file": ".trellis/tasks/archive/2026-05/05-27-oa-frontend-layout-page-fit-review/research/page-layout-and-fit-review.md", "reason": "Page taxonomy, fit matrix and frontend design direction"} diff --git a/.trellis/tasks/05-28-pc-frontend-layout-unification/implement.md b/.trellis/tasks/05-28-pc-frontend-layout-unification/implement.md new file mode 100644 index 00000000..68c771c6 --- /dev/null +++ b/.trellis/tasks/05-28-pc-frontend-layout-unification/implement.md @@ -0,0 +1,60 @@ +# 实施方案 + +## 推荐方案 + +采用“共享模板先行 + 重点页面收敛”的方式,而不是逐页重画。 + +1. 盘点现有 PC 页面是否已经使用 `ListWorkspace`、`WorkspaceHeader`、`FilterBar`、`PrimaryTable`、`PageScaffold` 和 `ops-*` / `finance-*` / `admin-*`。 +2. 先补共享层: + - 统一页面宽度、标题层级、标题动作区、统计条密度、命令区间距、表格容器边界。 + - 保持现有 class contract,不破坏已经通过 Wave2-Wave4 的页面。 +3. 再改重点页面: + - 工作台:突出今日动作和待办,折叠低频入口。 + - 报销/审批:列表统一筛选和主表,详情统一摘要、票据/附件、审批、付款/证据四区。 + - 财务/AP/票据池:保留高密,但统一统计、操作面板和表格焦点。 + - C 类管理页:统一统计条、命令区、表格、空状态,减少页面说明。 +4. 最后做视觉与交互验证: + - typecheck/build + - UI design rules + - focused Playwright + - 必要时用截图检查桌面和移动响应式。 + +## 风险控制 + +- 不动业务数据流、接口、权限、审批状态机和数据库。 +- 不把“视觉优化”变成流程重构。 +- 不新增重复 UI 系统;优先复用已有 pattern 和 CSS class。 +- 高风险动作只调整位置和呈现,不取消二次确认。 + +## 第一批文件候选 + +实际实现前再按代码确认,候选区域包括: + +- `client/src/components/patterns/` +- `client/src/index.css` +- `client/src/pages/PortalHomePage.tsx` +- `client/src/pages/ReimbursementsPage.tsx` +- `client/src/pages/ReimbursementDetailPage.tsx` +- `client/src/pages/WorkflowTasksPage.tsx` +- `client/src/pages/WorkflowTaskDetailPage.tsx` +- `client/src/pages/InvoicePoolPage.tsx` +- `client/src/pages/PaymentBatchesPage.tsx` +- `client/src/pages/ApOperationsPage.tsx` +- `client/src/pages/UserManagementPage.tsx` +- `client/src/pages/MasterDataPage.tsx` +- `client/src/pages/FeatureFlagsPage.tsx` +- `client/src/pages/NotificationChannelsPage.tsx` +- `client/src/pages/AuditLogsPage.tsx` + +## 不做事项 + +- 不新增登录、邮箱、企业微信功能。 +- 不接发票验真真实 provider。 +- 不改制度签收、用印台账、采购比价或审批阈值。 +- 不部署公网。 + +## 完成记录 + +- 共享层:收敛 `theme.css` 半径、`ListWorkspace` 标题/筛选/表格密度、`index.css` 的 `ops-*`、`finance-*`、`admin-*` 和 Portal 类。 +- 页面层:压缩 Portal 工作台文案与面板密度,系统设置改为带图标的管理入口卡片,报销批量操作、详情错误态、主数据/功能开关/通知渠道间距统一。 +- 验证:typecheck、build、UI design rules、Trellis governance、Wave2/Wave4 focused Playwright 均通过。 diff --git a/.trellis/tasks/05-28-pc-frontend-layout-unification/prd.md b/.trellis/tasks/05-28-pc-frontend-layout-unification/prd.md new file mode 100644 index 00000000..f2123880 --- /dev/null +++ b/.trellis/tasks/05-28-pc-frontend-layout-unification/prd.md @@ -0,0 +1,105 @@ +# PC 前端布局统一改造 + +## Goal + +在 OAOPS1 真实试运行并行推进的前提下,启动第一批实施类改造:统一 PC 页面布局、信息密度、命令区、表格/列表和详情区体验,降低“页面啰嗦、操作复杂、风格不统一”的用户体感问题。视觉裁决以 `frontend-design` 为准,但 OA 业务系统保持克制、密集、清晰的工作台风格。 + +## What I Already Know + +- OAOPS1 七天真实试运行仍是独立并行主线,不因本任务暂停。 +- 已归档审查结论建议第一批实施优先做 PC 前端布局统一,移动和流程规则后置。 +- 前端已有 Wave2-Wave4 基础,不能再做一次大而全重构。 +- 现有代码已经有可复用模式:`ListWorkspace`、`WorkspaceHeader`、`FilterBar`、`PrimaryTable`、`PageScaffold`、`EntityOverviewHero`、`SectionPanel`、`ops-*`、`detail-*`、`finance-*`、`admin-*`。 +- `frontend-design` 要求界面有明确设计方向;本任务的方向是“安静、精密、运营型 OA 工作台”,不是营销页、装饰页或大面积视觉噱头。 + +## Assumptions + +- 第一批优先 PC,不改移动主体验,除非发现 PC 改动破坏移动响应式。 +- 优先通过共享组件和共享 CSS class 收敛,不给每个页面各写一套新样式。 +- 本任务不改变审批、报销、付款、发票、权限、企业微信或后端业务规则。 +- 不做生产部署,除非完成本地验证后另行获得明确批准。 + +## Scope + +- PC 工作台、列表页、详情页、财务密集页和 C 类管理页的布局统一。 +- 共享前端 pattern、CSS class、页面容器、命令区、表格/列表容器和视觉密度调整。 +- 必要的 focused Playwright、typecheck、build 和 UI governance 验证。 +- 仅限前端展示层,不触碰业务规则、后端接口、数据库和生产配置。 + +## Requirements + +- 固化 PC 页面模板: + - 工作台:今日动作、待办、常用入口、异常提示,不做模块橱窗。 + - 列表页:`ListWorkspace + WorkspaceHeader + FilterBar + PrimaryTable + ops-*`。 + - 详情页:`PageScaffold + EntityOverviewHero + SectionPanel + detail-*`。 + - 财务密集页:`finance-* + ops-table-focus`,保留高密度但减少说明型文案。 + - 管理 C 类页:`admin-* + ops-*`,统一命令区和表格密度。 +- 第一批页面范围优先覆盖: + - `/portal` + - 报销列表与详情 + - 审批中心与审批详情 + - 票据池、付款批次、AP + - 系统设置、用户管理、主数据、功能开关、通知渠道、审计日志 +- 压缩页面文案:删除重复说明、弱化低频帮助文本,把复杂说明移到空状态、错误态或二次确认。 +- 统一操作区:主动作靠近页面标题或当前记录,危险/高风险动作必须保留二次确认。 +- 统一表格密度和状态展示:状态、金额、时间、人员、异常原因位置稳定。 +- 保持现有权限、路由、接口、feature flag、测试数据过滤和安全边界不变。 + +## Acceptance Criteria + +- [x] 关键 PC 页面采用统一页面骨架、命令区、表格/列表和详情模式。 +- [x] 页面文案明显收敛,不再出现重复说明型段落或页面级帮助堆叠。 +- [x] 财务/AP/票据池仍保持高密度操作效率,危险操作保留确认和审计提示。 +- [x] 管理页命令区、统计条、表格容器和空状态保持一致。 +- [x] 不改变后端接口、数据库、权限模型、审批规则、企业微信配置或生产配置。 +- [x] `cd client && npm run typecheck && npm run build` 通过。 +- [x] `node scripts/qa/check-ui-design-rules.mjs` 通过。 +- [x] 至少运行 focused Playwright 覆盖 PC 关键页,必要时补截图/交互证据。 + +## Definition of Done + +- 改造范围内页面在桌面宽度下没有明显布局漂移、文字挤压、操作区混乱或卡片套卡片。 +- 移动响应式没有被 PC 改造破坏。 +- 本地验证通过;如果用户要求可测,再获得部署批准后执行公网验证。 +- Trellis task 校验和治理检查通过。 +- 提交信息使用中文并引用本任务 ID。 + +## Out of Scope + +- 不重写整套设计系统。 +- 不改移动端业务主体验。 +- 不改业务流程、审批阈值、付款规则、发票验真 provider、权限模型或数据库 schema。 +- 不采购、部署或改生产配置。 +- 不把官网营销视觉照搬到 OA 工作台。 + +## Test Plan + +```bash +cd client && npm run typecheck +cd client && npm run build +node scripts/qa/check-ui-design-rules.mjs +python3 ./.trellis/scripts/task.py validate 05-28-pc-frontend-layout-unification +node scripts/qa/check-trellis-governance.mjs +git diff --check +``` + +Focused Playwright 根据最终修改页面选择,优先覆盖: + +```bash +cd client && npx playwright test tests/e2e/login-portal-ux.spec.ts +cd client && npx playwright test tests/e2e/workflow-*.spec.ts +cd client && npx playwright test tests/e2e/reimbursement-payment-batch-flow.spec.ts +cd client && npx playwright test tests/e2e/invoice-ocr-flow.spec.ts +``` + +## Technical Notes + +- Frontend spec: `.trellis/spec/hyb-oa/frontend-react-vite-design.md` +- Project governance: `.trellis/spec/hyb-oa/project-governance.md` +- Prior审查: `.trellis/tasks/archive/2026-05/05-27-oa-product-flow-test-policy-audit/research/overall-audit-matrices.md` +- 页面专项审查: `.trellis/tasks/archive/2026-05/05-27-oa-frontend-layout-page-fit-review/research/page-layout-and-fit-review.md` +- Likely shared code: `client/src/components/patterns/`、`client/src/index.css`、`client/src/design/` + +## Completion Note + +2026-05-28:已完成第一批 PC 布局统一改造。改动集中在共享 pattern/CSS、Portal、报销/审批详情、系统设置、主数据、功能开关和通知渠道等展示层;没有修改后端接口、数据库、权限、审批规则或生产配置。 diff --git a/.trellis/tasks/05-28-pc-frontend-layout-unification/task.json b/.trellis/tasks/05-28-pc-frontend-layout-unification/task.json new file mode 100644 index 00000000..08c66626 --- /dev/null +++ b/.trellis/tasks/05-28-pc-frontend-layout-unification/task.json @@ -0,0 +1,26 @@ +{ + "id": "pc-frontend-layout-unification", + "name": "pc-frontend-layout-unification", + "title": "PC前端布局统一改造", + "description": "在OAOPS1真实试运行并行推进的前提下,统一PC页面布局、信息密度、命令区、表格/列表和详情区体验。", + "status": "in_progress", + "dev_type": null, + "scope": "frontend-pc-layout", + "package": "client", + "priority": "P2", + "creator": "shunli", + "assignee": "shunli", + "createdAt": "2026-05-28", + "completedAt": null, + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": null, + "relatedFiles": [], + "notes": "", + "meta": {} +} \ No newline at end of file diff --git a/client/src/components/patterns/EntityOverviewHero.tsx b/client/src/components/patterns/EntityOverviewHero.tsx index 019cf2b3..1793ea94 100644 --- a/client/src/components/patterns/EntityOverviewHero.tsx +++ b/client/src/components/patterns/EntityOverviewHero.tsx @@ -18,7 +18,7 @@ export function EntityOverviewHero({ {subtitle ?

{subtitle}

: null} {meta ?
{meta}
: null} - {actions ?
{actions}
: null} + {actions ?
{actions}
: null} ); } diff --git a/client/src/components/patterns/ListWorkspace.tsx b/client/src/components/patterns/ListWorkspace.tsx index 4258be8f..14b43a54 100644 --- a/client/src/components/patterns/ListWorkspace.tsx +++ b/client/src/components/patterns/ListWorkspace.tsx @@ -21,20 +21,20 @@ export function ListWorkspace({ className, children }: WorkspaceChildrenProps) { export function WorkspaceHeader({ eyebrow, title, subtitle, meta, actions, className }: WorkspaceHeaderProps) { return ( -
+
{eyebrow ?
{eyebrow}
: null} -

{title}

- {subtitle ?
{subtitle}
: null} - {meta ?
{meta}
: null} +

{title}

+ {subtitle ?
{subtitle}
: null} + {meta ?
{meta}
: null}
- {actions ?
{actions}
: null} + {actions ?
{actions}
: null}
); } export function FilterBar({ className, children }: WorkspaceChildrenProps) { - return
{children}
; + return
{children}
; } export function FilterGrid({ className, children }: WorkspaceChildrenProps) { @@ -66,7 +66,7 @@ export function WorkspaceSection({ actions?: ReactNode; }) { return ( -
+
{title || description || actions ? (
@@ -86,7 +86,7 @@ export function ActionToolbar({ className, children }: WorkspaceChildrenProps) { } export function PrimaryTable({ className, children }: WorkspaceChildrenProps) { - return
{children}
; + return
{children}
; } export function WorkspaceEmptyState({ @@ -97,7 +97,7 @@ export function WorkspaceEmptyState({ children?: ReactNode; }) { return ( -
+
{children}
); @@ -123,7 +123,7 @@ export function WorkspaceNotice({ }[tone]; return ( -
+
{title}
diff --git a/client/src/design/theme.css b/client/src/design/theme.css index 78c92c07..23af92eb 100644 --- a/client/src/design/theme.css +++ b/client/src/design/theme.css @@ -20,10 +20,10 @@ --color-info: #00398a; --radius-sm: 0.5rem; --radius-md: 0.75rem; - --radius-lg: 1rem; - --radius-xl: 1rem; + --radius-lg: 0.75rem; + --radius-xl: 0.875rem; --radius-2xl: 1.25rem; - --radius-panel: 1rem; + --radius-panel: 0.75rem; --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.05); --shadow-sm: 0 4px 14px rgba(15, 23, 42, 0.055), 0 1px 2px rgba(15, 23, 42, 0.04); --shadow-md: 0 14px 34px rgba(0, 57, 138, 0.10); diff --git a/client/src/index.css b/client/src/index.css index 710aabaf..f20a78db 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -46,7 +46,7 @@ .page-scaffold { animation: page-reveal 320ms ease-out both; - @apply space-y-5; + @apply space-y-4 md:space-y-5; } .auth-shell { @@ -119,7 +119,7 @@ border: 1px solid rgba(226, 232, 240, 0.92); border-radius: var(--radius-panel); box-shadow: var(--shadow-xs); - @apply flex flex-col gap-4 px-5 py-5 md:flex-row md:items-end md:justify-between md:px-6; + @apply flex flex-col gap-4 px-4 py-4 md:flex-row md:items-end md:justify-between md:px-5 md:py-4; } .ops-status-strip { @@ -129,7 +129,7 @@ .ops-status-strip .metric-card { border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); - @apply px-3.5 py-3.5; + @apply min-h-[92px] px-3.5 py-3; } .ops-status-strip .metric-card::before { @@ -153,7 +153,7 @@ border-radius: var(--radius-lg); background: rgba(255, 255, 255, 0.94); box-shadow: var(--shadow-xs); - @apply p-3 md:p-3.5; + @apply p-3; } .ops-command-bar__row { @@ -168,6 +168,11 @@ @apply flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end; } + .ops-command-bar__actions > .select-sm, + .ops-command-bar__actions > .select-std { + min-width: 9rem; + } + .ops-filter-label { color: var(--color-text-secondary); @apply text-xs font-semibold; @@ -181,6 +186,8 @@ .ops-table-focus { border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); + border: 1px solid rgba(226, 232, 240, 0.94); + background: rgba(255, 255, 255, 0.98); } .ops-table-focus table { @@ -195,13 +202,13 @@ .ops-table-focus th, .ops-table-focus .table-th { color: var(--color-text-tertiary); - @apply px-4 py-3 text-xs font-semibold; + @apply px-3.5 py-2.5 text-xs font-semibold; } .ops-table-focus td, .ops-table-focus .table-td, .ops-table-focus .table-td-strong { - @apply px-4 py-3 text-sm; + @apply px-3.5 py-2.5 text-sm; } .ops-table-focus tbody tr:hover { @@ -238,7 +245,7 @@ } .workbench-hero--compact { - @apply gap-4 px-5 py-5 md:px-6 md:py-6; + @apply gap-4 px-4 py-4 md:px-5 md:py-5; } .workbench-hero--compact .workbench-hero__title { @@ -275,7 +282,7 @@ .section-panel { position: relative; overflow: hidden; - @apply p-4 md:p-5; + @apply p-3.5 md:p-4; } .section-panel::before { @@ -311,7 +318,7 @@ border: 1px solid rgba(226, 232, 240, 0.96); border-radius: var(--radius-panel); box-shadow: var(--shadow-xs); - @apply block px-4 py-4 transition duration-150 hover:border-slate-300 hover:bg-white; + @apply block px-3.5 py-3.5 transition duration-150 hover:border-slate-300 hover:bg-white; } .metric-card::before { @@ -348,12 +355,12 @@ .metric-card__value { color: var(--color-text-primary); - @apply mt-2 text-xl font-semibold tracking-tight; + @apply mt-1.5 text-xl font-semibold tracking-tight; } .metric-card__note { color: var(--color-text-secondary); - @apply mt-2 text-sm leading-6; + @apply mt-1.5 text-sm leading-6; } .info-chip { @@ -393,7 +400,7 @@ .table-container { border-color: rgba(226, 232, 240, 0.92); background: var(--color-bg-surface-raised); - @apply overflow-hidden rounded-2xl border shadow-sm backdrop-blur; + @apply overflow-hidden rounded-lg border shadow-sm backdrop-blur; } .table-header { @@ -537,7 +544,7 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.88)); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); - @apply border p-4; + @apply min-h-[92px] border p-3.5; } .finance-metric-card__label { @@ -547,7 +554,7 @@ .finance-metric-card__value { color: var(--color-text-primary); - @apply mt-2 text-2xl font-bold; + @apply mt-1.5 text-xl font-semibold; } .finance-workspace-grid { @@ -559,7 +566,7 @@ background: rgba(255, 255, 255, 0.97); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); - @apply border p-4 md:p-5; + @apply border p-3.5 md:p-4; } .finance-list-card { @@ -580,11 +587,11 @@ linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.9)); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); - @apply border p-4 md:p-5; + @apply border p-3.5 md:p-4; } .admin-tile-grid { - @apply grid gap-4 md:grid-cols-2 xl:grid-cols-3; + @apply grid gap-3 md:grid-cols-2 xl:grid-cols-4; } .admin-tile-card { @@ -592,7 +599,13 @@ background: rgba(255, 255, 255, 0.96); border-radius: var(--radius-lg); box-shadow: var(--shadow-xs); - @apply border p-4 transition-colors hover:border-slate-300 hover:bg-slate-50/60 md:p-5; + @apply border p-3.5 transition-colors hover:border-slate-300 hover:bg-slate-50/60 md:p-4; + } + + .admin-tile-card__icon { + background: rgba(0, 57, 138, 0.08); + color: var(--color-accent-primary); + @apply flex size-9 shrink-0 items-center justify-center rounded-lg; } .admin-workspace-grid { @@ -622,11 +635,11 @@ } .portal-home-grid { - @apply grid gap-5 xl:grid-cols-[minmax(0,2fr),minmax(320px,0.92fr)] xl:items-stretch; + @apply grid gap-4 xl:grid-cols-[minmax(0,1.72fr),minmax(300px,0.86fr)] xl:items-stretch; } .portal-home-grid--collaboration { - @apply xl:grid-cols-[minmax(0,1.55fr),minmax(320px,0.9fr)]; + @apply xl:grid-cols-[minmax(0,1.42fr),minmax(300px,0.92fr)]; } .portal-panel-fill { @@ -638,7 +651,7 @@ border: 1px solid rgba(226, 232, 240, 0.94); border-radius: var(--radius-sm); box-shadow: var(--shadow-xs); - @apply block px-3.5 py-3 transition duration-150; + @apply block px-3 py-2.5 transition duration-150; } .portal-list-card:hover { @@ -666,7 +679,7 @@ border: 1px solid rgba(226, 232, 240, 0.94); border-radius: var(--radius-sm); box-shadow: var(--shadow-xs); - @apply px-3 py-3 text-left transition duration-150; + @apply px-3 py-2.5 text-left transition duration-150; } .portal-action-tile:hover { @@ -700,7 +713,7 @@ background: rgba(255, 255, 255, 0.92); border: 1px solid rgba(226, 232, 240, 0.94); border-radius: var(--radius-sm); - @apply px-3.5 py-3; + @apply px-3 py-2.5; } .portal-team-list { @@ -728,7 +741,7 @@ } .portal-secondary-drawer { - @apply p-3.5 md:p-4; + @apply p-3 md:p-3.5; } .portal-secondary-summary { @@ -749,7 +762,7 @@ } .portal-compact-group { - @apply rounded-lg border border-slate-200 bg-white/80 px-3.5 py-3; + @apply rounded-lg border border-slate-200 bg-white/80 px-3 py-2.5; } .portal-compact-group__title { diff --git a/client/src/pages/FeatureFlagsPage.tsx b/client/src/pages/FeatureFlagsPage.tsx index 64d0c83a..914137f6 100644 --- a/client/src/pages/FeatureFlagsPage.tsx +++ b/client/src/pages/FeatureFlagsPage.tsx @@ -685,7 +685,7 @@ export function FeatureFlagsPage() {

) : null} {!impactQuery.isLoading && !impactQuery.isError && impactQuery.data ? ( -
+

前端导航

{impactQuery.data.navigationItems.length ? ( @@ -793,7 +793,7 @@ export function FeatureFlagsPage() { {batchMode ? ( -
+
已选择 {selectedItems.length} 个功能开关 diff --git a/client/src/pages/MasterDataPage.tsx b/client/src/pages/MasterDataPage.tsx index ea447205..4c42c008 100644 --- a/client/src/pages/MasterDataPage.tsx +++ b/client/src/pages/MasterDataPage.tsx @@ -341,7 +341,7 @@ export function MasterDataPage() { 供应商 - +

法体筛选

@@ -454,7 +454,7 @@ export function MasterDataPage() {
- +
- + - + -
+
diff --git a/client/src/pages/PortalHomePage.tsx b/client/src/pages/PortalHomePage.tsx index 62e54342..5f9ea488 100644 --- a/client/src/pages/PortalHomePage.tsx +++ b/client/src/pages/PortalHomePage.tsx @@ -524,7 +524,7 @@ function AdoptionSummaryPanel({ adoptionSummary }: { adoptionSummary: NonNullabl
{adoptionSummary.announcementCount}
-
+
本周观测提示
    {adoptionSummary.hints.map((hint) => ( @@ -589,7 +589,7 @@ function GettingStartedCard({ return ( ))} -
    +
    完成进度 {completedCount}/{items.length} @@ -726,10 +726,10 @@ function TodoAggregatePanel({ items }: { items: TodoAggregateItem[] }) {
    {item.icon}
    @@ -896,14 +896,14 @@ export function PortalHomePage() { const gettingStartedCompletedCount = gettingStartedItems.filter((item) => item.completed).length; if (portalQuery.isLoading) { - return
    加载工作台中...
    ; + return
    加载工作台中...
    ; } if (portalQuery.isError || !portalQuery.data) { const message = isApiError(portalQuery.error) ? `${portalQuery.error.code}: ${mapApiErrorMessage(portalQuery.error.code, portalQuery.error.details, portalQuery.error.message)}` : "工作台加载失败"; - return
    {message}
    ; + return
    {message}
    ; } const payload = portalQuery.data; @@ -1096,8 +1096,8 @@ export function PortalHomePage() { quickActions.push({ key: "attendance", icon: "schedule", - label: "考勤汇总", - description: "企微摘要 / OA 修正", + label: "考勤", + description: "企微摘要", to: "/attendance", }); if (payload.weeklyReport || payload.weeklySummary) { @@ -1105,7 +1105,7 @@ export function PortalHomePage() { key: "weekly", icon: "article", label: "提交周报", - description: "填写 / 查看缺口", + description: "填写 / 缺口", to: "/weekly-reports", }); } @@ -1161,7 +1161,7 @@ export function PortalHomePage() { fallback={( )} > @@ -1205,9 +1205,9 @@ export function PortalHomePage() { <> -
    +
    {roleCapabilities.canApproveTasks ? ( ) : null} @@ -1243,7 +1243,7 @@ export function PortalHomePage() { ) : (
    diff --git a/client/src/pages/ReimbursementDetailPage.tsx b/client/src/pages/ReimbursementDetailPage.tsx index 1afbd4e0..09bd0d07 100644 --- a/client/src/pages/ReimbursementDetailPage.tsx +++ b/client/src/pages/ReimbursementDetailPage.tsx @@ -740,7 +740,7 @@ export function ReimbursementDetailPage() { if (!reimbursementId) { return ( -
    +

    缺少 reimbursementId 参数。

    ); @@ -760,7 +760,7 @@ export function ReimbursementDetailPage() { : "加载报销详情失败"; return ( -
    +

    {message}