# 异步文件上传功能实施计划 - Part 4: 前端开发 ## 文档信息 - **创建日期**: 2026-03-05 - **版本**: v1.1 - **作者**: Claude - **关联设计**: [前端设计文档](../design/2026-03-05-async-file-upload-frontend-design.md) - **变更说明**: 移除WebSocket,改为页面轮询机制 ## 任务概述 根据前端设计文档,扩展UploadData.vue组件实现异步批量上传功能。 **预计工时**: 4.5个工作日 ## 任务清单 ### 任务 1: API接口封装(0.5天) **文件**: `ruoyi-ui/src/api/ccdiProjectUpload.js` **工作内容**: ```javascript // 批量上传文件 export function batchUploadFiles(projectId, files) { const formData = new FormData() files.forEach(file => formData.append('files', file)) formData.append('projectId', projectId) return request({ url: '/ccdi/file-upload/batch', method: 'post', data: formData, timeout: 300000 }) } // 查询文件上传记录列表 export function getFileUploadList(params) { return request({ url: '/ccdi/file-upload/list', method: 'get', params }) } // 查询文件上传统计 export function getFileUploadStatistics(projectId) { return request({ url: `/ccdi/file-upload/statistics/${projectId}`, method: 'get' }) } ``` ### 任务 2: 批量上传弹窗(1天) **文件**: `ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue` **主要修改**: 1. 添加批量上传弹窗状态 2. 修改`handleUploadClick`方法 3. 实现文件选择和校验逻辑 4. 实现批量上传功能 **关键代码**: ```javascript // 批量上传 async handleBatchUpload() { if (this.selectedFiles.length === 0) { this.$message.warning('请选择要上传的文件') return } this.uploadLoading = true try { await batchUploadFiles( this.projectId, this.selectedFiles.map(f => f.raw) ) this.uploadLoading = false this.batchUploadDialogVisible = false this.$message.success('上传任务已提交,请查看处理进度') // 刷新数据并启动轮询 await Promise.all([ this.loadStatistics(), this.loadFileList() ]) this.startPolling() } catch (error) { this.uploadLoading = false this.$message.error('上传失败:' + (error.msg || '未知错误')) } } ``` ### 任务 3: 统计卡片(0.5天) **工作内容**: 1. 添加统计数据状态 2. 实现统计卡片组件 3. 实现点击筛选功能 **模板代码**: ```vue
上传中
{{ statistics.uploading }}
``` ### 任务 4: 文件列表(1天) **工作内容**: 1. 添加文件列表状态 2. 实现文件列表组件 3. 实现分页和筛选 4. 实现操作按钮 **关键方法**: ```javascript // 加载文件列表 async loadFileList() { this.listLoading = true try { const res = await getFileUploadList({ projectId: this.projectId, fileStatus: this.queryParams.fileStatus, pageNum: this.queryParams.pageNum, pageSize: this.queryParams.pageSize }) this.fileList = res.rows || [] this.total = res.total || 0 } finally { this.listLoading = false } } ``` ### 任务 5: 轮询机制(0.5天) **优先级**: P0 **依赖**: 任务2、任务3、任务4完成 **工作内容**: 1. **添加轮询状态**: ```javascript data() { return { // 轮询相关 pollingTimer: null, pollingEnabled: false, pollingInterval: 5000 // 5秒轮询间隔 } } ``` 2. **生命周期钩子**: ```javascript mounted() { this.loadStatistics() this.loadFileList() // 检查是否需要启动轮询 this.$nextTick(() => { if (this.statistics.uploading > 0 || this.statistics.parsing > 0) { this.startPolling() } }) }, beforeDestroy() { this.stopPolling() } ``` 3. **轮询方法**: ```javascript methods: { /** * 启动轮询 */ startPolling() { if (this.pollingEnabled) { return // 已经在轮询中 } this.pollingEnabled = true console.log('启动轮询') const poll = () => { if (!this.pollingEnabled) { return } // 刷新统计数据和列表 Promise.all([ this.loadStatistics(), this.loadFileList() ]).then(() => { // 检查是否需要继续轮询 if (this.statistics.uploading === 0 && this.statistics.parsing === 0) { this.stopPolling() console.log('所有任务已完成,停止轮询') return } // 继续下一次轮询 this.pollingTimer = setTimeout(poll, this.pollingInterval) }).catch(error => { console.error('轮询失败:', error) // 发生错误时继续轮询 this.pollingTimer = setTimeout(poll, this.pollingInterval) }) } // 立即执行一次 poll() }, /** * 停止轮询 */ stopPolling() { this.pollingEnabled = false if (this.pollingTimer) { clearTimeout(this.pollingTimer) this.pollingTimer = null } console.log('停止轮询') }, /** * 手动刷新 */ async handleManualRefresh() { await Promise.all([ this.loadStatistics(), this.loadFileList() ]) this.$message.success('刷新成功') // 如果有进行中的任务,启动轮询 if (this.statistics.uploading > 0 || this.statistics.parsing > 0) { this.startPolling() } }, /** * 状态筛选 */ handleStatusFilter(status) { this.queryParams.fileStatus = status this.queryParams.pageNum = 1 this.loadFileList() } } ``` 4. **在模板中添加刷新按钮**: ```vue 刷新 ``` #### 5.2 验证方式 1. **启动轮询测试**: - 上传文件后,检查控制台输出"启动轮询" - 观察5秒后数据是否自动刷新 2. **停止轮询测试**: - 等待所有文件处理完成 - 检查控制台输出"停止轮询" 3. **手动刷新测试**: - 点击刷新按钮 - 验证数据立即更新 - 验证提示消息显示 4. **页面销毁测试**: - 切换到其他页面 - 检查控制台输出"停止轮询" - 确认定时器被清除 ### 任务 6: 联调测试(1天) **测试项**: 1. 批量上传功能 2. 统计卡片展示和筛选 3. 文件列表展示和分页 4. 轮询机制(启动、停止、手动刷新) 5. 操作按钮(查看流水、查看错误) ## 验收标准 - [ ] 所有API接口正常调用 - [ ] 批量上传弹窗正常工作 - [ ] 统计卡片正常显示和筛选 - [ ] 文件列表正常展示和操作 - [ ] 轮询机制正常(自动启动/停止/手动刷新) - [ ] 所有测试项通过 ## 轮询优化建议(可选) **智能轮询间隔**: ```javascript // 根据活跃任务数动态调整轮询间隔 getPollingInterval() { const { uploading, parsing } = this.statistics const activeCount = uploading + parsing if (activeCount > 50) { return 3000 // 大量任务时,3秒轮询 } else if (activeCount > 10) { return 5000 // 正常情况,5秒轮询 } else { return 10000 // 少量任务时,10秒轮询 } } ``` **用户体验优化**: - 在页面顶部显示"自动刷新中..."状态提示 - 支持用户手动开关轮询开关 --- **文档结束**