# 文件上传与任务状态管理优化设计文档 **方案选择**:A - 渐进式增强(用户体验优先) **版本**:V1.0 **日期**:2026-05-30 **状态**:待审核 --- ## 1. 设计概述 ### 1.1 项目背景 基于《文件管理接口文档》(V2.12.0)规范,对现有文件上传功能和文件列表下的任务向量化/出题状态组件进行系统性用户体验优化。 ### 1.2 优化目标 - **主要目标**:提升用户交互体验,增强功能易用性和反馈机制 - **次要目标**:改善性能表现,优化错误处理流程 - **非目标**:不进行架构重构,不改变核心数据流,不引入新技术栈 ### 1.3 设计原则 1. **KISS原则**:保持简单,避免过度工程化 2. **增量改进**:每个优化点独立可回滚 3. **向后兼容**:不破坏现有API和组件接口 4. **用户驱动**:所有改进围绕实际使用场景 5. **渐进增强**:在现有代码基础上添加功能,不重写 --- ## 2. 当前实现分析 ### 2.1 现有架构 ``` 前端组件结构: ├── FileSelector.vue # 文件选择器(用于AI对话中选择文件) ├── exam/ │ ├── UploadTaskItem.vue # 任务状态展示卡片 │ ├── composables/ │ │ ├── useUploadTasks.js # 任务状态管理逻辑 │ │ └── useTaskManager.js # 任务管理器 │ ├── GeneratePanel.vue # 向量化/出题面板 │ └── ExamModuleContainer.vue ├── api/ │ └── file.js # 文件API接口定义 └── views/ └── ReaderPage.vue # 文档阅读页面 ``` ### 2.2 已识别问题清单 #### **P0 - 必须修复(影响核心功能)** | 问题ID | 问题描述 | 影响范围 | 严重程度 | |--------|---------|----------|----------| | P0-01 | 无上传进度条显示 | 文件上传体验 | 🔴 高 | | P0-02 | 错误状态无重试机制 | 任务失败处理 | 🔴 高 | | P0-03 | 轮询策略固定(5秒间隔) | 性能浪费 | 🟡 中 | #### **P1 - 应该改进(显著提升体验)** | 问题ID | 问题描述 | 影响范围 | 严重程度 | |--------|---------|----------|----------| | P1-01 | 不支持拖拽上传 | 上传便捷性 | 🟡 中 | | P1-02 | 无前端文件验证 | 错误预防 | 🟡 中 | | P1-03 | 错误提示不够友好 | 用户理解 | 🟡 中 | | P1-04 | 不支持批量操作 | 效率提升 | 🟢 低 | | P1-05 | 移动端适配不完善 | 多设备支持 | 🟢 低 | #### **P2 - 可以优化(锦上添花)** | 问题ID | 问题描述 | 影响范围 | 严重程度 | |--------|---------|----------|----------| | P2-01 | 无状态变更通知提醒 | 用户感知 | 🟢 低 | | P2-02 | 缺少加载骨架屏 | 视觉体验 | 🟢 低 | | P2-03 | 任务列表无虚拟滚动 | 大列表性能 | 🟢 低 | --- ## 3. 详细设计方案 ### 3.1 模块一:文件上传增强(优先级:🔴 最高) #### **3.1.1 功能需求** ##### **FR-01: 上传进度条** - **描述**:显示实时上传百分比和预计剩余时间 - **触发条件**:文件大小 > 1MB 或上传时间 > 2秒时自动显示 - **UI设计**: ``` ┌─────────────────────────────────────┐ │ 📄 制度管理办法.docx (2.3MB) │ │ ████████████░░░░░░ 65% 剩余 3秒 │ └─────────────────────────────────────┘ ``` ##### **FR-02: 拖拽上传支持** - **描述**:支持将文件从桌面/资源管理器拖拽到上传区域 - **技术方案**:HTML5 Drag and Drop API - **交互细节**: - 拖拽悬停时:边框高亮 + 提示文字"释放以上传" - 拖拽离开时:恢复原状 - 支持多文件同时拖拽 ##### **FR-03: 前端文件验证** - **验证规则**: - ✅ 支持的文件类型:`.docx, .pdf, .txt, .md, .xlsx, .pptx` - ✅ 最大文件大小:50MB(可配置) - ✅ 文件名长度:≤200字符 - ✅ 特殊字符检查(禁止 `\ / : * ? " < > |`) - **错误提示**: - 类型不支持:"❌ 不支持的文件格式,请上传 .docx/.pdf/.txt 等文档" - 文件过大:"❌ 文件超过50MB限制,请压缩后重试" - 其他错误:"⚠️ 文件验证失败:{具体原因}" ##### **FR-04: 上传前预览** - **预览信息**: - 文件图标(根据扩展名显示不同图标) - 文件名(高亮显示) - 文件大小(格式化为KB/MB) - 文件类型标签(如"Word文档"、"PDF文件") ##### **FR-05: 友好的错误处理** - **错误分类**: - 🌐 **网络错误**:连接超时、服务器无响应 - 📁 **文件错误**:格式不支持、文件损坏 - 🔐 **权限错误**:未登录、无上传权限 - ⚙️ **服务器错误**:500内部错误、存储空间不足 - **错误展示**: - 图标 + 标题 + 详细说明 + 操作建议 - 示例: ``` ⚠️ 上传失败 原因:服务器响应超时(>60秒) 建议: • 检查网络连接是否正常 • 尝试压缩文件后重新上传 • 如持续失败,请联系管理员 [重新上传] [取消] ``` #### **3.1.2 技术实现方案** ##### **修改文件清单**: | 文件路径 | 改动类型 | 改动量 | 说明 | |---------|---------|--------|------| | `src/components/FileSelector.vue` | 修改 | ~150行 | 添加拖拽、验证、进度条 | | `src/api/file.js` | 修改 | ~20行 | 添加onUploadProgress回调 | | `src/utils/fileValidator.js` | 新增 | ~80行 | 文件验证工具函数 | | `src/components/ui/ProgressBar.vue` | 新增 | ~60行 | 可复用进度条组件 | | `src/components/ui/DropZone.vue` | 新增 | ~90行 | 拖拽上传区域组件 | ##### **核心代码示例**: **Axios进度监听** (`src/api/file.js`): ```javascript uploadFile: (formData, onProgress) => { return apiClient.post('/file/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (progressEvent) => { if (onProgress && progressEvent.total) { const percentCompleted = Math.round( (progressEvent.loaded * 100) / progressEvent.total ) onProgress({ loaded: progressEvent.loaded, total: progressEvent.total, percent: percentCompleted }) } } }) } ``` **拖拽上传组件** (`src/components/ui/DropZone.vue`): ```vue 拖拽文件到此处,或点击选择 支持 .docx .pdf .txt .xlsx .pptx,最大 50MB 📥 释放文件以上传 ``` --- ### 3.2 模块二:任务状态优化(优先级:🟡 高) #### **3.2.1 功能需求** ##### **FR-06: 一键重试按钮** - **触发条件**:任务状态为 error 时显示 - **位置**:UploadTaskItem 组件的错误标签旁 - **行为**: 1. 点击后立即调用重新处理API 2. 按钮变为加载状态(转圈图标) 3. 成功后自动刷新任务列表 4. 失败后显示错误详情 - **UI设计**: ``` ❌ 向量化失败 [🔄 重试] [📋 详情] ``` ##### **FR-07: 批量删除功能** - **使用场景**:清理大量失败/已完成的历史任务 - **交互流程**: 1. 进入批量模式(勾选框出现) 2. 选择多个任务(支持全选) 3. 点击"删除选中项(N)"按钮 4. 弹出确认对话框(显示即将删除的任务数) 5. 执行删除并显示进度 - **权限控制**:仅管理员可见此功能 ##### **FR-08: Toast通知系统** - **触发事件**: - ✅ 上传成功:"✅ 文件「{filename}」上传成功,正在处理中..." - ✅ 向量化完成:"🎉 「{filename}」向量化完成,准备生成题目..." - ✅ 出题完成:"📝 「{filename}」已生成{count}道题目" - ❌ 处理失败:"❌ 「{filename}」处理失败:{原因}" - **配置选项**: - 显示时长:成功=3秒,失败=5秒 - 位置:右下角 - 可关闭:是 - 堆叠方式:垂直堆叠(最多3条同时显示) ##### **FR-09: 智能轮询策略** - **当前问题**:固定5秒轮询,无论是否有活跃任务 - **优化方案**: | 任务状态 | 轮询间隔 | 说明 | |---------|---------|------| | 有处理中任务 | 3秒 | 快速反馈 | | 全部完成/失败 | 10秒 | 降低频率 | | 页面不可见 | 30秒 | 节省资源 | | 无任何任务 | 停止轮询 | 完全停止 | - **实现方式**:使用 `document.visibilitychange` 事件检测页面可见性 ##### **FR-10: 加载骨架屏** - **应用场景**: 1. 首次加载任务列表时 2. 刷新任务状态时(>500ms) - **UI效果**:灰色脉冲动画块模拟真实内容布局 - **组件复用**:创建通用 SkeletonCard 组件 #### **3.2.2 技术实现方案** ##### **修改文件清单**: | 文件路径 | 改动类型 | 改动量 | 说明 | |---------|---------|--------|------| | `src/components/exam/UploadTaskItem.vue` | 修改 | ~40行 | 添加重试按钮 | | `src/components/exam/composables/useUploadTasks.js` | 修改 | ~80行 | 智能轮询+批量操作 | | `src/components/ui/SkeletonCard.vue` | 新增 | ~50行 | 骨架屏组件 | | `src/components/ui/ToastNotification.vue` | 新增 | ~90行 | 通知组件 | | `src/utils/notification.js` | 新增 | ~60行 | 通知工具函数 | ##### **核心代码示例**: **智能轮询** (`useUploadTasks.js` 修改部分): ```javascript // 新增智能轮询配置 const POLL_CONFIG = { active: 3000, // 有活跃任务时:3秒 idle: 10000, // 全部空闲时:10秒 hidden: 30000, // 页面隐藏时:30秒 maxInterval: 30000 // 最大间隔上限 } let currentInterval = POLL_CONFIG.idle let visibilityHandler = null function updatePollingStrategy() { const hasActiveTasks = shouldPoll() const isHidden = document.hidden let newInterval if (isHidden) { newInterval = POLL_CONFIG.hidden } else if (hasActiveTasks) { newInterval = POLL_CONFIG.active } else { newInterval = POLL_CONFIG.idle } // 仅当间隔变化时才重启定时器 if (newInterval !== currentInterval) { currentInterval = newInterval stopPolling() if (tasks.value.length > 0) { startPolling() } console.log(`[useUploadTasks] 轮询间隔调整为 ${currentInterval}ms`) } } // 监听页面可见性 function setupVisibilityListener() { if (visibilityHandler) return visibilityHandler = () => { updatePollingStrategy() } document.addEventListener('visibilitychange', visibilityHandler) } onMounted(() => { setupVisibilityListener() }) onUnmounted(() => { if (visibilityHandler) { document.removeEventListener('visibilitychange', visibilityHandler) } }) ``` **一键重试** (`UploadTaskItem.vue` 修改部分): ```vue {{ vectorStatus.label }} 重试 ``` --- ### 3.3 模块三:移动端适配(优先级:🟢 中) #### **3.3.1 适配策略** ##### **断点定义**: | 断点名称 | 宽度范围 | 目标设备 | |---------|---------|---------| | `sm` | ≥640px | 大屏手机横屏/小平板 | | `md` | ≥768px | 平板竖屏 | | `lg` | ≥1024px | 桌面端 | ##### **关键改动**: 1. **UploadTaskItem 组件**: - 字体缩小(12px → 11px) - 状态标签换行显示 - 错误信息默认展开(无需点击"详情") 2. **文件列表**: - 卡片布局改为单列 - 操作按钮改为底部固定栏 - 添加下拉刷新手势支持 3. **上传区域**: - 拖拽区域全屏宽度 - 点击区域增大(最小44px触控目标) --- ## 4. 数据流与接口变更 ### 4.1 API接口调整 #### **新增接口**(可选,如后端已支持则使用): | 接口 | 方法 | 用途 | |------|------|------| | `/api/file/{id}/retry` | POST | 重试失败任务 | | `/api/file/batch-delete` | POST | 批量删除任务 | #### **兼容性处理**: 如果后端暂不支持上述接口,前端降级方案: - **重试功能**:调用原有上传接口重新上传同一文件 - **批量删除**:循环调用单个删除接口(带loading状态) ### 4.2 数据流图 ``` 用户操作 ↓ FileSelector.vue(拖拽/选择文件) ↓ fileValidator.js(前端验证) ├─ 通过 → 显示预览 → 开始上传 └─ 失败 → 显示友好错误提示 ↓ api/file.js uploadFile(带进度回调) ↓ ProgressBar.vue(实时更新进度) ↓ 上传完成 ↓ useUploadTasks.js(添加任务到列表) ↓ 智能轮询(3-30秒动态调整) ↓ UploadTaskItem.vue(展示状态) ├─ 处理中 → 动画图标 ├─ 完成 → 成功图标 + Toast通知 └─ 失败 → 错误图标 + 重试按钮 ``` --- ## 5. 性能与兼容性考虑 ### 5.1 性能优化措施 1. **按需加载**:新组件使用动态导入 ```javascript const DropZone = defineAsyncComponent(() => import('./components/ui/DropZone.vue')) ``` 2. **防抖/节流**: - 搜索输入:debounce 300ms - 窗口resize:throttle 150ms - 滚动事件:passive listener 3. **内存管理**: - 轮询定时器在组件卸载时清除 - 大文件上传完成后释放引用 - 图片/文件预览使用URL.revokeObjectURL() ### 5.2 浏览器兼容性 | 功能 | 最低版本 | 降级方案 | |------|---------|---------| | Drag & Drop API | IE10+, 所有现代浏览器 | 回退到点击上传 | | Progress Event | IE10+, 所有现代浏览器 | 不显示进度条 | | Visibility API | IE10+, Chrome 13+ | 固定10秒轮询 | | CSS Grid/Flexbox | IE11+ (partial), 现代浏览器全支持 | 使用float fallback | --- ## 6. 测试计划 ### 6.1 单元测试 | 测试场景 | 输入 | 预期输出 | 优先级 | |---------|------|---------|--------| | 文件类型验证 | `test.exe` | 返回错误"不支持的格式" | P0 | | 文件大小验证 | 60MB文件 | 返回错误"超过50MB限制" | P0 | | 进度计算 | loaded=50, total=100 | percent=50 | P0 | | 拖拽事件处理 | 有效文件 | 触发files-selected事件 | P1 | | 轮询间隔调整 | 页面hidden | 间隔变为30秒 | P1 | | 重试按钮点击 | error状态任务 | 调用retry事件 | P0 | ### 6.2 集成测试 1. **上传流程测试**: - 选择文件 → 验证 → 上传 → 进度显示 → 完成 - 拖拽文件 → 验证 → 上传 → 进度显示 → 完成 - 选择无效文件 → 显示错误 → 修正后重试 2. **任务状态测试**: - 上传后观察状态流转(UPLOADED→VECTORIZING→VECTORIZED→EXAM_GENERATING→COMPLETED) - 模拟失败场景 → 点击重试 → 验证重试逻辑 - 批量选择 → 删除 → 确认删除成功 3. **边界情况测试**: - 同时上传10个文件 - 网络中断后恢复 - 页面刷新后状态保持 - 移动端触摸操作 ### 6.3 兼容性测试 - ✅ Chrome 90+ - ✅ Firefox 88+ - ✅ Safari 14+ - ✅ Edge 90+ - ⚠️ iOS Safari 14+(移动端) - ⚠️ Android Chrome 90+ --- ## 7. 实施路线图 ### Phase 1:核心功能(第1天)- 6小时 **上午(3小时)**: - [ ] 创建 `src/utils/fileValidator.js` 文件验证工具 - [ ] 创建 `src/components/ui/ProgressBar.vue` 进度条组件 - [ ] 修改 `src/api/file.js` 添加进度回调支持 **下午(3小时)**: - [ ] 创建 `src/components/ui/DropZone.vue` 拖拽组件 - [ ] 修改 `src/components/FileSelector.vue` 集成新功能 - [ ] 测试上传流程(正常/异常场景) ### Phase 2:任务状态优化(第2天)- 6小时 **上午(3小时)**: - [ ] 修改 `UploadTaskItem.vue` 添加重试按钮 - [ ] 修改 `useUploadTasks.js` 实现智能轮询 - [ ] 创建 `src/components/ui/ToastNotification.vue` **下午(3小时)**: - [ ] 实现批量删除功能 - [ ] 创建骨架屏组件 - [ ] 测试任务状态流转 ### Phase 3:打磨与测试(第3天)- 6小时 **上午(3小时)**: - [ ] 移动端响应式适配 - [ ] 跨浏览器测试 - [ ] 性能 profiling **下午(3小时)**: - [ ] 用户体验走查 - [ ] Bug修复 - [ ] 文档编写 --- ## 8. 风险评估与缓解 ### 8.1 技术风险 | 风险 | 可能性 | 影响 | 缓解措施 | |------|-------|------|---------| | 后端不支持重试API | 中 | 中 | 前端降级为重新上传 | | 大文件上传内存溢出 | 低 | 高 | 使用分片上传(Phase 2考虑) | | 拖拽API兼容性问题 | 低 | 低 | Feature detection + 降级方案 | | 轮询性能开销 | 低 | 中 | 智能间隔 + 页面不可见时暂停 | ### 8.2 业务风险 | 风险 | 可能性 | 影响 | 缓解措施 | |------|-------|------|---------| | 用户不接受新交互 | 低 | 低 | A/B测试 + 快速回滚能力 | | 移动端体验不佳 | 中 | 中 | 充分的设备测试 | | 与现有工作流冲突 | 低 | 中 | 保持向后兼容 + 渐进启用 | --- ## 9. 成功指标(KPIs) ### 9.1 定量指标 | 指标 | 当前值 | 目标值 | 测量方法 | |------|-------|--------|---------| | 上传操作成功率 | 未知 | ≥98% | 错误日志统计 | | 平均上传等待感知时间 | 未知 | 减少30% | 用户调研 | | 任务状态查询次数/会话 | 固定12次/分钟 | 动态3-30次 | 性能监控 | | 错误重试成功率 | 0% | ≥80% | 重试按钮点击率 | ### 9.2 定性指标 - ✅ 用户能够清晰了解上传进度 - ✅ 任务失败时有明确的解决路径(重试按钮) - ✅ 移动端操作流畅无明显卡顿 - ✅ 错误信息易于理解和行动 --- ## 10. 附录 ### 10.1 参考文档 - [文件管理接口文档 V2.12.0](./文件管理接口文档.md) - Vue 3 官方文档:https://vuejs.org/ - Ant Design Vue 组件库:https://antdv.com/ - MDN Drag & Drop API:https://developer.mozilla.org/en-US/docs/Web/API/Drag_and_Drop ### 10.2 术语表 | 术语 | 定义 | |------|------| | **向量化(Vectorize)** | 将文档内容转换为向量表示,用于语义搜索 | | **出题(Exam Generation)** | 基于文档内容自动生成考试题目 | | **轮询(Polling)** | 客户端定期向服务器请求最新状态的机制 | | **骨架屏(Skeleton)** | 内容加载时的占位动画效果 | | **Toast通知** | 短暂出现的消息提示,通常位于屏幕角落 | --- **文档结束** *请审核本设计文档,确认后我们将进入实施阶段。*
拖拽文件到此处,或点击选择
支持 .docx .pdf .txt .xlsx .pptx,最大 50MB