优化VUE Element UI的上传插件
默认ElmentUI的文件列表只有一个删除按钮,我需要加预览、下载、编辑等,就需要优化显示结果。
优化后没用上传进度条,又加了一个进度条效果
代码
<template>
<div>
<el-upload
class="upload-demo"
action="/"
:file-list="fileList"
:disabled="isUpLoading"
:before-upload="beforeUpload"
:http-request="handleHttpRequest"
:on-remove="handleRemoveFile"
:on-progress="handleLoading"
:on-success="handleUploadSuccess">
<el-button size="small" :loading="isUpLoading" type="primary">{{this.isUpLoading?"附件上传中...":"点击上传"}} </el-button>
<div slot="tip" class="el-upload__tip">(建议上传附件大小在5M以内)</div>
</el-upload>
<div id="file-list">
<el-progress v-if="isUpLoading" :percentage="uploadingProgress"></el-progress>
<div v-for="(file,index) in fileList" :key="file.fileIdentifier" style="display: flex;justify-content: space-between;line-height: 25px;">
<div>{{index+1}}、{{file.name}} </div>
<div style="padding-right: 20px;">
<a href="javascript:void(0)" style="cursor:pointer;" @click="fileOption(file,'down')">下载</a>
<a href="javascript:void(0)" v-if = "officeFileType.includes(file.wjhz.toLowerCase())" style="margin-left: 10px;cursor:pointer;" @click="fileOption(file,'show')">查看</a>
<a href="javascript:void(0)" v-if = "officeFileType.includes(file.wjhz.toLowerCase())" style="margin-left: 10px;cursor: pointer;" @click="fileOption(file,'edit')">编辑</a>
<a href="javascript:void(0)" style="margin-left: 10px;cursor: pointer;" @click="fileOption(file,'del')">删除</a>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
::v-deep .el-upload-list{
display: none;
}
</style>
<script>
import md5 from "@/api/file/md5";
import { taskInfo, initTask, preSignUrl, merge, del, getFileList} from '@/api/file/api';
import Queue from 'promise-queue-plus';
import axios from 'axios'
import VXETable from 'vxe-table'
import { changeUserStatus } from '@/api/system/user'
export default {
name: 'upload-page',
props: {
// 文件类型
fjlxdm: {
required: true,
type: String
},
// 业务主建
ywbs: {
required: true,
type: String
},
},
created(){
this.initData();
},
data() {
return {
fileUploadChunkQueue:{},
lastUploadedSize:0,// 上次断点续传时上传的总大小
uploadedSize:0,// 已上传的大小
totalSize:0,// 文件总大小
startMs:'',// 开始上传的时间
taskRecord:{},
options:{},
fileList:[],
officeFileType:['.ppt', '.pptx', '.doc', '.docx', '.xls', '.xlsx','.pdf'],
isUpLoading:false,
uploadingProgress:0,
uploadTime:null,
}
},
methods: {
handleLoading(event, file, fileList){
if(this.uploadTime!=null){
clearInterval(this.uploadTime);
this.uploadTime=null;
}
this.uploadingProgress=parseFloat(event.percent);
},
fileOption(file,type){
if(type=="down"){//下载
window.open(file.url, "_blank");
return;
}
if(type=="show"){//查看
const { href } = this.$router.resolve({
name: 'office',
query: {
fjxxbs: file.fjxxbs,
viewUrl: file.viewUrl,
ot: 'detail'
}
})
window.open(href, '_blank')
return;
}
if(type=="edit"){//编辑
const { href } = this.$router.resolve({
name: 'office',
query: {
fjxxbs: file.fjxxbs,
viewUrl: file.viewUrl,
ot: 'edit'
}
})
window.open(href, '_blank')
return;
}
if(type=="del"){//删除
this.$confirm(
'确认删除该附件?',
"警告",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then( () => {
del(file.fjxxbs).then(ret => {
const index = this.fileList.findIndex((item) => item.fjxxbs === file.fjxxbs);
this.fileList.splice(index, 1);
this.msgSuccess("删除成功");
});
})
return;
}
},
/**
* 获取附件列表
*/
initData(){
this.uploadingProgress=100;
getFileList(this.ywbs,this.fjlxdm).then(ret => {
this.fileList = ret.data;
setTimeout(()=>{
this.isUpLoading=false;
},500);
})
},
/**
* 获取一个上传任务,没有则初始化一个
*/
async getTaskInfo(file){
let task;
const identifier = await md5(file)
const { code, data, msg } = await taskInfo(identifier,this.ywbs,this.fjlxdm);
if (code === 200) {
task = data
if (task===undefined) {
const initTaskData = {
identifier,
fileName: file.name,
totalSize: file.size,
chunkSize: 5 * 1024 * 1024,
ywbs:this.ywbs,
fjlxdm:this.fjlxdm
}
const { code, data, msg } = await initTask(initTaskData)
if (code === 200) {
task = data
} else {
this.$notify({
title:'提示',
message: '文件上传错误',
type: 'error',
duration: 2000
})
}
}
} else {
this.$notify({
title:'提示',
message: '文件上传错误',
type: 'error',
duration: 2000
})
}
return task
},
// 获取从开始上传到现在的平均速度(byte/s)
getSpeed(){
// 已上传的总大小 - 上次上传的总大小(断点续传)= 本次上传的总大小(byte)
const intervalSize = this.uploadedSize - this.lastUploadedSize
const nowMs = new Date().getTime()
// 时间间隔(s)
const intervalTime = (nowMs - this.startMs) / 1000
return intervalSize / intervalTime
},
async uploadNext(partNumber){
const {chunkSize,fileIdentifier} = this.taskRecord;
const start = new Number(chunkSize) * (partNumber - 1)
const end = start + new Number(chunkSize)
const blob = this.options.file.slice(start, end)
const { code, data, msg } = await preSignUrl({ identifier: fileIdentifier, partNumber: partNumber , ywbs:this.ywbs , fjlxdm:this.fjlxdm} )
if (code === 200 && data) {
await axios.request({
url: data,
method: 'PUT',
data: blob,
headers: {'Content-Type': 'application/octet-stream'}
})
return Promise.resolve({ partNumber: partNumber, uploadedSize: blob.size })
}
return Promise.reject(`分片${partNumber}, 获取上传地址失败`)
},
/**
* 更新上传进度
* @param increment 为已上传的进度增加的字节量
*/
updateProcess(increment){
increment = new Number(increment)
const { onProgress } = this.options
let factor = 1000; // 每次增加1000 byte
let from = 0;
// 通过循环一点一点的增加进度
while (from <= increment) {
from += factor
this.uploadedSize += factor
const percent = Math.round(this.uploadedSize / this.totalSize * 100).toFixed(2);
onProgress({percent: percent})
}
const speed = this.getSpeed();
const remainingTime = speed != 0 ? Math.ceil((this.totalSize - this.uploadedSize) / speed) + 's' : '未知'
console.log('剩余大小:', (this.totalSize - this.uploadedSize) / 1024 / 1024, 'mb');
console.log('当前速度:', (speed / 1024 / 1024).toFixed(2), 'mbps');
console.log('预计完成:', remainingTime);
},
handleUpload(file, taskRecord){
this.lastUploadedSize = 0; // 上次断点续传时上传的总大小
this.uploadedSize = 0 // 已上传的大小
this.totalSize = file.size || 0 // 文件总大小
this.startMs = new Date().getTime(); // 开始上传的时间
this.taskRecord = taskRecord;
const { exitPartList, chunkNum} = taskRecord
return new Promise(resolve => {
const failArr = [];
const queue = Queue(5, {
"retry": 3, //Number of retries
"retryIsJump": false, //retry now?
"workReject": function(reason,queue){
failArr.push(reason)
},
"queueEnd": function(queue){
resolve(failArr);
}
})
this.fileUploadChunkQueue[file.uid] = queue
for (let partNumber = 1; partNumber <= chunkNum; partNumber++) {
const exitPart = (exitPartList || []).find(exitPart => exitPart.partNumber == partNumber)
if (exitPart) {
// 分片已上传完成,累计到上传完成的总额中,同时记录一下上次断点上传的大小,用于计算上传速度
this.lastUploadedSize += new Number(exitPart.size)
this.updateProcess(exitPart.size)
} else {
queue.push(() => this.uploadNext(partNumber).then(res => {
// 单片文件上传完成再更新上传进度
this.updateProcess(res.uploadedSize)
}))
}
}
if (queue.getLength() == 0) {
// 所有分片都上传完,但未合并,直接return出去,进行合并操作
resolve(failArr);
return;
}
queue.start()
})
},
async handleHttpRequest(options){
this.options = options;
const file = options.file
const task = await this.getTaskInfo(file)
const that = this;
if (task) {
const { finished, path, taskRecord } = task
const {fileIdentifier,fjxxbs } = taskRecord
if (finished) {
return {fileIdentifier,fjxxbs}
} else {
const errorList = await this.handleUpload(file, taskRecord)
if (errorList.length > 0) {
this.$notify({
title:'文件上传错误',
message: '部分分片上传失败,请尝试重新上传文件',
type: 'error',
duration: 2000
})
return;
}
const { code, data, msg } = await merge(fileIdentifier,that.ywbs,that.fjlxdm)
if (code === 200) {
return {fileIdentifier,fjxxbs};
} else {
this.$notify({
title:'提示',
message: '文件上传错误',
type: 'error',
duration: 2000
})
}
}
} else {
this.$notify({
title:'文件上传错误',
message: '获取上传任务失败',
type: 'error',
duration: 2000
})
}
},
/**
* 重复上传
* @param {} file
*/
beforeUpload(file){
return new Promise((resolve, reject) => {
md5(file).then(result => {
const index = this.fileList.findIndex((item) => item.fileIdentifier === result);
if(index==-1){
this.isUpLoading=true;
this.uploadingProgress=0;
this.uploadTime=setInterval(()=>{
this.uploadingProgress+=1;
},500)
return resolve(true);
}else{
return reject(false);
}
})
});
},
handleRemoveFile(uploadFile, uploadFiles){
const queueObject = this.fileUploadChunkQueue[uploadFile.uid]
if (queueObject) {
queueObject.stop()
this.fileUploadChunkQueue[uploadFile.uid] = undefined;
}
if(uploadFile.fjxxbs != undefined){
del(uploadFile.fjxxbs).then(ret => {
const index = this.fileList.findIndex((item) => item.fjxxbs === uploadFile.fjxxbs);
this.fileList.splice(index, 1);
})
}
},
/**
* 上传成功
*/
handleUploadSuccess(res, file, fileList) {
// file.fileIdentifier = res.fileIdentifier;
// file.fjxxbs = res.fjxxbs;
// this.fileList.push(file);
this.initData();
}
}
}
</script>