base64和二进制流分片上传文件

发布时间 2023-09-27 10:38:56作者: sk-xm

主要是写了一个大体的思路,需微调整


    import Compressor from 'compressorjs'
    import {satrtUpload,satrtBinaryUpload,remuseUpload, remuseBinaryUpload} from serviceData
    
    // 转base64或二进制流 blob 二进制文件 tupe base64 和 binary
    const blobToBase64 = (blob, type = 'BASE64')=>{
      return new Promise((resolve,reject)=>{
        try{
          const render = new FileReader()
          if(type === 'BASE64'){
            render.readAsDataURL(Blob)
          }else{
            render.readAsArrayBuffer(blob)
          }
          render.onload = (e) =>{
            if(type = 'BASE64'){
              resolve(e.target.result)
            }else{
              const binaryArr = new Int8Array(render.result)
              resolve(binaryArr)
            }
          }
        } catch(e){
          reject(e)
        }
      })
    }

    // 文件压缩
    const compress = (file) => {
      return new Promise((resolve, reject) => {
        if (!file) {
          return reject(new Error('文件上传失败,请重试'))
        }

        let quality = 0.6
        const fileSize = Number(file.size) || 0
        if (fileSize >= 10485760) {
          quality = 0.1
        } else if (fileSize < 3145728 && fileSize >= 1048576) {
          quality = 0.3
        } else if (fileSize < 1048576 && fileSize >= 524288) {
          quality = 0.8
        } else {
          quality = 1
        }

        new Compressor(file, {
          quality,
          success: async (result) =>{
            const base64 = await blobToBase64(result)
            const binary = await blobToBase64(result, 'BINARY')
            let base64Str = base64
            if(base64 && base64.length > 20){
              if(base64.indexOf(',') > -1){
                base64Str = base64.split(',')[1]
              }
              resolve({base64,base64Str, binary})
            }else{
              reject(new Error('图片流为空'))
            }
          },
          error: (err)=>{
            reject(err)
          }
        })
      })
    }

    let base64Data = ''
    let binaryData = []
    let fileType = ''
    let fileSize = ''
    // 文件change事件
    const fileChange = async (e) =>{
      const file = e.target.files[0]
      const {base64,binary} = await compress(file)
      base64Data = base64
      binaryData = binary
      fileType = file.type.split('/')[1]
      fileSize = file.size
      beforeUpload('BINARY')
    }
    
    // 分片上传参数
    let uploadCount = '' //次数
    let uploadId = '' //id
    let uploadSize = '' //单次上传大小
    let remainIds = [] 
    let uploaded = []
    let retryTimes = 0 //重试次数
    let allIds = []
    // 开始上传
    const  beforeUpload = async(fileDataType = 'BASE64') =>{
      let data = {}
      if(fileDataType === 'BASE64'){
        data = await satrtUpload({fileSize: base64Data.length})
      }else{
        data = await satrtBinaryUpload({fileSize,fileType})
      }
      if(data.type === 1){
        // 直接上传
        this.$emit('afterUpload',1)
      }else if(data.type === 2){
        // 分片上传
        uploadCount = data.count
        uploadId = data.id
        uploadSize = data.size
        uploadCount = data.count
        const temp = []
        for(let i = 0; i <uploadCount; i++){
          temp.push(i)
        }
        allIds = temp
        initResume([])
      }
    }

    let initResume = async (uploaded) =>{
      remainIds = await allIds.filter(item =>{
        uploaded.indexOf(item) < 0
      })
      resumeUpload()
    }
    
    // 分片上传
    const resumeUpload = async () =>{
      if(retryTimes >= 10){
        return toast('上传重试达到10次,已取消上传')
      }
      for(let i = 0; i < remainIds.length; i++){
        const no = remainIds[i]
        let remuseData = ''
        if(fileDataType === 'BASE64'){
          remuseData = base64Data.slice(uploadSize * no, uploadSize * (no + 1))
          await remuseUpload({no,remuseData})
          uploaded.push(no)
        }else{
          remuseData = binaryData.slice(uploadSize * no, uploadSize * (no + 1))
          let form = new FormData()
          form.append('no',no)
          form.append('uploadId',uploadId)
          form.append('remuseData',remuseData)
          await remuseBinaryUpload({no,remuseData})
          uploaded.push(no)
        }
      }

      let data = {}
      if(fileDataType === 'BASE64'){
        data = await endUpoad({})
      }else{
        data = await endBinaryUpoad({uploadId})
      }
      if(data.remainCount > 0){
        // 重试
        retryTimes++
        uploaded = data.uploaded
        await initResume(uploaded)
      }else{
        // 上传完成
        this.$emit('afterUpload',2,uploadId)
      }
    }