**根目录清理:** - 删除 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 更新滞后/推送不及时警告
11 KiB
前端工程化改进实施计划
设计规格:
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
详细步骤:
- 在
useApiRequest返回值中新增loading: boolean状态:
interface UseApiRequestReturn {
execute: <T>(fn: () => Promise<T>, successMsg?: string) => Promise<T | null>;
loading: boolean;
}
execute内部在调用前setLoading(true),finally 中setLoading(false)- 保持现有调用点无需修改 — 返回值是对象解构,新增字段不影响旧代码
- 选取 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
详细步骤:
- 增强 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 }
- 函数重载保持旧
(fetchFn, pageSize?)签名兼容 - 新增
filters/setFilters状态,fetchFn调用时传入当前 filters - 迁移 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
详细步骤:
- 在
useHealthStore新增批量解析方法:batchResolvePatientNames(ids: string[]): Promise<Record<string, string>>batchResolveDoctorNames(ids: string[]): Promise<Record<string, string>>
- 内部实现:去重 → 过滤已缓存 → 并发加载(限制 5 并发)→ 写入缓存并返回
- 在 AppointmentList 中移除 nameCache state,改用 store 方法
- 在 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 行)
详细步骤:
- 创建
hooks/usePluginData.ts:提取 CRUD 操作、导入导出逻辑、Drawer 可见性状态 - 创建
CRUDTable.tsx:表格列定义 + 行操作按钮,props 接收 data/onDelete/onEdit/onDetail - 创建
CRUDForm.tsx:新增/编辑表单 + Drawer,包含校验规则 - 创建
DetailDrawer.tsx:详情展示 + 操作历史 Timeline - 创建
ImportExport.tsx:导入面板 + 导出按钮 - 改写
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 行)
详细步骤:
useGraphData.ts:数据加载、边/节点格式转换、字段映射useGraphLayout.ts:Dagre/elkjs 布局算法、节点位置计算、自动布局触发GraphCanvas.tsx:ReactFlow 渲染、自定义节点样式、拖拽交互GraphToolbar.tsx:缩放控制、自动布局、布局方向切换- 容器组件组装以上模块
验收标准:
- 插件关系图页面正常渲染和交互
- 拖拽节点、自动布局、缩放功能正常
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 行)
详细步骤:
useOrgTree.ts:树数据加载、CRUD 操作、选中节点状态OrgTree.tsx:左侧树形选择(DirectoryTree + 搜索 + 右键菜单)OrgDetail.tsx:右侧组织详情/编辑表单DeptMemberList.tsx:部门成员列表 + 人员分配 Modal- 容器组件三栏布局组装
验收标准:
- 组织管理 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 行)
详细步骤:
useStatsData.ts:五个统计 API 并行加载、loading/error 状态、时间范围变更触发刷新PatientTrendChart.tsx:患者趋势折线图(@ant-design/charts Line)AppointmentStats.tsx:预约统计饼图/柱状图OverviewCards.tsx:概览数字卡片组(Statistic + Card)TimeRangeSelector.tsx:日期范围选择 + 快捷选项(近7天/近30天/近90天)- 容器组件组装,布局使用 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
详细步骤:
- 在
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';
- 对应页面添加路由级
React.lazy():StatisticsDashboard→lazy(() => import('./health/StatisticsDashboard'))PluginGraphPage→lazy(() => import('./plugins/PluginGraphPage'))ArticleEditor→lazy(() => import('./health/ArticleEditor'))
- 将
chunkSizeWarningLimit从 600 降至 500 - 运行
pnpm build对比拆分前后各 chunk 大小
验收标准:
- 主 chunk 体积 < 400KB(gzip 前约 600KB 以内)
vendor-charts、vendor-flow、vendor-editor独立生成pnpm build无警告- 统计仪表板、插件关系图、文章编辑器页面功能正常(懒加载无闪烁)
Task 9: columns 配置 useMemo 化
目标: 消除 PluginCRUDPage 和健康模块列表页的 columns 重复创建,减少不必要的 re-render。
涉及文件:
- 修改:
apps/web/src/pages/plugins/components/CRUDTable.tsx(Phase 2 Task 4 产物) - 修改:
apps/web/src/pages/health/PatientList.tsx - 修改:
apps/web/src/pages/health/AppointmentList.tsx - 修改:
apps/web/src/pages/health/FollowUpTaskList.tsx
详细步骤:
- 在每个列表页中,将
columns数组定义包裹在useMemo中 - 依赖项包含 columns 中引用的回调函数(如 onDelete、onEdit)
- 确保回调函数通过
useCallback缓存,避免 useMemo 失效 - 使用 React DevTools Profiler 验证翻页/筛选时减少不必要渲染
验收标准:
- 列表翻页时 Table 组件不因 columns 引用变化触发全量渲染
- 所有列表页功能正常(排序、筛选、操作按钮)
pnpm build通过
Task 10: API 层新代码统一为对象风格
目标: 确认新增 API 文件采用对象风格(xxxApi.list() 而非 listXxx()),修改已有文件时顺手迁移。
涉及文件:
- 修改:
apps/web/src/api/health/下近期新增的 API 文件(如alerts.ts、deviceReadings.ts)
详细步骤:
- 审计
apps/web/src/api/下所有文件,标记函数风格的文件清单 - 近期新增的文件(alerts、deviceReadings 等)统一改为对象风格:
export const alertApi = {
list: (params) => client.get('/alerts', { params }),
acknowledge: (id) => client.post(`/alerts/${id}/acknowledge`),
};
- 更新引用处的 import(页面组件中的调用方式)
- 旧文件不强制迁移,仅记录待迁移清单
验收标准:
alerts.ts和deviceReadings.ts为对象风格导出- 对应页面功能正常
pnpm build通过
执行原则
- 每 Task 完成后立即提交 — 不积压,保持可追溯
- 先基础设施后拆分 — Phase 1 的 hook 增强完成后再做 Phase 2 组件拆分
- 每步验证 — 每个 Task 完成后
pnpm build验证,拆分任务额外验证页面功能 - 渐进迁移 — 重复模式统一采用渐进策略,不一次性全量迁移