Files
hms/wiki/miniprogram.md
iven 40b5141832
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 文档至当前实现状态
9 个 wiki 页面全部更新:
- index: 关键数字更新(15 crate/48 表/50 迁移/6 模块)
- erp-health: 从"规划中"更新为"已实现"(18 实体/14 权限)
- erp-server: 6 模块注册/8 环境变量/5 后台任务
- database: 50 迁移/48 表/健康模块迁移(m000042-m000050)
- frontend: 10 健康路由/12 共享组件/7 健康 API/3 单元测试
- miniprogram: 20 页面/10 服务/9 组件
- testing: 93 后端测试+3 前端测试/全链路验证结果
- erp-core: 新增 erp-health 集成契约
- architecture: 6 模块实现状态表/预约 CAS/PII 加密
2026-04-25 11:57:20 +08:00

206 lines
7.5 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: 微信小程序(患者端)
updated: 2026-04-25
status: active
tags: [miniprogram, taro, wechat, patient]
---
# 微信小程序(患者端)
> 从 [[index]] 导航。关联: [[infrastructure]] [[erp-server]] [[erp-health]]
## 1. 设计决策
- **Taro 4.2 + React 18** — 跨平台小程序框架React 生态
- **Zustand 状态管理** — 与 Web 前端一致的 store 模式
- **微信登录流程** — `Taro.login()` → code → 后端 `jscode2session` → openid → JWT
- **build 时注入环境变量** — `process.env` 在小程序运行时不存在,必须通过 `defineConstants` 编译时替换
- **不使用浏览器 Web API** — `btoa`/`atob` 等在小程序中不可用,用 Taro 原生 API 替代
- **Zod 输入验证** — 健康数据录入使用 Zod schema 验证
### 版本
Taro 4.2 / React 18 / TypeScript / Zustand 5 / Sass / Zod
## 2. 关键文件 + 数据流
### 核心文件
| 文件 | 职责 |
|------|------|
| `apps/miniprogram/config/index.ts` | Taro 构建配置defineConstants 注入环境变量) |
| `apps/miniprogram/src/services/request.ts` | HTTP 请求封装401 自动刷新、错误处理) |
| `apps/miniprogram/src/services/auth.ts` | 微信登录/绑定手机号 API |
| `apps/miniprogram/src/stores/auth.ts` | 认证状态login/bindPhone/restore |
| `apps/miniprogram/src/utils/secure-storage.ts` | token 安全存储XOR + Base64 混淆) |
| `apps/miniprogram/project.config.json` | 微信开发者工具配置AppID、urlCheck |
### 微信登录流程
```
用户点击"微信一键登录"
Taro.login() → 临时 code
POST /auth/wechat/login { code }
后端调用微信 jscode2session → 获取 openid + session_key
查询 wechat_users 表
├── 已绑定 → 返回 { bound: true, token: JWT } → 跳转首页
└── 未绑定 → 返回 { bound: false, openid } → 显示"授权手机号"按钮
↓ 用户授权手机号
POST /auth/wechat/bind-phone { openid, encrypted_data, iv }
后端解密手机号 → 创建/关联用户 → 返回 JWT → 跳转首页
```
### 页面结构20 个页面10 个目录)
| 页面路径 | 说明 |
|----------|------|
| `pages/login/index` | 登录页(微信登录 + 协议勾选) |
| `pages/index/index` | 首页(今日健康、快捷服务) |
| `pages/health/trend/index` | 健康趋势(体征数据折线图) |
| `pages/health/input/index` | 健康数据录入Zod 验证) |
| `pages/appointment/create/index` | 预约挂号 |
| `pages/appointment/detail/index` | 预约详情 |
| `pages/article/index` | 健康资讯 |
| `pages/profile/index` | 个人中心 |
| `pages/profile/family/index` | 家庭成员管理 |
| `pages/followup/detail/index` | 随访详情 |
| `pages/report/index` | 健康报告查看 |
| `pages/legal/user-agreement` | 用户服务协议 |
| `pages/legal/privacy-policy` | 隐私政策 |
### 服务层10 个文件)
| 文件 | 覆盖 |
|------|------|
| `request.ts` | HTTP 封装401 刷新、错误处理) |
| `auth.ts` | 微信登录/绑定手机号 |
| `health.ts` | 体征数据/健康趋势 |
| `patient.ts` | 患者信息/家庭成员 |
| `appointment.ts` | 预约挂号/详情/取消 |
| `followup.ts` | 随访任务/详情 |
| `article.ts` | 健康文章 |
| `report.ts` | 健康报告 |
| `analytics.ts` | 数据分析 |
| `wechat-templates.ts` | 微信模板消息 ID |
### 组件9 个)
| 组件 | 用途 |
|------|------|
| `EmptyState` | 空状态占位 |
| `ErrorBoundary` | 错误边界捕获 |
| `ErrorState` | 错误状态展示 |
| `FamilyPicker` | 家庭成员选择器 |
| `HealthCard` | 健康数据卡片 |
| `Loading` | 加载状态 |
| `StepIndicator` | 步骤指示器 |
| `TrendChart` | 趋势图表ECharts |
| `WeekCalendar` | 周日历组件 |
### 集成契约
| 方向 | 模块 | 接口 | 触发时机 |
|------|------|------|---------|
| 调用 → | [[erp-server]] | `POST /auth/wechat/login` | 微信登录 |
| 调用 → | [[erp-server]] | `POST /auth/wechat/bind-phone` | 手机号绑定 |
| 调用 → | [[erp-health]] | `/api/v1/health/*` | 健康数据查询 |
| 调用 → | [[erp-server]] | `/api/v1/auth/refresh` | Token 刷新 |
## 3. 代码逻辑
### 环境变量注入(关键)
小程序运行时没有 `process.env`,必须在 `config/index.ts` 中通过 `defineConstants` 编译时替换:
```typescript
defineConstants: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.TARO_APP_API_URL': JSON.stringify(process.env.TARO_APP_API_URL || 'http://localhost:3000/api/v1'),
'process.env.TARO_APP_ENCRYPTION_KEY': JSON.stringify(process.env.TARO_APP_ENCRYPTION_KEY || ''),
},
```
### Token 安全存储
`secure-storage.ts` 使用 XOR 混淆 + Base64 编码存储 token
- **不使用 `btoa`/`atob`** — 小程序环境不支持
- 使用 `Taro.arrayBufferToBase64` / `Taro.base64ToArrayBuffer` 替代
- 加密密钥通过 `TARO_APP_ENCRYPTION_KEY` 环境变量注入
### 请求封装request.ts
- 401 自动尝试 refresh token失败后跳转登录页
- 错误响应格式: `{ error: string, message: string }`(无 `success` 字段)
- 成功响应格式: `{ success: true, data: T }`
- 当前 URL 拼接方式构建查询参数(待重构为 params 对象)
### 健康数据录入验证
使用 Zod schema 验证用户输入的体征数据(血压、心率、体重、血糖),确保数据类型和范围合法。
## 4. 构建与调试
### 构建
```bash
cd apps/miniprogram && pnpm build:weapp # 生产构建
cd apps/miniprogram && npx taro build --type weapp # 等效
```
### 微信开发者工具配置
| 配置项 | 值 | 说明 |
|--------|-----|------|
| AppID | `wx20f4ef9cc2ec66c5` | 真实微信 AppID |
| urlCheck | `false` | 不校验合法域名(开发模式) |
| miniprogramRoot | `dist/` | 编译输出目录 |
### 后端微信配置
`crates/erp-server/config/default.toml`:
```toml
[wechat]
appid = "wx20f4ef9cc2ec66c5"
secret = "<通过环境变量 ERP__WECHAT__SECRET 设置>"
```
## 5. 活跃问题 + 陷阱
### 历史教训
| 问题 | 根因 | 修复 |
|------|------|------|
| 页面空白 `ReferenceError: process is not defined` | `process.env` 在运行时不存在 | `defineConstants` 编译时替换 |
| 登录成功但前端报失败 `btoa is not defined` | `secure-storage.ts` 使用 Web API | 改用 `Taro.arrayBufferToBase64` |
| 微信登录 500 `wechat_users.created_by 不存在` | 迁移创建的表缺少标准字段 | `ALTER TABLE` 补列 |
| 401 循环重定向 | 首页未登录时 `request.ts` 反复 redirectTo | 检查当前路径避免重复跳转 |
### 待优化
| 问题 | 级别 | 说明 |
|------|------|------|
| URL 拼接构建查询参数 | P2 | `request.ts` 应支持 params 对象 |
| 加密密钥硬编码 | P0 | 需外部化到 `TARO_APP_ENCRYPTION_KEY` 环境变量 |
| Auth token 日志输出 | P0 | 生产环境需移除 console.log |
| 生产配置 | P2 | `urlCheck`/`minified` 需区分环境 |
### 注意事项
- `Taro.login()` 的 code 一次性使用,每次调用会返回新 code
- `session_key` 缓存 5 分钟TTL过期需重新登录
- 微信开发者工具中 `getPhoneNumber` 需要真机调试或使用测试号
- Redis 不可达时限流降级为 fail-open不影响登录
## 6. 变更记录
| 日期 | 变更 |
|------|------|
| 2026-04-25 | 全面更新20 页面、10 服务、9 组件、Zod 验证、加密密钥外部化说明 |
| 2026-04-24 | 创建小程序 wiki 页面,记录登录流程、环境配置、历史陷阱 |