Files
hms/wiki/frontend.md
iven 2474905727
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
docs(wiki): 更新 VitalSignsChart 重设计记录 + 历史教训
2026-04-26 12:23:00 +08:00

204 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Web 前端
updated: 2026-04-25
status: stable
tags: [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. UI 规范
### SaaS 后台布局
经典 SaaS 后台管理布局(响应式,支持移动端):
```text
┌─────────────────────────────────────────────┐
│ LOGO 搜索... 🔔 5 👤 Admin ▾ │ ← 顶部导航栏
├─────────┬───────────────────────────────────┤
│ 📊 首页 │ │
│ 👥 用户 │ 主内容区域 │
│ 🔐 权限 │ (多标签页切换) │
│ 📋 流程 │ │
│ 💬 消息 │ │
│ ⚙️ 设置 │ │
│─────────│ │
│ 📦 进销存│ │
│ 🏭 生产 │ │
│ 💰 财务 │ │
│─────────│ │
│ ▸ 更多 │ │
└─────────┴───────────────────────────────────┘
```
### UI 规则
- 使用 Ant Design 组件库,不自造轮子
- 中文优先,所有文案通过 i18n key 引用
- 支持暗色/亮色主题切换
- 侧边栏按模块分组:基础模块 / 行业模块
- 表单验证使用 Ant Design Form 的 validateRules
## 3. 关键文件 + 数据流
### 核心文件
| 文件 | 职责 |
|------|------|
| `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|graph|dashboard|kanban/:name` | 插件多视图页面 |
**健康管理路由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` | 多指标趋势图:概览卡片条(5 指标 sparkline) + 点击展开详情折线图 |
| `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/*` | 健康模块所有数据操作 |
## 4. 代码逻辑
### 状态管理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')` 转字符串
### 代理配置
```
http://localhost:5174/api/* → http://localhost:3000/* (API)
ws://localhost:5174/ws/* → ws://localhost:3000/* (WebSocket)
```
## 5. 活跃问题 + 陷阱
⚠️ 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 排班需要)
- 趋势图后端 DTO `Vec<(NaiveDate, f64)>` 序列化为 JSON 数组 `[[date, value]]` 而非对象 `[{date, value}]` → 改用 `Vec<DataPoint>` 修复;前端 `extractData` 需同时处理 `ApiResponse` 包装和裸数组两种响应格式
- `IndicatorTimeseriesResp` 返回 `{ indicator, data: [...] }` 包装对象,不是裸数组 — `Array.isArray(res)` 为 false必须从 `res.data` 取值
## 6. 变更记录
| 日期 | 变更 |
|------|------|
| 2026-04-26 | 从 CLAUDE.md 迁移UI 布局规范§8 |
| 2026-04-26 | VitalSignsChart 重设计:概览卡片条 + 点击展开详情图5 指标独立 Y 轴 |
| 2026-04-25 | 全面更新10 条健康路由、12 个共享组件、7 个健康 API 文件、3 个单元测试 |
| 2026-04-24 | 添加小程序交叉引用 |
| 2026-04-23 | 重构为 5 节结构,更新为当前完整前端状态 |