定制软件vue实现文件批量上传及进度条展示

定制软件主要实现功能

 

1.定制软件多文件拖拽上传

2.定制软件显示文件上传进度条

3.上传期间,定制软件还可以继续拖拽上传

4.定制软件可以支持手动修改上传并发任务数

5.上传失败自动重试,最大重试次数3次

6.上传过程中可以手动取消上传

 本次使用的是element ui ,上传拖拽是通过实现的。

  1. <el-upload
  2. :before-upload="beforeUpload"
  3. action="#"
  4. class="upload"
  5. drag
  6. multiple
  7. >
  8. <el-icon class="el-icon--upload">
  9. <upload-filled/>
  10. </el-icon>
  11. <div class="el-upload__text">
  12. 拖拽或 <em>点击上传</em>
  13. </div>
  14. <template #tip>
  15. <div class="el-upload__tip">
  16. 请上传文件,仅支持上传文件,不支持文件夹
  17. </div>
  18. </template>
  19. </el-upload>

 上传之前,触发 beforeUpload 方法,该方法进行封装调用 

  1. beforeUpload(raw) {
  2. addUploadFile(raw)
  3. return false
  4. }

上传初始化逻辑

 初始化进度条等相关数据

  1. export function addUploadFile(raw) {
  2. const upload = uploadStore()
  3. const uploadProgress = {
  4. progress: 0,
  5. file_id: '',
  6. file_name: raw.name,
  7. percent: [],
  8. speed: '0 MB',
  9. file_size: raw.size,
  10. upload_size: 0,
  11. upload_time: new Date()
  12. }
  13. // status上传状态 0 队列,1 上传中,2 上传成功 , 3 取消上传
  14. // failTryCount 失败上传次数, 没上传一次,自动减去已,当为0的时候,停止上传
  15. upload.multiFileList.push({file: raw, progress: uploadProgress, status: 0, failTryCount: 3})
  16. multiUpload()
  17. }

该代码引用了一个类似vuex的存储库 

 下面内容通过定义了一个存储,存储有三个字段

uploadStore()

  1. export const uploadStore = defineStore('upload', {
  2. state: () => ({
  3. multiFileList: [],
  4. processNumber: 3,
  5. promise: []
  6. })
  7. })

multiUpload()

 文件上传核心内容就是该方法了,主要时过滤上传状态为0,然后批量加入上传队列

  1. export function multiUpload() {
  2. const upload = uploadStore()
  3. const readFileList = []
  4. upload.multiFileList.forEach(res => {
  5. if (res.status === 0) {
  6. readFileList.push(res)
  7. }
  8. })
  9. if (readFileList.length > 0) {
  10. multiRun(upload, readFileList.slice(0, upload.processNumber), uploadAsync)
  11. }
  12. }

 multiRun()

该方法,就是并发上传核心逻辑,通过Promise进行批量上传 

  1. function multiRun(upload, keyList, func) {
  2. const processNumber = upload.processNumber
  3. const promise = upload.promise
  4. for (let i = 0; i < processNumber - promise.length; i++) {
  5. promise.push(Promise.resolve())
  6. }
  7. let reduceNumber = promise.length - processNumber
  8. if (reduceNumber > 0) {
  9. upload.promise = promise.slice(0, reduceNumber)
  10. }
  11. for (let j = 0; j < keyList.length; j += processNumber) {
  12. for (let i = 0; i < processNumber; i++) {
  13. if (i + j < keyList.length) {
  14. promise[(j + i) % processNumber] = promise[(j + i) % processNumber].then(() => func(keyList[i + j])).catch(({
  15. fileInfo,
  16. err
  17. }) => {
  18. if (fileInfo.status === 3) {
  19. console.log(fileInfo.file.name, '取消上传')
  20. } else {
  21. fileInfo.status = 0
  22. fileInfo.failTryCount -= 1
  23. if (fileInfo.failTryCount < 1) {
  24. ElMessage.error(`${fileInfo.file.name} 超过最大重试次数,停止上传`)
  25. } else {
  26. ElMessage.error(`${fileInfo.file.name} 上传失败,正在重试`)
  27. console.log(fileInfo.file.name, err)
  28. multiUpload()
  29. }
  30. }
  31. })
  32. }
  33. }
  34. }
  35. }

uploadAsync(fileInfo)

上传文件逻辑,进行文件的上传,进度计算等功能。本功能是模拟上传操作

  1. function uploadAsync(fileInfo) {
  2. const progress = fileInfo.progress
  3. const file = fileInfo.file
  4. return new Promise((resolve, reject) => {
  5. progress.file_name = file.name
  6. progress.file_size = file.size
  7. if (fileInfo.status === 0) {
  8. fileInfo.status = 1
  9. } else {
  10. return resolve()
  11. }
  12. progress.progress = 10
  13. getUploadSid().then(async res => {
  14. // ElMessage.info(fileName + ' 文件读取中')
  15. progress.speed = '文件读取中'
  16. let hash = await PreHash(file, progress)
  17. let fileHashInfo = {
  18. sid: res.data.sid,
  19. file_name: progress.file_name,
  20. file_size: progress.file_size,
  21. pre_hash: hash
  22. }
  23. progress.progress = 20
  24. checkPreHash(fileHashInfo).then(async pRes => {
  25. if (pRes.data.check_status === true) {
  26. // 秒传逻辑
  27. progress.progress = 30
  28. const md5Code = pRes.data.md5_token
  29. progress.speed = '文件校验中'
  30. // ElMessage.info(fileInfo.file_name + ' 秒传检测中')
  31. let hash = await ContentHash(file, md5Code, progress)
  32. fileHashInfo.proof_code = hash.proofCode
  33. fileHashInfo.content_hash = hash.conHash
  34. checkContentHash(fileHashInfo).then(async cRes => {
  35. if (cRes.data.check_status === true) {
  36. progress.progress = 100
  37. progress.upload_size = progress.file_size
  38. progress.speed = '秒传成功'
  39. // ElMessage.success(fileName + ' 上传成功')
  40. fileInfo.status = 2
  41. fileInfo.upload_time = new Date()
  42. multiUpload()
  43. resolve()
  44. } else {
  45. return await ChunkedUpload(fileInfo, fileHashInfo, cRes.data.upload_extra, cRes.data.part_info_list, () => {
  46. fileInfo.status = 2
  47. fileInfo.upload_time = new Date()
  48. multiUpload()
  49. resolve()
  50. }, (err) => {
  51. reject({fileInfo, err})
  52. })
  53. }
  54. }).catch((err) => {
  55. reject({fileInfo, err})
  56. })
  57. } else {
  58. return await ChunkedUpload(fileInfo, fileHashInfo, pRes.data.upload_extra, pRes.data.part_info_list, () => {
  59. fileInfo.status = 2
  60. fileInfo.upload_time = new Date()
  61. multiUpload()
  62. resolve()
  63. }, (err) => {
  64. reject({fileInfo, err})
  65. })
  66. }
  67. }).catch((err) => {
  68. reject({fileInfo, err})
  69. })
  70. }).catch((err) => {
  71. reject({fileInfo, err})
  72. })
  73. })
  74. }

 核心上传大概就是这些逻辑

代码源码:

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发