自定义批量上传一些逻辑

<template>
  <!-- 上传弹窗 -->
  <el-dialog title="上传文档" width="648px"
      :close-on-press-escape="false" 
      :close-on-click-modal="false"
      :visible.sync="uploadDialogVisible" 
      :before-close="uploadCancel">
      <el-upload
        class="upload-component-content"
        drag
        action=""
        :http-request="uploadToServer"
        ref="upload"
        :auto-upload="false"
        :show-file-list="false"
        :on-progress="handleUploadProgress"
        :on-change="handleUploadChange"
        accept=".ppt,.pptx"
        multiple>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖拽至此处,或<em>点击选择文件</em></div>
        <div class="el-upload__tip" slot="tip">支持上传100MB以内的ppt、pptx文档格式,一次最多上传5个文件</div>
      </el-upload>

      <div class="upload-list-info" v-if="uploadListData.length>0">
        共{{uploadListData.length}}个:上传成功 {{uploadSuccessCount}}  上传失败  {{uploadFailCount}}  上传中 {{uploadingCount}}
      </div>

      <div class="upload-list" v-if="uploadListData.length>0 && !isNetworkDisconnect">
        <el-table :data="uploadListData" max-height="200" v-loading.body="uploadListLoading" element-loading-text="Loading">
          <el-table-column prop="name" width="200" :show-overflow-tooltip="true" label="文件名"></el-table-column>
          <el-table-column prop="size" label="大小">
            <template slot-scope="scope">
              {{scope.row.size | sizeFilter}}
            </template>
          </el-table-column>
          <el-table-column prop="status" label="状态">
            <template slot-scope="scope">
              <span v-if="scope.row.status === 'uploading'">{{scope.row.percent}}%</span>
              <span v-else :class="{
                'error-color': scope.row.status === 'fail' || scope.row.status.includes('error'), 
                'success-color':  scope.row.status === 'success'}">
                {{scope.row.status | statusFilter()}}</span>
            </template>
          </el-table-column>
          <el-table-column align="center" label="操作">
            <template slot-scope="scope">
              <el-link v-if="scope.row.status==='uploading'" type="danger" @click="cancelUploading(scope.row)" class="error-color" :underline="false">取消上传</el-link>
              <el-link v-else title="移除" icon="el-icon-delete" @click="removeUploadFile(scope)" type="danger" 
                :underline="false">
              </el-link>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <div class="upload-warning" v-if="uploadListData.length>0">
        <i class="el-icon-warning"></i>上传期间请勿关闭本页面,否则会上传失败。
      </div>

      <div slot="footer" class="dialog-footer" v-if="!uploadConfirmed">
        <el-button @click="uploadCancel()">取 消</el-button>
        <el-button type="primary" @click="uploadConfirm">确认上传</el-button>
      </div>
    </el-dialog>
</template>

<script>
import { uploadShareDoc } from '@/api/document'
import axios from 'axios'
export default {
  name: 'UploadDialog',
  props: ['visible','type','userId','conferenceId','conferenceNo'],
  data() {
    return {
      uploadDialogVisible:false,
      uploadListData:[],
      uploadListLoading:false,
      uploadConfirmed:false,
      cancelSourceData:[],
    }
  },

  watch: {
    visible: {
      handler(value) {
        this.uploadDialogVisible = value
        if(value) 
           this.uploadConfirmed = false
      },
      immediate: true
    } 
  },

  computed: {
    isNetworkDisconnect () {
      return this.$store.state.network.isNetworkDisconnect
    },

    uploadFailCount() {
      return this.uploadListData.filter(
        item => item.status === 'fail').length
    },

    uploadSuccessCount() {
      return this.uploadListData.filter(
        item => item.status === 'success').length
    },

    uploadingCount() {
      return this.uploadListData.filter(
        item => item.status === 'uploading').length
    },

    uploadTypeErrorCount() {
      return this.uploadListData.filter(
        item => item.status === 'type_error').length
    },

    uploadSizeErrorCount() {
      return this.uploadListData.filter(
        item => item.status === 'size_error').length
    }
  },

  filters: {
    sizeFilter(size) {
      if (size < 1024) {
          return size + 'B'
      } else if (size >= 1024 && size < Math.pow(1024, 2)) {
          return parseFloat(size / 1024).toFixed(2) + 'KB'
      } else if (size >= Math.pow(1024, 2) && size < Math.pow(1024, 3)) {
          return parseFloat(size / Math.pow(1024, 2)).toFixed(2) + 'MB'
      } else if (size > Math.pow(1024, 3)) {
          return parseFloat(size / Math.pow(1024, 3)).toFixed(2) + 'GB'
      } else {
          return 0 + 'B'
      }
    },
    statusFilter(status,) {
      if (status === 'success') {
        return '上传成功'
      } else if (status === 'fail') {
        return '上传失败'
      } else if (status === 'type_error') {
        return '格式错误'
      } else if (status === 'size_error') {
        return '超出规定文件大小'
      } else {
        return '——'
      }
    }
  },

  methods: {
    /*********************  上传处理  ***********************************/
    //上传前文件格式、大小等校验
    //上传100MB以内的ppt、pptx文档格式
    validUploadFiles(file) {
      const fileType = file.type || file.raw.type
      const isType = fileType.includes('application/vnd.ms-powerpoint') || fileType.includes('application/vnd.openxmlformats-officedocument.presentationml.presentation');
      const validResult = { status: 'success' }
      if (!isType) {
          if(file.name){
              let fileNameSplit = file.name.split('.');
              let suffix = fileNameSplit[ fileNameSplit.length - 1 ];
              if(!suffix.includes('pptx')){
                validResult.status = 'type_error'
              }
          }else{
              validResult.status = 'type_error'
          }
      }
      const isLt100M = file.size / 1024 / 1024
      if (isLt100M > 100) {
          validResult.status = 'size_error'
      }
      return validResult
    },

    uploadCancel() {
      if(this.uploadListData.length === 0) {
         this.$refs.upload.clearFiles()
         this.$emit('close')
         return
      }
      this.$confirm(`当前有文档正在上传,确认取消吗?`, '上传提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          //取消上传
          this.$refs.upload.abort()
          this.$refs.upload.clearFiles()
          this.cancelSourceData.forEach(
            item => item.source.cancel()
          )
          if(this.uploadSuccessCount>0) {
            this.$emit('upload-complete')
          }

          this.uploadListData = []
          this.cancelSourceData = []
          this.$emit('close')
        }).catch(() => {    
      }) 
    },

    //上传中取消
    cancelUploading(row) {
      this.cancelSourceData.forEach((item,idx) => {
          if (item.uid === row.uid) {
            item.source.cancel('cancel')
            row.status = 'ready'
            this.updateUploadFile(row)
            this.cancelSourceData.splice(idx,1)
          }
        }
      )
    },
    //移除准备上传的文件
    removeUploadFile(scope) {
      const choiceIndex = scope.$index
      if (choiceIndex > -1) this.uploadListData.splice(choiceIndex, 1)
    },

    uploadConfirm() {
      //上传前网络校验
      if (this.isNetworkDisconnect) {
        this.$message.error('网络异常,请检测网络后重新上传')
        return
      } 

      const uploadReadyCount = this.uploadListData.filter(
        item => item.status === 'ready').length
      if(this.uploadListData.length === 0 || uploadReadyCount === 0) {
        this.$message.error('没有待上传的文件,请添加')
        return
      }

      //文件添加文件数量校验 一次最多上传5个文件
      if(this.uploadListData.length > 5) {
        this.$message.error('添加文件数量超出限制')
        return
      }

      //校验文件 添加文件大小超出限制 添加文件格式错误
      this.uploadListData.map(fileItem => {
          const { status } = this.validUploadFiles(fileItem)
          if (status === 'type_error' || status === 'size_error') {
            fileItem.status = status
          }
          return fileItem
        }
      )
      if (this.uploadTypeErrorCount > 0) {
        this.$message.error('添加文件格式错误');
        return
      }
      if (this.uploadSizeErrorCount > 0) {
        this.$message.error('添加文件大小超出限制');
        return
      }
      
      this.uploadConfirmed = true
      this.$refs.upload.submit()
    },

    //更新列表数据
    updateUploadFile(file) {
      const idx = this.uploadListData.findIndex(item => item.uid === file.uid)
      this.uploadListData[idx] = file 
      this.$set(this.uploadListData,idx,file)
    },

    //上传 回调
    handleUploadProgress(val, file, fileList) {
      file.percent = val
      this.updateUploadFile(file)
    },

    handleUploadChange(file, fileList) {
      if (file && file.status === 'ready') {
        this.uploadListData.push(file)
      }
    },

    //上传到服务器
    uploadToServer(params) {
      if(params.file.status 
         && params.file.status !== 'ready') return

      const formData = new FormData();

      const materialParam = {
         ******
      }
      const json = JSON.stringify(materialParam);
      const blob = new Blob([json], {type: 'application/json'});
      formData.append('fileUpload', blob);
      formData.append('files', params.file)

      //进度条处理
      const uploadProgressHandler = ({ total, loaded }) => {
        const percent = (loaded / total) * 100
        params.onProgress(percent.toFixed(0))
      }

      //cancelToken处理
      let CancelToken = axios.CancelToken;
      let source = CancelToken.source();
      this.cancelSourceData.push({ source, uid: params.file.uid })

      api(formData, uploadProgressHandler,source.token).then(res => {
        if (res.code === 200) {
          params.file.status = 'success'
          this.updateUploadFile(params.file)
          this.uploadConfirmed = false
          if(this.uploadSuccessCount === this.uploadListData.length) {
            this.$message.success('上传文档完成')
            this.$emit('close')
            this.uploadListData = []
            this.$emit('upload-complete')
          }
        } else{
          params.file.status = 'fail'
          this.updateUploadFile(params.file)
          this.uploadConfirmed = false
          this.$message.error(res.msg || '上传文档失败')
        }
      })
      .catch(err => {
        if (!err.message || err.message !== 'cancel') {
          params.file.status = 'fail'
          this.updateUploadFile(params.file)
          this.$message.error('上传文档失败')
        }
        this.uploadConfirmed = false
        console.error(err)
      }) 
    },
  }
}
</script>

 

posted @ 2023-02-16 12:55  创业男生  阅读(22)  评论(0编辑  收藏  举报