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:
97
docs/audits/v3-beta/01-executive-summary.md
Normal file
97
docs/audits/v3-beta/01-executive-summary.md
Normal 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 2643ms(render 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% | F(token 问题) |
|
||||
| 小程序功能(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` |
|
||||
119
docs/audits/v3-beta/02-web-functional.md
Normal file
119
docs/audits/v3-beta/02-web-functional.md
Normal 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 个
|
||||
175
docs/audits/v3-beta/03-web-perf-compat.md
Normal file
175
docs/audits/v3-beta/03-web-perf-compat.md
Normal 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 加载导致 FOUT,5 个 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 |
|
||||
146
docs/audits/v3-beta/04-miniprogram.md
Normal file
146
docs/audits/v3-beta/04-miniprogram.md
Normal 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** | 200,checked_in_today=true,连续 2 天 |
|
||||
| 咨询列表 | GET /health/consultation-sessions | **PASS** | 200,1 条 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 经独立验证全部正常。
|
||||
159
docs/audits/v3-beta/05-api-deep-test.md
Normal file
159
docs/audits/v3-beta/05-api-deep-test.md
Normal 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 |
|
||||
139
docs/audits/v3-beta/06-static-analysis.md
Normal file
139
docs/audits/v3-beta/06-static-analysis.md
Normal 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 | 小 |
|
||||
222
docs/audits/v3-beta/07-brainstorm.md
Normal file
222
docs/audits/v3-beta/07-brainstorm.md
Normal 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 反馈)
|
||||
142
docs/audits/v3-beta/08-beta-checklist.md
Normal file
142
docs/audits/v3-beta/08-beta-checklist.md
Normal 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 天时间线 |
|
||||
Reference in New Issue
Block a user