hooks >useUploadByPices

/**
 * 分片上传成功后提交表单数据到服务器
 * @module useUploadByPieces
 */
import { ref, reactive } from 'vue'
import { useStore } from 'vuex'
import { ElMessage } from 'element-plus'
import { uploadByPieces } from '@/utils/LuploadPieces'

/**
 * @method useUploadByPieces
 * @param {string} uploadUrl 上传文件的地址
 * @param {Object} formParams form表单需要的额外参数
 */

function useUploadByPieces(uploadUrl, formParams = { files: [] }) {
  const store = useStore()
  let formdata = reactive({ ...formParams })
  let loading = ref(false)
  let LoadingText = ref('Loading...')
  let fileListshow = ref([])
  let fileList = ref([])

  /**
   * @method uploadByPiecesAction
   * @param {string} sendUrl 表单提交服务器的地址
   */

  function uploadByPiecesAction(sendUrl) {
    loading.value = true
    return new Promise((resolve, reject) => {
      // 重置相关数据
      const reset = () => {
        fileList.value = []
        formdata.files = []
        fileListshow.value = []
      }
      // 提交表单数据到服务端
      const ajaxDispach = (sendUrl, formdata) => {
        console.log(55555, formdata)
        store.dispatch(sendUrl, formdata).then(res => {
          resolve('success')
        }).catch(err => {
          reset()
          reject(err)
        }).finally(() => {
          loading.value = false
        })
      }
      if (fileList.value.length) {
        // 用户上传了附件的情况
        LoadingText.value = '请耐心等待,附件上传中...'
        uploadByPieces({
          files: fileList.value,
          pieceSize: 5,
          chunkUrl: uploadUrl,
          fileUrl: uploadUrl,
          validator: (text) => {
            // 上传文件合法性效验
            reset()
            ElMessage.error(text)
            loading.value = false
          },
          success: (res, fileName) => {
            if (res.data.code == 200) {
              // 文件的所有切片上传成功后
              formdata.files.push(res.data.id)
            }
            if (fileList.value.length == formdata.files.length) {
              // 所有多选文件都上传成功后
              LoadingText.value = 'Loading...'
              ajaxDispach(sendUrl, formdata)
            }
          },
          error: (e) => {
            reset()
            reject(e)
            ElMessage.error('上传失败')
            return false
          }
        })
      } else {
        // 用户没有上传附件的情况
        formdata.files = []
        ajaxDispach(sendUrl, formdata)
      }
    })
  }

  return {
    formdata,
    loading,
    LoadingText,
    fileListshow,
    fileList,
    uploadByPiecesAction
  }
}
export default useUploadByPieces

utils > LuploadPieces

/* eslint-disable no-async-promise-executor */
import md5 from 'js-md5'
import axios from 'axios'
// http request拦截器 添加一个请求拦截器
axios.interceptors.request.use(function(config) {
  // Do something before request is sent
  const token = sessionStorage.getItem('T')
  const prjInternalNum = sessionStorage.getItem('prjInternalNum')

  if (token) {
    config.headers.bcmpUserToken = token
  }
  if (prjInternalNum) {
    config.headers.bcmpPrjInternalNum = prjInternalNum
  }
  return config
}, function(error) {
  // Do something with request error
  return Promise.reject(error)
})
/*
* 分片上传函数 支持多个文件
* @param options
* options.file 表示源文件
* options.pieceSize 表示需要分片的大小 默认是5m
* options.chunkUrl 分片上传的后端地址
* options.fileUrl 整个文件的上传地址
* progress 进度回调
* success 成功回调
* error 失败回调
* validator 合法性验证回调
*/
export const uploadByPieces = ({ files, chunkUrl, fileUrl, pieceSize = 5, progress, success, error, validator }) => {
  if (!files || !files.length) return
  // 上传过程中用到的变量
  let fileList = [] // 总文件列表
  let progressNum = 1 // 进度
  let successAllCount = 0 // 上传成功的片数
  let AllChunk = 0 // 所有文件的chunk数之和
  let AllFileSize = 0 // 所有文件size
  // 验证方法
  const validatorHandle = (files) => {
    let result = true
    let filesName = []
    for (let i = 0; i < files.length; i++) {
      if (files[i].size <= 0) {
        // 为空字节文本
        validator && validator('上传附件中不能有空文件')
        result = false
        filesName = []
        break
      }
      filesName.push(files[i].name)
    }
    let filesNameSet = new Set(filesName)
    if (Array.from(filesNameSet).length != filesName.length) {
      validator && validator('上传附件中不能有重复的文件名')
      filesName = []
      result = false
    }
    return result
  }
  // 获取md5
  const readFileMD5 = (files) => {
    // 读取每个文件的md5
    if (validatorHandle(files)) {
      return new Promise(async (resolve, reject) => {
        try {
          files.map(async (file, index) => {
            fileList.push({ name: file.name, file })
            AllFileSize = AllFileSize + file.size
            if (index === files.length - 1) await readChunkMD5(fileList)
          })
          resolve()
        } catch (e) {
          reject(e)
        }
      })
    }
  }
  const getChunkInfo = (file, currentChunk, chunkSize) => {
    let start = (currentChunk - 1) * chunkSize
    let end = Math.min(file.size, start + chunkSize)
    let chunk = file.slice(start, end)
    return { start, end, chunk }
  }
  const loadChunk = (chunkFR) => {
    return new Promise(function(resolve, reject) {
      chunkFR.addEventListener('load', e => {
        let chunkBolb = e.target.result
        let chunkMD5 = md5(chunkBolb)
        resolve(chunkMD5)
      }, false)
    })
  }
  // 针对每个文件进行chunk处理
  const readChunkMD5 = (fileList) => {
    return new Promise(async (resolve, reject) => {
      try {
        fileList.map(async (currentFile, fileIndex) => {
          const chunkSize = pieceSize * 1024 * 1024 // 5MB一片
          const chunkCount = Math.ceil(currentFile.file.size / chunkSize) // 总片数
          AllChunk = AllChunk + chunkCount // 计算全局chunk数
          // let fileSize = currentFile.file.size // 文件大小
          // 针对单个文件进行chunk上传
          let firstRes = {}
          let chunkMD5O = {}

          for (let i = 1; i < chunkCount + 1; i++) {
            const { chunk } = getChunkInfo(currentFile.file, i, chunkSize)
            let chunkFR = new FileReader()
            chunkFR.readAsArrayBuffer(chunk)
            let chunkMD5 = await loadChunk(chunkFR)
            chunkMD5O[`i${i}`] = chunkMD5

            if (i === 1) {
              firstRes = await uploadChunk(currentFile, { chunkMD5: chunkMD5O.i1, chunk, currentChunk: 1, chunkCount, fileFirstHashCode: chunkMD5O.i1 }, fileIndex)
              if (firstRes && Number(firstRes.nextPart) > 2) {
                successAllCount = successAllCount + (Number(firstRes.nextPart) - 2)
              }
            } else {
              if (Number(firstRes.statusCode) !== 200) {
                if (Number(firstRes.nextPart) > 2) {
                  if (Number(firstRes.nextPart) < i || Number(firstRes.nextPart) == i) {
                    await uploadChunk(currentFile, { chunkMD5: chunkMD5O[`i${i}`], id: firstRes.id, chunk, currentChunk: i, chunkCount, fileFirstHashCode: chunkMD5O.i1 }, fileIndex)
                  }
                } else {
                  await uploadChunk(currentFile, { chunkMD5: chunkMD5O[`i${i}`], id: firstRes.id, chunk, currentChunk: i, chunkCount, fileFirstHashCode: chunkMD5O.i1 }, fileIndex)
                }
              }
            }
          }
        })

        resolve()
      } catch (e) {
        reject(e)
      }
    })
  }
  // 更新进度
  const progressFun = () => {
    progressNum = Math.ceil(successAllCount / AllChunk * 100)
    progress && progress(progressNum)
  }

  const uploadChunk = (currentFile, chunkInfo, fileIndex) => {
    let fetchForm1 = new FormData()
    // if (chunkInfo.currentChunk == 1) {
    fetchForm1.append('fileHashCode', chunkInfo.fileFirstHashCode)
    // }
    fetchForm1.append('file', chunkInfo.chunk)
    fetchForm1.append('fileName', currentFile.name)
    fetchForm1.append('size', currentFile.file.size)
    fetchForm1.append('part', chunkInfo.currentChunk)
    fetchForm1.append('md5Code', chunkInfo.chunkMD5)
    fetchForm1.append('allCount', chunkInfo.chunkCount)
    if (chunkInfo.currentChunk != 1) {
      fetchForm1.append('fileIdFromWeb', chunkInfo.id)
    }
    return new Promise(async (resolve, reject) => {
      axios.post(chunkUrl, fetchForm1)
        .then(res => {
          if (chunkInfo.currentChunk == 1 && res.data.code == 200) {
            successAllCount = successAllCount + chunkInfo.chunkCount
          } else {
            successAllCount++
          }
          progressFun()
          if (res.data.next_part) {
            let firstRes = {
              id: res.data.file_id,
              nextPart: res.data.next_part || 2,
              statusCode: res.data.code
            }
            resolve(firstRes)
          } else {
            resolve({
              id: res.data.file_id,
              statusCode: res.data.code
            })
          }
          success && success(res, currentFile.name)
        }).catch(e => {
          error && error(e)
          reject(e)
        })
    })
  }
  readFileMD5(files) // 开始执行代码
}

 

/**
 * 分片上传成功后提交表单数据到服务器
 * @moduleuseUploadByPieces
 */
import { ref, reactive } from 'vue'
import { useStore } from 'vuex'
import { ElMessage } from 'element-plus'
import { uploadByPieces } from '@/utils/LuploadPieces'

/**
 * @methoduseUploadByPieces
 * @param{string}uploadUrl 上传文件的地址
 * @param{Object}formParams form表单需要的额外参数
 */

function useUploadByPieces(uploadUrl, formParams = { files: [] }) {
  const store = useStore()
  let formdata = reactive({ ...formParams })
  let loading = ref(false)
  let LoadingText = ref('Loading...')
  let fileListshow = ref([])
  let fileList = ref([])

  /**
   * @methoduploadByPiecesAction
   * @param{string}sendUrl 表单提交服务器的地址
   */

  function uploadByPiecesAction(sendUrl) {
    loading.value = true
    return new Promise((resolve, reject) => {
      // 重置相关数据
      const reset = () => {
        fileList.value = []
        formdata.files = []
        fileListshow.value = []
      }
      // 提交表单数据到服务端
      const ajaxDispach = (sendUrl, formdata) => {
        console.log(55555, formdata)
        store.dispatch(sendUrl, formdata).then(res => {
          resolve('success')
        }).catch(err => {
          reset()
          reject(err)
        }).finally(() => {
          loading.value = false
        })
      }
      if (fileList.value.length) {
        // 用户上传了附件的情况
        LoadingText.value = '请耐心等待,附件上传中...'
        uploadByPieces({
          files: fileList.value,
          pieceSize: 5,
          chunkUrl: uploadUrl,
          fileUrl: uploadUrl,
          validator: (text) => {
            // 上传文件合法性效验
            reset()
            ElMessage.error(text)
            loading.value = false
          },
          success: (res, fileName) => {
            if (res.data.code == 200) {
              // 文件的所有切片上传成功后
              formdata.files.push(res.data.id)
            }
            if (fileList.value.length == formdata.files.length) {
              // 所有多选文件都上传成功后
              LoadingText.value = 'Loading...'
              ajaxDispach(sendUrl, formdata)
            }
          },
          error: (e) => {
            reset()
            reject(e)
            ElMessage.error('上传失败')
            return false
          }
        })
      } else {
        // 用户没有上传附件的情况
        formdata.files = []
        ajaxDispach(sendUrl, formdata)
      }
    })
  }

  return {
    formdata,
    loading,
    LoadingText,
    fileListshow,
    fileList,
    uploadByPiecesAction
  }
}
export default useUploadByPieces
LuploadPieces
posted on 2025-06-03 07:11  铭の  阅读(16)  评论(0)    收藏  举报

友情链接:箫竹影(Java工程师)