Files
hms/wiki/miniprogram.md
iven ec87ae85cf docs(wiki): 全量 wiki 更新 — C1 晚间血压已修复标记 + 数据校正
- miniprogram.md: 晚间血压 CRITICAL 标记为已修复
- index.md: 症状导航表更新
- architecture/database/erp-core/erp-health/frontend/testing: 同步更新
2026-05-03 19:32:30 +08:00

25 KiB
Raw Blame History

title, updated, status, tags
title updated status tags
微信小程序(患者端) 2026-04-27 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

设计哲学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 遍地配。

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

组件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 刷新

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 检查当前路径避免重复跳转
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 后端 12 路由完整,小程序 0 个 API 调用、0 个页面
知情同意完全无入口 HIGH 后端完整,小程序 0 入口
体温/血氧未映射 MEDIUM body_temperature/spo2 无 indicator_type
健康记录小程序无入口 MEDIUM 患者移动端无法查看健康档案
诊断记录小程序无入口 MEDIUM 患者移动端无法查看诊断
小程序完全无测试 HIGH 40 个页面全靠手工验证

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

功能域 完成度 关键差距
咨询管理 95% 无导出(预期)
预约管理 90% 基本对齐
随访管理 70% 仅列表+创建
患者管理 85% 无删除(预期)
健康数据 60% 丢失晚间血压/体温/血氧
告警系统 60% 仅查看+处理
统计仪表盘 30% 仅医护端 3 个统计
AI 分析 30% 仅历史查看
透析管理 0% 完全空白
知情同意 0% 完全空白

注意事项

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

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

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

6.1 前置条件

  1. 后端运行cargo run 启动 http://localhost:3000
  2. 小程序以 dev 模式构建 — 必须使用 NODE_ENV=development 构建(详见 §6.4
    cd apps/miniprogram
    # 清空加密密钥(必须,否则 encrypt/decrypt 不一致)
    echo 'TARO_APP_API_URL=http://localhost:3000/api/v1
    

TARO_APP_ENCRYPTION_KEY=' > .env

dev 模式构建

NODE_ENV=development npx taro build --type weapp

3. **微信开发者工具已打开项目** — 加载 `apps/miniprogram/dist/`
4. **自动化端口已开启** — `project.config.json` 中 `"automationAudits": true`,端口 9420

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

### 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`Taro.login()` 返回的 code 走真实微信 `jscode2session` 接口DevTools 模拟器会返回 mock code 导致后端 500。

#### 方案一:明文 token 注入(推荐,用于自动化测试)

**原理:** 以 dev 模式重编译(空加密密钥),`secure-storage.ts` 走明文路径,直接用 `wx.setStorageSync` 写入。

**步骤:**

  1. 准备:确保已按 §6.1 以 dev 模式构建

  2. 获取 admin token: POST http://localhost:3000/api/v1/auth/login Body: { "username": "admin", "password": "Admin@2026" } 返回: { data: { access_token, refresh_token, user: { id, username, ... } } }

  3. 通过 automator.evaluate() 注入明文 storage: mp.evaluate((at, rt, ud, ur, tid, pid) => { wx.setStorageSync('access_token', at); wx.setStorageSync('refresh_token', rt); wx.setStorageSync('user_data', ud); wx.setStorageSync('user_roles', ur); wx.setStorageSync('tenant_id', tid); wx.setStorageSync('current_patient_id', pid); wx.setStorageSync('current_patient', { id: pid, name: 'TestPatient', gender: 'male', birth_date: '1990-01-15', status: 'active' }); }, accessToken, refreshToken, userDataJson, rolesJson, tenantId, patientId);

  4. reLaunch 到首页: mp.reLaunch('/pages/index/index'); await sleep(3000);


**关键 tenant/patient ID**
- `tenant_id`: `019d80da-7a2c-7820-b0a3-3d5266a3a324`
- `current_patient_id`: `019dcd34-bc4d-72c1-8c19-77ce1f4839d6`

**为什么不用 mp_callWx**
- 加密 token~2100 字符)通过 `mp_callWx setStorageSync` 传输时会被截断/损坏
- `automator.evaluate()` 直接在小程序 JS 上下文执行,无传输问题
- `require('./utils/secure-storage')` 在 evaluate 中不可用webpack 用数字 ID 注册模块),只能用 `wx.setStorageSync`

#### 方案二:加密 token 注入(用于真实环境测试)

如果需要测试加密存储路径(密钥非空),可以:

  1. 恢复 .env 中的加密密钥: TARO_APP_ENCRYPTION_KEY=0a17b71d46064b06f993c9c202b342425e311a79f5be026d830562e7ad51f522

  2. 重新构建: pnpm build:weapp

  3. 使用 inject-auth.cjs 脚本(内含 CryptoJS AES 加密逻辑)


> ⚠️ 实测发现加密 token 通过 MCP 传输存在截断问题,方案二仅在需要测试加密存储时使用。

#### 注意事项

- 写完 storage 后**必须立即 reLaunch**,否则 app 的 API 请求会因 token 无效触发 401 → logout 清空 storage
- `reLaunch` 后等待 2-3 秒再进行后续操作,页面需要时间加载和初始化
- 恢复 `.env` 加密密钥后需重新构建,否则 `secure-storage.ts` 行为不一致

### 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 超出 10 页栈** | 小程序 webview 限制最多 10 层页面栈 | 批量测试用 `reLaunch` 逐页导航 |
| **加密 token MCP 传输截断** | AES 加密后的 token~2100 字符)通过 `mp_callWx` 传输时损坏 | 使用 `evaluate()` 在 JS 上下文内直接写入 |
| **require() 在 evaluate 不可用** | webpack 用数字 ID 注册模块,非文件路径 | 直接使用 `wx.setStorageSync` / `wx.getStorageSync` |
| **CryptoJS 非全局变量** | CryptoJS 打包在 webpack bundle 内evaluate 上下文无法访问 | 绕过加密dev 模式 + 空密钥 |
| **auth 重定向** | request interceptor 检测 401 后自动跳转 login 并清空 storage | 确保 token 有效reLaunch 后等待 2-3 秒 |
| **生产构建 decrypt 抛异常** | 空密钥 + `NODE_ENV=production` 时 `decrypt()` 直接 throw | 使用 `NODE_ENV=development` 构建 |

### 6.7 自动化审计脚本

| 脚本 | 用途 | 运行 |
|------|------|------|
| `apps/miniprogram/inject-auth.cjs` | 注入明文 tokendev 模式) | `node inject-auth.cjs` |
| `apps/miniprogram/audit-pages.cjs` | 批量审计 24 个非 TabBar 页面 | `node audit-pages.cjs` |
| `apps/miniprogram/audit-detail-pages.cjs` | 审计 11 个详情页(假 ID 优雅降级) | `node audit-detail-pages.cjs` |
| `apps/miniprogram/e2e-final.cjs` | 完整 E2E 链路验证11 UI + 10 API | `node e2e-final.cjs` |

#### 批量审计脚本模板

```javascript
const automator = require('miniprogram-automator');

async function main() {
  const mp = await automator.connect({ wsEndpoint: 'ws://localhost:9420' });
  const results = { ok: [], crash: [], login: [] };

  for (const pageUrl of PAGES) {
    try {
      await mp.reLaunch(`/${pageUrl}`);
      await new Promise(r => setTimeout(r, 2000));
      const current = await mp.currentPage();
      if (current.path === pageUrl.split('?')[0]) {
        results.ok.push(pageUrl);
      } else if (current.path === 'pages/login/index') {
        results.login.push(pageUrl);
      } else {
        results.crash.push(pageUrl);
      }
    } catch (e) {
      results.crash.push(pageUrl);
    }
  }

  console.log(`OK: ${results.ok.length}, Login: ${results.login.length}, Crash: ${results.crash.length}`);
  await mp.disconnect();
}
main();

6.8 审计结果2026-04-27 实测)

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

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

核心 API 数据链路验证13 端点):

API 端点 状态 说明
GET /health/vital-signs/today 200
GET /health/patients 200
GET /health/doctors 200
GET /health/appointments 200
GET /health/consultation-sessions 200
GET /health/follow-up-tasks 200
GET /health/articles 200
GET /health/points/products 200
GET /ai/analysis/history 200
GET /health/points/account 404 admin 无患者档案(预期)
GET /health/points/transactions 404 同上
GET /health/points/orders 404 同上
GET /health/points/checkin/status 404 同上

积分端点 404 说明:路由已注册在 module.rs:454-484resolve_patient_id() 要求登录用户关联患者档案。admin 是管理员账号,无患者档案,因此返回 "当前用户未关联患者档案"。这是正确的业务逻辑。

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

7. 变更记录

日期 变更
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 页面,记录登录流程、环境配置、历史陷阱