title, updated, status, tags
| title |
updated |
status |
tags |
| Web 前端 |
2026-04-25 |
stable |
| frontend |
| react |
| antd |
| vite |
| spa |
|
Web 前端
从 index 导航。关联: erp-server infrastructure erp-health
1. 设计决策
- 组件库优先 — Ant Design 6,不自造轮子
- 状态集中 — Zustand 管理全局状态(4 个 store)
- API 层分离 — HTTP 调用封装到
src/api/(28 个文件),组件不直接 fetch
- 代理开发 — Vite 代理
/api 到后端 3000 端口
- HashRouter — 不需要服务端 fallback 配置,部署更稳健
- 懒加载 — 除 Login 外所有页面使用
lazy() 按需加载
版本(以实际 package.json 为准)
React 19.2.4 / Ant Design 6.3.5 / React Router 7.14.0 / Zustand 5.0.12 / Vite 8.0.4 / TypeScript 6.0.2
2. 关键文件 + 数据流
核心文件
| 文件 |
职责 |
apps/web/src/main.tsx |
React 入口 |
apps/web/src/App.tsx |
路由定义(公开 + 受保护) |
apps/web/src/layouts/MainLayout.tsx |
SaaS 后台管理布局 |
apps/web/src/stores/ |
4 个 Zustand store |
apps/web/src/api/ |
28 个 API 服务文件(含 7 个健康模块 API) |
apps/web/vite.config.ts |
Vite 配置 + API 代理 |
微信小程序(患者端)是独立前端项目,详见 miniprogram
路由结构
公开: /login
受保护(MainLayout 包裹):
| 路径 |
页面 |
/ |
首页 |
/users, /roles, /organizations |
用户/角色/组织管理 |
/workflow |
工作流 |
/messages |
消息中心 |
/settings |
系统设置 |
/plugins/admin, /plugins/market |
插件管理/市场 |
/plugins/:pluginId/:entityName |
插件 CRUD(动态生成) |
| `/plugins/:pluginId/tabs |
tree |
健康管理路由(10 条):
| 路径 |
页面 |
/health/patients |
患者列表 |
/health/patients/:id |
患者详情(5 个标签页:基本信息/体征/化验/健康档案/随访) |
/health/patient-tags |
患者标签管理 |
/health/doctors |
医护管理 |
/health/schedules |
排班管理(含日历视图) |
/health/appointments |
预约管理(含状态流转) |
/health/follow-up-tasks |
随访任务列表 |
/health/follow-up-records |
随访记录 |
/health/consultations |
咨询会话列表 |
/health/consultations/:id |
咨询详情(含消息 + 导出) |
健康模块共享组件(12 个)
| 组件 |
用途 |
StatusTag |
预约/随访/咨询状态标签(含单元测试) |
PatientSelect |
患者搜索选择器(远程搜索) |
DoctorSelect |
医护搜索选择器(远程搜索) |
CalendarView |
排班日历视图 |
ExportButton |
咨询记录导出按钮 |
VitalSignsChart |
体征数据折线图 |
VitalSignsTab |
患者详情-体征标签页 |
LabReportsTab |
患者详情-化验报告标签页 |
HealthRecordsTab |
患者详情-健康档案标签页 |
FollowUpTab |
患者详情-随访标签页 |
ImagePreview |
图片预览组件 |
集成契约
| 方向 |
模块 |
接口 |
触发时机 |
| 调用 → |
erp-server |
/api/v1/* REST |
所有数据操作 |
| 调用 → |
erp-server |
ws://localhost:3000/ws/* |
WebSocket |
| 消费 ← |
插件系统 |
plugin.toml schema |
动态生成插件页面 |
| 调用 → |
erp-health |
/api/v1/health/* |
健康模块所有数据操作 |
3. 代码逻辑
状态管理(4 个 Zustand Store)
| Store |
状态 |
app.ts |
theme(light/dark), sidebarCollapsed |
auth.ts |
user, isAuthenticated, localStorage 持久化 |
message.ts |
unreadCount, recentMessages, 请求去重 |
plugin.ts |
plugins 列表, 动态菜单, schema 缓存, 请求去重 |
健康模块 API 文件(7 个)
| 文件 |
覆盖端点 |
patients.ts |
患者 CRUD + 标签 + 健康摘要 + 家庭成员 |
doctors.ts |
医护档案 CRUD |
appointments.ts |
预约 CRUD + 状态流转 |
healthData.ts |
体征/化验/健康档案/趋势 |
followUp.ts |
随访任务 + 记录 |
consultations.ts |
咨询会话 + 消息 + 导出 |
articles.ts |
健康文章 |
前端单元测试(3 个)
| 文件 |
测试内容 |
constants/health.test.ts |
健康常量定义验证 |
hooks/useThemeMode.test.ts |
暗色模式 hook |
pages/health/components/StatusTag.test.tsx |
状态标签渲染 |
插件页面系统
插件通过 plugin.toml schema 声明页面,前端根据 schema 动态生成:
PluginCRUDPage — 标准列表+表单
PluginTabsPage — 标签页切换
PluginTreePage — 树形展示
PluginGraphPage — 关系图谱
PluginKanbanPage — 看板视图
PluginDashboardPage — 仪表盘
⚡ 不变量: 插件菜单由 plugin.ts store 从 API 动态获取,不硬编码
⚡ 不变量: API client 在请求前 30s 检查 token 过期,提前刷新避免 401
⚡ 不变量: DatePicker 返回 dayjs 对象,提交前必须 .format('YYYY-MM-DD') 转字符串
代理配置
4. 活跃问题 + 陷阱
⚠️ Ant Design 6 废弃 destroyOnClose,应使用 destroyOnHidden
⚠️ Ant Design 6 废弃 API 警告(valueStyle/Spin tip/trailColor)已在历史版本中修复
⚠️ antd.setScaleParam 强制回流 64ms — antd 内部问题,无法直接修复
历史教训
- DatePicker 提交 dayjs 对象而非字符串 → 后端 422
birth_date trailing input — 必须调用 .format('YYYY-MM-DD')
- 预约表单医护字段标为可选但后端必填 → 400
doctor_id is required — 医护为必填(CAS 排班需要)
5. 变更记录
| 日期 |
变更 |
| 2026-04-25 |
全面更新:10 条健康路由、12 个共享组件、7 个健康 API 文件、3 个单元测试 |
| 2026-04-24 |
添加小程序交叉引用 |
| 2026-04-23 |
重构为 5 节结构,更新为当前完整前端状态 |