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,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 |