From 8f38687186187751f3ed95c35d45ca9660cb452e Mon Sep 17 00:00:00 2001 From: shunli Date: Thu, 28 May 2026 23:03:40 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=89=8D=E7=AB=AF=20Wave0-2?= =?UTF-8?q?=20=E4=BD=93=E9=AA=8C=E5=9F=BA=E7=BA=BF=EF=BC=8805-28-frontend-?= =?UTF-8?q?ux-redesign=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spec/hyb-oa/frontend-react-vite-design.md | 39 ++++ .../05-28-frontend-ux-redesign/check.jsonl | 3 + .../implement.jsonl | 3 + .../05-28-frontend-ux-redesign/implement.md | 32 +++ .../tasks/05-28-frontend-ux-redesign/prd.md | 194 ++++++++++++++++++ .../research/ux-audit-matrix.md | 45 ++++ .../05-28-frontend-ux-redesign/task.json | 26 +++ client/src/components/common/PageHeader.tsx | 10 +- client/src/components/navigation/NavLinks.tsx | 96 +++++++-- client/src/components/navigation/Sidebar.tsx | 8 +- client/src/components/navigation/Topbar.tsx | 21 +- .../src/components/patterns/ListWorkspace.tsx | 10 +- client/src/features/navigation/schema.ts | 64 +++--- client/src/index.css | 129 +++++++++++- client/src/layouts/AppShellLayout.tsx | 4 +- client/src/pages/ForgotPasswordPage.tsx | 13 +- client/src/pages/LoginPage.tsx | 12 +- client/src/pages/NotificationsPage.tsx | 46 ++--- client/src/pages/PortalHomePage.tsx | 16 +- client/src/pages/ReimbursementDetailPage.tsx | 23 ++- client/src/pages/ReimbursementsPage.tsx | 17 +- client/src/pages/WorkflowTasksPage.tsx | 37 ++-- client/tests/e2e/login-portal-ux.spec.ts | 9 +- 23 files changed, 711 insertions(+), 146 deletions(-) create mode 100644 .trellis/tasks/05-28-frontend-ux-redesign/check.jsonl create mode 100644 .trellis/tasks/05-28-frontend-ux-redesign/implement.jsonl create mode 100644 .trellis/tasks/05-28-frontend-ux-redesign/implement.md create mode 100644 .trellis/tasks/05-28-frontend-ux-redesign/prd.md create mode 100644 .trellis/tasks/05-28-frontend-ux-redesign/research/ux-audit-matrix.md create mode 100644 .trellis/tasks/05-28-frontend-ux-redesign/task.json diff --git a/.trellis/spec/hyb-oa/frontend-react-vite-design.md b/.trellis/spec/hyb-oa/frontend-react-vite-design.md index 9c5baa82..ed8718da 100644 --- a/.trellis/spec/hyb-oa/frontend-react-vite-design.md +++ b/.trellis/spec/hyb-oa/frontend-react-vite-design.md @@ -152,6 +152,45 @@ change the visual treatment once while preserving component contracts. - Focused Playwright screenshot coverage when changing login, Portal, primary PC list pages or command-bar/table styling. +## Convention: Global Shell And Page Header Baseline + +**What**: PC page redesigns should preserve the shared Wave0-2 shell and +header baseline instead of recreating page-local wrappers: + +- `AppShellLayout` owns the PC shell background and content offset through + `app-shell` and `app-shell-main`. +- `Sidebar` and `NavLinks` own primary navigation grouping. The mental model is + `工作` -> `业务` -> `财务` -> `管理` -> collapsed `更多`. +- `Topbar` is a compact command surface: page title, group badge, user context, + global search and notifications. Do not expand it back into a large hero. +- `PageHeader` and `WorkspaceHeader` should use `page-header-shell`, + `page-header-shell__eyebrow`, `page-header-shell__title`, + `page-header-shell__subtitle` and `page-header-shell__actions`. +- Auth guidance and step hints may use `ux-command-note`, `ux-step-list` and + `ux-step-item` when they explain the next action without adding page-local + warning cards. + +**Why**: The shell/header baseline gives Wave3-5 pages a stable visual entry +point and prevents each route from inventing a different title/action layout. + +**Example**: + +```tsx + +``` + +**Tests Required**: + +- `cd client && npm run typecheck` +- `cd client && npm run build` +- Focused Playwright coverage when changing `AppShellLayout`, `Sidebar`, + `Topbar`, `NavLinks`, `PageHeader`, `WorkspaceHeader`, login, Portal or other + A-class pages. + ## Convention: Detail And Mobile Command Surfaces **What**: PC detail pages and notification-like flows should reuse the Wave3 diff --git a/.trellis/tasks/05-28-frontend-ux-redesign/check.jsonl b/.trellis/tasks/05-28-frontend-ux-redesign/check.jsonl new file mode 100644 index 00000000..e958c4dd --- /dev/null +++ b/.trellis/tasks/05-28-frontend-ux-redesign/check.jsonl @@ -0,0 +1,3 @@ +{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend quality checklist and linked project rules."} +{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Required frontend checks, auth/page visual rules and Playwright expectations."} +{"file": ".trellis/tasks/05-28-frontend-ux-redesign/research/ux-audit-matrix.md", "reason": "Scope and acceptance basis for Wave0-Wave2 UX review."} diff --git a/.trellis/tasks/05-28-frontend-ux-redesign/implement.jsonl b/.trellis/tasks/05-28-frontend-ux-redesign/implement.jsonl new file mode 100644 index 00000000..3738e19d --- /dev/null +++ b/.trellis/tasks/05-28-frontend-ux-redesign/implement.jsonl @@ -0,0 +1,3 @@ +{"file": ".trellis/spec/frontend/index.md", "reason": "Frontend task entrypoint and project-specific spec routing."} +{"file": ".trellis/spec/hyb-oa/frontend-react-vite-design.md", "reason": "Frontend React/Vite design and validation rules for OA pages."} +{"file": ".trellis/tasks/05-28-frontend-ux-redesign/research/ux-audit-matrix.md", "reason": "Wave0 audit findings and Wave1/Wave2 implementation direction."} diff --git a/.trellis/tasks/05-28-frontend-ux-redesign/implement.md b/.trellis/tasks/05-28-frontend-ux-redesign/implement.md new file mode 100644 index 00000000..2db209b9 --- /dev/null +++ b/.trellis/tasks/05-28-frontend-ux-redesign/implement.md @@ -0,0 +1,32 @@ +# Implementation Notes + +## Scope Implemented + +- Wave 0: wrote `research/ux-audit-matrix.md` with global findings, Wave 2 page audit and Wave 3-5 follow-up grouping. +- Wave 1: updated global shell, sidebar, topbar, page headers and shared layout classes. +- Wave 2: refined login, forgot password, portal, workflow tasks, reimbursements, reimbursement detail and notifications with clearer hierarchy and next-step language. + +## UX Decisions + +- Visual direction: precise, restrained OA operations console. +- Navigation groups now reflect user tasks: 工作、业务、财务、管理、更多. +- Search is presented as a command entry in the Topbar. +- Notifications now behave as an inbox and return to the workbench, not the legacy dashboard. +- Login and password reset retain the generic “如账号可用” copy to avoid account enumeration. +- Wave 3-5 stay as follow-up tasks because they require different validation surfaces. + +## Validation + +- `cd client && npm run typecheck` — PASS. +- `cd client && npm run build` — PASS. +- `cd client && npx playwright test tests/e2e/pc-core-workflow-visual-wave2.spec.ts tests/e2e/login-portal-ux.spec.ts --workers=1 --reporter=list` — PASS, 11 tests. +- `cd client && npx playwright test tests/e2e/r89-mobile-login-navigation.spec.ts --workers=1 --reporter=list` — PASS, 3 tests. +- `python3 ./.trellis/scripts/task.py validate 05-28-frontend-ux-redesign` — PASS. +- `node scripts/qa/check-trellis-governance.mjs` — PASS. +- `git diff --check` — PASS. + +## Not Done In This Task + +- No backend permission, workflow, status-machine or data model changes. +- No deployment or public smoke yet. +- Wave 3-5 pages are recorded for follow-up tasks, not completed here. diff --git a/.trellis/tasks/05-28-frontend-ux-redesign/prd.md b/.trellis/tasks/05-28-frontend-ux-redesign/prd.md new file mode 100644 index 00000000..8b3600b0 --- /dev/null +++ b/.trellis/tasks/05-28-frontend-ux-redesign/prd.md @@ -0,0 +1,194 @@ +# 全站前端体验重构 + +## Goal + +从用户角度系统重构 hyb-oa 前端体验,让 PC 与移动端页面形成统一、克制、专业、可扫描的 OA 工作界面;降低用户理解成本、减少无效操作、统一页面布局和交互模式,并优先保障真实试运行中的核心业务路径。 + +## What I already know + +- 用户已明确希望“重新优化改进全部页面”,从用户角度、用户交互、用户体验思考,也可参考优秀系统设计。 +- 已确认前端视觉、布局、组件观感、字体、颜色、动效、间距和交互细节的最终裁决以 `frontend-design` skill 为准。 +- `docs/产品设计规则.md` 已瘦身为产品体验事实源,不再作为视觉规则手册。 +- 当前前端为 React + TypeScript + Vite + Tailwind,页面集中在 `client/src/pages/`,全局框架包括 `AppShellLayout`、`Sidebar`、`Topbar`、`NavLinks` 和 `components/patterns/*`。 +- 现有页面数量较多,覆盖登录、工作台、审批、报销、通知、项目、合同、采购、票据池、付款、AP、资产、考勤、人员和系统管理。 +- 真实试运行仍在进行,面向用户可测试的页面改动必须部署与公网检查通过后才能告知用户可测试。 + +## Product Direction + +采用“克制、专业、可扫描的运营后台”方向: + +- 不做营销站式大图、口号或装饰性卡片。 +- PC 端以高效扫描、批量查看、筛选、审批、复核和导出为核心。 +- 移动/企业微信端以快速提交、补材料、查状态、处理待办和消息直达为核心。 +- 视觉要有品牌感和统一性,但不牺牲信息密度、可读性和业务判断效率。 + +## Scope + +本任务实施 Wave 0 + Wave 1 + Wave 2: + +- Wave 0:完成全路由 UX 审计矩阵,记录页面优先级、问题类型和后续分批依据。 +- Wave 1:统一 PC 全局框架、侧边栏、Topbar、页面标题区、列表/详情基础视觉基线。 +- Wave 2:优化登录、找回密码、工作台、审批中心、报销列表、报销详情和通知中心。 + +本任务只做前端体验重构与自动化验证;不修改后端权限模型、审批状态机、业务数据结构、生产配置或真实业务数据。 + +## User Roles + +- 普通员工:提交报销/采购/材料、查看进度、补充附件、阅读公告、处理个人待办。 +- 审批人/负责人:快速判断待办、查看关键信息、批准/驳回、追踪项目和合同状态。 +- 财务/AP:复核票据、报销、付款批次、银行回单、应付台账、导出与审计。 +- 管理员:维护组织、用户、审批规则、系统设置、功能开关和审计日志。 + +## Requirements + +### R1. 全局信息架构 + +- 重新梳理 PC 侧导航分组:工作台、待办/审批、报销、项目/合同、财务、管理。 +- 高频入口稳定可见,低频和管理员入口收纳,不让普通员工被管理功能干扰。 +- 保留全局搜索、最近访问、通知/待办入口,但减少重复入口和解释文案。 + +### R2. 统一页面布局 + +- 建立统一页面骨架:标题区、关键状态区、主操作区、筛选/搜索区、主体区、辅助信息区。 +- 列表页、详情页、工作台页、配置页分别形成稳定模式。 +- 详情页优先呈现“当前状态、下一步动作、关键明细、附件/审计”,避免把操作埋在页面底部。 + +### R3. 文案和操作降噪 + +- 页面文案从功能说明改为用户下一步动作提示。 +- 长说明收进帮助、提示、空状态或详情抽屉。 +- 当前状态不可用的按钮不强行展示;必须展示时要解释原因。 +- 表单字段、按钮、状态标签和错误信息使用一致的业务语言。 + +### R4. 核心业务流程优化 + +- 登录/找回密码、工作台、审批中心、报销列表、报销详情、通知中心优先优化。 +- 审批页突出“我需要判断什么、依据是什么、点按钮的后果是什么”。 +- 报销/票据/附件页面突出状态、重复、缺失、可补材料和审计边界。 +- 财务/AP/付款页面突出批量复核、风险提示、下载用途和导出边界。 + +### R5. 视觉和组件系统 + +- 统一页面宽度、间距、标题层级、按钮层级、状态色、表格密度、卡片/面板样式。 +- 复用或升级 `PageScaffold`、`ListWorkspace`、`SectionPanel`、`StatusBadge`、`MetricCard` 等公共组件。 +- 避免一页一个风格,不再新增局部随意样式。 +- 交互动效只服务状态变化、加载、确认和导航,不做干扰业务判断的装饰动效。 + +### R6. 移动和企业微信入口 + +- 移动端优先保证从企业微信消息或移动首页进入目标业务后,少步骤完成提交、补材料、审批或查看状态。 +- 移动详情页不照搬 PC 表格;用分组信息、底部主操作和清晰状态解释。 +- 企业微信只做脱敏消息和 OA deeplink,附件和审批动作仍按 OA 权限执行。 + +### R7. 验证和发布 + +- 每一批前端改动必须通过 `cd client && npm run typecheck` 和 `cd client && npm run build`。 +- 高频页面需要 Playwright 视觉/交互检查,至少覆盖 PC 宽屏、常规桌面和移动视口。 +- 面向用户测试前必须完成部署和公网检查。 + +## Proposed Delivery Waves + +### Wave 0:UX 审计与页面矩阵 + +- 盘点所有 PC/移动路由。 +- 按 A/B/C 页面等级记录布局、文案、操作、状态、权限、移动适配问题。 +- 产出本任务内的整改矩阵,不新增独立噪音文档。 + +### Wave 1:全局框架与设计基线 + +- 重构 AppShell、侧边栏、Topbar、页面骨架、列表/详情/面板公共模式。 +- 统一按钮、状态、空状态、加载态、错误态、表格密度和基础间距。 +- 这一步是后续全站一致性的前提。 + +### Wave 2:高频核心页 + +- 登录/找回密码、工作台、审批中心、报销列表、报销详情、通知中心。 +- 目标是显著减少啰嗦、减少点击、清晰展示下一步动作。 + +### Wave 3:业务详情和移动关键页 + +- 审批详情、项目详情、合同台账/详情、移动报销、移动审批、移动通知、企微入口页。 + +### Wave 4:财务和运营页 + +- 票据池、AP、付款批次、采购/费用、资产、合同归档。 +- 重点是表格、筛选、批量操作、附件下载审计和状态解释。 + +### Wave 5:管理配置页 + +- 用户、组织、审批规则、流程定义、系统设置、功能开关、审计日志。 +- 允许信息密度较高,但统一排版、权限提示和排障语言。 + +## Suggested MVP for This Task + +建议本任务第一轮实施 Wave 0 + Wave 1 + Wave 2,原因: + +- 先统一全局框架和高频核心页,能最快改善真实试运行体验。 +- Wave 3-5 页面数量多、业务差异大,应在统一组件模式建立后批量套用。 +- 一次性改完全部页面风险过高,容易产生回归、遗漏权限状态或视觉不一致。 + +## Test Plan + +- `cd client && npm run typecheck` +- `cd client && npm run build` +- `cd client && npx playwright test tests/e2e/pc-core-workflow-visual-wave2.spec.ts tests/e2e/login-portal-ux.spec.ts --workers=1 --reporter=list` +- `cd client && npx playwright test tests/e2e/r89-mobile-login-navigation.spec.ts --workers=1 --reporter=list` +- `python3 ./.trellis/scripts/task.py validate 05-28-frontend-ux-redesign` +- `node scripts/qa/check-trellis-governance.mjs` +- `git diff --check` +- 若要交给用户公网试用,必须另行部署并完成公网 smoke/视觉检查后再勾选部署验收项。 + +## Follow-up Plan for Wave 3-5 + +Wave 3-5 必须记录在本任务中,避免 Wave 0-2 完成后遗忘;但不建议在本任务内同时实施。 + +推荐排期: + +1. Wave 0-2 完成、通过验证并部署公网检查后,立即新建 `frontend-ux-wave3-business-mobile` 任务。 +2. Wave 3 完成后,再新建 `frontend-ux-wave4-finance-ops` 任务。 +3. Wave 4 完成后,再新建 `frontend-ux-wave5-admin-config` 任务。 + +拆开的理由: + +- Wave 3 涉及业务详情页和移动/企微入口,验证重点是真实业务链路和移动交互。 +- Wave 4 涉及财务、付款、AP、票据和资产,验证重点是表格、批量操作、附件下载审计和权限边界。 +- Wave 5 涉及管理配置和审计,验证重点是高信息密度、排障语言、权限提示和误操作防护。 +- 三类页面的用户角色、交互风险和测试路径不同,强行放在一个大任务里会降低质量。 + +Wave 3-5 不作为本任务验收阻断项;本任务结束时必须在交付总结中明确下一任务建议和页面清单。 + +## Acceptance Criteria + +- [x] 已完成全路由页面 UX 审计矩阵,并按 A/B/C 级标记优先级。 +- [x] 已确立统一页面骨架和公共组件使用方式。 +- [x] PC 全局导航、Topbar 和内容容器明显统一,低频入口不干扰高频用户路径。 +- [x] Wave 2 高频核心页完成第一轮体验重构。 +- [x] Wave 3-5 后续任务计划已记录,且不被误判为本任务已完成范围。 +- [x] 页面文案明显降噪,主要页面能直接说明当前状态和下一步动作。 +- [x] 桌面与移动关键视口无明显文本溢出、遮挡、错位和不可点击问题。 +- [x] `cd client && npm run typecheck` 通过。 +- [x] `cd client && npm run build` 通过。 +- [x] 高频页面完成 Playwright 截图/交互验证。 +- [ ] 若部署给用户测试,已完成公网检查并记录证据。 + +## Out of Scope + +- 不改变后端权限模型、审批状态机或业务数据结构。 +- 不新增真实业务写入、企业微信写入、生产配置变更或数据库迁移。 +- 不把移动端改造成完整 PC 管理后台。 +- 不在本任务恢复差旅主线能力。 +- 不为了视觉统一删除已有业务能力;如发现业务流程不合理,记录为后续任务。 + +## Technical Notes + +- 重点代码区域: + - `client/src/layouts/AppShellLayout.tsx` + - `client/src/components/navigation/*` + - `client/src/components/patterns/*` + - `client/src/components/common/*` + - `client/src/pages/*` +- 设计依据: + - `frontend-design` skill 决定视觉和交互方向。 + - `docs/产品设计规则.md` 只提供 hyb-oa 产品体验事实、用户角色和页面职责。 + - `.trellis/spec/hyb-oa/frontend-react-vite-design.md` 和 `.trellis/spec/frontend/index.md` 约束工程实现。 +- 已按用户确认实施 Wave 0 + Wave 1 + Wave 2;Wave 3-5 作为后续任务拆分,不计入本任务完成范围。 diff --git a/.trellis/tasks/05-28-frontend-ux-redesign/research/ux-audit-matrix.md b/.trellis/tasks/05-28-frontend-ux-redesign/research/ux-audit-matrix.md new file mode 100644 index 00000000..3a3edf45 --- /dev/null +++ b/.trellis/tasks/05-28-frontend-ux-redesign/research/ux-audit-matrix.md @@ -0,0 +1,45 @@ +# UX Audit Matrix + +## Audit Method + +- 依据 `client/src/router/index.tsx`、`client/src/features/navigation/schema.ts` 和页面源码盘点。 +- 页面分级沿用 `docs/产品设计规则.md`:A 类核心流程、B 类业务运营、C 类管理配置。 +- 本轮实施范围为 Wave 0-2;Wave 3-5 只记录后续任务,不作为当前验收完成范围。 + +## Global Findings + +| Area | Finding | Impact | Current Task Action | +| --- | --- | --- | --- | +| PC navigation | 主导航、管理入口、备用模块的分类偏业务历史,财务/项目/合同等用户心智未成组。 | 用户找入口需要读说明,普通员工容易看到过多低频项。 | Wave 1 重排导航分组和侧栏信息。 | +| Topbar | 顶部展示页面组、标题和问候,信息占高较多;搜索按钮不够像命令入口。 | PC 页面有效内容首屏被压缩。 | Wave 1 做紧凑命令栏。 | +| Page headers | `PageHeader`、`WorkspaceHeader`、`WorkbenchHero`、`EntityOverviewHero` 并存,标题/说明/action 的密度不完全一致。 | 页面风格统一度不足。 | Wave 1 统一 header 视觉和行动区。 | +| Cards/panels | 大量页面已复用 `SectionPanel`、`ListWorkspace`,但局部还存在 page-local 卡片和提示块。 | 视觉统一改动需要多点修复。 | Wave 1 先统一 shared pattern class。 | +| Lists/tables | PC 操作列表已有 `ops-*` 规范,但部分空态、错误态和筛选控件仍不一致。 | 审批、报销、通知的扫描效率不稳定。 | Wave 2 聚焦核心列表。 | +| Copy | 部分页面说明偏“模块解释”,不是“下一步动作”。 | 用户需要理解系统设计而非直接完成任务。 | Wave 2 降噪。 | +| Mobile | 移动壳和卡片模式已存在;关键详情页属于 Wave 3。 | 本轮只避免 Wave 2 改动破坏移动入口。 | Wave 3 继续。 | + +## Wave 2 Page Audit + +| Page | Class | Current Issues | Target Change | +| --- | --- | --- | --- | +| Login | A | 功能完整,但登录方式、企微入口、邮箱验证码和密码入口信息层级仍可更清楚。 | 保留成熟功能,改为更明确的登录方式分区、辅助状态和焦点顺序。 | +| Forgot password | A | 流程可用,但验证码、有效期、密码要求和返回登录的提示仍偏散。 | 强化步骤感和状态提示。 | +| Portal home | A | 信息丰富但首屏模块多,角色摘要、待处理和常用动作可更聚焦。 | 工作台突出“待处理 + 常用动作 + 关键指标”,次要信息收纳。 | +| Workflow tasks | A | 已使用 `ListWorkspace` 和 `ops-*`,但 subtitle 太短,缺少“下一步如何处理”的上下文。 | 提升标题说明、状态指标和空态语义。 | +| Reimbursements | A | 已支持批量、导出、范围、模板,但筛选/范围/导出动作密度偏高。 | 保持功能,优化 header、command bar 和列表扫描字段。 | +| Reimbursement detail | A | 信息完整,分区较多;状态、下一步动作、票据和附件需要更强层级。 | 保留功能,优化 hero 说明、摘要和证据区语义。 | +| Notifications | A | 已改为 inbox 卡片,但返回仪表盘不符合当前主路径,筛选区和未读统计可以更统一。 | 改为通知收件箱工作区,直达业务、全部已读、类型筛选稳定。 | + +## Follow-up Page Groups + +| Wave | Pages | Reason To Split | +| --- | --- | --- | +| Wave 3 | 审批详情、项目详情、合同台账/详情、移动报销、移动审批、移动通知、企微入口页 | 详情和移动链路要验证业务直达和移动操作,不适合和全局框架同批扩大。 | +| Wave 4 | 票据池、AP、付款批次、采购/费用、资产、合同归档 | 财务运营页涉及批量操作、附件审计、导出和权限边界。 | +| Wave 5 | 用户、组织、审批规则、流程定义、系统设置、功能开关、审计日志 | 管理页信息密度高,重在排障语言和误操作防护。 | + +## Design Direction Locked For Implementation + +- Tone: 精密、克制、运营后台。 +- Differentiation: 所有页面都能先回答“现在是什么状态、我下一步做什么、动作有什么后果”。 +- Visual rule: 通过 shared shell、header、command bar、status strip 和 detail surface 统一,而不是每页单独美化。 diff --git a/.trellis/tasks/05-28-frontend-ux-redesign/task.json b/.trellis/tasks/05-28-frontend-ux-redesign/task.json new file mode 100644 index 00000000..a826c55e --- /dev/null +++ b/.trellis/tasks/05-28-frontend-ux-redesign/task.json @@ -0,0 +1,26 @@ +{ + "id": "frontend-ux-redesign", + "name": "frontend-ux-redesign", + "title": "全站前端体验重构", + "description": "统一 hyb-oa 前端 Wave0-2 体验基线:UX 审计、全局框架和高频核心页。", + "status": "in_progress", + "dev_type": null, + "scope": "client/frontend-ux-wave0-2", + "package": null, + "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": {} +} diff --git a/client/src/components/common/PageHeader.tsx b/client/src/components/common/PageHeader.tsx index 628e2e1f..991dfbca 100644 --- a/client/src/components/common/PageHeader.tsx +++ b/client/src/components/common/PageHeader.tsx @@ -13,16 +13,16 @@ type PageHeaderProps = { export function PageHeader({ title, subtitle, actions, eyebrow, meta, className }: PageHeaderProps) { return ( -
+
{eyebrow ? ( -
{eyebrow}
+
{eyebrow}
) : null} -

{title}

- {subtitle ?

{subtitle}

: null} +

{title}

+ {subtitle ?

{subtitle}

: null} {meta ?
{meta}
: null}
- {actions ?
{actions}
: null} + {actions ?
{actions}
: null}
); } diff --git a/client/src/components/navigation/NavLinks.tsx b/client/src/components/navigation/NavLinks.tsx index c0877607..effe7b07 100644 --- a/client/src/components/navigation/NavLinks.tsx +++ b/client/src/components/navigation/NavLinks.tsx @@ -56,6 +56,31 @@ const LEGACY_ACCESSIBLE_LABELS: Record = { "/assets": "资产台账", }; +const WORK_NAV_ORDER = ["/portal", "/workflow/tasks", "/reimbursements", "/todos"]; +const BUSINESS_NAV_ORDER = [ + "/projects", + "/contracts-registry", + "/purchase-requests", + "/assets", + "/weekly-reports", + "/team", + "/announcements", + "/leave-requests", + "/attendance", + "/wecom-approval-archive", +]; +const FINANCE_NAV_ORDER = ["/payment-batches", "/ap-operations", "/invoice-pool", "/budgets", "/inventory-checks"]; +const MANAGEMENT_NAV_ORDER = [ + "/people", + "/organization", + "/system/workspace", + "/system/workflow-definitions", + "/system/settings", + "/system/feature-flags", + "/audit-logs", +]; +const MORE_NAV_ORDER = ["/travel-requests", "/dashboard", "/settings/profile", "/system/cutover", "/system/integrations/erp"]; + type ResolvedNavItem = { key?: string; href: string; @@ -75,10 +100,8 @@ function renderNavItem(item: ResolvedNavItem, onNavigate?: () => void) { onClick={() => onNavigate?.()} className={({ isActive }) => cn( - "group flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm transition duration-150", - isActive - ? "bg-primary/10 text-primary ring-1 ring-primary/10" - : "text-[var(--color-text-secondary)] hover:bg-slate-50 hover:text-[var(--color-text-primary)]", + "group nav-link-item", + isActive ? "nav-link-item--active" : "nav-link-item--idle", ) } > @@ -86,10 +109,8 @@ function renderNavItem(item: ResolvedNavItem, onNavigate?: () => void) { <> {item.icon} @@ -101,17 +122,14 @@ function renderNavItem(item: ResolvedNavItem, onNavigate?: () => void) { ); } -function renderSection(title: string, description: string, items: ResolvedNavItem[], onNavigate?: () => void) { +function renderSection(title: string, items: ResolvedNavItem[], onNavigate?: () => void) { if (!items.length) { return null; } return ( -
-
-
{title}
-
{description}
-
+
+
{title}
{items.map((item) => renderNavItem(item, onNavigate))}
); @@ -126,10 +144,10 @@ function renderBackupSection(items: ResolvedNavItem[], onNavigate?: () => void)
-
备用模块
-
默认收起,不干扰主路径
+
更多
+
低频入口和历史模块
- 按需展开 + expand_more
{items.map((item) => renderNavItem(item, onNavigate))}
@@ -186,6 +204,41 @@ function normalizeSections(sections: { main: NavigationItem[]; admin: Navigation }; } +function regroupSections(sections: { main: ResolvedNavItem[]; admin: ResolvedNavItem[]; backup: ResolvedNavItem[] }) { + const allItems = [...sections.main, ...sections.admin, ...sections.backup]; + const byHref = new Map(); + for (const item of allItems) { + if (!byHref.has(item.href)) { + byHref.set(item.href, item); + } + } + + const used = new Set(); + const take = (hrefs: string[]) => + hrefs + .map((href) => { + const item = byHref.get(href); + if (item) { + used.add(href); + } + return item; + }) + .filter((item): item is ResolvedNavItem => Boolean(item)); + + return { + work: take(WORK_NAV_ORDER), + business: take(BUSINESS_NAV_ORDER), + finance: take(FINANCE_NAV_ORDER), + management: take(MANAGEMENT_NAV_ORDER), + more: [ + ...take(MORE_NAV_ORDER), + ...allItems + .filter((item) => !used.has(item.href)) + .map((item) => ({ key: item.key, href: item.href, label: item.label, icon: item.icon })), + ], + }; +} + export function NavLinks({ onNavigate }: { onNavigate?: () => void }) { const { me, permissions } = useAuth(); const navigationQuery = useQuery({ @@ -197,12 +250,15 @@ export function NavLinks({ onNavigate }: { onNavigate?: () => void }) { const sections = navigationQuery.data?.sections ? normalizeSections(navigationQuery.data.sections) : buildFallbackItems(permissions, me?.roleCodes ?? []); + const groupedSections = regroupSections(sections); return ( ); } diff --git a/client/src/components/navigation/Sidebar.tsx b/client/src/components/navigation/Sidebar.tsx index b04c56a1..dc1911b1 100644 --- a/client/src/components/navigation/Sidebar.tsx +++ b/client/src/components/navigation/Sidebar.tsx @@ -3,15 +3,15 @@ import { NavLinks } from "./NavLinks"; export function Sidebar() { return ( -