<template>
  <div>
    <el-upload
      ref="upload"
      name="attach"
      :accept="accept"
      :multiple="multiple"
      :action="uploadAc"
      :show-file-list="true"
      :auto-upload="false"
      with-credentials
      :on-remove="handleRemove"
      :http-request="
        debounce(() => {
          uploadRequest()
        })
      "
      :limit="multiple ? limit : 2"
      :on-change="
        debounce((file, fileList) => {
          onChange(file, fileList)
        })
      "
      :file-list="fileList"
      :before-upload="beforeUpload"
    >
      <!-- :on-preview="handlePreview" -->
      <!-- :limit="1" -->
      <el-button slot="trigger" type="primary" size="mini">{{
        zh_en('上传文件', 'Upload Files')
      }}</el-button>
      <!-- <el-dropdown type="primary" size="mini">
                      <el-button
                        type="primary"
                        size="mini"
                        @click="uploadFloder"
                      >
                        选择文件
                        <i class="el-icon-arrow-down el-icon--right" />
                      </el-button>
                      <el-dropdown-menu slot="dropdown">
                        <el-button
                          type="primary"
                          size="mini"
                          @click="uploadFloders"
                        >选择文件夹
                        </el-button>
                      </el-dropdown-menu>
                    </el-dropdown>  -->
      <span style="paddingLeft:10px;color:#2D8CF0;fontSize:12px;">
        {{ uploadNotes }}
      </span>
      <span
        v-if="multiple"
        style="paddingLeft:10px;color:#ff4949;fontSize:12px;display:block"
      >
        {{
          zh_en(
            '建议单次选择文件数不超过300个,可多次选择例如要上传900张发票,请分3次选择,然后一起提交,这样上传速度最快。',
            'It is recommended that you select no more than 300 invoices at a time. You can select multiple times .For example, to upload 900 invoices, please select them in three times and submit them together, so that the upload speed is the fastest.'
          )
        }}
      </span>
    </el-upload>
    <el-dialog
      :append-to-body="true"
      :visible.sync="dialog.show"
      center
      :show-close="false"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      class="noBackground"
    >
      <el-progress type="circle" :percentage="dialog.percentage" />
      <p>{{ zh_en('正在上传...', 'Be uploading...') }}</p>
    </el-dialog>
  </div>
</template>

 

<script>
export default {
  components: {},
  props: {
    accept: {
      type: String,
      default: '.pdf,.ofd'
    },
    uploadAc: {
      type: String,
      default: ''
    },
    multiple: {
      type: Boolean,
      default: true
    },
    limit: {
      type: Number,
      default: null
    },
    require: {
      type: Boolean,
      default: true
    },
    successFunction: {
      type: Function,
      default: () => {
        return new Promise((resolve, reject) => {
          console.log('success')
          resolve()
        })
      }
    },
    uploadNotes: {
      type: String,
      default: null
    }
  },
  data() {
    return {
      fileList: [],
      formData: new FormData(),
      token: null,
      dialog: {
        show: false,
        percentage: 0
      }
    }
  },

 

  computed: {
    // uploadAc() {
    //   return `${process.env.VUE_APP_BASE_API}/station/import`
    // }
  },

 

  mounted() {},

 

  methods: {
    clear() {
      this.$refs['upload'].clearFiles()
      this.fileList = []
    },
    // 支持上传文件夹
    uploadFunction() {
      this.$nextTick(() => {
        document.getElementsByClassName(
          'el-upload__input'
        )[0].webkitdirectory = true
      })
    },
    handleRemove(val, b) {
      console.log('val', val)
      this.fileList = b
    },
    uploadFloder() {
      this.$nextTick(() => {
        document.getElementsByClassName(
          'el-upload__input'
        )[0].webkitdirectory = false
      })
    },
    uploadFloders() {
      this.$nextTick(() => {
        document.getElementsByClassName(
          'el-upload__input'
        )[0].webkitdirectory = true
      })
    },
    handlePreview(file) {
      console.log(file)
    },
    // 执行压缩方法生成压缩文件
    handleBefore(fileList) {
      // const loading = this.$loading({
      //   lock: true,
      //   text: 'Loading',
      //   spinner: 'el-icon-loading',
      //   background: 'rgba(0, 0, 0, 0.7)'
      // })
      // var new_zip = new JsZip()
      // const date = new Date()
      // fileList.map(file => {
      //   new_zip.file(file.name, file.raw)
      // })
      // new_zip
      //   .generateAsync({ type: 'Blob', compression: 'DEFLATE' })
      //   .then(function(content) {
      //     loading.close()
      //     console.log('数量:', fileList.length, 'time:', new Date() - date)
      //     console.log(
      //       'zip包大小:',
      //       (content.size / (1024 * 1024)).toFixed(2) + 'M'
      //     )
      //     // see FileSaver.js
      //     FileSaver(content, 'example.zip')
      //   })
    },
    onChange(file, fileList) {
      // console.log(file, fileList)
      // if (this.multiple) {
      //   const filterFileList = fileList.filter(item => {
      //     return (
      //       this.getFileType(item.name) === 'ofd' ||
      //       this.getFileType(item.name) === 'pdf'
      //     )
      //   })
      // 单个文件上传时新的文件更新旧的文件
      if (!this.multiple) {
        if (fileList.length > 0) {
          this.fileList = [fileList[fileList.length - 1]] // 这一步,是 展示最后一次选择文件
          return
        }
      } else {
        console.log(file)
        // this.fileList = [
        //   ...fileList.filter(item => {
        //     return item.raw.name !== file.name
        //   }),
        //   file
        // ]
        const fullLoading = this.fullLoading()
        // 过滤重复文件
        this.fileList = fileList.reduce((prev, next) => {
          // console.log(prev)
          if (
            prev.find(item => {
              return item.raw.name === next.raw.name
            })
          ) {
            return prev
          } else {
            return [...prev, next]
          }
        }, [])
        setTimeout(() => {
          fullLoading.close()
        }, 1000)
      }
      // }
    },
    getFileType(filePath) {
      var startIndex = filePath.lastIndexOf('.')
      if (startIndex !== -1) {
        return filePath.substring(startIndex + 1, filePath.length).toLowerCase()
      } else return ''
    },
    // throttle(callback, wait = 500) {
    //   let timer = null
    //   let startTime
    //   return function() {
    //     const ctx = this
    //     const args = arguments
    //     const now = +new Date()
    //     if (startTime && now < startTime + wait) {
    //       clearTimeout(timer)
    //       timer = setTimeout(function() {
    //         startTime = now
    //         callback.apply(ctx, args)
    //       }, wait)
    //     } else {
    //       startTime = now
    //       callback.apply(ctx, args)
    //     }
    //   }
    // },
    debounce(fn, delay) {
      var timer = null
      return function() {
        var context = this
        var args = arguments
        clearTimeout(timer)
        timer = setTimeout(function() {
          fn.apply(context, args)
        }, delay)
      }
    },
    beforeUpload(file) {
      // var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
      // const accept = this.accept
      // //   const extension = testmsg === 'xls'
      // //   const extension2 = testmsg === 'xlsx'
      // const isLt2M = file.size / 1024 / 1024 < 20 // 这里做文件大小限制
      // const isAccept =
      //   accept.indexOf(testmsg) !== -1 && accept.indexOf(testmsg) !== '-1'
      // if (!isAccept) {
      //   this.message_alert_withObject({
      //     message: this.zh_en(
      //       `上传文件只能是 ${accept}格式!`,
      //       `The uploaded file must be in ${accept} format only`
      //     ),
      //     type: 'error'
      //   })
      //   return false
      // }
      // if (!isLt2M) {
      //   this.message_alert_withObject({
      //     message: this.zh_en(
      //       `上传文件大小不能超过 20MB!`,
      //       `The uploaded file size cannot exceed 20MB!`
      //     ),
      //     type: 'error'
      //   })
      //   return false
      // }

 

      // // const formData = this.formData
      // // if (this.multiple) {
      // //   formData.append('files', file, file.name)
      // // } else {
      // //   formData.append('file', file, file.name)
      // // }
      // //   return extension || (extension2 && isLt2M)
      // return isLt2M && isAccept
      return true
    },
    // 文件列表复制到上传组件中
    fileListToFormData() {
      const fileList = this.fileList
      const formData = new FormData()
      formData.append('token', this.token)
      if (this.multiple) {
        fileList.forEach(file => {
          formData.append('files', file['raw'], file.name)
        })
      } else {
        // ie 不支持 formData.set
        formData.append('file', fileList[0]['raw'], fileList[0]['name'])
      }
      this.formData = formData
    },
    // async getToken() {
    //   try {
    //     const tokenRes = await this.$store.dispatch('file/getToken') // 获取token
    //     // const tokenRes = 'token' // 获取token
    //     this.token = tokenRes.data
    //   } catch (error) {
    //     console.log(error)
    //   }
    // },
    async uploadRequest(fileObj) {
      // const formData = this.formData
      this.uploadFiles()
      // if (this.multiple) {
      //   // fileList 的赋值放到了提交之前
      //   if (formData.getAll('files').length === this.fileList.length) {
      //     this.uploadFiles()
      //   }
      // } else {
      //   this.uploadFiles()
      // }
    },
    cutArray(array, subLength) {
      let index = 0
      const newArr = []
      while (index < array.length) {
        newArr.push(array.slice(index, (index += subLength)))
      }
      return newArr
    },
    sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms))
    },
    async uploadFiles() {
      // const fullLoading = this.fullLoading()
      try {
        const formData = this.formData
        const multiple = this.multiple
        // const totalFileServerRes = []
        let fileResponse = {}
        let filesResponse = []
        this.dialog.show = true
        let result = null
        if (multiple) {
          // const filesList = this.formData.getAll('files')
          const filesList = this.fileList
          // 每次最大文件上传数量
          const maxRequest = 10
          // 并发请求数量
          const maxConcurrency = 6
          // 接收 上传文件列表,返回size 合计20M以内的数量
          const checkSizeNumber = list => {
            let number = 0
            let filesSize = 0
            for (const file of list) {
              filesSize += file.size
              if (filesSize / 1024 / 1024 < 20 && number < maxRequest) {
                number++
              }
            }
            return number
          }
          const doMutilRequest = async list => {
            return new Promise((resolve, reject) => {
              const requestPromise = []
              const cutArrayResult = this.cutArray(list, checkSizeNumber(list))
              for (const items of cutArrayResult) {
                const formDataList = new FormData()
                formDataList.append('token', this.token)
                // fileList 与 formData中的files不同
                items.map(file => {
                  formDataList.append('files', file['raw'], file.name)
                })
                requestPromise.push(
                  new Promise((res, rej) => {
                    // this.sleep(Math.random() * 1000).then(r => {
                    //   res(['1', '2', '3', '4', 5, 6, 7, 8, 9, 0])
                    // })
                    this.$store
                      .dispatch('file/multiUploadFiles', formDataList)
                      .then(urls => {
                        res(urls.split(','))
                        // res(['1', '2', '3', '4', 5, 6, 7, 8, 9, 0])
                      })
                      .catch(error => {
                        rej(error)
                      })
                  })
                )
              }
              Promise.all(requestPromise)
                .then(urlsArray => {
                  resolve(
                    urlsArray.reduce((a, b) => {
                      return [...a, ...b]
                    }, [])
                  )
                })
                .catch(error => {
                  reject(error)
                })
            })
          }
          const checkRequestNumber = (list, receiveUrls) => {
            return new Promise((resolve, reject) => {
              // 更新进度条状态
              this.dialog.percentage =
                parseInt((receiveUrls.length * 10000) / filesList.length) / 100
              // 上传文件数量超过预定限制,分批次请求
              doMutilRequest(list.slice(0, maxRequest * maxConcurrency))
                .then(urls => {
                  if (list.length > maxRequest * maxConcurrency) {
                    const undealList = list.slice(maxRequest * maxConcurrency)
                    checkRequestNumber(undealList, [...receiveUrls, ...urls])
                      .then(r => {
                        resolve(r)
                      })
                      .catch(error => {
                        reject(error)
                      })
                  } else {
                    // 更新进度条状态
                    this.dialog.percentage = 100
                    resolve({
                      list: list,
                      receiveUrls: [...receiveUrls, ...urls]
                    })
                  }
                })
                .catch(error => {
                  reject(error)
                })
            })
          }
          const res = await checkRequestNumber(filesList, [])
          const filePaths = res.receiveUrls
          filesResponse = filesList.map((it, index) => {
            const item = {}
            item.scale = filesList[index].size
            item.storeName = filePaths[index]
            item.displayName = filesList[index].name
            return item
          })
          result = filesResponse
        } else {
          const fileServerRes = await this.$store.dispatch(
            'file/uploadFile',
            formData
          )
          // IE 11 不支持formData.get方法
          // const file = formData.get('file')
          const file = this.fileList[0]
          fileResponse = {
            scale: file.size,
            storeName: fileServerRes,
            displayName: file.name
          }
          result = fileResponse
        }
        await new Promise((resolve, reject) => {
          this.successFunction(result)
            .then(resolve())
            .catch(err => {
              console.log(err)
              this.$confirm(
                this.zh_en('出现错误,再试一次?', 'Error occurred,try again?'),
                this.zh_en('提示', 'Warning'),
                {
                  confirmButtonText: this.zh_en('重试', 'Retry'),
                  cancelButtonText: this.zh_en('取消', 'Cancel'),
                  type: 'warning'
                }
              )
                .then(_ => {
                  // this.$emit('close', this.selected)
                  this.successFunction(result)
                    .then(resolve())
                    .catch(err => {
                      reject(err)
                    })
                })
                .catch(_ => {
                  this.message_alert(this.zh_en('取消!', 'Cancel!'))
                  reject('取消!')
                })
            })
        })
        this.dialog.show = false
        // 完成后formData置空
        // this.formData = new FormData()
        // this.fileList = []
      } catch (error) {
        console.log(error)
        this.dialog.show = false
        if (this.$refs['upload']) {
          // console.log('清空文件')
          // this.$refs['upload'].clearFiles()
        }
      } finally {
        console.log('close dialog')
        // this.dialog.show = false
        // fullLoading.close()
      }
    },
    async submit() {
      // 判断是否是必选,若为必选则判断fileList是否为空
      const fileList = this.fileList
      if (this.require && !(fileList && fileList.length)) {
        this.message_alert(
          this.zh_en('请选择上载文件', 'Please choose upload file')
        )
        return false
      }
      const accept = this.accept
      const isAccept = fileList.every(file => {
        var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
        const result = accept.includes(testmsg.toLowerCase())
        return result
      })
      if (!isAccept) {
        this.message_alert_withObject({
          message: this.zh_en(
            `上传文件只能是 ${accept}格式!`,
            `The uploaded file must be in ${accept} format only`
          ),
          type: 'error'
        })
        return
      }
      const isLt2M = fileList.every(file => {
        const result = file.size / 1024 / 1024 < 20
        return result
      })
      if (!isLt2M) {
        this.message_alert_withObject({
          message: this.zh_en(
            `上传文件大小不能超过 20MB!`,
            `The uploaded file size cannot exceed 20MB!`
          ),
          type: 'error'
        })
        return false
      }
      const fullLoading = this.fullLoading()
      try {
        // this.btnLoading = true
        const tokenRes = await this.$store.dispatch('file/getToken') // 获取token
        this.token = tokenRes.data
        this.fileListToFormData()
        this.$refs['upload'].submit()
        // 解决上传后无法继续上传的问题
        // if (
        //   formData.getAll('files').length === this.fileList.length ||
        //   formData.get('file')
        // ) {
        //   this.uploadRequest()
        // } else {
        //   this.$refs['upload'].submit()
        // }
      } catch (error) {
        console.log(error)
      } finally {
        // this.btnLoading = false
        fullLoading.close()
      }
    }
  }
}
</script>
<style lang="scss" scoped>
/deep/ .noBackground {
  .el-dialog {
    background: none;
    box-shadow: none;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    position: absolute;
    margin-top: 0 !important;
    p {
      color: #409eff;
    }
  }
  .el-dialog__body {
    text-align: center;
    border: none;
  }
}
</style>
posted on 2021-12-14 16:34  啦啦啦12345  阅读(272)  评论(0编辑  收藏  举报