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