根因:主包 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
140 lines
5.5 KiB
Markdown
140 lines
5.5 KiB
Markdown
# 前端代码静态分析报告
|
||
|
||
> 分析范围: 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 | 小 |
|