# HMS 患者小程序设计规格 > **版本**: v1.0 > **日期**: 2026-04-23 > **状态**: 草案 > **关联**: 健康模块设计规格 `2026-04-23-health-management-module-design.md` --- ## 1. 概述 ### 1.1 产品定位 HMS 患者小程序是**综合健康管理入口**,面向体检中心/医疗机构的患者。覆盖体检预约、报告查询、健康数据长期监测、随访管理、家庭健康管理等场景。 医护端以 PC 管理后台(`apps/web/`)为主力,小程序聚焦患者体验。医护端小程序可在后续按需补一个轻量版(随访提醒、排班查看),不在本规格范围内。 ### 1.2 核心决策 | 维度 | 决策 | 原因 | |------|------|------| | 技术选型 | Taro 4 + React 19 | 与 Web 端 React 技能复用,支持多端编译 | | 架构方案 | 直连后端 | MVP 阶段最务实,复用 erp-server API | | 登录方式 | 微信授权 + 手机号补充 | 降低门槛 + 确保身份可靠 | | 代码位置 | `apps/miniprogram/`(Monorepo) | 方便接口同步,共享类型定义 | | 目标平台 | 微信小程序优先 | 覆盖最广泛用户,后续可扩展 | | 数据录入 | 手动 + 蓝牙预留接口 | MVP 快速交付,后续对接设备 | | 视觉风格 | 医疗清新(青色主调) | 专业可靠,沿用现有 HTML 原型风格 | ### 1.3 MVP 功能范围 **MVP 包含(7 个功能模块):** 1. 登录 + 个人中心 2. 健康数据录入 + 趋势图 3. 预约挂号 4. 报告查询 5. 随访管理 6. 家庭健康管理(就诊人切换) 7. 健康资讯 + 用药提醒 **后续版本:** - 在线咨询(即时通讯,WebSocket 长连接) --- ## 2. 项目结构 ``` apps/miniprogram/ ├── config/ # Taro 编译配置 │ ├── index.ts # 通用配置 │ ├── dev.ts # 开发环境 │ └── prod.ts # 生产环境 ├── project.config.json # 微信小程序项目配置 ├── src/ │ ├── app.config.ts # Taro 全局配置(TabBar、页面路由) │ ├── app.tsx # 入口组件 │ ├── app.scss # 全局样式(医疗清新主题变量) │ ├── components/ # 通用组件 │ │ ├── HealthCard/ # 健康指标卡片(血压/血糖/体重) │ │ ├── AppointmentCard/ # 预约卡片 │ │ ├── ReportItem/ # 报告列表项 │ │ ├── FamilyPicker/ # 就诊人切换器 │ │ ├── EmptyState/ # 空状态占位 │ │ └── TrendChart/ # 趋势图(echarts-taro3-react) │ ├── pages/ │ │ ├── index/ # 首页(今日健康+快捷入口+待办) │ │ ├── health/ # 健康数据(录入+趋势图) │ │ ├── appointment/ # 预约(列表+新建预约) │ │ ├── report/ # 报告(体检报告+化验单) │ │ ├── followup/ # 随访(任务+问卷填写) │ │ ├── article/ # 健康资讯(文章列表+详情) │ │ ├── profile/ # 我的(个人信息+就诊人管理+设置) │ │ └── login/ # 登录(微信授权+手机号) │ ├── services/ # API 调用层 │ │ ├── request.ts # 封装 Taro.request(JWT 注入、错误处理) │ │ ├── auth.ts # 登录/刷新 token │ │ ├── health.ts # 健康数据 CRUD │ │ ├── appointment.ts # 预约 CRUD │ │ ├── report.ts # 报告查询 │ │ ├── followup.ts # 随访任务/记录 │ │ └── article.ts # 资讯/科普 │ ├── stores/ # Zustand 状态管理 │ │ ├── auth.ts # 登录态、用户信息、就诊人列表 │ │ └── health.ts # 健康数据缓存 │ ├── utils/ │ │ ├── bluetooth.ts # 蓝牙接口预留(MVP 不实现) │ │ ├── format.ts # 日期/数值格式化 │ │ └── constants.ts # 常量定义 │ └── styles/ │ ├── variables.scss # 主题变量(青色主调) │ └── mixins.scss # 常用样式混入 ├── package.json └── tsconfig.json ``` **设计原则:** - services 层与 Web 端 `apps/web/src/api/` 职责对齐,用 Taro.request 替代 fetch - stores 复用 Zustand 模式,与 Web 端保持一致的状态管理风格 - 组件命名 PascalCase 目录,与 Web 端风格统一 - MVP 阶段不强抽取 `packages/shared/`,等两端跑起来后根据重复度决定 --- ## 3. 认证流程 ### 3.1 整体流程 ``` 用户打开小程序 ↓ 检查本地 storage 有无有效 JWT ├── 有且未过期 → 直接进入首页 └── 无或已过期 ↓ Step 1: 微信静默登录 wx.login() → code → POST /api/v1/auth/wechat/login { code } → 后端用 code 换 openid,查找绑定用户 ├── 已绑定 → 签发 JWT { token, user } └── 未绑定 → 返回 { need_bind: true, openid } Step 2: 手机号绑定(仅新用户) wx.getPhoneNumber 按钮组件 → encryptedData + iv → POST /api/v1/auth/wechat/bind-phone { openid, encryptedData, iv } → 后端解密手机号,创建/关联 user + patient 档案 → 签发 JWT { token, user, patient } Step 3: 补充档案(首次绑定后) → 引导填写姓名、性别、出生日期、身份证号(可选) → PUT /api/v1/health/patients/me { name, gender, birthday } ``` ### 3.2 后端新增内容 **`erp-auth` 新增:** | 新增 | 说明 | |------|------| | `wechat_users` 表 | `id, openid, union_id, user_id, phone, created_at, updated_at` | | `POST /api/v1/auth/wechat/login` | code → openid 查询,返回绑定状态 | | `POST /api/v1/auth/wechat/bind-phone` | 绑定手机号,创建 user + patient | | `GET /api/v1/auth/wechat/qrcode` | 生成带参数小程序码(PC 端扫码登录场景) | `wechat_users` 表必须包含 `tenant_id`(多租户隔离)和标准审计字段(`created_at`, `updated_at`, `deleted_at`)。 ### 3.3 Token 策略 | Token | 有效期 | 存储 | |-------|--------|------| | Access Token (JWT) | 15 分钟 | 内存 + Taro.setStorage | | Refresh Token | 7 天 | Taro.setStorage | 自动刷新机制:`services/request.ts` 拦截 401 → 调用 `POST /auth/refresh` → 重试原请求。刷新失败则跳转登录页。 ### 3.4 多就诊人 - 一个微信账号可管理多个 patient(本人 + 家人) - 切换就诊人时请求 header 带 `X-Patient-Id` - 后端校验该 patient 属于当前 user --- ## 4. 页面结构与导航 ### 4.1 Tab Bar 底部导航栏 5 个入口: | Tab | 图标 | 页面路径 | |-----|------|----------| | 首页 | 🏠 | /pages/index/index | | 健康 | 📊 | /pages/health/index | | 预约 | 📅 | /pages/appointment/index | | 资讯 | 📰 | /pages/article/index | | 我的 | 👤 | /pages/profile/index | ### 4.2 页面层级 ``` Tab: 首页 /pages/index ├── /pages/notifications/index # 通知列表 └── /pages/followup/detail/index # 随访任务详情 Tab: 健康 /pages/health ├── /pages/health/input/index # 录入数据 ├── /pages/health/trend/index # 指标趋势 └── /pages/health/history/index # 历史记录 Tab: 预约 /pages/appointment ├── /pages/appointment/create/index # 新建预约 └── /pages/appointment/detail/index # 预约详情 Tab: 资讯 /pages/article └── /pages/article/detail/index # 文章详情 Tab: 我的 /pages/profile ├── /pages/profile/family/index # 就诊人管理 ├── /pages/profile/family-add/index # 添加就诊人 ├── /pages/profile/reports/index # 我的报告 ├── /pages/profile/followups/index # 我的随访 ├── /pages/profile/medication/index # 用药提醒 └── /pages/profile/settings/index # 设置 独立页面(不在 Tab 内): ├── /pages/login/index # 登录 └── /pages/login/profile/index # 档案补全 ``` ### 4.3 首页布局 ``` ┌─────────────────────────────┐ │ 问候栏(渐变青色背景) │ 用户名 + 日期 + 通知铃铛 ├─────────────────────────────┤ │ 今日健康卡片(上浮 -20px) │ 血压/心率/血糖/体重 2×2 网格 ├─────────────────────────────┤ │ 快捷服务(4 宫格) │ 录数据/预约/报告/随访 ├─────────────────────────────┤ │ 即将到来 │ 最近 1 条预约卡片 ├─────────────────────────────┤ │ 待办随访 │ 最多 2 条待办 + 查看全部 ├─────────────────────────────┤ │ [ 首页 ] [ 健康 ] [ 预约 ] [ 资讯 ] [ 我的 ] │ └─────────────────────────────┘ ``` --- ## 5. 核心功能数据流 ### 5.1 健康数据录入 ``` 选择指标类型 → 输入数值 + 测量时间 → 添加备注(可选)→ POST /vital-signs ↓ 成功 → 更新首页卡片 + 趋势缓存 失败 → Toast + 本地暂存 ``` **MVP 支持的指标类型:** | 指标 | 单位 | 输入控件 | |------|------|---------| | 收缩压 / 舒张压 | mmHg | 两个数字输入框 | | 心率 | bpm | 数字输入框 | | 空腹血糖 | mmol/L | 数字输入框 | | 餐后血糖 | mmol/L | 数字输入框 | | 体重 | kg | 数字输入框(1 位小数) | | 体温 | ℃ | 数字输入框(1 位小数) | 每次可同时填多项或只填一项。录入时间默认当前,可手动调整为当天任意时间。 ### 5.2 预约挂号 ``` 选择科室 → 选择医生 → 选择日期(排班日历)→ 选择时段 → 确认预约 ↓ POST /appointments ↓ 成功 → 订阅消息通知 + 日历同步 满员 → 提示"该时段已满" ``` **关键交互:** - 排班日历用周视图,有排班的日期标绿点 - 点击日期后展示该日可用时段 - 时段显示"剩余 X 位" - 预约成功后支持微信订阅消息提醒 ### 5.3 报告查询 ``` 报告列表(分页,时间倒序) ↓ 点击某份报告 报告详情 → 基本信息卡 + 指标列表 + PDF/图片附件预览 ``` **指标状态标记:** - 异常偏高:红色 + ↑ 箭头 - 异常偏低:红色 + ↓ 箭头 - 正常范围:灰色 ### 5.4 随访管理 ``` 待办列表(按截止日期排序) ↓ 支持"待完成/已完成/已过期"筛选 点击任务 → 动态表单(后端定义字段)→ 提交 → 标记完成 ``` 问卷由 PC 端医护创建(follow_up_task),小程序负责展示和填写。提交后创建 follow_up_record。 ### 5.5 家庭健康管理 ``` 就诊人列表(本人 + 已添加家属) ↓ 点击头像或下拉切换 切换就诊人 → 全局 X-Patient-Id 更新 → 所有页面数据刷新 ↓ 添加家属 填写信息 → 姓名 + 关系 + 身份证号(可选)→ POST /patients ``` 切换就诊人通过全局 store 更新,所有 service 请求自动携带新 `X-Patient-Id`。 ### 5.6 健康资讯 + 用药提醒 **资讯:** - `GET /articles` → 分页列表(缩略图 + 标题 + 摘要 + 时间) - 文章详情使用 Taro `RichText` 组件渲染富文本 **用药提醒(MVP):** - 小程序本地 storage 存储提醒规则(药品名 + 频率 + 时间) - 每日触发检查 - 通过微信订阅消息推送提醒 - 不依赖后端新表 --- ## 6. API 集成与状态管理 ### 6.1 请求层封装 `services/request.ts` 职责: | 拦截点 | 行为 | |--------|------| | 请求拦截 | 自动注入 `Authorization: Bearer {token}` | | 请求拦截 | 自动注入 `X-Patient-Id`(当前选中就诊人) | | 请求拦截 | 自动注入 `X-Tenant-Id`(从登录信息获取) | | 响应拦截 | 401 → 静默刷新 token → 重试原请求 | | 响应拦截 | 刷新失败 → 跳转登录页 | | 错误处理 | 网络错误 / 业务错误 / 超时统一处理 | 多租户处理:患者只属于一个租户。登录时后端返回 `tenant_id`,前端每次请求带上。不走 `tenant_id` 中间件自动注入。 ### 6.2 Zustand Stores **auth store:** ```typescript interface AuthState { token: string | null refreshToken: string | null user: { id: string; name: string; phone: string; avatar: string } | null currentPatient: Patient | null patients: Patient[] setCurrentPatient: (id: string) => void login: (code: string) => Promise bindPhone: (data: BindPhoneData) => Promise logout: () => void } ``` **health store:** ```typescript interface HealthState { todaySummary: VitalSigns | null trendData: Record refreshToday: () => Promise getTrend: (type: string, range: '7d' | '30d' | '90d') => Promise } ``` ### 6.3 API 端点对应表 | 小程序 service | 后端端点 | 方法 | |----------------|----------|------| | `auth.login(code)` | `/api/v1/auth/wechat/login` | POST | | `auth.bindPhone(data)` | `/api/v1/auth/wechat/bind-phone` | POST | | `auth.refresh()` | `/api/v1/auth/refresh` | POST | | `health.getToday()` | `/api/v1/health/vital-signs?date=today` | GET | | `health.input(data)` | `/api/v1/health/vital-signs` | POST | | `health.getTrend(type, range)` | `/api/v1/health/vital-signs/trend` | GET | | `appointment.list()` | `/api/v1/health/appointments` | GET | | `appointment.create(data)` | `/api/v1/health/appointments` | POST | | `appointment.cancel(id)` | `/api/v1/health/appointments/:id/cancel` | PUT | | `schedule.getByDoctor(id)` | `/api/v1/health/doctor-schedules` | GET | | `report.list()` | `/api/v1/health/lab-reports` | GET | | `report.detail(id)` | `/api/v1/health/lab-reports/:id` | GET | | `followup.list()` | `/api/v1/health/follow-up-tasks` | GET | | `followup.submit(id, data)` | `/api/v1/health/follow-up-records` | POST | | `patient.list()` | `/api/v1/health/patients` | GET | | `patient.create(data)` | `/api/v1/health/patients` | POST | | `patient.update(id, data)` | `/api/v1/health/patients/:id` | PUT | **后端需新增的端点(尚未实现):** | 端点 | 说明 | |------|------| | `POST /auth/wechat/login` | 微信登录 | | `POST /auth/wechat/bind-phone` | 手机号绑定 | | `GET /vital-signs/trend` | 趋势聚合查询 | | `GET /doctor-schedules` | 按科室/医生查询排班 | | `GET /articles` | 健康资讯列表 | | `GET /articles/:id` | 资讯详情 | --- ## 7. 视觉设计 ### 7.1 主题色 沿用现有 HTML 原型的医疗清新风格: | 用途 | 色值 | 说明 | |------|------|------| | 主色 | `#0891B2` | 青色,按钮、导航、强调 | | 主色浅 | `#E0F7FA` | 背景、卡片高亮 | | 主色深 | `#065A73` | 渐变、按压态 | | 辅助色 | `#059669` | 绿色,成功、正常指标 | | 危险色 | `#DC2626` | 红色,异常指标、删除 | | 警告色 | `#D97706` | 琥珀,待办、提醒 | | 背景色 | `#F0FDFA` | 页面底色 | | 卡片色 | `#FFFFFF` | 卡片背景 | | 主文字 | `#134E4A` | 标题、正文 | | 副文字 | `#6B7280` | 说明、标签 | | 轻文字 | `#94A3B8` | 时间戳、占位符 | ### 7.2 圆角规范 | 元素 | 圆角 | |------|------| | 卡片 | 12px | | 按钮 | 8px | | 输入框 | 8px | | 头像 | 50% | | 快捷图标 | 14px | ### 7.3 阴影规范 | 层级 | 值 | |------|---| | 轻阴影 | `0 1px 3px rgba(0,0,0,.04)` | | 标准阴影 | `0 2px 8px rgba(0,0,0,.06)` | | 中阴影 | `0 4px 16px rgba(0,0,0,.08)` | | 重阴影 | `0 8px 32px rgba(0,0,0,.12)` | --- ## 8. 开发工作流 ### 8.1 开发环境 ```bash # 安装依赖 cd apps/miniprogram && pnpm install # 开发模式(需配合微信开发者工具) pnpm dev:weapp # Taro 编译 + watch → dist/ # 用微信开发者工具打开 dist/ 目录预览 # 生产构建 pnpm build:weapp # 压缩 + tree-shaking # 后端联调 # 需同时运行 erp-server (port 3000) # 小程序开发设置中关闭域名校验(开发阶段) ``` ### 8.2 与 Web 端的代码复用 | 复用内容 | 方式 | 说明 | |---------|------|------| | TypeScript 类型 | 按需引用 Web 端 DTO 类型 | API 请求/响应结构一致 | | 主题变量值 | Web CSS 变量 → SCSS 变量 | 青色主调色值保持一致 | | Zustand 模式 | 相同 store 设计模式 | 各自独立实现 | | API 接口定义 | service 层函数签名对齐 | Web 用 fetch,小程序用 Taro.request | ### 8.3 后端需同步开发的内容 | 优先级 | 内容 | 涉及 crate | |--------|------|-----------| | P0 | `wechat_users` 表 + 微信登录/绑定 API | erp-auth | | P0 | `vital_signs` 趋势查询 API | erp-health | | P0 | `doctor_schedules` 按科室/医生查询 API | erp-health | | P1 | `lab_reports` 指标异常标注字段 | erp-health | | P1 | `follow_up_tasks` 动态问卷字段扩展 | erp-health | | P2 | `articles` 表 + CRUD | erp-health | | P2 | 微信订阅消息模板注册 | erp-server | --- ## 9. 分期交付计划 | 阶段 | 内容 | 目标 | |------|------|------| | Phase 1 | 项目骨架 + 登录流程 + 首页(静态数据) | 基础搭建 | | Phase 2 | 健康数据录入 + 趋势图 | 核心功能 | | Phase 3 | 预约挂号 + 排班日历 | 核心功能 | | Phase 4 | 报告查询 + 家庭管理 | 扩展功能 | | Phase 5 | 随访 + 资讯 + 用药提醒 | 扩展功能 | | Phase 6 | 打磨 + 真机测试 + 提审 | 上线准备 | 每个 Phase 内部遵循:先对接后端 API → 再实现 UI → 真机验证 → 提交。 --- ## 10. 约束与风险 | 约束/风险 | 应对策略 | |-----------|---------| | 小程序包体积限制(2MB 主包) | 按功能分包加载,图表库按需引入 | | 微信审核周期(3-7 天) | Phase 6 预留充足审核时间 | | 后端 API 部分未实现 | 小程序开发与后端同步推进,优先实现 P0 端点 | | 微信订阅消息需用户主动触发 | 在预约成功、随访提交等场景引导用户订阅 | | 蓝牙设备适配复杂 | MVP 预留接口不实现,后续按设备型号逐一对接 | | 多就诊人数据隔离 | 后端严格校验 user-patient 归属关系 |