上传为post请求,请求需要携带四个参数,其中有file上传的文件
自定义上传时显示进度条,正在上传的文件删除要杀死当前这个请求,这里是用的file.uid进行的对号查找
当有任务上传时,关闭或者刷新页面要杀死所有请求。
组件代码:
<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>