zoukankan      html  css  js  c++  java
  • 多文件上传

    <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>
  • 相关阅读:
    eclipse运行纯servlet程序
    VS中lib和dll
    eclipse部署web项目至本地的tomcat但在webapps中找不到
    【2018.07.28】(字符串/回文串)学习Manacher算法小记
    【2018.07.26】建立博客~
    【2018.07.27】(字符串/找相同)学习KMP算法小记
    [转]数据库范式那些事
    [转]Windows平台下的多线程编程
    mondrian schema学习(1)
    [转]SQL查询入门
  • 原文地址:https://www.cnblogs.com/3542446186qq/p/15688646.html
Copyright © 2011-2022 走看看