From 7c3616ff98cfc85ada20e78908eb85b0d8f658b2 Mon Sep 17 00:00:00 2001 From: houhuan Date: Tue, 12 May 2026 21:06:05 +0800 Subject: [PATCH] docs: add frontend bug fix and code quality design spec Addresses 11 issues across 3 phases: critical bug fixes (fetchUser, silent errors, loading states, stats fallback, global error handler), code quality (extract composables, remove dead code), and minor improvements (password validation, batch delete endpoint). Co-Authored-By: Claude Opus 4.7 --- ...26-05-12-frontend-bugfix-quality-design.md | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-12-frontend-bugfix-quality-design.md diff --git a/docs/superpowers/specs/2026-05-12-frontend-bugfix-quality-design.md b/docs/superpowers/specs/2026-05-12-frontend-bugfix-quality-design.md new file mode 100644 index 0000000..4144af5 --- /dev/null +++ b/docs/superpowers/specs/2026-05-12-frontend-bugfix-quality-design.md @@ -0,0 +1,211 @@ +# 前端 Bug 修复 + 代码质量提升设计文档 + +日期: 2026-05-12 +状态: 待审核 + +## 背景 + +通过全面审计 Web 前端(Vue 3 + Element Plus),发现了 50+ 个问题。本文档聚焦于前端高优先级 Bug 修复和代码质量改进,分 3 个阶段执行。 + +## 阶段 1:关键 Bug 修复 + +### 1.1 修复 fetchUser 未调用 + +**问题**: `Layout.vue` 在 `onMounted` 时未调用 `authStore.fetchUser()`。页面刷新后 `authStore.username` 为空,头像显示 "U" 而非用户名首字母。 + +**修复**: 在 `Layout.vue` 的 `onMounted` 中添加 `await authStore.fetchUser()`。 + +**影响文件**: `web/frontend/src/views/Layout.vue` + +### 1.2 修复静默吞错 + +**问题**: 以下文件的 catch 块完全为空,API 失败时用户无任何反馈: + +| 文件 | 函数 | 行号 | +|------|------|------| +| `files/Images.vue` | `loadData()` | 165 | +| `files/Tables.vue` | `loadData()` | 161 | +| `files/Orders.vue` | `loadData()` | 168 | +| `Sync.vue` | `checkStatus()` | 127 | +| `Tasks.vue` | `loadStats()` | 207 | +| `Logs.vue` | `loadStats()` | 164 | +| `files/Images.vue` | `deleteFile()` | 272 | +| `files/Tables.vue` | `deleteFile()` | 250 | +| `files/Orders.vue` | `deleteFile()` | 242 | + +**修复**: 所有 catch 块添加 `ElMessage.error()` 提示,使用中文错误消息。 + +**影响文件**: 上述 6 个 Vue 文件 + +### 1.3 修复 loading 状态管理 + +**问题**: `Images.vue`、`Tables.vue`、`Orders.vue` 的 `loadData()` 中 `loading.value = false` 不在 `finally` 块中。异常发生时 loading 转圈卡住。 + +**修复**: 统一改为 `try { ... } finally { loading.value = false }` 模式。 + +**影响文件**: `files/Images.vue`、`files/Tables.vue`、`files/Orders.vue` + +### 1.4 修复内存统计回退逻辑 + +**问题**: `Memory.vue` 当 API 不返回 stats 时,从 `items.value`(当前页 50 条)计算置信度统计,显示为全局数据,严重误导用户。 + +**修复**: 移除误导性回退逻辑,当 stats 不可用时显示 "暂无统计数据" 占位。 + +**影响文件**: `web/frontend/src/views/Memory.vue` + +### 1.5 添加全局错误处理 + +**问题**: `main.ts` 没有 `app.config.errorHandler`,未捕获的 Vue 错误只输出到 console.warn,用户无感知。 + +**修复**: 在 `main.ts` 注册全局错误处理器: + +```typescript +app.config.errorHandler = (err, instance, info) => { + console.error('Vue error:', err, info) + ElMessage.error('操作失败,请稍后重试') +} +``` + +**影响文件**: `web/frontend/src/main.ts` + +--- + +## 阶段 2:代码质量 — 提取共享逻辑 + +### 2.1 提取 useDebounce composable + +**问题**: `useDebounce` 函数在 4 个文件中完全重复(Memory.vue:166-174, Barcodes.vue:190-198, Tasks.vue:144-152, Logs.vue:107-115)。 + +**修复**: 创建 `web/frontend/src/composables/useDebounce.ts`: + +```typescript +import { ref } from 'vue' + +export function useDebounce(fn: Function, delay = 300) { + const timer = ref | null>(null) + return (...args: any[]) => { + if (timer.value) clearTimeout(timer.value) + timer.value = setTimeout(() => fn(...args), delay) + } +} +``` + +4 个文件改为 `import { useDebounce } from '@/composables/useDebounce'`。 + +**影响文件**: +- 新建: `web/frontend/src/composables/useDebounce.ts` +- 修改: `Memory.vue`、`Barcodes.vue`、`Tasks.vue`、`Logs.vue` + +### 2.2 提取文件视图共享逻辑 + +**问题**: `Images.vue`、`Tables.vue`、`Orders.vue` 有大量重复代码: +- `statusType()`、`statusText()`、`fmtTime()` 函数完全相同 +- 预览对话框模板 + 逻辑 + CSS 完全相同 +- 详情对话框模板 + 逻辑完全相同 +- 分页、多选、排序模式完全相同 +- 批量删除模式完全相同 + +**修复**: 创建 3 个共享 composable: + +#### `composables/useFileUtils.ts` +```typescript +export function statusType(status: string): string { ... } +export function statusText(status: string): string { ... } +export function fmtTime(t: string): string { ... } +``` + +#### `composables/useFilePreview.ts` +```typescript +export function useFilePreview() { + // previewVisible, previewContent, previewTitle, previewLoading + // openPreview(), closePreview() + return { ... } +} +``` + +#### `composables/useFileSelection.ts` +```typescript +export function useFileSelection(fetchFn: Function) { + // selectedFiles, currentPage, pageSize, total, sortProp, sortOrder + // handleSelectionChange(), handlePageChange(), handleSortChange(), toggleSelectAll() + return { ... } +} +``` + +3 个文件视图改为使用这些 composable,每个文件预计减少 100-150 行重复代码。 + +**影响文件**: +- 新建: `composables/useFileUtils.ts`、`composables/useFilePreview.ts`、`composables/useFileSelection.ts` +- 修改: `files/Images.vue`、`files/Tables.vue`、`files/Orders.vue` + +### 2.3 清理死代码 + +| 文件 | 死代码 | 行号 | +|------|--------|------| +| `Layout.vue` | `navItems` 数组(未被引用) | 175-183 | +| `stores/processing.ts` | `pollTaskStatus` 函数(未被调用) | 124-129 | +| `router/index.ts` | `routeLoadingTimer` 逻辑(无消费者) | 87-94 | +| `Barcodes.vue` | `Plus` 图标导入(未使用) | 186 | + +**影响文件**: 上述 4 个文件 + +--- + +## 阶段 3:小改进 + +### 3.1 修改密码表单验证 + +**问题**: `Layout.vue` 的修改密码对话框无任何验证:无最小长度要求、无确认密码字段。 + +**修复**: +- 添加 el-form 验证规则:密码最少 6 位 +- 添加确认密码字段,验证两次输入一致 +- 提交前调用 `formRef.validate()` + +**影响文件**: `web/frontend/src/views/Layout.vue` + +### 3.2 修复 Layout.vue 冗余代码 + +**问题**: `navigator.onLine !== false` 冗余(`navigator.onLine` 已经是 boolean)。 + +**修复**: 改为 `navigator.onLine`。 + +**影响文件**: `web/frontend/src/views/Layout.vue` + +### 3.3 后端批量删除端点 + +**问题**: 前端批量删除是 N+1 API 调用(每个文件 2 次请求),50 个文件 = 100 次 HTTP 请求。 + +**修复**: +- 后端添加 `POST /api/files/batch-delete` 端点,接受 `files: [{directory, filename}]` 数组 +- 前端批量删除改为单次 API 调用 + +**影响文件**: +- 新建/修改: `web/backend/routers/files.py` +- 修改: `files/Images.vue`、`files/Tables.vue`、`files/Orders.vue` + +--- + +## 不在范围内 + +以下问题记录但不在本次修复范围内: +- 响应式布局(仅 Dashboard 有 @media 查询) +- 键盘快捷键 +- 类型感知配置编辑器 +- 后端安全问题(路径遍历、登录限流等) +- WebSocket 认证 token 刷新 +- 产品记忆批量操作/导出 +- 任务取消支持 + +## 验证标准 + +1. 页面刷新后头像正确显示用户名首字母 +2. API 失败时用户看到错误提示 toast +3. loading 状态不会卡住 +4. 统计数据准确或显示占位 +5. 未捕获的 Vue 错误有用户提示 +6. useDebounce 在 4 个文件中通过 import 使用,无重复定义 +7. 3 个文件视图使用共享 composable,每个文件减少 100+ 行 +8. 4 处死代码已清理 +9. 修改密码表单有验证规则和确认字段 +10. 批量删除为单次 API 调用