# S1 全面扫描 — 汇总报告 日期: 2026-06-08 ## 统计总览 | 优先级 | 数量 | 说明 | |--------|------|------| | P0 | 0 | 无数据丢失/安全漏洞/崩溃风险 | | P1 | 1 | 功能问题 | | P2 | 4 | 体验/规范问题 | | P3 | 7 | 建议改进 | | **合计** | **12** | | --- ## P1 — 高优先级(1 项) ### 1. notifications 页面使用 emoji 违反设计规范 | 文件 | 行号 | 问题 | 影响 | |------|------|------|------| | [notifications/index.vue](client/src/pages/notifications/index.vue) | 43 | `📌` 使用 emoji 作为图钉图标 | 设计规范明确禁止 emoji,必须使用 Icon 组件 | **修复方向**:将 `📌` 替换为 `` --- ## P2 — 中优先级(4 项) ### 2. stats 趋势条动画缺少 prefers-reduced-motion | 文件 | 行号 | 问题 | 影响 | |------|------|------|------| | [stats/index.vue](client/src/pages/stats/index.vue) | 550 | `.trend-bar { transition: width 0.6s ease-out; }` 无 `prefers-reduced-motion` 处理 | 对动画敏感用户不友好 | **修复方向**:添加 `@media (prefers-reduced-motion: reduce) { .trend-bar { transition: none; } }` ### 3. admin/logs 页面日期选择触发双重请求 | 文件 | 行号 | 问题 | 影响 | |------|------|------|------| | [admin/logs.vue](client/src/pages/admin/logs.vue) | 181-185, 206-209 | `selectDate()` 直接调用 `loadLogs()`,同时 `watch([filterLevel, selectedDate])` 也触发 `loadLogs()`,导致日期变更时请求发两次 | 浪费带宽,可能导致竞态 | **修复方向**:`selectDate()` 只设置 `selectedDate.value`,删除手动 `loadLogs()` 调用,由 watcher 统一触发。 ### 4. bills 页面列表参数使用 any 类型 | 文件 | 行号 | 问题 | 影响 | |------|------|------|------| | [bills/index.vue](client/src/pages/bills/index.vue) | 109, 165 | `txList: any[]` 和 `params: any` 丢失类型安全 | 重构时易引入 bug | **修复方向**:使用 `Transaction[]` 和 `TransactionParams` 类型。 ### 5. bills 空状态缺少图标 | 文件 | 行号 | 问题 | 影响 | |------|------|------|------| | [bills/index.vue](client/src/pages/bills/index.vue) | 82-84 | 空状态只显示文字「暂无账单记录」,无图标 | 与其他页面空状态不一致(其他页面都有 Icon) | **修复方向**:添加 `` --- ## P3 — 建议改进(7 项) ### 6. 多处使用 `any` 类型 | 文件 | 行号 | 问题 | |------|------|------| | [index/index.vue](client/src/pages/index/index.vue) | 168 | `recentTx` 类型 `any[]`,应为 `Transaction[]` | | [add/index.vue](client/src/pages/add/index.vue) | 139 | `getCurrentPages()` 结果 cast `as any` | | [budget/index.vue](client/src/pages/budget/index.vue) | 93 | `budget` 类型 `any`,应为 `Budget \| null` | | [profile/index.vue](client/src/pages/profile/index.vue) | 329 | `allList` 类型 `any[]`,应为 `Transaction[]` | | [admin/users.vue](client/src/pages/admin/users.vue) | 99 | `params` 类型 `any`,应为具名类型 | | [admin/feedback.vue](client/src/pages/admin/feedback.vue) | 105 | `list` 类型 `any[]`,应使用 Feedback 类型 | ### 7. stats 页面 loadData / loadTabData 代码重复 | 文件 | 行号 | 问题 | |------|------|------| | [stats/index.vue](client/src/pages/stats/index.vue) | 245-281 | `loadData` 和 `loadTabData` 有大量重复代码(loadSeq、错误处理),可抽取公共函数 | --- ## 总体评价 代码质量整体良好,主要体现在: - ✅ **认证机制完善**:HMAC-SHA256 token + timingSafeEqual,30天过期 - ✅ **竞态保护**:bills、stats、notifications 页面均使用 `loadSeq` 防止并发覆盖 - ✅ **401 队列重试**:`request.ts` 自动重登录 + 队列重试,设计精良 - ✅ **统一设计系统**:SCSS 变量、mixin 复用度高,Claymorphism 风格统一 - ✅ **响应格式统一**:后端 API 返回 `{ code, data/message }` 标准格式 - ✅ **输入校验**:前后端均有校验(金额范围、必填字段、类型白名单) - ✅ **参数化查询**:后端 SQL 使用 `?` 占位符,无 SQL 注入风险 - ✅ **空状态/加载态/错误态**:大部分页面三态齐全 - ✅ **小程序适配**:胶囊按钮避让 `capsuleRight` 使用正确 - ✅ **数据加载模式**:`waitForReady()` + `initialLoaded` 守卫模式统一 - ✅ **动画可访问性**:大部分页面有 `prefers-reduced-motion` 处理 主要改进方向集中在: 1. 消除 emoji(1 处) 2. 补全 `prefers-reduced-motion`(1 处) 3. 修复重复请求(1 处) 4. 统一空状态样式(1 处) 5. 减少 `any` 类型使用(6 处)