Files
hms/docs/audits/v3-beta/06-static-analysis.md
iven 1e59007bd5 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
2026-05-24 11:32:40 +08:00

140 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 前端代码静态分析报告
> 分析范围: 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 | 小 |