Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

el-upload上传之自定义上传/关闭页面中断请求_el-upload取消上传-CSDN博客 #100

Open
HenryTSZ opened this issue Jun 20, 2024 · 0 comments

Comments

@HenryTSZ
Copy link
Owner

el-upload上传之自定义上传/关闭页面中断请求_el-upload取消上传-CSDN博客

上传组件:组件效果

功能说明:

  1. 上传为post请求,请求需要携带四个参数,其中有file上传的文件

  2. 自定义上传时显示进度条,正在上传的文件删除要杀死当前这个请求,这里是用的file.uid进行的对号查找

  3. 当有任务上传时,关闭或者刷新页面要杀死所有请求。

组件代码:

<template>
  <div class="children_box">
    <div class="inner">
    <span v-if="title" class="subTitle">
    <el-tooltip
      :disabled="disabledFn(childData.data.directoryName)"
      :content="childData.data.directoryName"
      placement="top"
      effect="light"
    >
    <span> {{ getDirNameFn(childData.data.directoryName) }}</span>
    </el-tooltip>
    </span>
      <div class="opt" :style="getOptStyle()">
        <svg-icon icon-class="btn_shangchuan"></svg-icon>
        <span class="s" @click="uploadClickFn(childData.data.id)">上传文件</span>
      </div>
    </div>
    <div class="upload_box">
      <el-upload
        ref="fileRefs"
        class="upload-box"
        action="#"
        :http-request="UploadFn"
        :on-remove="handleRemove"
        :before-remove="beforeRemove"
        :before-upload="beforeUpload"
        :on-success="handleSuccess"
        :file-list="fileList"
      >
        <el-button v-if="false" size="small" type="primary">点击上传</el-button>
      </el-upload>
    </div>
  </div>
</template>
<script>
import axios from 'axios'
import { taskDetailUpload, taskDetailFileList, taskDetailFileDelete } from '@/views/testManage/TDUpload/constants/API'
import { getStringLength } from '@/utils/getStringLength'
export default {
  props: {
    childData: {
      required: true
    },
    needObj: {
      required: true,
      type: Object
    },
    title: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      fileList: [],
      //  上传接口
      taskDetailUpload,
      //   上传入参
      sendData: {
        projectId: this.needObj.projectId,
        taskId: this.needObj.taskId,
        directoryId: ''
      },
      // 存储当前要取消的请求
      source: [],
      // 存储请求的数组
      requestArr: [],
      //  上传成功标志
      isSuccess: true,
      // 是否在中断取消时候出现message提示框
      isShowCancel: false,
      // 上传文件是否符合规定大小,因为beforeUpload方法不符合大小会触发remove方法,所以做个判定,
      // 默认值为必须为true,为了回显文件列表的时候也能走beforeRomove删除逻辑
      fileSizeError: true
    }
  },
  watch: {
    isSuccess(val) {
      if (!val) {
        // 当还有正在上传的文件,此时关闭或刷新浏览器,杀死所有请求
        window.addEventListener('beforeunload', this.sureCloseWinowFn)
      }
    }
  },
  created() {
    this.getFilesListFn()
  },
  mounted() {},
  destroyed() {
    window.removeEventListener('beforeunload', this.sureCloseWinowFn)
  },
  methods: {
    sureCloseWinowFn(e) {
      e = e || window.event
      e.preventDefault()
      e.returnValue = ''
      this.isShowCancel = true
      this.requestArr.forEach(x => {
        x.cancel()
      })
    },
    // 回显上传列表
    getFilesListFn() {
      const params = {
        directoryId: this.childData.data.id,
        taskId: this.sendData.taskId
      }
      taskDetailFileList(params).then(res => {
        // console.log(res, '回显文件列表数据')
        // 回显已经上传的文件列表
        this.fileList = res.map(item => {
          return {
            name: item.fileName,
            fileId: item.fileId,
            directoryId: item.directoryId,
            id: item.id
          }
        })
      })
    },
    // 自定义上传方式
    UploadFn(params) {
      // console.log(params, '上传参数')
      const formData = new FormData()
      formData.append('file', params.file)
      formData.append('projectId', this.needObj.projectId)
      formData.append('taskId', this.needObj.taskId)
      formData.append('directoryId', this.childData.data.id)
      const CancelToken = axios.CancelToken
      const source = CancelToken.source()
      axios({
        method: 'post',
        url: taskDetailUpload,
        data: formData,
        cancelToken: source.token,
        onUploadProgress: progressEvent => {
          // axios自带api,获取上传进度
          const complete = parseInt(((progressEvent.loaded / progressEvent.total) * 100) | 0, 10)
          params.onProgress({ percent: complete }) // 调用组件自带进度条
          // 还没有上传成功标识
          this.isSuccess = false
        }
      })
        .then(res => {
          // 触发handleSuccess函数
          // 显示完成按钮小图标
          params.onSuccess({
            status: true,
            id: res.data.data
          })
        })
        .catch(err => {
          //   console.log(this.$refs.fileRefs.uploadFiles, '上传文件列表??')
          if (!this.isShowCancel) {
            this.$message.warning(err.message)
          }
          const uid = params.file.uid
          const idx = this.$refs.fileRefs.uploadFiles.findIndex(item => item.uid === uid) // 关键作用代码,去除文件列表失败文件(uploadFiles为el-upload中的ref值)
          if (idx > 0) {
            this.$refs.fileRefs.uploadFiles.splice(idx, 1) // 关键作用代码,去除文件列表失败文件
          }
        })
      // 存储一份uid,知道在删除的时候是杀死的哪个请求
      this.source.push({
        source: source,
        uid: params.file.uid
      })
      // 这个直接存储,为了关闭页面刷新页面全部杀死请求
      this.requestArr.push(source)
    },
    uploadClickFn(id) {
      this.sendData.directoryId = id
      this.$refs['fileRefs'].$refs['upload-inner'].handleClick()
    },
    handleSuccess(response, file, fileList) {
      console.log(response, '----', file, '====', fileList)
      this.isSuccess = response.status
      // this.getFilesListFn()//删除后及时显示在列表中,不用刷新回显列表
    },
    beforeUpload(file) {
      // 判断文件是否大于10G  10000
      const isSize = file.size / 1024 / 1024 < 10000
      if (!isSize) {
        this.$message.warning('文件不得大于10G')
        this.fileSizeError = false
      } else {
        this.fileSizeError = true
      }
      return isSize
    },
    handleRemove(file, fileList) {
      console.log(file, fileList)
    },
    beforeRemove(file) {
      // console.log(file, '当前文件')
      if (this.fileSizeError) {
        console.log(file)
        // alert(1223)
        return this.$confirm(`确定删除 ${file.name}?`).then(() => {
          // 如果有id,说明是已经传上去的文件做删除,
          // file.response.id是在上传成功后我们自动装进去的后端返回的id,目的在于因为上传后不重新调回显接口(调了后我们对filelist做了渲染的组装数据),不调是因为万一有大文件在上传就会丢失当前上传列表,所以这里是file.response是我们自己组装的数据,目的在于我们删除一个刚上传的数据又做了删除操作。能取到我们组装好的id
          if (file.id || file.response.id) {
            // 删除接口
            taskDetailFileDelete({ id: file.id }).then(() => {
              this.$message.success('删除成功')
              // this.getFilesListFn() //删除后及时显示在列表中,不用刷新回显列表(防止还有别的大文件在上传)
            })
          } else {
            // 没上传完成点击删除就中断请求
            this.source.forEach(item => {
              if (item.uid === file.uid) {
                item.source.cancel('您已取消了请求') // 这里的提示会在axios的catch的error中捕获到
              }
            })
          }
        })
      }
    },
    getDirNameFn(val) {
      return getStringLength(val) <= 20 ? val : val.substr(0, 18) + '...'
    },
    // 判断节点的文字长度是否出现tool-tip
    disabledFn(attr) {
      if (!attr) return true
      if (getStringLength(attr) < 20) return true
    },
    getOptStyle() {
      return this.title ? { marginLeft: '26px' } : { marginLeft: 0 }
    }
  }
}
</script>
<style scoped lang="scss">
@mixin buttonStyle {
  padding-left: 16px;
  line-height: 28px;
  padding-right: 24px;
  border: 1px solid #fe992c;
  border-radius: 8px;
  color: #fe992c;
  text-align: center;
  cursor: pointer;
  svg {
    vertical-align: middle;
  }
  .s {
    font-size: 14px;
    padding-left: 5px;
    vertical-align: middle;
  }
}
.children_box {
  margin: 20px 40px 0 -20px;
  .inner {
    display: flex;
    align-items: center;
    .subTitle {
      color: rgba(191, 191, 191, 1);
    }
    .opt {
      width: 130px;
      height: 32px;
      @include buttonStyle;
    }
  }
  .upload_box {
    // height: 200px;
    // background: red;
    padding-bottom: 10px;
  }
  ::v-deep .el-upload-list__item-name [class^='el-icon'],
  ::v-deep .el-upload-list__item .el-icon-close-tip {
    color: rgba(250, 140, 22, 1);
  }
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant