fix(mp): DevTools 卡死 + 主包 2MB→766KB + 代码质量 4 项全通过

根因:主包 2MB 全量组件注入导致 DevTools 渲染引擎内存渐增,
叠加离线时固定 3s 抑制期后的请求洪泛。

修复:
- app.config.ts 添加 lazyCodeLoading: requiredComponents
  主包 2.0MB→766KB,taro.js 526→131KB,vendors.js 230→28KB
- request.ts 离线抑制改为指数退避(3s→6s→12s→30s cap)
  后端不可达时自动延长抑制,防止请求风暴
- SegmentTabs Tab 接口改为 readonly,修复 TS 编译错误
- AbortController polyfill 补齐小程序运行时缺失
- 健康首页/设备同步/健康档案/报告/设置页 UI 重构
- 文章页公开端点适配游客访问
- 健康首页 Swiper 间隔优化 4s→5s,动画 500→300ms
This commit is contained in:
iven
2026-05-24 11:32:40 +08:00
parent 675f8a4b10
commit 1e59007bd5
58 changed files with 4950 additions and 494 deletions

View File

@@ -0,0 +1,97 @@
# HMS V3 Beta 多学科综合测试报告 — 执行摘要
> 测试日期: 2026-05-21 | 分支: feat/media-library-banner
> 测试团队: 5 个专家团队并行Web功能 / 性能兼容 / 小程序 / API / 静态分析)
> 报告版本: v1.0
## 1. 测试范围与方法
| 维度 | 方法 | 工具 |
|------|------|------|
| Web 前端功能 | 核心业务流程操作 + 边缘场景 | chrome-devtools MCP |
| Web 性能/兼容性 | Lighthouse + Core Web Vitals + 5 种视口 | chrome-devtools MCP |
| 小程序功能 | 5 Tab 页 + 核心功能 + API 验证 | weapp-local MCP |
| API 端点 | 69 个测试用例CRUD/权限/注入/边界值) | curl/Bash |
| 静态代码分析 | TypeScript 类型/安全/性能反模式 | Grep/Read/Bash |
## 2. 总体评估
| 指标 | 值 |
|------|-----|
| **综合质量评级** | **B- (6.5/10)** |
| **测试总项数** | **248 项**(功能 54 + 性能 26 + API 69 + 静态 99+ |
| **综合通过率** | **78.2%** |
| **发现问题总数** | **36 个** |
| **CRITICAL** | **4 个** |
| **HIGH** | **8 个** |
| **MEDIUM** | **15 个** |
| **LOW** | **9 个** |
## 3. 关键发现
### CRITICAL阻塞 Beta 发布)
| ID | 来源 | 问题 | 影响 |
|----|------|------|------|
| C-01 | 小程序 | `inject_auth` 写明文键,`request.ts` 只读加密键,所有 API 无 token | 小程序所有认证功能不可用 |
| C-02 | 小程序 | `secure-storage.ts` UTF-16 截断中文,加密存储后解密损坏 | 用户数据(含中文名)存储失败 |
| C-03 | Web 兼容 | 移动端 375px 表格不可用,无响应式替代布局 | 移动端用户完全无法操作 |
| C-04 | Web 兼容 | 移动横屏 812x375 内容区域空白 | 横屏模式页面无法使用 |
### HIGH影响核心业务流程
| ID | 来源 | 问题 | 影响 |
|----|------|------|------|
| H-01 | Web 功能 | 患者创建表单缺少前端必填校验,空表单提交成功 | 脏数据进入系统 |
| H-02 | Web 功能 | 预约列表 API 网络连接异常,无数据显示 | 预约管理不可用 |
| H-03 | Web 兼容 | 平板 768px 表格数据不加载 | 平板端不可用 |
| H-04 | Web 性能 | 患者列表 LCP 2643msrender delay 99.8% | 页面加载慢 |
| H-05 | Web 性能 | 仪表盘 API 每个端点重复调用 4 次 | 不必要的网络/服务器负载 |
| H-06 | API | 健康数据 DTO-Entity 映射断裂,测量值全存 null通过率 20% | 日常监测功能实质失效 |
| H-07 | API | 500 字符文章标题导致 HTTP 500 内部错误 | 应返回 400 验证错误 |
| H-08 | 静态分析 | Web 前端 10+ 处 `.catch(() => {})` 静默吞错 | 错误不可追踪 |
## 4. 各维度通过率
| 测试域 | 通过率 | 评级 |
|--------|--------|------|
| API 端点69 项) | 82.6% | B |
| 小程序 UI 渲染38 项) | 100% | A |
| 小程序功能(应用内 3 项) | 0% | Ftoken 问题) |
| 小程序功能API 直测 4 项) | 100% | A |
| Web 前端功能8 大领域) | 62.5%5/8 完全通过) | B- |
| Lighthouse Desktop | 94/100/100 | A |
| Lighthouse Mobile | 94/100/100 | A |
| Web Desktop 视口 | PASS | A |
| Web Tablet 视口 | FAIL | D |
| Web Mobile 视口 | FAIL | F |
## 5. 发布就绪度判定
### 结论: **CONDITIONAL BETA** — 需修复 4 个 CRITICAL + 3 个 HIGH 后可发布
### 阻塞项(必须修复,预计 3-4 天)
1. **C-01/C-02 小程序 token/加密问题** — 统一 `safeGet` fallback + 修复 UTF-8 编码(预计 3h
2. **C-03/C-04 移动端响应式** — 添加卡片视图 + 修复 768px 断点(预计 2d
3. **H-01 患者表单验证** — 前端添加 `form.validateFields()`(预计 1h
4. **H-06 健康数据 DTO 映射** — 修复字段映射(预计 4h
5. **H-07 文章标题 500 错误** — 添加 DTO 长度校验(预计 30min
### 建议项Beta 后迭代,预计 5-7 天)
- M-01~M-05: 对比度/暗色模式/API 校验/XSS/搜索等
- L-01~L-09: 弃用警告/i18n/内联样式等
## 6. 报告索引
| 章节 | 文件 |
|------|------|
| 执行摘要(本文档) | `01-executive-summary.md` |
| Web 前端功能测试 | `02-web-functional.md` |
| Web 性能与兼容性测试 | `03-web-perf-compat.md` |
| 小程序功能测试 | `04-miniprogram.md` |
| API 深度测试 | `05-api-deep-test.md` |
| 静态代码分析 | `06-static-analysis.md` |
| 跨部门头脑风暴 | `07-brainstorm.md` |
| Beta 就绪验收清单 | `08-beta-checklist.md` |

View File

@@ -0,0 +1,119 @@
# Web 前端核心业务功能测试
> 测试工具: chrome-devtools MCP | 环境: Chrome, 1920x1080
> 测试账号: admin / Admin@2026 | 截图: `docs/qa/screenshots/`
## 1. 登录流程 — PASS
| 测试项 | 结果 | 说明 |
|--------|------|------|
| 登录页渲染 | PASS | 双栏布局,品牌信息完整 |
| 登录后跳转 | PASS | 跳转至工作台 `/#/` |
| 侧边栏菜单 | PASS | 7 个一级菜单加载(工作台/患者中心/随访关怀/健康监测/运营管理/AI助手/系统管理) |
| 用户信息显示 | PASS | 右上角"系统管理员" + 头像 |
| 权限不足页面 | PASS | 403 页面清晰,含返回首页按钮 |
| XSS 安全 | PASS | SQL 注入测试数据 `Robert"); DROP TABLE patients;--` 正确转义显示 |
## 2. 患者管理 — FAIL (2 issues)
| 测试项 | 结果 | 说明 |
|--------|------|------|
| 患者列表加载 | PASS | 136 条记录7 页分页 |
| 分页切换 | PASS | 第 2 页数据正确 |
| 创建表单打开 | PASS | 4 个分组(基本信息/联系方式/医疗信息/紧急联系人) |
| 编辑表单 | PASS | 预填充已有数据 |
| **空表单提交** | **FAIL** | 空表单成功提交创建患者(后端有校验但前端未拦截) |
| **搜索功能** | **FAIL** | 输入 "Test" 搜索后列表仍显示全部 136 条 |
### H-01: 患者创建表单缺少前端必填校验
- **严重性:** HIGH
- **证据:** 点击"保存"空表单后审计日志显示"创建 了 患者"
- **根因:** Ant Design Form 未配置 `rules: [{ required: true }]` 或未调用 `form.validateFields()`
- **修复:** 在 `PatientList.tsx` 的 DrawerForm 中添加 `rules` 配置,提交前调 `form.validateFields()`
- **预计工时:** 1h
### M-01: 患者搜索不生效
- **严重性:** MEDIUM
- **证据:** 搜索框输入 "Test" + 回车,列表无变化
- **根因:** 搜索框 `keyword` 参数可能未正确传递到 API 请求
- **修复:** 检查搜索输入与 API 参数绑定
- **预计工时:** 2h
## 3. 健康数据/实时监控 — PASS
| 测试项 | 结果 | 说明 |
|--------|------|------|
| 实时监控页 | PASS | 危急/高危/中等/低危告警计数正确 |
| 告警面板 | PASS | 1 个高危患者活跃告警 |
| 告警列表 | PASS | 5 条告警记录,状态/严重程度正确 |
| 筛选功能 | PASS | 患者下拉框存在 |
## 4. 预约管理 — FAIL (1 issue)
| 测试项 | 结果 | 说明 |
|--------|------|------|
| 预约列表页渲染 | PASS | 表头正确(患者/医护/类型/日期/时段/状态/创建时间/备注/操作) |
| **预约数据** | **FAIL** | 表格显示 "No data" + "网络连接异常,请检查网络" |
| 新建预约按钮 | PASS | 按钮可见 |
### H-02: 预约列表 API 网络连接异常
- **严重性:** HIGH
- **证据:** 页面显示"网络连接异常"No data"同时出现
- **根因:** 可能是后端 API 错误或前端 API 路径不匹配
- **修复:** 检查 `/api/v1/health/appointments` 端点状态和前端 API 路径
- **预计工时:** 2h
## 5. 咨询管理 — PASS
| 测试项 | 结果 | 说明 |
|--------|------|------|
| 咨询列表加载 | PASS | 18 条咨询记录 |
| 状态显示 | PASS | 已关闭/进行中/等待中正确 |
| 操作按钮 | PASS | 进行中的会话显示"关闭"按钮 |
| 未读消息计数 | PASS | 患者端/医护端分别显示 |
| 筛选/导出 | PASS | 状态筛选、日期范围、导出按钮均存在 |
## 6. 工作台/仪表盘 — PASS_WITH_ISSUES
| 测试项 | 结果 | 说明 |
|--------|------|------|
| 工作台首页 | PASS | 6 大状态卡片 + 统计 + 模块状态 + 活跃度 |
| 系统状态 | PASS | PostgreSQL/API/定时任务/文件存储/消息队列/缓存 全绿 |
| 统计数据 | PASS | 注册用户 27/今日活跃 4/本周 9/月活 18 |
| 最近操作 | PASS | 实时显示登录/创建/删除操作 |
| 通知面板 | PASS | 危急值告警和待办事项正常 |
| 侧边栏折叠 | PASS | 折叠后仅图标,悬停展开子菜单 |
| **Admin Dashboard** | **FAIL** | `/#/health/admin-dashboard` 显示 403 |
### M-02: Admin Dashboard URL 直接访问 403
- **严重性:** MEDIUM
- **说明:** AdminDashboard 组件存在但路由未注册,该页面可能仅作为工作台内嵌组件使用
- **修复:** 移除直接访问路径或正确注册路由并配置权限
- **预计工时:** 1h
## 7. 主题切换 — PASS (4/4)
| 主题 | 结果 | 说明 |
|------|------|------|
| 信任蓝(默认) | PASS | 蓝色系侧边栏 |
| 深邃夜色 | PASS | 深色侧边栏和页头 |
| 翡翠清雅 | PASS | 绿色系 |
| 温润东方 | PASS | 暖色调 |
| 持久化 | PASS | localStorage `hms-theme` 保存,刷新后保持 |
## 8. 控制台警告
| 类型 | 消息 | 严重性 |
|------|------|--------|
| WARN | `[antd: Drawer] width is deprecated. Please use size instead.` | LOW |
| WARN | `[antd: List] component is deprecated. And will be removed in next major version.` | LOW |
## 小结
- **完全通过领域:** 5/8登录/健康数据/咨询/工作台/主题)
- **存在问题领域:** 3/8患者管理/预约/仪表盘路由)
- **HIGH 问题:** 2 个 | **MEDIUM 问题:** 2 个 | **LOW 问题:** 2 个

View File

@@ -0,0 +1,175 @@
# Web 前端性能与兼容性测试
> 测试工具: chrome-devtools MCP (Lighthouse + Performance Trace + Emulate)
> 截图: `g:\hms\screenshots/` | 追踪: `g:\hms\trace-*.json`
## 1. Lighthouse 审计
### 1.1 Desktop (Navigation)
| 类别 | 分数 | 状态 |
|------|------|------|
| Accessibility | **94** | GOOD |
| Best Practices | **100** | PERFECT |
| SEO | **100** | PERFECT |
| Agentic Browsing | **61** | NEEDS_WORK |
**失败审计项 (4):**
1. CLS 0.127 超过 0.1 阈值Desktop 有Mobile 无)
2. 浅色模式 `#94a3b8` 灰色文字在白底上对比度 2.56:1需 4.5:1
3. h1 后直接跳 h3缺少 h2 层级
4. llms.txt 文件缺少 H1 标题和链接
### 1.2 Mobile (Navigation)
| 类别 | 分数 | 状态 |
|------|------|------|
| Accessibility | **94** | GOOD |
| Best Practices | **100** | PERFECT |
| SEO | **100** | PERFECT |
| Agentic Browsing | **67** | NEEDS_WORK |
**失败项与 Desktop 相同**color-contrast + heading-order + llms-txt。Mobile CLS 为 0 通过。
### 1.3 Dark Mode (Snapshot)
| 类别 | 分数 | 下降 |
|------|------|------|
| Accessibility | **92** | -2 |
| Best Practices | **100** | — |
| SEO | **80** | -20 |
**Dark Mode 额外问题:**
- 侧边栏菜单项对比度不足4.39:1 / 3.95:1 / 4.45:1均未达 4.5:1
- 表单元素缺少 `label` 关联
- 分页链接不可爬取
## 2. Core Web Vitals
### 2.1 工作台Dashboard
| 指标 | 值 | 评级 |
|------|-----|------|
| **LCP** | **1381ms** | NEEDS IMPROVEMENT |
| **CLS** | **0.04** | GOOD |
| **TTFB** | **6ms** | GOOD |
| DOM 大小 | 311 elements | GOOD |
| DOM 深度 | 13 层 | GOOD |
**LCP 瓶颈:** TTFB 6ms (0.4%) + Render Delay **1375ms (99.6%)**
**CLS 根因:** Noto Sans SC 字体从 Google Fonts 加载导致 FOUT5 个 woff2 文件
### 2.2 患者列表
| 指标 | 值 | 评级 |
|------|-----|------|
| **LCP** | **2643ms** | NEEDS IMPROVEMENT |
| **CLS** | **0.01** | GOOD |
| **TTFB** | **4ms** | GOOD |
| DOM 大小 | 944 elements | MODERATE |
**LCP 瓶颈:** TTFB 4ms (0.2%) + Render Delay **2639ms (99.8%)**
**强制回流:** 总计 **460ms**
- `measureScrollbarSize` (antd): 341ms + 43ms
- `setScaleParam` (antd): 76ms
- 全部来自 Ant Design 表格组件内部
## 3. 多视口兼容性
### 3.1 Desktop 1920×1080 — PASS
- 侧边栏展开,菜单完整
- 表格完整显示
- **注意:** 仪表盘出现"网络连接异常"错误提示
### 3.2 Laptop 1366×768 — PASS
- 侧边栏正常展开
- 患者表格完整,分页器可见
- 筛选栏全部可见
### 3.3 Tablet iPad 768×1024 — **FAIL (HIGH)**
- 侧边栏折叠为仅图标模式
- **面包屑显示"页面"而非实际名称**
- **表格数据完全未加载** — 主内容区只有头部和筛选栏,表格区域为空
- 评级: **H-03**
### 3.4 Mobile iPhone 375×812 — **FAIL (CRITICAL)**
- 侧边栏展开覆盖全屏
- 8 列数据在 375px 宽度严重挤压
- 出现 3 条错误消息("网络连接异常" + 2×"加载数据失败"
- 操作按钮edit/delete极小触摸目标不足 44px
- 评级: **C-03** — 应提供卡片视图替代
### 3.5 Mobile Landscape 812×375 — **FAIL (CRITICAL)**
- **内容区域完全空白** — main 区域只有 loading/busy 状态
- 面包屑显示"页面"
- 评级: **C-04**
## 4. Dark Mode 对比度问题
### 4.1 侧边栏低对比度
| 元素 | 对比度 | 标准 |
|------|--------|------|
| 跳转链接 / H logo | 4.07:1 | 需 4.5:1 |
| 患者中心 | 4.39:1 | 需 4.5:1 |
| 患者管理 | 3.95:1 | 需 4.5:1 |
### 4.2 系统管理卡片浅色背景Dark Mode 下不协调)
| 元素 | 对比度 | 背景 |
|------|--------|------|
| 运行中 | 3.15:1 | 浅绿 |
| 菜单管理 | 3.84:1 | 浅蓝 |
| 系统配置 | 3.07:1 | 浅黄 |
**根因:** 系统管理区块在 Dark Mode 下仍使用浅色背景,未跟随主题切换。
## 5. 网络请求分析
### 5.1 API 重复调用
仪表盘每个端点被调用 **4 次**:
| 端点 | 调用次数 |
|------|---------|
| `/health/admin/statistics/patients` | ×4 |
| `/health/admin/statistics/consultations` | ×4 |
| `/health/admin/statistics/follow-ups` | ×4 |
| `/health/admin/points/statistics` | ×4 |
| `/health/admin/statistics/health-data` | ×4 |
| `/health/admin/statistics/dialysis` | ×4 |
| `/health/doctors` | ×4 |
| `/menus/user` | ×4 |
| `/config/themes` | ×4 |
| `/health/action-inbox` | ×4 |
**根因:** 可能来自 React Strict Mode 双重渲染 + 组件重复挂载
**评级:** H-05
### 5.2 第三方资源
| 资源 | 大小 | 影响 |
|------|------|------|
| Google Fonts (Noto Sans SC) | 1.3 MB | 最大外部资源,导致 CLS |
## 6. 问题汇总
| ID | 严重性 | 问题 | 修复建议 | 工时 |
|----|--------|------|----------|------|
| C-03 | CRITICAL | Mobile 375px 表格不可用 | 添加 `<768px` 卡片视图 | 2d |
| C-04 | CRITICAL | Mobile 横屏内容空白 | 修复 812×375 路由加载 | 4h |
| H-03 | HIGH | Tablet 768px 数据不加载 | 修复断点 + 侧边栏同步 | 4h |
| H-04 | HIGH | 患者列表 LCP 2643ms | 字体预加载 + 虚拟滚动 | 1d |
| H-05 | HIGH | 仪表盘 API ×4 重复调用 | 检查 useEffect 依赖 | 4h |
| M-03 | MEDIUM | 浅色模式 #94a3b8 对比度 | 改为 #64748b | 30min |
| M-04 | MEDIUM | Dark Mode 系统管理卡片 | 深色背景变体 | 4h |
| M-05 | MEDIUM | Antd 表格 reflow 460ms | 固定 scroll.x/y | 2h |
| M-06 | MEDIUM | Noto Sans SC 1.3MB CLS | font-display: optional | 1h |
| M-07 | MEDIUM | 面包屑显示"页面" | 修复 tablet/mobile 路由名 | 1h |
| L-01 | LOW | heading-order h1→h3 | 插入 h2 或 aria-level | 30min |
| L-02 | LOW | 表单元素缺 label | 添加 aria-label | 1h |
| L-03 | LOW | antd Drawer width 弃用 | 迁移到 size 属性 | 30min |

View File

@@ -0,0 +1,146 @@
# 小程序功能测试报告
> 测试工具: weapp-local MCP | 环境: 微信开发者工具, iPhone 12/13 Pro 模拟器
> iOS 10.0.1, 390×844 | 分支: feat/media-library-banner
## 1. 连接与认证
| 项目 | 结果 | 说明 |
|------|------|------|
| MCP 连接 | PASS | ws://localhost:9420 连接成功 |
| inject_auth | PASS_WITH_ISSUES | 报告"注入成功"但存在集成问题C-01 |
| Auth 手动恢复 | PASS | 通过 `__hms` bridge 手动 restoreAuth 成功 |
## 2. Tab 页面测试
### 2.1 首页 (pages/index/index) — PASS
| 检查项 | 结果 | 详情 |
|--------|------|------|
| 问候语 | PASS | "晚上好,系统管理员" + "5月21日周四" |
| 消息铃铛 | PASS | 可点击 |
| 签到卡片 | PASS | 进度环 0%4 个 capsule血压/心率/血糖/体重) |
| 今日体征 | PASS | 4 张卡片,值"---",标签"未记录" |
| 操作按钮 | PASS | "记录体征" + "预约挂号" |
| SOS 按钮 | PASS | 存在 |
| 访客模式 | PASS | 未登录显示轮播图 + 健康资讯 + 注册 CTA |
| Console 错误 | PASS | 无 |
### 2.2 健康 Tab (pages/health/index) — PASS_WITH_ISSUES
| 检查项 | 结果 | 详情 |
|--------|------|------|
| 页面加载 | PASS | 分段选项卡(血压/心率/血糖/体重) |
| 录入表单 | PASS | 收缩压+舒张压输入框 + 参考范围提示 |
| 趋势图 | PASS | 空状态"暂无趋势数据"正确显示 |
| **保存功能** | **FAIL** | 日志 `[health] 保存体征数据失败: {}`C-01 |
### 2.3 助手 Tab / AI 聊天 (pages/messages/index) — PASS
| 检查项 | 结果 | 详情 |
|--------|------|------|
| 页面加载 | PASS | 标题"健康助手 . 小华" |
| 在线状态 | PASS | 绿色圆点 + "24小时在线" |
| 输入框 | PASS | placeholder "输入您的问题..." |
| 发送按钮 | PASS | 存在,无输入时 disabled |
### 2.4 我的 Tab (pages/profile/index) — PASS
| 检查项 | 结果 | 详情 |
|--------|------|------|
| 用户卡片 | PASS | 头像"系" + "系统管理员" |
| 统计数据 | PASS | 健康积分 0 + 连续打卡 0 天 |
| 功能菜单 | PASS | 5 大分组 17 个菜单项完整 |
| 退出登录 | PASS | 红色按钮存在 |
| Console 错误 | PASS | 无 |
### 2.5 商城 Tab — 不在 TabBar 内,需导航访问
## 3. 非 Tab 页面测试
### 3.1 积分商城 (pages/mall/index) — PASS_WITH_ISSUES
| 检查项 | 结果 | 详情 |
|--------|------|------|
| 页面加载 | PASS | 积分头部 + 签到按钮 |
| 空状态 | PASS | "暂无商品" + "更多好物即将上架" |
| **签到功能** | **FAIL** | 日志 `[points] 签到失败: {}`C-01 |
### 3.2 咨询列表 (pages/consultation/index) — PASS_WITH_ISSUES
| 检查项 | 结果 | 详情 |
|--------|------|------|
| 页面导航 | PASS | 成功导航 |
| 骨架屏 | PASS | 4 个 loading card |
| **数据加载** | **FAIL** | 永久 loading 状态无超时提示C-01 + BUG-03 |
## 4. 核心功能 API 验证(绕过小程序 request 层)
| API | 方法 | 结果 | 详情 |
|-----|------|------|------|
| 积分账户 | GET /health/points/account | **PASS** | 余额 40总获得 50总消费 10 |
| 血压保存 | POST /health/patients/{id}/vital-signs | **PASS** | 200返回完整记录 |
| 每日签到 | POST /health/points/checkin | **PASS** | 200checked_in_today=true连续 2 天 |
| 咨询列表 | GET /health/consultation-sessions | **PASS** | 2001 条 active 会话 |
**结论:** 后端 API 全部正常,所有功能性问题源于小程序端 token 读取。
## 5. BUG 详细分析
### C-01: inject_auth 与 request.ts 的 storage 键不匹配
- **严重性:** CRITICAL
- **文件:** `services/request.ts:23-29`
- **现象:** `inject_auth` 写入明文键(`access_token``request.ts``safeGet()` 只调用 `secureGet()`(读 `_es_` 前缀加密键),不 fallback 到明文键
- **根因:** `safeGet``secureGet` 返回空字符串时不 fallback空字符串不抛异常只在 catch 中 fallback。而 `auth.ts``storageGet``secureGet` 返回 falsy 时正确 fallback
- **影响:** 所有需要认证的功能不可用(体征保存、签到、咨询、数据加载)
- **修复:** 统一 `safeGet``storageGet` 的 fallback 逻辑,或让 `inject_auth` 写入加密键
- **预计工时:** 1h
### C-02: secure-storage.ts UTF-16 截断中文字符
- **严重性:** CRITICAL
- **文件:** `utils/secure-storage.ts:13-23`
- **现象:** `toBase64` 使用 `Uint8Array` 截断 UTF-16 高位字节
- **根因:** `charCodeAt` 返回的 UTF-16 编码值超过 255 时被截断为 8 位
- **影响:** 任何含中文的数据(如 `display_name`="系统管理员")经 encrypt-decrypt 循环后损坏,`JSON.parse` 失败
- **修复:** 使用 `TextEncoder`/`TextDecoder` 进行 UTF-8 编解码
- **预计工时:** 2h
### BUG-03: 咨询列表无超时处理
- **严重性:** MEDIUM
- **文件:** `pages/consultation/index`
- **现象:** API 失败时无用户反馈,页面永远显示骨架屏
- **修复:** 添加加载超时和错误状态 UI
- **预计工时:** 1h
### BUG-04: 错误日志输出空对象
- **严重性:** MEDIUM
- **现象:** 签到/体征保存失败时 `catch` 输出 `{}`
- **修复:** 使用 `JSON.stringify(err, Object.getOwnPropertyNames(err))` 输出完整错误
- **预计工时:** 30min
## 6. 测试统计
| 类别 | 测试项 | PASS | FAIL | PASS_WITH_ISSUES |
|------|--------|------|------|------------------|
| 连接与认证 | 3 | 1 | 0 | 2 |
| Tab 页面 | 4 | 3 | 0 | 1 |
| 非 Tab 页面 | 2 | 0 | 0 | 2 |
| UI 元素 | 38 | 38 | 0 | 0 |
| 核心功能API 直测) | 4 | 4 | 0 | 0 |
| 核心功能(应用内) | 3 | 0 | 3 | 0 |
| **合计** | **54** | **46** | **3** | **5** |
**UI 渲染通过率:** 100% (38/38)
**API 直测通过率:** 100% (4/4)
**应用内功能通过率:** 0% (0/3) — 全部因 C-01 失败
**综合通过率:** 85.2% (46/54)
## 7. 评价
**UI 层质量:** 优秀A 级)— 所有页面正确渲染,空状态处理完善,设计系统一致性好。
**功能层质量:** 失败F 级)— 但根因集中在一个 CRITICAL 问题C-01 token 读取),修复后预计 100% 通过。后端 API 经独立验证全部正常。

View File

@@ -0,0 +1,159 @@
# API 端点深度测试报告
> 测试工具: curl/Bash | 环境: http://localhost:3000
> 测试账号: admin / Admin@2026 (完整权限) | 总用例: 69
## 1. 模块通过率汇总
| 模块 | 测试数 | 通过 | 失败 | 通过率 |
|------|--------|------|------|--------|
| 认证与权限 | 8 | 8 | 0 | **100%** |
| 患者 CRUD | 11 | 10 | 1 | **90.9%** |
| 患者分页/注入 | 7 | 5 | 2 | **71.4%** |
| 患者删除 | 2 | 2 | 0 | **100%** |
| 健康数据 | 5 | 1 | 4 | **20%** |
| 预约系统 | 7 | 7 | 0 | **100%** |
| 咨询管理 | 9 | 7 | 2 | **77.8%** |
| 内容管理 | 13 | 10 | 3 | **76.9%** |
| 通用/跨切面 | 7 | 7 | 0 | **100%** |
| **总计** | **69** | **57** | **12** | **82.6%** |
## 2. 认证与权限 — 100% PASS
| ID | 测试 | 结果 |
|----|------|------|
| AUTH-01 | 错误密码 | PASS — `message=未授权` |
| AUTH-02 | 不存在的用户 | PASS — `message=未授权` |
| AUTH-03 | 无 Token 访问 | PASS — HTTP 401 |
| AUTH-04 | 无效 Token | PASS — HTTP 401 |
| AUTH-05 | 空 body 登录 | PASS — 429 限流触发 |
| AUTH-06 | SQL 注入 (`' OR 1=1 --`) | PASS — 无数据泄漏 |
| AUTH-07 | 超长密码 (10000 字符) | PASS — 429 限流触发 |
| AUTH-08 | 有效 Token | PASS — 200 + data |
**亮点:** 限流机制有效,登录端点不泄漏信息(统一返回"未授权"SQL 注入被正确处理。
## 3. 患者 CRUD — 90.9% PASS
| ID | 测试 | 结果 | 说明 |
|----|------|------|------|
| PATIENT-01 | 空名称创建 | PASS | `400: 患者姓名不能为空` |
| PATIENT-02 | 500 字符名称 | PASS | `400: 长度不能超过255` |
| PATIENT-03 | 未来出生日期 (2099) | PASS | `400: 出生日期不能是未来日期` |
| PATIENT-04 | XSS in name (`<script>`) | **FAIL** | HTTP 200, 存储原值 |
| PATIENT-05 | 无效 gender | PASS | `400: 不是有效值` |
| PATIENT-06 | 有效创建 | PASS | success, version=1 |
| PATIENT-14 | 按 ID 查询 | PASS | success |
| PATIENT-15 | 不存在的 ID | PASS | `404: 患者不存在` |
| PATIENT-16 | 有效更新 | PASS | version=2 |
| PATIENT-17 | 乐观锁冲突 | PASS | `409: 版本冲突` |
| PATIENT-18 | 未来日期更新 | PASS | `400: 出生日期不能是未来日期` |
### PATIENT-04: XSS 存储未消毒 (MEDIUM)
- `<script>alert(1)</script>` 直接存入 name 字段
- 前端 React 默认转义,但建议服务端也做消毒
- **修复:** 添加 HTML sanitize 或正则剥离标签
### 患者分页/注入测试
| ID | 测试 | 结果 |
|----|------|------|
| PATIENT-10 | limit=10000 | **FAIL (LOW)** — 无上限,可能导致性能问题 |
| PATIENT-12 | SQL 注入 in search | **FAIL (MEDIUM)** — 连接错误 (HTTP 000) |
## 4. 健康数据 — 20% PASS (最差模块)
| ID | 测试 | 结果 | 说明 |
|----|------|------|------|
| HEALTH-01 | 极端血压 (0/0) | **FAIL** | HTTP 200值存为 null |
| HEALTH-02 | 极端心率 (999) | **FAIL** | HTTP 200值存为 null |
| HEALTH-03 | 负值 (-10) | **FAIL** | HTTP 200值存为 null |
| HEALTH-04 | 无效 UUID | PASS | `422: UUID parsing failed` |
| HEALTH-05 | 未来日期 (2099) | **FAIL** | HTTP 200记录被创建 |
### H-06: 日常监测 DTO-Entity 映射断裂 (HIGH)
**这是本次测试发现的最严重的后端问题。**
- **现象:** API 接受 `indicator_type``value``systolic``diastolic` 等字段但静默忽略,创建的记录所有测量字段为 null
- **根因:** DTO 字段与 Entity 列名不匹配。DTO 使用 `systolic`/`diastolic`Entity 期望 `morning_bp_systolic`/`morning_bp_diastolic`
- **影响:** 日常监测功能实质失效 — 小程序录入的体征数据无法正确存储
- **修复:** 重构 DTO 字段映射,或统一 DTO/Entity 字段命名
- **预计工时:** 4h
**同时发现:** 无值范围校验(血压 0、心率 999 被接受)、未来 record_date 无校验。
## 5. 预约系统 — 100% PASS
| ID | 测试 | 结果 |
|----|------|------|
| APPOINT-01 | 列表查询 | PASS |
| APPOINT-02 | 空 doctor_id | PASS — 422 |
| APPOINT-03 | 无效 UUID | PASS — 422 |
| APPOINT-04 | 不存在的预约 | PASS — 404 |
| APPOINT-05 | page=0 | PASS |
| APPOINT-11 | 排班已满 | PASS — `400: 排班已满` |
| APPOINT-12 | 重复预约 | PASS — `400: 排班已满` |
**亮点:** UUID 校验、容量检查、404 处理全部正确。
## 6. 咨询管理 — 77.8% PASS
| ID | 测试 | 结果 |
|----|------|------|
| CONSULT-02 | 空描述创建 | **FAIL (LOW)** — 接受空描述 |
| CONSULT-05 | XSS in description | **FAIL (MEDIUM)** — XSS 存储原值 |
| CONSULT-06~09 | 评分范围 1-5 | **PASS** — 校验完善 |
**亮点:** 评分校验优秀1-5 范围 + 只能评已关闭会话)。
## 7. 内容管理 — 76.9% PASS
| ID | 测试 | 结果 |
|----|------|------|
| ARTICLE-04 | 500 字符标题 | **FAIL (HIGH)** — HTTP 500 内部错误 |
| CATEGORY-02 | 空分类名称 | **FAIL (MEDIUM)** — 接受空名称 |
| TAG-04 | 重复标签名 | **FAIL (LOW)** — 允许重复 |
### ARTICLE-04: 500 字符标题导致 500 错误 (HIGH)
- **现象:** 500 字符文章标题返回 HTTP 500 Internal Server Error
- **根因:** DTO 缺少 `#[validate(length(max=255))]`,数据库列长度约束违反导致未处理的 DB 错误
- **修复:** 添加 DTO 长度校验 + 全局 DB 错误映射
- **预计工时:** 30min
### CATEGORY-02: 空分类名称被接受 (MEDIUM)
- 文章标题有空校验,标签名称有空校验,但分类名称没有
- **修复:** 添加 `#[validate(length(min=1))]`
## 8. 通用/跨切面 — 100% PASS
| ID | 测试 | 结果 |
|----|------|------|
| GENERIC-01 | 3 个并发更新 | PASS — 1 成功 + 2 冲突 (409) |
| GENERIC-02 | 错误 JSON body | PASS — 400 |
| GENERIC-03 | 缺少 Content-Type | PASS — 415 |
| GENERIC-04 | GET 带 body | PASS — body 被忽略 |
| GENERIC-05 | 超大页码 | PASS — 空列表 |
| GENERIC-06 | 快速连续请求 | PASS — 全 200 |
| GENERIC-07 | 不存在的文章 ID | PASS — 404 |
**亮点:** 乐观锁在并发下表现完美1 成功 + 2 冲突HTTP 状态码使用规范。
## 9. 失败项汇总
| ID | 严重性 | 模块 | 问题 | 修复 | 工时 |
|----|--------|------|------|------|------|
| H-06 | HIGH | 健康数据 | DTO-Entity 映射断裂 | 重构字段映射 | 4h |
| H-07 | HIGH | 内容管理 | 500 字符标题 → HTTP 500 | 添加 DTO 校验 | 30min |
| M-08 | MEDIUM | 健康数据 | 极端值无校验 | 添加范围校验 | 2h |
| M-09 | MEDIUM | 健康数据 | 未来 record_date | 添加日期校验 | 30min |
| M-10 | MEDIUM | 咨询 | XSS 存储未消毒 | HTML sanitize | 1h |
| M-11 | MEDIUM | 内容管理 | 空分类名被接受 | 添加 validate | 30min |
| M-12 | MEDIUM | 患者 | SQL 注入导致连接错误 | 调查 URL 编码 | 2h |
| M-13 | MEDIUM | 患者 | XSS 存储未消毒 | HTML sanitize | 1h |
| L-04 | LOW | 患者 | limit 无上限 | 设 max=200 | 30min |
| L-05 | LOW | 咨询 | 空描述被接受 | validate 或文档 | 30min |
| L-06 | LOW | 内容管理 | 重复标签名 | 唯一约束 | 1h |

View File

@@ -0,0 +1,139 @@
# 前端代码静态分析报告
> 分析范围: apps/web/src/ (316 TS/TSX) + apps/miniprogram/src/ (167 TS/TSX)
> 分析工具: Grep/Read/Bash
## 1. TypeScript 类型安全 — MEDIUM
### Web 前端
生产代码仅 1 处 `any`:
| 文件 | 行号 | 问题 |
|------|------|------|
| `hooks/usePaginatedData.ts` | 39 | `fetchFn: (...args: any[]) =>` — 建议用泛型 `A extends unknown[]` |
测试文件中 17 处 `as any`mock 场景),影响低。
### 小程序 — 10 处 `as any`
| 文件 | 行号 | 问题 | 严重性 |
|------|------|------|--------|
| `app.tsx` | 24, 29 | `(globalThis as any).__hms` | LOW — 调试辅助 |
| `pages/login/index.tsx` | 9 | `(__wxConfig as any).envVersion` | MEDIUM |
| `services/request.ts` | 250 | `method: method as any` | MEDIUM |
| `pages/pkg-health/device-sync/index.tsx` | 69 | `(bleManager as any).dataBuffer` | HIGH |
| `pages/appointment/create/index.tsx` | 132 | `(Taro.requestSubscribeMessage as any)` | MEDIUM |
**修复建议:** 创建 `types/global.d.ts``types/taro.d.ts` 补全缺失类型。
## 2. 错误处理 — HIGH
### Web 前端静默吞错 (10+ 处)
| 文件 | 行号 | 模式 |
|------|------|------|
| `pages/Home.tsx` | 224, 232, 238 | 个人统计加载失败被吞 |
| `pages/Roles.tsx` | 46 | 权限列表加载失败被吞 |
| `pages/health/ArticleManageList.tsx` | 119 | 文章列表加载失败被吞 |
| `pages/health/DialysisManageList.tsx` | 49 | 透析列表加载失败被吞 |
| `pages/health/components/DoctorSelect.tsx` | 28 | 医生列表加载失败被吞 |
| `pages/health/components/workbench/OperatorWorkbench.tsx` | 35 | 工作台数据加载失败被吞 |
另有 10 处 `catch { }`ChatPage 4 处 / useAlertSSE 2 处 / MainLayout 1 处 / usePaginatedData 1 处 / NotificationPanel 1 处 / App.tsx 1 处)。
**修复:** `.catch(() => {})``.catch((err) => console.warn('[context] 操作失败:', err))`,或设置错误状态。
### 小程序
仅 1 处静默 catch`followups/detail/index.tsx:58`),有注释解释,属合理模式。
## 3. 安全问题 — HIGH (1 处)
### dangerouslySetInnerHTML 无消毒
`pages/health/articleEditor/ArticlePhonePreview.tsx:243`:
```tsx
<div dangerouslySetInnerHTML={{ __html: content }} />
```
- `content` 来自 wangEditor 富文本输出
- 后台管理预览组件,内容由管理员创建(非 UGC
- **仍建议引入 DOMPurify 做客户端消毒**
- 预计工时: 30min
### 硬编码 URL — LOW
| 文件 | 内容 | 评估 |
|------|------|------|
| `AiConfigPage.tsx:340,402` | `http://localhost:11434` | Ollama 默认 URL仅作 placeholder |
| `miniprogram/services/request.ts:4` | `localhost:3000` fallback | 开发环境 fallback生产需运行时校验 |
**无硬编码密钥或密码。**
## 4. 可访问性 — LOW
- 未发现缺少 `alt``<img>` — Web 前端全用 Ant Design 组件
- 3 处 `onClick` 在非 button 元素上使用MainLayout 侧边栏 logo/折叠按钮 + ActionThreadDrawer 事件链接)
- **修复:** 添加 `role="button"` + `tabIndex={0}` + `onKeyDown`
## 5. 大文件 — MEDIUM
### Web 前端 (500+ 行)
| 文件 | 行数 | 建议 |
|------|------|------|
| `AdminDashboard.tsx` | 734 | 拆分统计卡片、图表、表格 |
| `ArticleManageList.tsx` | 654 | 拆分筛选栏、表格、详情抽屉 |
| `FollowUpTaskList.tsx` | 543 | 拆分筛选、列表、详情 |
| `ConsultationDetail.tsx` | 542 | 拆分消息区、信息栏 |
| `BannerManage.tsx` | 526 | 拆分表格和表单 |
| `AppointmentList.tsx` | 520 | 拆分筛选和表格 |
| `AiKnowledgePage.tsx` | 508 | 拆分列表和编辑 |
所有文件在 800 行限制内CLAUDE.md 规范),但建议拆分提升可维护性。
### 小程序 (300+ 行)
| 文件 | 行数 |
|------|------|
| `daily-monitoring/index.tsx` | 449 |
| `health/index.tsx` | 376 |
| `index/index.tsx` | 371 |
小程序文件总体控制得更好。
## 6. 国际化 — MEDIUM (不阻塞)
- **Web 前端:** 97 个文件 / 375 处硬编码中文文本
- **高频文件:** DashboardWidgets (47) / DoctorWorkbench (19) / OperatorWorkbench (18)
- **影响:** 当前定位国内单语平台,短期不影响
- **建议:** 新代码使用 i18n key旧代码逐步迁移
## 7. 内联样式 — LOW
- **1,548 处** `style={{}}` 分布在 129 个文件
- **高频:** DoctorWorkbench (68) / AdminDashboard (54) / OperatorWorkbench (49) / DashboardWidgets (47)
- 部分动态计算width/height不可避免静态样式应迁移到 CSS
## 8. 值得肯定的方面
1. **TypeScript 类型安全整体优秀** — 生产代码仅 1 处 `any`
2. **小程序已完全消除 Web API 依赖** — 无 `localStorage`/`btoa`/`atob`
3. **无硬编码密钥或密码** — 敏感值全走环境变量
4. **eslint-disable 使用规范** — 每处有注释解释
5. **所有文件在 800 行限制内**
6. **小程序 console 日志格式统一**`[模块名] 描述: error`
## 9. 问题汇总
| 严重性 | 问题 | 文件数 | 修复工作量 |
|--------|------|--------|-----------|
| HIGH | 静默吞错 `.catch(() => {})` | 10+ | 小 — 改为 warn 日志 |
| HIGH | dangerouslySetInnerHTML 无消毒 | 1 | 小 — 引入 DOMPurify |
| MEDIUM | 小程序 `as any` 类型断言 | 10 | 中 — 补全类型声明 |
| MEDIUM | 硬编码中文 (i18n) | 97 | 大 — 渐进迁移 |
| MEDIUM | 500+ 行大文件 | 7 | 中 — 拆分子组件 |
| LOW | 内联样式过多 | 129 | 大 — 渐进迁移 |
| LOW | localhost fallback URL | 2 | 小 — 运行时校验 |
| LOW | 非交互元素 onClick 缺 a11y | 3 | 小 |

View File

@@ -0,0 +1,222 @@
# 跨部门头脑风暴 — 问题研讨与优化方案
> 日期: 2026-05-21 | 参与方: 前端/后端/小程序/安全/UX/DevOps
> 基于 V3 Beta 综合测试发现
## 1. 会议议题
基于 5 个专家团队的测试发现,识别出 **4 个 CRITICAL + 8 个 HIGH + 15 个 MEDIUM** 问题。本次头脑风暴聚焦于:
1. CRITICAL 问题修复方案与优先级
2. 移动端响应式架构决策
3. 小程序安全存储架构改进
4. 后端 DTO-Entity 映射质量管控
5. Beta 发布时间线
---
## 2. 议题一: 小程序认证链路断裂 (C-01 + C-02)
### 问题
`inject_auth` → 明文键 → `request.ts safeGet` 只读加密键 → 所有 API 无 token
`secure-storage.ts` → UTF-16 截断 → 中文数据加密后解密损坏
### 方案讨论
| 方案 | 描述 | 优点 | 缺点 |
|------|------|------|------|
| **A. 统一 safeGet fallback** | `safeGet``secureGet` 返回空时 fallback 到明文键 | 改动最小1 文件) | 认证路径依赖两套存储 |
| **B. inject_auth 写加密键** | MCP 注入时直接写 `_es_` 前缀加密键 | 根因修复 | MCP 需实现加密逻辑 |
| **C. 统一存储层重构** | 所有读写走单一 `storageGet/storageSet`,内部处理加密/明文 fallback | 架构最优 | 改动范围大 |
### 决策
**采用方案 A + 修复 C-02**,预计 3h
1. `request.ts safeGet` 添加与 `auth.ts storageGet` 一致的 fallback 逻辑
2. `secure-storage.ts toBase64/fromBase64` 改用 `TextEncoder/TextDecoder`
3. 添加单元测试验证中文字符加密/解密循环
---
## 3. 议题二: 移动端响应式 (C-03 + C-04 + H-03)
### 问题
- 375px: 表格不可用,列严重挤压
- 812×375: 内容区域空白
- 768px: 表格数据不加载
### 方案讨论
| 方案 | 描述 | 工时 | 效果 |
|------|------|------|------|
| **A. Ant Design ProTable 响应式** | 使用 `responsive` 配置自动切换卡片视图 | 2d | 列表页全覆盖 |
| **B. CSS Grid + 媒体查询** | 手写 `@media` 断点,表格→卡片 | 3d | 精细控制 |
| **C. 独立移动端组件** | 为移动端创建 `MobilePatientCard` 等组件 | 5d | 最佳 UX |
### 决策
**采用方案 A**Ant Design ProTable 自带 responsive 支持:
1.`<768px` 启用 `cardView` 模式
2. 修复 768px 断点侧边栏折叠同步问题
3. 修复 812×375 高度不足导致懒加载未触发
**注意:** HMS 定位为 PC 管理后台,移动端支持优先级低于小程序。方案 A 满足"基本可用"即可。
---
## 4. 议题三: 健康数据 DTO 映射 (H-06)
### 问题
日常监测 API 通过率 20%DTO 字段(`systolic`/`diastolic`)与 Entity 列名(`morning_bp_systolic`/`morning_bp_diastolic`)不匹配,导致所有测量值存为 null。
### 根因分析
1. DTO 设计采用通用字段名Entity 使用具体时段字段名
2. Handler 层缺少 DTO→Entity 的显式映射逻辑
3. SeaORM 隐式匹配字段名,不匹配的静默为 null
### 修复方案
1. **DTO 重构:** 定义 `CreateDailyMonitoringReq` 明确映射到 Entity 字段
2. **Handler 添加映射:** 显式 `entity.morning_bp_systolic = dto.systolic`
3. **添加集成测试:** 确保写入后能正确读回
4. **值范围校验:** 血压 60-300 / 心率 30-250 / 血糖 1-50
5. **日期校验:** `record_date <= today`
预计工时: 4h
---
## 5. 议题四: 安全问题汇总 (XSS + SSRF + 输入校验)
### 发现清单
| 问题 | 位置 | 风险 |
|------|------|------|
| XSS 存储未消毒(患者名/咨询描述) | patient_handler / consultation_handler | Stored XSS |
| dangerouslySetInnerHTML 无消毒 | ArticlePhonePreview.tsx | DOM XSS |
| 空分类名被接受 | article_category_handler | 数据质量 |
| 文章标题超长导致 500 | article_handler | DoS/信息泄漏 |
| API limit 无上限 | 多个 list 端点 | 资源耗尽 |
### 修复优先级
1. **P0 (1h):** 文章标题添加 `#[validate(length(max=255))]`
2. **P1 (2h):** 患者名/咨询描述添加 HTML sanitize
3. **P1 (30min):** ArticlePhonePreview 引入 DOMPurify
4. **P2 (1h):** 所有 list 端点 limit 上限设为 200
5. **P2 (30min):** 分类名称添加 `#[validate(length(min=1))]`
---
## 6. 议题五: 性能优化路线图
### 关键性能指标
| 指标 | 当前值 | 目标 | 优先级 |
|------|--------|------|--------|
| Dashboard LCP | 1381ms | < 1000ms | P1 |
| Patient List LCP | 2643ms | < 2000ms | P1 |
| API 重复调用 | ×4 | ×1 | P0 |
| Antd Table Reflow | 460ms | < 100ms | P2 |
| Noto Sans SC | 1.3MB | < 300KB | P2 |
### 优化方案
1. **API 去重 (P0, 4h):** 检查 AdminDashboard useEffect 依赖项,考虑 React Query 缓存
2. **字体优化 (P2, 1h):** `font-display: optional` + 预加载关键子集
3. **虚拟滚动 (P2, 2h):** Antd Table `scroll={{ virtual: true }}`
4. **固定 scroll (P2, 1h):** 设置固定 `scroll.x`/`scroll.y` 避免 `measureScrollbarSize`
---
## 7. 议题六: 代码质量提升
### 静默吞错治理
**原则:** 所有 catch 块至少记录 `console.warn`,关键路径设置错误状态。
```typescript
// BAD
.catch(() => {})
// GOOD
.catch((err) => {
console.warn('[PatientList] 加载统计数据失败:', err);
// 可选: setErrorState(true)
})
```
### 大文件拆分计划
| 文件 | 行数 | 拆分方案 | 优先级 |
|------|------|---------|--------|
| AdminDashboard.tsx | 734 | StatsCards + Charts + ModuleStatus | P2 |
| ArticleManageList.tsx | 654 | FilterBar + ArticleTable + DetailDrawer | P2 |
| FollowUpTaskList.tsx | 543 | TaskFilter + TaskTable + TaskDetail | P3 |
---
## 8. 行动计划与时间线
### Phase 0: CRITICAL 修复Day 1-2阻塞 Beta
| 任务 | 负责方 | 工时 | 依赖 |
|------|--------|------|------|
| C-01: safeGet fallback | 前端 | 1h | — |
| C-02: UTF-8 编码 | 前端 | 2h | — |
| H-01: 患者表单验证 | 前端 | 1h | — |
| H-06: DTO-Entity 映射 | 后端 | 4h | — |
| H-07: 文章标题校验 | 后端 | 30min | — |
| H-02: 预约列表 API | 全栈 | 2h | 需调查根因 |
### Phase 1: HIGH 修复Day 3-4
| 任务 | 负责方 | 工时 |
|------|--------|------|
| C-03/C-04: 移动端卡片视图 | 前端 | 2d |
| H-03: 768px 断点修复 | 前端 | 4h |
| H-05: API 去重 | 前端 | 4h |
| XSS sanitize (患者/咨询) | 后端 | 2h |
### Phase 2: MEDIUM + 性能优化Day 5-7
| 任务 | 负责方 | 工时 |
|------|--------|------|
| 对比度修复 | 前端 | 30min |
| Dark Mode 卡片 | 前端 | 4h |
| 静默吞错治理 | 前端 | 2h |
| 字体优化 | 前端 | 1h |
| API 输入校验补全 | 后端 | 3h |
### Phase 3: LOW + 技术债Beta 后迭代)
- i18n 迁移(渐进)
- 大文件拆分(渐进)
- 内联样式清理(渐进)
- 类型声明补全(小程序)
---
## 9. 会议结论
### Beta 发布条件
**必须在 Phase 0 + Phase 1 完成后才能发布 Beta 版本:**
1. ✅ 4 个 CRITICAL 全部修复
2. ✅ 8 个 HIGH 全部修复
3. ✅ 所有修复通过回归测试
4.`cargo check` + `cargo test` + `pnpm build` 全部通过
5. ✅ 浏览器 + 小程序手动验证核心流程
### 预计时间线
- **Phase 0:** Day 1-2 (CRITICAL + HIGH 后端)
- **Phase 1:** Day 3-4 (移动端 + API 去重 + XSS)
- **Beta 发布:** Day 4 结束
- **Phase 2:** Day 5-7 (MEDIUM + 性能)
- **正式版 V1:** Day 7+ (根据 Beta 反馈)

View File

@@ -0,0 +1,142 @@
# Beta 就绪验收清单
> 基于 V3 Beta 综合测试发现 | 更新: 2026-05-21
> 目标: 明确 Beta 发布前的必须完成项和验证标准
## 1. 阻塞项(必须修复)— Phase 0
### 1.1 小程序认证链路
- [ ] **C-01:** `services/request.ts``safeGet` 添加明文键 fallback 逻辑
- [ ] **C-02:** `utils/secure-storage.ts``toBase64/fromBase64` 改用 `TextEncoder/TextDecoder`
- [ ] 验证: 小程序内体征保存、签到、咨询列表 API 调用成功
- [ ] 验证: 含中文的 `user_data` 加密存储后解密正确
### 1.2 Web 前端核心功能
- [ ] **H-01:** `PatientList.tsx` 创建表单添加 `form.validateFields()` 前端校验
- [ ] **H-02:** 预约列表 API 网络异常排查修复
- [ ] 验证: 空表单提交被前端拦截,显示校验错误
- [ ] 验证: 预约列表页正常加载数据
### 1.3 后端数据完整性
- [ ] **H-06:** 日常监测 DTO-Entity 字段映射修复
- [ ] **H-07:** 文章标题 DTO 添加 `#[validate(length(max=255))]`
- [ ] 验证: 血压/心率/血糖写入后能正确读回
- [ ] 验证: 500 字符标题返回 400 而非 500
## 2. HIGH 项(应该修复)— Phase 1
### 2.1 移动端响应式
- [ ] **C-03:** Mobile 375px 添加卡片/列表视图替代表格
- [ ] **C-04:** Mobile 横屏 812×375 内容区域空白修复
- [ ] **H-03:** Tablet 768px 侧边栏折叠与内容区域同步
- [ ] 验证: 5 种视口 (1920×1080 / 1366×768 / 768×1024 / 375×812 / 812×375) 全部 PASS
### 2.2 性能
- [ ] **H-04:** 患者列表 LCP 优化至 < 2000ms
- [ ] **H-05:** 仪表盘 API 每个端点从 ×4 降至 ×1
- [ ] 验证: Lighthouse Desktop Accessibility ≥ 94
### 2.3 安全
- [ ] 患者名/咨询描述 HTML sanitize
- [ ] ArticlePhonePreview 引入 DOMPurify
- [ ] 验证: XSS payload 存储后不执行
## 3. 构建与部署验证
### 3.1 后端
- [ ] `cargo check --workspace` 无错误
- [ ] `cargo test --workspace` 全部通过
- [ ] `cargo clippy -- -D warnings` 无警告
- [ ] 后端服务正常启动,健康检查 200
### 3.2 Web 前端
- [ ] `pnpm build` 生产构建通过
- [ ] `pnpm test` 单元测试通过
- [ ] 4 种主题切换正常
- [ ] 所有核心页面加载无 console error
### 3.3 小程序
- [ ] `pnpm build:weapp` 构建通过
- [ ] 微信开发者工具中 5 个 Tab 页全部可访问
- [ ] 体征保存、签到、咨询功能正常
- [ ] 无 JS 异常
## 4. 回归测试清单
### 4.1 核心业务流程
| 流程 | 验证点 | 状态 |
|------|--------|------|
| 登录 → 工作台 | 菜单加载、统计数据显示 | ⬜ |
| 患者创建 | 表单校验、数据保存 | ⬜ |
| 患者搜索 | 关键字过滤生效 | ⬜ |
| 预约列表 | 数据加载、分页 | ⬜ |
| 咨询管理 | 列表、状态切换、评分 | ⬜ |
| 主题切换 | 4 种主题 + 持久化 | ⬜ |
### 4.2 API 端点抽检
| 端点 | 方法 | 验证 | 状态 |
|------|------|------|------|
| /auth/login | POST | 正确/错误密码 | ⬜ |
| /health/patients | GET/POST | CRUD + 校验 | ⬜ |
| /health/daily-monitoring | POST | DTO 映射正确 | ⬜ |
| /health/articles | POST | 标题长度校验 | ⬜ |
| /health/appointments | GET | 列表加载 | ⬜ |
### 4.3 小程序核心功能
| 功能 | 验证点 | 状态 |
|------|--------|------|
| 登录 | Token 获取、存储、读取 | ⬜ |
| 首页 | 体征概览、操作按钮 | ⬜ |
| 体征保存 | 血压写入 + 读回 | ⬜ |
| 签到 | 积分增加 | ⬜ |
| AI 聊天 | 消息发送 | ⬜ |
| 咨询列表 | 数据加载 | ⬜ |
## 5. 发布签名
| 角色 | 确认 | 日期 |
|------|------|------|
| 前端负责人 | ⬜ | — |
| 后端负责人 | ⬜ | — |
| 小程序负责人 | ⬜ | — |
| 安全负责人 | ⬜ | — |
| QA 负责人 | ⬜ | — |
| 产品负责人 | ⬜ | — |
---
## 6. 已知限制Beta 版本)
以下问题在 Beta 版本中 **不阻塞**,将在后续迭代中修复:
1. **移动端响应式** — PC 管理后台移动端体验不佳(有小程序替代)
2. **i18n** — 375 处硬编码中文(国内单语定位)
3. **内联样式** — 1,548 处 `style={{}}`(功能不影响)
4. **API limit 上限** — 无 200 上限(可通过浏览器 DevTools 触发)
5. **重复标签** — 无唯一约束(管理员操作,风险低)
6. **Dark Mode 对比度** — 部分卡片浅色背景(视觉问题,不影响功能)
7. **大文件** — 7 个 500+ 行 TSX 文件(可维护性,非功能问题)
## 7. 测试报告索引
| 章节 | 文件 | 关键发现 |
|------|------|---------|
| 执行摘要 | `01-executive-summary.md` | 36 个问题B- 评级 |
| Web 功能测试 | `02-web-functional.md` | 8 领域 5 通过H×2 M×2 |
| 性能/兼容性 | `03-web-perf-compat.md` | Lighthouse 94/100/100移动端 FAIL |
| 小程序测试 | `04-miniprogram.md` | UI 100%,功能 0%token 问题) |
| API 深度测试 | `05-api-deep-test.md` | 82.6% 通过率,健康数据 20% |
| 静态分析 | `06-static-analysis.md` | 吞错 10+i18n 375 处 |
| 头脑风暴 | `07-brainstorm.md` | 3 Phase 修复计划7 天时间线 |