- wiki/miniprogram.md §6: 完整 MCP 联调文档 - 前置条件与建立连接 - 16 个 MCP 工具使用说明 - 绕过微信登录的 storage 注入流程 - TabBar 页面列表与导航注意事项 - 已知限制:screenshot 超时、navigateTo 超时、auth 重定向 - e2e 验证脚本说明 - wiki/index.md: 新增 3 条 MCP 相关症状导航
13 KiB
title, updated, status, tags
| title | updated | status | tags | ||||
|---|---|---|---|---|---|---|---|
| 微信小程序(患者端) | 2026-04-26 | active |
|
微信小程序(患者端)
从 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 → 跳转首页
页面结构(40 个页面,15 个目录)
患者端页面
| 页面路径 | 说明 |
|---|---|
pages/login/index |
登录页(微信登录 + 协议勾选) |
pages/index/index |
首页(今日健康、快捷服务) |
pages/health/index |
健康上报(Tab 页) |
pages/health/input/index |
健康数据录入(Zod 验证) |
pages/health/trend/index |
健康趋势(体征数据折线图) |
pages/health/daily-monitoring/index |
日常监测数据 |
pages/appointment/index |
预约列表 |
pages/appointment/create/index |
预约挂号 |
pages/appointment/detail/index |
预约详情 |
pages/article/index |
健康资讯列表 |
pages/article/detail/index |
文章详情 |
pages/report/detail/index |
健康报告详情 |
pages/ai-report/list/index |
AI 分析报告列表 |
pages/ai-report/detail/index |
AI 分析报告详情 |
pages/followup/detail/index |
随访详情 |
pages/consultation/index |
咨询列表(Tab 页) |
pages/consultation/detail/index |
咨询详情 |
pages/mall/index |
积分商城(Tab 页) |
pages/mall/detail/index |
商品详情 |
pages/mall/exchange/index |
积分兑换 |
pages/mall/orders/index |
积分订单 |
pages/events/index |
线下活动 |
pages/profile/index |
个人中心(Tab 页) |
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 |
设置 |
pages/legal/user-agreement |
用户服务协议 |
pages/legal/privacy-policy |
隐私政策 |
医护端页面(8 个)
| 页面路径 | 说明 |
|---|---|
pages/doctor/index |
医护首页 |
pages/doctor/patients/index |
患者列表 |
pages/doctor/patients/detail/index |
患者详情 |
pages/doctor/consultation/index |
咨询管理 |
pages/doctor/consultation/detail/index |
咨询详情 |
pages/doctor/followup/index |
随访管理 |
pages/doctor/followup/detail/index |
随访详情 |
pages/doctor/report/index |
报告管理 |
pages/doctor/report/detail/index |
报告详情 |
服务层(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 编译时替换:
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. 构建与调试
构建
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:
[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 一次性使用,每次调用会返回新 codesession_key缓存 5 分钟(TTL),过期需重新登录- 微信开发者工具中
getPhoneNumber需要真机调试或使用测试号 - Redis 不可达时限流降级为 fail-open,不影响登录
6. MCP 联调(微信开发者工具自动化)
通过 MCP (Model Context Protocol) 工具直接操控微信开发者工具中的小程序模拟器,实现页面导航、元素交互、数据读取等操作。
6.1 前置条件
- 后端运行 —
cargo run启动http://localhost:3000 - 小程序已构建 —
cd apps/miniprogram && pnpm build:weapp - 微信开发者工具已打开项目 — 加载
apps/miniprogram/dist/ - 自动化端口已开启 —
project.config.json中"automationAudits": true,端口 9420
6.2 建立连接
调用 mp_ensureConnection → 自动连接 ws://localhost:9420
成功后返回系统信息(SDK 版本、设备型号、屏幕尺寸等)。
6.3 常用 MCP 操作
| 操作 | MCP 工具 | 说明 |
|---|---|---|
| 查看当前页面 | mp_currentPage |
返回路径、尺寸、数据 |
| 导航到页面 | mp_navigate |
navigateTo / switchTab / reLaunch |
| 返回上一页 | mp_navigate |
transition: "navigateBack" |
| 截图 | mp_screenshot |
⚠️ 当前版本超时,见下方限制 |
| 读取 storage | mp_callWx |
method: getStorageSync |
| 写入 storage | mp_callWx |
method: setStorageSync |
| 查找元素 | page_getElement |
CSS 选择器,返回标签/文本/尺寸 |
| 查找多个元素 | page_getElements |
CSS 选择器数组 |
| 点击元素 | element_tap |
CSS 选择器定位后点击 |
| 输入文本 | element_input |
CSS 选择器 + 值 |
| 读取组件数据 | element_getData |
获取自定义组件的 data |
| 设置组件数据 | element_setData |
修改自定义组件的 data |
| 读取页面数据 | page_getData |
获取当前页面 data 对象 |
| 设置页面数据 | page_setData |
修改当前页面 data |
| 调用页面方法 | page_callMethod |
调用当前页面上暴露的方法 |
| 等待元素出现 | page_waitElement |
轮询等待选择器匹配 |
6.4 绕过微信登录
MCP 无法模拟微信 OAuth,需要通过 mp_callWx 直接写入加密 auth 数据:
1. 调用后端 API 获取 admin token:
POST /api/v1/auth/login { username: "admin", password: "Admin@2026" }
2. 用 CryptoJS.AES.encrypt(token, ENC_KEY) 加密
3. 通过 mp_callWx 写入 storage:
setStorageSync("access_token", encrypted_token)
setStorageSync("refresh_token", encrypted_refresh)
setStorageSync("user_data", encrypted_user_json)
setStorageSync("user_roles", encrypted_roles_json)
setStorageSync("tenant_id", encrypted_tenant_id)
setStorageSync("current_patient", patient_object)
setStorageSync("current_patient_id", patient_id)
4. reLaunch 到首页
ENC_KEY: 0a17b71d46064b06f993c9c202b342425e311a79f5be026d830562e7ad51f522
⚠️ 注意:写完 storage 后必须立即 reLaunch,否则 app 的 API 请求会因 token 无效触发 401 → logout 清空 storage。
6.5 TabBar 页面列表
以下页面是 TabBar 页面,必须用 switchTab 导航(不能用 navigateTo):
pages/index/index— 首页pages/health/index— 健康数据pages/consultation/index— 咨询pages/mall/index— 积分商城pages/profile/index— 个人中心
6.6 已知限制
| 问题 | 原因 | 替代方案 |
|---|---|---|
| mp_screenshot 超时 | miniprogram-automator 的 screenshot() 方法在当前 DevTools 版本卡死 |
用 page_getElement + page_getData 获取 UI 状态 |
| navigateTo 超时 | 某些页面的 API 调用阻塞了页面渲染回调 | 页面实际已加载,用 mp_currentPage 确认路径 |
| auth 重定向 | app 的 request interceptor 检测 401 后自动跳转 login 并清空 storage | 确保 token 有效,reLaunch 后等待足够时间 |
| getStorageSync 返回空 | reLaunch 触发 app 初始化,401 → logout 清空了 storage | 检查 token 是否过期,必要时重新注入 |
6.7 端到端验证脚本
apps/miniprogram/e2e-final.cjs 使用 miniprogram-automator Node.js 库执行完整链路验证:
- 11 条 UI 链路(页面导航 + 元素交互)
- 10 个 API 数据闭环验证
- 加密 storage 注入绕过微信登录
- 超时保护避免卡死
运行:cd apps/miniprogram && node e2e-final.cjs
7. 变更记录
| 日期 | 变更 |
|---|---|
| 2026-04-27 | 新增 §6 MCP 联调章节:连接、操作列表、绕过登录、已知限制、e2e 脚本 |
| 2026-04-26 | 全面更新:40 页面(含 9 个医护端页面)、15 目录、5 个 Tab 页、积分商城、线下活动 |
| 2026-04-25 | 全面更新:20 页面、10 服务、9 组件、Zod 验证、加密密钥外部化说明 |
| 2026-04-24 | 创建小程序 wiki 页面,记录登录流程、环境配置、历史陷阱 |