Files
hms/docs/archive/superpowers-completed/2026-04-26-frontend-engineering.md
iven 18fa6ce6d4 docs: 全局文档梳理归档 — 删除过期文件 + 归档 V1/早期设计 + wiki 数据校正 + CLAUDE.md 规则优化
**根目录清理:**
- 删除 CLAUDE-1.md(ZCLAW 旧项目配置,HMS 已完全脱离)
- 移动 DESIGN.md → docs/archive/(ERP 旧设计系统)
- 删除 plans/ 98 个临时会话计划文件

**归档重组:**
- V1 审计(12 文件)→ docs/archive/audits-v1/
- 早期 CRM/插件迭代设计(13 文件)→ docs/archive/superpowers-early/
- 已完成/已取代设计(28 文件)→ docs/archive/superpowers-completed/
- 早期讨论/测试报告 → docs/archive/discussions-early/ + test-reports-early/
- QA 重复文件清理(3 个旧版 result 文件)

**wiki 数据校正:**
- 迁移数 137→145,源文件 599→649,提交数 720→800+
- 小程序文件 124→163,Web 前端 297→332
- 后端测试 999→943(实际统计),权限码 75+→128
- 文档索引新增归档目录说明

**CLAUDE.md 规则优化:**
- §2.5 闭环工作法:提交+文档+推送三合一 + wiki 更新触发条件
- §2.6 Feature DoD:新增文档一致性检查项
- §6 反模式:新增 wiki 更新滞后/推送不及时警告
2026-05-15 09:29:04 +08:00

11 KiB
Raw Blame History

前端工程化改进实施计划

设计规格: docs/superpowers/specs/2026-04-26-frontend-engineering-design.md 日期: 2026-04-26 | 状态: draft | 总周期: 7 天


Phase 1: 重复模式统一Day 1-2

Task 1: 增强 useApiRequest hook统一错误处理

目标: 补齐 loading 状态,消除组件内联 catch (err) { message.error(...) } 模式。

涉及文件:

  • 修改: apps/web/src/hooks/useApiRequest.ts

详细步骤:

  1. useApiRequest 返回值中新增 loading: boolean 状态:
interface UseApiRequestReturn {
  execute: <T>(fn: () => Promise<T>, successMsg?: string) => Promise<T | null>;
  loading: boolean;
}
  1. execute 内部在调用前 setLoading(true)finally 中 setLoading(false)
  2. 保持现有调用点无需修改 — 返回值是对象解构,新增字段不影响旧代码
  3. 选取 3 个健康模块页面PatientList、AppointmentList、FollowUpTaskList迁移为使用 execute + loading

验收标准:

  • pnpm build 通过
  • 3 个迁移页面的 catch 块不再有内联 message.error,统一走 handleApiError
  • loading 状态正确绑定到页面按钮/Spin 组件

Task 2: 增强 usePaginatedData hook健康模块页面迁移

目标: 支持泛型筛选参数,迁移 6 个健康列表页使用统一 hook。

涉及文件:

  • 修改: apps/web/src/hooks/usePaginatedData.ts
  • 修改: apps/web/src/pages/health/PatientList.tsx
  • 修改: apps/web/src/pages/health/OfflineEventList.tsx
  • 修改: apps/web/src/pages/health/PointsProductList.tsx

详细步骤:

  1. 增强 hook 签名为泛型筛选:
function usePaginatedData<T, F = string>(
  fetchFn: (page: number, pageSize: number, filters: F) => Promise<{ data: T[]; total: number }>,
  options?: { pageSize?: number; defaultFilters: F; autoFetch?: boolean }
): { data, total, page, loading, filters, setFilters, refresh }
  1. 函数重载保持旧 (fetchFn, pageSize?) 签名兼容
  2. 新增 filters / setFilters 状态,fetchFn 调用时传入当前 filters
  3. 迁移 PatientList按 status/name/gender 筛选)和 OfflineEventList按 status/dateRange 筛选)

验收标准:

  • 旧调用点(不传 filters行为不变
  • PatientList 和 OfflineEventList 筛选功能正常,代码行数各减少 15-25 行
  • pnpm build 通过

Task 3: 移除 nameCache统一用 useHealthStore

目标: 消除 AppointmentList 和 PointsOrderList 自建的 useState<Record<string, string>> nameCache。

涉及文件:

  • 修改: apps/web/src/stores/health.ts
  • 修改: apps/web/src/pages/health/AppointmentList.tsx
  • 修改: apps/web/src/pages/health/PointsOrderList.tsx

详细步骤:

  1. useHealthStore 新增批量解析方法:
    • batchResolvePatientNames(ids: string[]): Promise<Record<string, string>>
    • batchResolveDoctorNames(ids: string[]): Promise<Record<string, string>>
  2. 内部实现:去重 → 过滤已缓存 → 并发加载(限制 5 并发)→ 写入缓存并返回
  3. 在 AppointmentList 中移除 nameCache state改用 store 方法
  4. 在 PointsOrderList 中同样迁移

验收标准:

  • 两个页面无 useState<Record<string, string>> nameCache 代码
  • 患者姓名/医生姓名在列表中正确显示
  • pnpm build 通过

Phase 2: 大组件拆分Day 3-5

Task 4: PluginCRUDPage 拆分为 CRUDTable/CRUDForm/DetailDrawer/ImportExport

目标: 将 872 行的 PluginCRUDPage.tsx 拆为容器 + 展示组件。

涉及文件:

  • 新增: apps/web/src/pages/plugins/components/CRUDTable.tsx (~150 行)
  • 新增: apps/web/src/pages/plugins/components/CRUDForm.tsx (~180 行)
  • 新增: apps/web/src/pages/plugins/components/DetailDrawer.tsx (~80 行)
  • 新增: apps/web/src/pages/plugins/components/ImportExport.tsx (~100 行)
  • 新增: apps/web/src/pages/plugins/hooks/usePluginData.ts (~120 行)
  • 修改: apps/web/src/pages/plugins/PluginCRUDPage.tsx (缩减至 ~80 行)

详细步骤:

  1. 创建 hooks/usePluginData.ts:提取 CRUD 操作、导入导出逻辑、Drawer 可见性状态
  2. 创建 CRUDTable.tsx:表格列定义 + 行操作按钮props 接收 data/onDelete/onEdit/onDetail
  3. 创建 CRUDForm.tsx:新增/编辑表单 + Drawer包含校验规则
  4. 创建 DetailDrawer.tsx:详情展示 + 操作历史 Timeline
  5. 创建 ImportExport.tsx:导入面板 + 导出按钮
  6. 改写 PluginCRUDPage.tsx 为容器组件:调用 usePluginData hook组装子组件

验收标准:

  • pnpm build 通过
  • 插件 CRUD 所有功能正常(新增、编辑、删除、详情、导入、导出)
  • PluginCRUDPage.tsx <= 100 行,无子组件超过 200 行

Task 5: PluginGraphPage 抽取 useGraphCanvas hook

目标: 将 759 行的 PluginGraphPage.tsx 拆为 hook + 展示组件。

涉及文件:

  • 新增: apps/web/src/pages/plugins/hooks/useGraphLayout.ts (~100 行)
  • 新增: apps/web/src/pages/plugins/hooks/useGraphData.ts (~80 行)
  • 新增: apps/web/src/pages/plugins/components/GraphCanvas.tsx (~200 行)
  • 新增: apps/web/src/pages/plugins/components/GraphToolbar.tsx (~60 行)
  • 修改: apps/web/src/pages/plugins/PluginGraphPage.tsx (缩减至 ~60 行)

详细步骤:

  1. useGraphData.ts:数据加载、边/节点格式转换、字段映射
  2. useGraphLayout.tsDagre/elkjs 布局算法、节点位置计算、自动布局触发
  3. GraphCanvas.tsxReactFlow 渲染、自定义节点样式、拖拽交互
  4. GraphToolbar.tsx:缩放控制、自动布局、布局方向切换
  5. 容器组件组装以上模块

验收标准:

  • 插件关系图页面正常渲染和交互
  • 拖拽节点、自动布局、缩放功能正常
  • pnpm build 通过

Task 6: Organizations.tsx 抽象 TreeEntityManager

目标: 将 622 行的 Organizations.tsx 按三层模式拆分。

涉及文件:

  • 新增: apps/web/src/pages/system/hooks/useOrgTree.ts (~80 行)
  • 新增: apps/web/src/pages/system/components/OrgTree.tsx (~120 行)
  • 新增: apps/web/src/pages/system/components/OrgDetail.tsx (~150 行)
  • 新增: apps/web/src/pages/system/components/DeptMemberList.tsx (~100 行)
  • 修改: apps/web/src/pages/system/Organizations.tsx (缩减至 ~60 行)

详细步骤:

  1. useOrgTree.ts树数据加载、CRUD 操作、选中节点状态
  2. OrgTree.tsx左侧树形选择DirectoryTree + 搜索 + 右键菜单)
  3. OrgDetail.tsx:右侧组织详情/编辑表单
  4. DeptMemberList.tsx:部门成员列表 + 人员分配 Modal
  5. 容器组件三栏布局组装

验收标准:

  • 组织管理 CRUD 功能正常(新增/编辑/删除组织、部门、人员分配)
  • 树形选择、搜索过滤正常
  • pnpm build 通过

Task 7: StatisticsDashboard 拆分为独立卡片组件

目标: 将 580 行的 StatisticsDashboard.tsx 拆为 hook + 独立图表卡片。

涉及文件:

  • 新增: apps/web/src/pages/health/hooks/useStatsData.ts (~100 行)
  • 新增: apps/web/src/pages/health/components/PatientTrendChart.tsx (~80 行)
  • 新增: apps/web/src/pages/health/components/AppointmentStats.tsx (~80 行)
  • 新增: apps/web/src/pages/health/components/OverviewCards.tsx (~60 行)
  • 新增: apps/web/src/pages/health/components/TimeRangeSelector.tsx (~40 行)
  • 修改: apps/web/src/pages/health/StatisticsDashboard.tsx (缩减至 ~50 行)

详细步骤:

  1. useStatsData.ts:五个统计 API 并行加载、loading/error 状态、时间范围变更触发刷新
  2. PatientTrendChart.tsx:患者趋势折线图(@ant-design/charts Line
  3. AppointmentStats.tsx:预约统计饼图/柱状图
  4. OverviewCards.tsx概览数字卡片组Statistic + Card
  5. TimeRangeSelector.tsx:日期范围选择 + 快捷选项近7天/近30天/近90天
  6. 容器组件组装,布局使用 Row + Col

验收标准:

  • 统计仪表板页面渲染正常,图表数据正确
  • 时间范围切换触发数据刷新
  • pnpm build 通过

Phase 3: Bundle 优化Day 6-7

Task 8: vite.config.ts manualChunks 拆分重型依赖

目标: 将 @ant-design/charts、@xyflow/react、@wangeditor/editor 拆为独立 chunk降低主 chunk 体积。

涉及文件:

  • 修改: apps/web/vite.config.ts

详细步骤:

  1. manualChunks 配置中新增三条规则:
if (id.includes('@ant-design/charts') || id.includes('@antv/')) return 'vendor-charts';
if (id.includes('@xyflow/react') || id.includes('@reactflow/')) return 'vendor-flow';
if (id.includes('@wangeditor/')) return 'vendor-editor';
  1. 对应页面添加路由级 React.lazy()
    • StatisticsDashboardlazy(() => import('./health/StatisticsDashboard'))
    • PluginGraphPagelazy(() => import('./plugins/PluginGraphPage'))
    • ArticleEditorlazy(() => import('./health/ArticleEditor'))
  2. chunkSizeWarningLimit 从 600 降至 500
  3. 运行 pnpm build 对比拆分前后各 chunk 大小

验收标准:

  • 主 chunk 体积 < 400KBgzip 前约 600KB 以内)
  • vendor-chartsvendor-flowvendor-editor 独立生成
  • pnpm build 无警告
  • 统计仪表板、插件关系图、文章编辑器页面功能正常(懒加载无闪烁)

Task 9: columns 配置 useMemo 化

目标: 消除 PluginCRUDPage 和健康模块列表页的 columns 重复创建,减少不必要的 re-render。

涉及文件:

  • 修改: apps/web/src/pages/plugins/components/CRUDTable.tsxPhase 2 Task 4 产物)
  • 修改: apps/web/src/pages/health/PatientList.tsx
  • 修改: apps/web/src/pages/health/AppointmentList.tsx
  • 修改: apps/web/src/pages/health/FollowUpTaskList.tsx

详细步骤:

  1. 在每个列表页中,将 columns 数组定义包裹在 useMemo
  2. 依赖项包含 columns 中引用的回调函数(如 onDelete、onEdit
  3. 确保回调函数通过 useCallback 缓存,避免 useMemo 失效
  4. 使用 React DevTools Profiler 验证翻页/筛选时减少不必要渲染

验收标准:

  • 列表翻页时 Table 组件不因 columns 引用变化触发全量渲染
  • 所有列表页功能正常(排序、筛选、操作按钮)
  • pnpm build 通过

Task 10: API 层新代码统一为对象风格

目标: 确认新增 API 文件采用对象风格(xxxApi.list() 而非 listXxx()),修改已有文件时顺手迁移。

涉及文件:

  • 修改: apps/web/src/api/health/ 下近期新增的 API 文件(如 alerts.tsdeviceReadings.ts

详细步骤:

  1. 审计 apps/web/src/api/ 下所有文件,标记函数风格的文件清单
  2. 近期新增的文件alerts、deviceReadings 等)统一改为对象风格:
export const alertApi = {
  list: (params) => client.get('/alerts', { params }),
  acknowledge: (id) => client.post(`/alerts/${id}/acknowledge`),
};
  1. 更新引用处的 import页面组件中的调用方式
  2. 旧文件不强制迁移,仅记录待迁移清单

验收标准:

  • alerts.tsdeviceReadings.ts 为对象风格导出
  • 对应页面功能正常
  • pnpm build 通过

执行原则

  1. 每 Task 完成后立即提交 — 不积压,保持可追溯
  2. 先基础设施后拆分 — Phase 1 的 hook 增强完成后再做 Phase 2 组件拆分
  3. 每步验证 — 每个 Task 完成后 pnpm build 验证,拆分任务额外验证页面功能
  4. 渐进迁移 — 重复模式统一采用渐进策略,不一次性全量迁移