Files
hms/wiki/miniprogram.md
iven c06e986090 fix(mp): 小程序页面优化 + E2E 测试报告更新
- 小程序各页面优化和修复
- 更新联调报告和 E2E 测试报告
- 更新 miniprogram wiki
2026-05-15 23:03:21 +08:00

51 KiB
Raw Blame History

title, updated, status, tags
title updated status tags
微信小程序(患者端) 2026-05-10 active
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 APIbtoa/atob 等在小程序中不可用,用 Taro 原生 API 替代
  • Zod 输入验证 — 健康数据录入使用 Zod schema 验证

版本

Taro 4.2 / React 18 / TypeScript / Zustand 5 / Sass / Zod / ECharts 6按需引入

依赖统一2026-04-27 移除 echarts-taro3-react(内嵌 Taro 3.0.8 + React 16导致 webpack 模块 ID 不一致 → Cannot read property 'call' of undefined)。改为自定义 EcCanvas 组件 + echarts/core 按需引入。taro.js chunk 从 152KB 降至 133KB。

1.1 设计系统:温润东方风

自 2026-04-27 起采用。所有新增/修改页面必须遵循此设计系统,保持视觉一致性。

设计系统源文件:apps/miniprogram/src/styles/variables.scss + mixins.scss + tokens.scss

设计哲学Kenya Hara 式东方极简。温润米底 + 单一赤土橙贯穿全场,留白呼吸感优先。

色彩

角色 变量名 色值 用途
强调色 $pri #C4623A 按钮、链接、活跃 tab、品牌色
强调浅 $pri-l #F0DDD4 图标底色、高亮背景
强调深 $pri-d #8B3E1F 渐变终点、暗色变体
背景 $bg #F5F0EB 页面底色warm cream
卡片 $card #FFFFFF 白色卡片
辅助底 $surface-alt #EDE8E2 次级表面、分隔
主文字 $tx #2D2A26 warm black标题和正文
次文字 $tx2 #7A756E 辅助说明、标签
淡文字 $tx3 #A8A29E 占位、时间戳、箭头
边框 $bd / $bd-l #E8E2DC / #F0EBE5 分隔线、卡片边框
成功 $acc / $acc-l #5B7A5E / #E8F0E8 sage green 正常状态
警告 $wrn / $wrn-l #C4873A / #FFF3E0 warm amber 偏高/待确认
危险 $dan / $dan-l #B54A4A / #FDEAEA muted red 异常/删除

字体

用途 字体栈 说明
标题 / 数据数字 Georgia, Times New Roman, serif 衬线体,传递专业与温度。用 @include serif-number
正文 / 辅助 -apple-system, PingFang SC, sans-serif 系统无衬线,清晰可读
章节标题 @include section-title 30rpx / bold / serif统一样式

圆角 / 阴影 / 间距

元素 圆角 阴影
卡片 $r 12px $shadow-md (0 2px 12px rgba(45,42,38,0.08))
小元素(标签、输入框) $r-sm 8px $shadow-sm (0 1px 4px rgba(45,42,38,0.04))
浮层、弹窗 $r-lg 16px $shadow-lg (0 8px 32px rgba(45,42,38,0.12))
水平间距 页面两侧 24rpx卡片内 24-28rpx
垂直间距 区块间 24rpx卡片内标题与内容 20rpx

组件规范

按钮:主按钮 $pri 实色 + 白字 + 圆角 12px + 阴影。次按钮 $pri 边框透明底。禁用 $surface-alt 底 + $tx3 字。

状态标签:用 @include tag(背景色, 文字色) 生成。不用粗边框、不用 emoji 状态图标。颜色映射:正常 → $acc/$acc-l,偏高 → $wrn/$wrn-l,异常 → $dan/$dan-l,默认 → $tx2/$bd-l

健康数据卡片2×2 网格,衬线大数字居中,小标签 + 状态标签在底部。数据用 @include serif-number 等宽数字。

列表项:白色卡片容器,每行 14-24rpx padding$bd-l 底部分隔。右侧箭头用 字符。无左侧彩色 border accent。

图标:禁止用 emoji 作图标。用线性 SVG 或首字衬线体作为图标占位。图标底色用 $pri-l

禁止事项:紫色渐变 / emoji 作图标 / 圆角卡片+左彩色 border / 无意义渐变背景 / 装饰性 icon 遍地配。

Design Token 系统

自 2026-05-09 起全面接入。68 个 SCSS 文件59 页面 + 9 组件)全部使用 var(--tk-*) 引用字号和结构值。

源文件:apps/miniprogram/src/styles/tokens.scss

架构原理:通过 CSS 自定义属性Custom Properties实现单一真相源。page {} 定义正常值,.elder-mode {} 覆写关怀值,所有页面通过 var(--tk-*) 引用,关怀模式自动级联生效,无需逐页维护覆写。

Taro 兼容性Taro 编译器正确处理 CSS 自定义属性中的 px→rpx 转换(如 --tk-font-h1: 26px--tk-font-h1: 52rpx)。

字号 Token10 级)
Token 正常值 关怀值 倍率 语义 覆盖场景
--tk-font-hero 48px 56px ×1.17 装饰图标、空状态字符 大型装饰元素
--tk-font-h1 26px 30px ×1.15 页面/区块标题 99 处
--tk-font-h2 24px 28px ×1.17 副标题、日期 86 处
--tk-font-body-lg 28px 34px ×1.21 大正文、按钮 110 处
--tk-font-body 22px 30px ×1.36 正文、标签 92 处
--tk-font-body-sm 16px 22px ×1.38 中等正文、列表项 26 处
--tk-font-num 30px 34px ×1.13 数值显示 56 处
--tk-font-num-lg 34px 40px ×1.18 大数值、统计 21 处
--tk-font-cap 13px 18px ×1.38 说明文字、时间戳 54 处
--tk-font-micro 11px 17px ×1.55 角标、标签 22 处
结构 Token
Token 正常值 关怀值 语义
--tk-line-height 1.5 1.7 行高
--tk-touch-min 48px 56px 最小触控区域
--tk-btn-primary-h 56px 64px 主按钮高度
--tk-text-secondary #78716C #5A554F 辅助文字颜色(关怀模式提升对比度)
使用规则

新增页面必须使用 token,禁止硬编码 font-size: Npx

// 正确
.title { font-size: var(--tk-font-h1); }
.desc { font-size: var(--tk-font-cap); color: var(--tk-text-secondary); }
.number { font-size: var(--tk-font-num); @include serif-number; }

// 错误
.title { font-size: 26px; }  // 禁止

特殊值例外(仅允许以下场景硬编码):

  • 72px — 积分余额大数字(装饰性,不走 token
  • 80px — 错误状态图标(组件内部装饰)
  • 21px — 长辈模式预览页(特殊 UI
关怀模式Elder Mode

通过 Zustand store (stores/ui.ts) 的 DisplayMode 控制。useElderClass() hook 在根 View 添加 .elder-mode class触发所有 token 的关怀值级联。

elder-mode.scss~120 行仅保留结构布局覆写grid 列数、padding、gap所有字号/颜色覆写已通过 token 级联自动处理。

2. 关键文件 + 数据流

核心文件

文件 职责
apps/miniprogram/config/index.ts Taro 构建配置defineConstants 注入环境变量)
apps/miniprogram/src/services/request.ts HTTP 请求封装401 自动刷新、并发限制、缓存、AbortSignal 取消、resetForTesting() 测试隔离)
apps/miniprogram/src/services/auth.ts 微信登录/绑定手机号 API
apps/miniprogram/src/stores/auth.ts 认证状态login/bindPhone/restore
apps/miniprogram/src/stores/index.ts resetAllStores() 统一清理(解耦 store 间依赖)
apps/miniprogram/src/hooks/usePageData.ts 统一页面数据加载 hook(节流 + 下拉刷新 + 防重入)
apps/miniprogram/src/pages/index/useHomeData.ts 首页数据 hook从 424 行页面组件中提取)
apps/miniprogram/src/pages/health/useHealthData.ts 健康页数据 hook从 422 行页面组件中提取)
apps/miniprogram/src/utils/secure-storage.ts token 安全存储(明文存储,保留接口兼容)
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 → 跳转首页

页面结构59 个页面6 个主包 + 10 个子包)

TabBar 页面3 个)

页面路径 说明
pages/index/index 首页(今日健康、快捷服务)
pages/health/index 健康上报Tab 页)
pages/messages/index 消息中心Tab 页)

患者端主页面

页面路径 说明
pages/login/index 登录页(微信登录 + 协议勾选)
pages/consultation/index 咨询列表
pages/consultation/detail/index 咨询详情
pages/mall/index 积分商城
pages/profile/index 个人中心
pages/appointment/index 预约列表
pages/appointment/create/index 预约挂号
pages/appointment/detail/index 预约详情
pages/legal/user-agreement 用户服务协议
pages/legal/privacy-policy 隐私政策

健康子包pkg-health4 个)

页面路径 说明
pages/pkg-health/trend/index 健康趋势(体征数据折线图)
pages/pkg-health/input/index 健康数据录入Zod 验证)
pages/pkg-health/daily-monitoring/index 日常监测数据
pages/pkg-health/alerts/index 告警列表

医生端子包doctor16 个)

页面路径 说明
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 报告详情
pages/doctor/alerts/index 告警管理
pages/doctor/alerts/detail/index 告警详情
pages/doctor/action-inbox/index 待办事项
pages/doctor/dialysis/index 透析管理
pages/doctor/dialysis/detail/index 透析详情
pages/doctor/dialysis/create/index 创建透析记录
pages/doctor/prescription/index 处方管理
pages/doctor/prescription/detail/index 处方详情
pages/doctor/prescription/create/index 开具处方

商城子包pkg-mall3 个)

页面路径 说明
pages/pkg-mall/exchange/index 积分兑换
pages/pkg-mall/orders/index 积分订单
pages/pkg-mall/detail/index 商品详情

个人中心子包pkg-profile12 个)

页面路径 说明
pages/pkg-profile/family/index 家庭成员管理
pages/pkg-profile/family-add/index 添加家庭成员
pages/pkg-profile/reports/index 我的报告
pages/pkg-profile/followups/index 我的随访
pages/pkg-profile/medication/index 用药记录
pages/pkg-profile/settings/index 设置
pages/pkg-profile/dialysis-records/index 透析记录
pages/pkg-profile/dialysis-records/detail/index 透析记录详情
pages/pkg-profile/dialysis-prescriptions/index 透析处方
pages/pkg-profile/dialysis-prescriptions/detail/index 透析处方详情
pages/pkg-profile/consents/index 知情同意
pages/pkg-profile/health-records/index 健康档案
pages/pkg-profile/diagnoses/index 诊断记录

其他子包9 个)

页面路径 说明
pages/ai-report/list/index AI 分析报告列表
pages/ai-report/detail/index AI 分析报告详情
pages/article/index 健康资讯列表
pages/article/detail/index 文章详情
pages/report/detail/index 健康报告详情
pages/followup/detail/index 随访详情
pages/events/index 线下活动
pages/device-sync/index 设备数据同步

Hook 层7 个)

Hook 用途
usePageData 统一页面数据加载useDidShow 节流 + usePullDownRefresh + loadingRef 防重入 + enabled 条件守卫。44/58 页面已接入
useThrottledDidShow 带节流的 useDidShow(已迁移页面不再直接使用,保留兼容)
useSafeTimeout 页面隐藏时自动 clearTimeout
usePageRefresh 下拉刷新封装
usePagination 通用分页逻辑
useAuthRequired 登录态检查
useElderClass 长者模式 CSS class
useLongPolling 通用长轮询generation counter 防重叠 + useDidShow/Hide 可见性控制 + 失败退避delay = min(failCount×2s, 30s)+ enabled 条件守卫。咨询详情页(患者+医生端)已接入

服务层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

组件10 个)

组件 用途
EcCanvas ECharts Canvas 包装Taro 4 兼容,按需引入 echarts/core
EmptyState 空状态占位
ErrorBoundary 错误边界捕获
ErrorState 错误状态展示
FamilyPicker 家庭成员选择器
HealthCard 健康数据卡片
Loading 加载状态
StepIndicator 步骤指示器
TrendChart 趋势图表(基于 EcCanvas
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 刷新
调用 → erp-health GET /public/banners 访客首页轮播图(无需认证)
调用 → erp-health GET /public/banner-image/{id} 轮播图图片下载(wx.downloadFile,无需认证)
调用 → erp-health GET /public/articles 访客首页文章列表(无需认证)
调用 → erp-health GET /public/articles/{id} 访客文章详情(无需认证)

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 || ''),
  'process.env.TARO_APP_DEFAULT_TENANT_ID': JSON.stringify(process.env.TARO_APP_DEFAULT_TENANT_ID || ''),
},

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 检查当前路径避免重复跳转
Cannot read property 'call' of undefined echarts-taro3-react 内嵌 Taro 3.0.8 + React 16与 Taro 4.2 + React 18 产生双实例webpack 模块 ID 不匹配 移除 echarts-taro3-react,改为自定义 EcCanvas + echarts/core 按需引入

待优化

问题 级别 说明
Auth token 日志输出 P0 已解决 terser drop_console 移除生产日志
Token 刷新竞态 P0 已解决 refreshPromise 单例 + GET 请求去重
ECharts 全量引入 P2 已解决 分包后 echarts 514KB 仅在趋势页按需加载
积分商城降级 UI P0 未关联患者档案时 Tab 页空白,需引导用户建档
daily-monitoring 无 Zod 验证 P1 对齐 health/input 的验证标准
文章列表返回草稿 P1 患者端应只展示 published 状态文章
URL 拼接构建查询参数 P2 request.ts 已支持 buildQuery(params) 但内部使用
生产配置 P2 urlCheck/minified 需区分环境

2026-04-30 审计发现

三端对齐差距(小程序 API 覆盖 76 个Web 235 个,后端 328 个):

发现 严重性 说明
晚间血压数据永久丢失 CRITICAL 已修复 新增 blood_pressure_evening indicator_type小程序录入页 + 日常监测页 + 后端 service + 集成测试均已覆盖
透析管理完全无入口 HIGH 已修复 医生端新增 dialysis 3 页面 + prescription 3 页面,患者端新增 dialysis-records 2 页面 + dialysis-prescriptions 2 页面
知情同意完全无入口 HIGH 已修复 患者端新增 pkg-profile/consents 页面
体温/血氧未映射 MEDIUM body_temperature/spo2 无 indicator_type
健康记录小程序无入口 MEDIUM 已修复 患者端新增 pkg-profile/health-records 页面
诊断记录小程序无入口 MEDIUM 已修复 患者端新增 pkg-profile/diagnoses 页面
小程序无自动化测试 HIGH 已建立 MCP 自动化审计流程4 角色 236 次探测通过率 96.2%

功能域完成度(小程序端):

功能域 完成度 关键差距
咨询管理 95% 无导出(预期)
预约管理 90% 基本对齐
随访管理 70% 仅列表+创建
患者管理 85% 无删除(预期)
健康数据 80% 丢失晚间血压 已修复
告警系统 80% 查看+处理+医护端管理
透析管理 70% 医护端管理+患者端查看记录/处方
知情同意 60% 患者端查看,无签署流程
健康档案 60% 患者端可查看健康档案和诊断
统计仪表盘 30% 仅医护端 3 个统计
AI 分析 30% 仅历史查看

注意事项

  • Taro.login() 的 code 一次性使用,每次调用会返回新 code
  • session_key 缓存 5 分钟TTL过期需重新登录
  • 微信开发者工具中 getPhoneNumber 需要真机调试或使用测试号
  • Redis 不可达时限流降级为 fail-open不影响登录

2026-05-14 全页面性能与稳定性审查5 专家组 × 58 页面)

组织 5 个并行专家组,逐一审查全部 58 个页面 + stores/hooks/utils/components/services 基础设施层。 审查重点开发者工具卡死、CPU 飙升、逻辑链路异常、内存泄漏。

发现汇总

级别 数量 说明
CRITICAL 3 长轮询紧密递归、BLE 模块单例、TrendChart 同步 API
HIGH 8 原生 HTML input、客户端过滤、Storage 渲染路径、messagesRef 不同步等
MEDIUM 15+ 缺少 useThrottledDidShow、IIFE 渲染、loading 竞态等

CRITICAL 级别(已修复)

# 问题 文件 修复
1 长轮询 delay=0 紧密递归成功轮询后无间隔立即递归后端快速响应时构成紧密循环CPU 飙升 consultation/detail(患者+医生端) 成功路径加 3s 间隔 + 连续失败上限 50 次
2 BLE 模块级单例BLEManager 在模块顶层实例化,生命周期不与页面绑定;liveReadings 无上限增长 device-sync/index.tsx 改为 useRef 懒初始化 + MAX_LIVE_READINGS=200 上限
3 TrendChart 模块级同步 APITaro.getSystemInfoSync() 在模块加载时执行,阻塞首帧 components/TrendChart 改为延迟求值 getDPR() 函数

HIGH 级别(已修复)

# 问题 文件 修复
1 原生 HTML <input type='date'>Taro 不支持原生 HTML 标签,日期选择器完全不可用 doctor/followup/detail 替换为 <Picker mode='date'>
2 告警详情用列表+客户端过滤:加载 100 条列表找单条告警,超过 100 条永远找不到 doctor/alerts/detail 新增 getAlert(id) API 函数,单条查询
3 透析列表客户端过滤:服务端返回全状态数据,前端用 activeTab 过滤导致分页不准确 doctor/dialysis/index status 参数给服务端,移除客户端过滤
4 getStorageSync 在渲染路径:组件顶层调用同步 Storage 读取,每次渲染都执行 IPC report/detail 改用 useAuthStore((s) => s.currentPatient)
5 handleSendmessagesRef 未同步:发送消息后 state 更新但 ref 未更新,长轮询可能重复拉取 consultation/detail(患者+医生端) setMessages 回调中同步更新 ref
6 医护工作台无自动刷新:返回工作台时数据不更新 doctor/index 添加 useThrottledDidShow 10s 节流刷新

MEDIUM 级别(已知,按需修复)

问题 文件 说明
ai-report/list 缺少 useThrottledDidShow ai-report/list 只在挂载时加载,从详情页返回不刷新
events/list 缺少分页 events/index 固定加载 50 条,无滚动加载更多
device-sync tryAutoSync 无并发保护 device-sync 快速进出页面可能重复上传
health/index loadTrend 无并发保护 health/index 已修复: 添加 loadingRef 防重入
doctor/prescription handleSearch loading 竞态 doctor/prescription handleSearch 和 useEffect 的 loadData 可能闪烁

架构建议(已完成标注

  1. 统一数据加载模式 已完成:所有列表/详情页使用 usePageData hook44/58 页面已接入
  2. 长轮询通用化 已完成:抽取 useLongPolling hookgeneration counter + useDidShow/Hide + 失败退避),患者端+医生端 consultation/detail 已接入
  3. 服务端过滤优先 已完成:所有列表页的 Tab 过滤传参给后端
  4. BLE 管理器生命周期 已完成:改为 useRef 懒初始化
  5. getStorageSync 出渲染路径 已完成:通过 Zustand store 获取

2026-05-15 患者端登录后卡死深度审查3 专家组 × 请求链路 + 并发分析 + 端点可达性)

游客端卡死修复后,患者登录后又频繁出现开发者工具卡死。组织 3 个并行专家组深度审查。 根因:全局并发请求超过微信 10 个限制,快速 Tab 切换时首页 5 个 + 健康页 4 个 + analytics 1 个 + 个人中心 2 个 = 12 个并发请求,超限排队阻塞 UI。

审查发现

级别 问题 说明
根因 请求并发超微信 10 限制 快速 Tab 切换产生 12+ 并发请求,超出排队;慢请求占位导致后续全部阻塞
HIGH doRefresh 失败未设 isLoggingOut Storage 清了但标志未设401 路径可能重入
HIGH 401 失败后 reLaunch 首页而非登录页 首页 restoreAuth 又发请求,可能循环
MEDIUM 长轮询 useDidShow 重启时新旧循环重叠 pollingRef 设 true 时旧 setTimeout 回调也会继续
MEDIUM 首页 loadReminders 无并发保护 useThrottledDidShow + pullDownRefresh 可同时触发
MEDIUM health store refreshToday 无防重入 两个页面同时调用会发两次请求
MEDIUM 健康页 loadTrend/loadAiSuggestions 无防重入 下拉刷新 + useThrottledDidShow 双倍请求

端点可达性验证

所有 33 个小程序 service 端点后端均已实现,无 ghost endpoint特别确认 /analytics/batch/messages/unread-count/ai/suggestions 均存在)。

Tab 切换请求链路分析

每次 Tab 切换触发两层回调:

层级 操作 开销
App 级 useDidShow restoreAuth() + restoreUI() 4-6 次同步 Storage IPC约 10-50ms
页面级 useThrottledDidShow 页面数据加载 1-5 个异步 API 请求timeout 15s

最坏情况(所有缓存过期):

页面 并发请求数
首页 HomeDashboard 5refreshToday + 3 个 loadReminders + getUnreadCount
健康页 4refreshToday + getTrend + listPendingSuggestions + getHealthThresholds
消息页 1listConsultations 或 listNotifications
个人中心 2getAccount + getCheckinStatus
analytics flushEvents 1POST /analytics/batch每 30s
合计 13 个 — 超限 3 个

修复清单6 项,全部已修复)

# 级别 文件 修复
1 HIGH services/request.ts doRefresh 失败后设 isLoggingOut=true + 清理所有 Storagecurrent_patient+ 清请求缓存 + 重置 headers 缓存
2 HIGH services/request.ts 401 失败后跳 /pages/login/index(而非首页);重试成功后重置 isLoggingOut
3 HIGH services/request.ts 新增全局并发限制 MAX_CONCURRENT=8acquireSlot/releaseSlot 队列机制,防止超过微信 10 个请求限制;用 try/finally 确保所有路径释放槽位
4 MEDIUM pages/consultation/detail + doctor/consultation/detail 长轮询改为 generation counterstartLongPolling 递增 generation旧循环检测到 generation 变化自动退出,杜绝新旧循环重叠
5 MEDIUM pages/index/index.tsx 首页 loadReminders 添加 remindersLoadingRef 防重入
6 MEDIUM pages/health/index.tsx + stores/health.ts 健康页整体 loadingRef 防重入health store refreshToday 添加全局 refreshingToday 去重

并发限制器原理

// request.ts — acquireSlot/releaseSlot 队列
const MAX_CONCURRENT = 8; // 留 2 个空位给系统请求
let activeRequests = 0;
const pendingQueue: Array<() => void> = [];

function acquireSlot(): Promise<void> {
  if (activeRequests < MAX_CONCURRENT) {
    activeRequests++;
    return Promise.resolve();
  }
  return new Promise<void>((resolve) => { pendingQueue.push(resolve); });
}

function releaseSlot(): void {
  activeRequests--;
  const next = pendingQueue.shift();
  if (next) { activeRequests++; next(); }
}

所有页面请求共享同一队列,保证同时最多 8 个网络请求在飞。超出自动排队,先到先得。

6. MCP 联调(微信开发者工具自动化)

通过 MCP (Model Context Protocol) 工具直接操控微信开发者工具中的小程序模拟器,实现页面导航、元素交互、数据读取等操作。

当前使用自建 MCP 服务器 @hms/weapp-mcptools/weapp-mcp/),基于 @weapp-vite/miniprogram-automator@1.1.0(社区活跃维护 fork。 原有的 @yfme/weapp-dev-mcp 在 DevTools 2.01.2510290 版本后不兼容,已弃用。

6.1 前置条件

  1. 后端运行cargo run 启动 http://localhost:3000
  2. 小程序以 dev 模式构建 — 必须使用 NODE_ENV=development 构建(详见 §6.4
    cd apps/miniprogram
    echo 'TARO_APP_API_URL=http://localhost:3000/api/v1
    

TARO_APP_DEFAULT_TENANT_ID=019d80da-7a2c-7820-b0a3-3d5266a3a324 TARO_APP_ENCRYPTION_KEY=' > .env NODE_ENV=development npx taro build --type weapp

3. **微信开发者工具已登录** — 确保已扫码登录CLI 命令需要登录态)
4. **微信开发者工具打开项目** — 手动打开,加载 `apps/miniprogram/dist/`
5. **自动化端口已开启** — `project.config.json` 中 `"automationAudits": true`

> ⚠️ **为什么必须 dev 模式?** 生产构建(`pnpm build:weapp`)设置 `NODE_ENV=production``secure-storage.ts` 的 `decrypt()` 在密钥为空时会抛异常。dev 模式允许空密钥走明文存储。

### 6.2 启动调试环境

> **铁律:只允许一个 DevTools 实例运行。** 多实例会导致 App 级别自动化命令全部超时(无法恢复,必须全部关闭重开)。

#### 方式 ALauncher.launch() 自动启动(推荐)

通过 `@weapp-vite/miniprogram-automator` 的 `Launcher` 自动启动 DevTools 并开启自动化端口,无需手动操作。

```bash
# 步骤 1确认没有残留的 DevTools 进程
tasklist | findstr wechatdevtools
# 如有残留taskkill /F /IM wechatdevtools.exe

# 步骤 2MCP 的 inject_auth 或 connect 工具会自动调用 Launcher.launch()
# 或者手动测试:
cd tools/weapp-mcp
node --input-type=module -e "
import { Launcher } from '@weapp-vite/miniprogram-automator';
const mp = await new Launcher().launch({
 cliPath: 'D:/微信web开发者工具/cli.bat',
 projectPath: 'G:/hms/apps/miniprogram/dist',
});
console.log('OK:', (await mp.systemInfo()).model);
// 不要 disconnect保持连接供 MCP 使用
"
# 自动在端口 9420 开启自动化

方式 B手动启动 + CLI 开端口

# 步骤 1确认没有残留的 DevTools 进程
taskkill /F /IM wechatdevtools.exe

# 步骤 2手动打开微信开发者工具加载 apps/miniprogram/dist/
# 等待模拟器完全加载,确认无报错

# 步骤 3通过 CLI 开启自动化端口(端口 9420
"D:/微信web开发者工具/cli.bat" auto --project G:/hms/apps/miniprogram/dist --auto-port 9420
# 看到 "✔ auto" 即成功

# 步骤 4验证端口已开启
netstat -ano | findstr 9420
# 应看到 LISTENING 状态

成功后可通过 mcp__weapp-local__connect 连接。

6.3 常用 MCP 操作weapp-local 工具集)

操作 MCP 工具 说明
连接 connect 连接自动化端口,返回系统信息
断开 disconnect 断开连接
查看当前页面 current_page 返回路径、尺寸,可选包含 data
导航到页面 navigate navigateTo / switchTab / reLaunch / redirectTo / navigateBack
查找元素 get_element CSS 选择器,支持 [index=N] 语法
查找多个元素 get_elements CSS 选择器数组
点击元素 tap CSS 选择器定位后点击
输入文本 input CSS 选择器 + 值
滚动 scroll scroll-view 的 CSS 选择器 + x/y 坐标
读取页面数据 page_data 获取当前页面 data 对象(可选路径)
设置页面数据 page_data JSON data 参数 → setData
读取组件数据 element_data 组件 CSS 选择器 + 可选路径
设置组件数据 element_data CSS 选择器 + JSON data → setData
调用页面方法 page_call_method 调用当前页面上暴露的方法
执行 JS evaluate 在 AppService 上下文执行 JavaScript
调用 wx API call_wx getStorageSyncsetStorageSync
Mock wx API mock_wx Mock 一个 wx API 返回指定结果
恢复 wx API restore_wx 恢复被 mock 的 wx API
获取 WXML get_wxml 获取元素的 WXML 结构
截图 screenshot ⚠️ 当前版本超时,见 §6.6
日志 get_logs 获取 console 日志和异常
等待元素 wait_for 轮询等待选择器匹配
注入认证 inject_auth 一键获取后端 token + 注入 storage + 跳转首页
审计页面 audit_page 导航 → 检查加载 → 收集错误 → 健康报告
批量审计 audit_all 批量审计所有小程序页面

6.4 绕过微信登录

MCP 无法模拟微信 OAuthTaro.login() 返回的 code 走真实微信 jscode2session 接口DevTools 模拟器会返回 mock code 导致后端 500

方案一inject_auth 一键注入(推荐)

原理: 以 dev 模式重编译(空加密密钥),通过 MCP 的 inject_auth 工具自动完成:获取 admin token → evaluate 注入 storage → reLaunch 首页。

auth store restore() 读取的 storage key关键

Storage Key 说明 restore() 读取方式
access_token JWT access token secureGet('access_token')
refresh_token JWT refresh token secureGet('refresh_token')
user_data 用户 JSONid/username/display_name/phone/tenant_id secureGet('user_data') → JSON.parse
user_roles 角色数组 JSON["admin","doctor"] secureGet('user_roles') → JSON.parse
tenant_id 租户 ID secureGet('tenant_id')
current_patient 当前患者对象(含 id/name/phone Taro.getStorageSync('current_patient')
current_patient_id 当前患者 ID Taro.getStorageSync('current_patient_id')

⚠️ secureGet 在 dev 模式(空加密密钥)下等同于 wx.getStorageSync。生产模式下使用 XOR 混淆。

⚠️ 简单的 wx.setStorageSync('token', jwt) 不会生效 — auth store 的 restore() 不读取 token key它读取的是 access_token(通过 secureGet/secureSet)。必须使用 inject_auth 工具或手动调用 wx.setStorageSync('access_token', jwt) + wx.setStorageSync('user_data', JSON.stringify({...})) 等。

1. 准备:确保已按 §6.1 以 dev 模式构建,且已连接 MCPconnect

2. 调用 inject_auth 工具(默认参数即可):
   - 自动 POST /auth/login 获取 admin token
   - 通过 evaluate() 注入 access_token / refresh_token / user_data / user_roles / tenant_id / current_patient_id
   - reLaunch 到 /pages/index/index
   - 等待 2 秒后返回当前页面路径

3. 成功后即可正常操作各页面

关键 ID默认值

  • tenant_id: 019d80da-7a2c-7820-b0a3-3d5266a3a324
  • patient_id: 019dcd34-bc4d-72c1-8c19-77ce1f4839d6

方案二:手动分步注入

# 1. 获取 admin token
curl -X POST http://localhost:3000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"Admin@2026"}'

# 2. 通过 MCP call_wx 逐个写入 storage
# 3. 通过 MCP navigate reLaunch 到首页

⚠️ 长字符串 token 通过 call_wx 传输可能截断。建议用 inject_auth 工具(内部用 evaluate 直接执行,无传输问题)。

6.5 TabBar 页面列表

以下页面是 TabBar 页面,必须用 switchTab 导航(不能用 navigateTo

  • pages/index/index — 首页
  • pages/health/index — 健康数据
  • pages/messages/index — 消息中心

注意:咨询、商城、个人中心虽然显示为 Tab 样式,但实际不是 TabBar 页面(使用 reLaunch 导航)。

6.6 已知限制

问题 原因 替代方案
screenshot 超时 App.captureScreenshot 在 DevTools 2.01.2510290 不响应 get_element + page_data 获取 UI 状态
多实例导致全挂 两个 DevTools 实例抢端口App 域命令全部超时且不可恢复 taskkill /F /IM wechatdevtools.exe 后重开
navigateTo 超出 10 页栈 小程序 webview 限制最多 10 层页面栈 批量测试用 reLaunch 逐页导航
CLI 需要登录 cli.bat auto 要求 DevTools 已扫码登录 在 DevTools 中先扫码登录
SummerCompiler 报错 project.config.json 缺少必要字段 已配置 packNpmManually/packNpmRelationList/ignoreUploadUnusedFiles/condition
require() 在 evaluate 不可用 webpack 用数字 ID 注册模块 直接用 wx.setStorageSync / wx.getStorageSync
auth 重定向 request interceptor 检测 401 后跳转 login 并清空 storage 确保 token 有效reLaunch 后等待 2-3 秒
生产构建 decrypt 抛异常 空密钥 + NODE_ENV=productiondecrypt() 直接 throw 使用 NODE_ENV=development 构建
DevTools 频繁卡死 Electron 多进程累积文件描述符泄漏14+ 进程 3.5GB+ 内存 见下方 §6.9 DevTools 性能优化

6.9 DevTools 性能优化

微信开发者工具基于 Electron多进程架构主进程 + 渲染进程 + GPU + 插件)在长时间运行后会出现 EMFILE: too many open files 导致卡死。

常见触发场景:

  • 频繁 MCP 调用evaluate/reLaunch导致 fd 累积
  • Taro 热重载文件监视器与 DevTools 自带监视器重叠
  • 长时间(>2 小时)不重启 DevTools

优化措施:

# 1. 定期清理 DevTools 进程(推荐每 30 分钟或卡顿时执行)
taskkill /F /IM wechatdevtools.exe
# 然后重新打开项目

# 2. 检查进程资源占用
Get-Process wechatdevtools | Measure-Object WorkingSet64 -Sum | Select Count, @{N='MB';E={[math]::Round($_.Sum/1MB)}}
# 正常:< 1500MB | 需要重启:> 3000MB

# 3. 关闭不必要的 DevTools 功能
# 设置 → 编辑器设置 → 取消勾选「文件保存时自动编译」
# 设置 → 代理 → 关闭(不用代理时)

MCP 联调最佳实践:

  • 每轮 MCP 测试结束后 disconnect 断开连接
  • 批量测试分批执行,每批 ≤ 10 页后重启 DevTools
  • 避免在 DevTools 编辑器中同时打开多个文件

6.7 MCP 服务器架构

tools/weapp-mcp/
├── src/
│   ├── index.ts        # MCP 服务器入口25 个工具注册
│   └── automator.ts    # 连接管理器(@weapp-vite/miniprogram-automator
├── package.json        # @hms/weapp-mcp, 依赖 @weapp-vite/miniprogram-automator@1.1.0
└── tsconfig.json

.mcp.json 配置:

{
  "weapp-local": {
    "command": "node",
    "args": ["tools/weapp-mcp/dist/index.js"],
    "env": {
      "WEAPP_WS_ENDPOINT": "ws://localhost:9420",
      "WEAPP_CLI_PATH": "D:/微信web开发者工具/cli.bat",
      "WEAPP_PROJECT_PATH": "G:/hms/apps/miniprogram/dist",
      "HMS_API_URL": "http://localhost:3000/api/v1"
    }
  }
}

修改后需 cd tools/weapp-mcp && npm run build 重新编译。

6.8 自动化审计脚本

脚本 用途 运行
tools/weapp-mcp/scripts/audit-pages.mjs 多角色分批审计(推荐) node scripts/audit-pages.mjs --role admin
apps/miniprogram/inject-auth.cjs 注入明文 tokendev 模式) node inject-auth.cjs
apps/miniprogram/e2e-final.cjs 完整 E2E 链路验证11 UI + 10 API node e2e-final.cjs

分批审计脚本用法

# 在 tools/weapp-mcp/ 目录下运行
cd tools/weapp-mcp

# 审计指定角色admin/doctor/nurse/operator
node scripts/audit-pages.mjs --role admin

# 自定义批次大小(默认 10 页/批,每批重启 DevTools 防止多实例超时)
node scripts/audit-pages.mjs --role doctor --batch-size 8

# 输出:
# - 控制台实时显示每页状态OK / LOGIN_REDIRECT / ERROR
# - JSON 报告保存到 docs/qa/role-test-results/MP-{role}-audit.json

设计要点:

  • 每批 N 页后自动 taskkill 所有 DevTools 进程并重新 Launcher.launch(),避免多实例导致 App 级命令超时
  • 通过 mp.evaluate() 注入 storagewx.setStorageSync),写入 access_token/refresh_token/user_data/user_roles/tenant_id/current_patient_id
  • 测试用户密码均为 Admin@2026(不是 Test@2026

⚠️ 旧脚本 audit-pages.cjs / audit-detail-pages.cjs 基于 miniprogram-automator(已弃用),请使用新的 audit-pages.mjs

6.9 审计结果

2026-05-13 T40 UI 设计系统合规审计60 页面)

基于 docs/qa/T40-miniprogram-ui-audit-plan.md 对全部 60 个页面进行设计系统合规审计,覆盖 Design Token、SCSS 变量、色彩/圆角/字号/组件规范。

审计结果汇总:

级别 页面数 占比
PASS 31 52%
PASS_WITH_ISSUES 27 45%
NEEDS_WORK 2 3%

发现并修复的问题(全部已修复):

类别 数量 修复内容
HIGH 2 趋势页缺 Loading/EmptyState文章列表缺 mixins 导入
MEDIUM 6 硬编码字号(72px→--tk-font-display)ErrorState 图标字号AI报告离调色板颜色(#7c3aed/#f0e6ff→$pri/$pri-l);医生患者列表 inline style咨询页 GuestGuard 统一3处 TSX inline 颜色提取为 SCSS 类
LOW — #fff 统一 44 新增 $white 变量,所有 color: #fff$whitebackground: #fff$card
LOW — 圆角统一 14 8px$r-xs7文件20px$r-lg2文件16px$r1文件
LOW — 静默 catch 2 article/health 的空 catch 块添加状态清理
LOW — ErrorBoundary 重构 1 6 个 inline style 硬编码提取为 SCSS 类 + Design Token
LOW — 离调色板颜色 2 #0284C7(冷蓝) → $tx2#94A3B8(冷灰) → $tx3
LOW — #FFFFFF 统一 4 index/exchange/mixins/variables 中 #FFFFFF$white

设计系统新增:

  • variables.scss: 新增 $white: #FFFFFF 语义变量
  • tokens.scss: 新增 --tk-font-display Token72px/80px大数字装饰用
  • ErrorBoundary: 新增 SCSS 文件,从 inline style 迁移到设计系统

影响文件: 25 个 SCSS + 10 个 TSX + 1 个新增 SCSS + 2 个样式系统文件

报告文件:docs/qa/role-test-results/T40-ui-audit-results.md

2026-05-08 多角色自动化审计59 页面 × 4 角色)

使用分批审计脚本对全部 59 个页面进行 4 角色全面审计236 次页面探测):

角色 OK LOGIN_REDIRECT ERROR 通过率
admin患者 57 0 2 96.6%
doctor医生 58 1 0 98.3%
nurse护士 57 0 2 96.6%
operator运营 55 0 4 93.2%
合计 227 1 8 96.2%

关键结论:

  • 8 个 ERROR 全部是 DevTools 模拟器随机 timeout非产品缺陷
  • 1 个 LOGIN_REDIRECT 是 doctor 首页首次加载时序问题
  • 所有 59 个页面在所有角色下均可正常渲染(排除测试工具因素)
  • 测试用户密码均为 Admin@2026(之前误用 Test@2026 导致大量 LOGIN_REDIRECT

报告文件:docs/qa/role-test-results/MP-{role}-audit.json

2026-04-27 初次审计40 页面,单角色)

通过 MCP 自动化工具对全部 40 个页面进行渲染审计:

类别 数量 结果
TabBar 页面 5 5/5 OK
患者端子页面 24 24/24 OK
详情页(假 ID 11 11/11 优雅降级
合计 40 40/40 全部通过

详细审计报告见 docs/discussions/2026-04-27-miniprogram-audit-report.md

7. 变更记录

日期 变更
2026-05-15 MCP 联调 auth 注入踩坑§6.4 补充 auth store restore() 读取的 7 个 storage key 精确映射表;明确 wx.setStorageSync('token') 不生效auth store 读取的是 access_token via secureGet补充 inject_auth 注入的完整 key 列表
2026-05-15 五专家组最终审查:架构 7.5 + 性能 8.0 + 安全 7.5 + 工程 7.5 + UX 6.5 = 综合 7.4/10(B);发现 HIGH×15 + MEDIUM×25核心问题隐私政策与实际不一致、8 页面绕过 patientId 架构、测试覆盖不足10 service + 4 store + 8 hook 零测试)、触摸反馈缺失;详细报告见 docs/discussions/2026-05-15-miniprogram-final-audit-five-experts.md
2026-05-15 架构重构 P3长轮询通用化 useLongPolling:抽取 useLongPolling hookgeneration counter + useDidShow/Hide 可见性 + 失败退避 + enabled 守卫);患者端 + 医生端 consultation/detail 接入,删除 ~80 行重复代码;架构建议 #2 全部完成
2026-05-15 架构重构 P2request.ts 模块级状态收编 + AbortSignal + Analytics 受控:提取 ConcurrencyLimiter 类(并发限制)、ResponseCache 类(缓存+去重+patientId 绑定);新增 resetForTesting() 测试隔离函数;api.get/post/put/delete 支持 AbortSignal 请求取消app.tsx Analytics 定时器改为 useDidShow/useDidHide 控制后台暂停;构建通过 + 测试 74/75
2026-05-15 患者端登录后卡死深度审查3 专家组):根因 — 全局并发请求超微信 10 限制排队阻塞;端点可达性验证 33/33 全部存在Tab 切换请求链路分析(最坏 13 并发);修复 HIGH×3doRefresh 状态清理 + 401 跳转登录页 + 全局并发限制 MAX_CONCURRENT=8+ MEDIUM×3长轮询 generation counter + 首页/健康页 loadingRef 防重入 + refreshToday 去重)
2026-05-15 全量审计修复(第二轮):修复 CRITICAL×1pollingRef 未定义回归,咨询详情页 loadData 引用已删除的 pollingRef → 闭会话时 ReferenceError 崩溃HIGH×3 — 401 重试递归占用双 slot 改为循环结构释放后重入、4 个医生端列表页consultation/alerts/dialysis/prescription添加 loadingRef 防重入、safeNavigateTo 页栈溢出保护栈≥9 自动 redirectTo新增 safeNavigateTo 工具函数(utils/navigate.ts
2026-05-15 setTimeout 无清理修复:新增 useSafeTimeout hook页面隐藏时自动 clearTimeout10 个页面接入 — daily-monitoring2、exchange4、family-add、health/input、prescription detail/create、dialysis detail/create、appointment detail/create所有 fire-and-forget 定时器替换为 safeSetTimeout
2026-05-14 全页面性能与稳定性审查5 专家组):审查 58 页面 + 基础设施层;修复 CRITICAL×3长轮询紧密递归、BLE 模块单例、TrendChart 同步 API+ HIGH×6原生 HTML input、客户端过滤→服务端、Storage 渲染路径、messagesRef 同步、工作台刷新、告警单条查询);新增 §5 审查发现章节 + 架构建议
2026-05-13 T40 UI 设计系统合规审计+修复60 页面全覆盖审计PASS 31 / PASS_WITH_ISSUES 27 / NEEDS_WORK 2修复 HIGH×2 + MEDIUM×6 + LOW×67新增 $white 变量 + --tk-font-display Token44 处 #fff 统一为 $white14 处圆角硬编码统一为变量3 处 TSX inline 颜色提取为 SCSS 类ErrorBoundary 重构为 SCSS2 处静默 catch 修复2 处离调色板颜色修正
2026-05-10 访客首页改造:轮播图接入 /public/banners API + wx.downloadFile 下载图片到本地临时路径;文章列表接入 /public/articles API文章详情页根据登录状态选择认证/公开 APIgetPublicArticleDetail.env 新增 TARO_APP_DEFAULT_TENANT_ID;集成契约新增 4 个公开端点
2026-05-09 Design Token 全面接入68 SCSS 文件全面迁移 font-size: Npxvar(--tk-*)634 token 引用 / 3 个特殊硬编码;新增 §1.1 Design Token 系统文档
2026-05-08 多角色自动化审计4 角色admin/doctor/nurse/operator× 59 页面 = 236 次探测,综合通过率 96.2%;更新 §2 页面结构为 59 页面完整列表(含医生端 dialysis/prescription/action-inbox + 患者端 dialysis-records/prescriptions/consents/health-records/diagnoses更新 §5 审计发现(透析/知情同意/诊断/健康记录标记为已修复);更新 §6.5 TabBar 为 3 个;新增 §6.8 分批审计脚本;更新 §6.9 多角色审计结果
2026-05-08 MCP 联调全面重写:自建 MCP 服务器 @hms/weapp-mcp 替代 @yfme/weapp-dev-mcp;基于 @weapp-vite/miniprogram-automator@1.1.0;新增 §6.2 启动步骤(登录+单实例铁律);更新工具列表为 weapp-local 25 个工具;新增 inject_auth 一键注入;新增 §6.7 MCP 服务器架构说明多实例冲突、CLI 登录、SummerCompiler 等已知限制
2026-05-01 审计发现更新CRITICAL 晚间血压丢失 / HIGH 透析+知情同意完全空白 / 功能域完成度矩阵
2026-04-28 全面性能优化分包加载6 分包,主包 517KB→275KBvendors 192KB→36KBGET 请求去重+60s TTL 缓存points store 集中积分/签到状态todaySummary 60s TTL7 组件 React.memoTrendChart 双重渲染修复restoreAuth 提升 App 级别prod terser drop_consolecrypto-js 按需引入
2026-04-27 移除 echarts-taro3-react:内嵌 Taro 3 + React 16 导致 webpack 模块加载失败,改为自定义 EcCanvas 组件 + echarts/core 按需引入;更新版本说明 + 历史教训 + 组件列表
2026-04-27 MCP 联调全面更新§6.1 增加 dev 构建前置条件§6.4 重写为明文 token 注入法评估两种方案§6.6 补充 7 条已知限制,新增 §6.7 审计脚本说明 + §6.8 实测审计结果40/40 页面通过§5 补充 4 条审计发现
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 页面,记录登录流程、环境配置、历史陷阱