2024-08-31 18:02:48 +08:00

472 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<div class="container">
<div class="item">
<el-upload action="#"
ref="uploadFolder"
:on-change="onChange"
:on-remove="handleRemove"
:show-file-list="false"
:headers="headers"
:accept="accept"
:file-list="fileList"
:before-upload="beforeUploadsg"
:on-success="uploadSuccess"
:on-error="uploadError"
:on-exceed="exceed"
:auto-upload="true"
:http-request="uploadFile"
:multiple="true">
<el-button slot="trigger" id="myButton" size="small" type="primary" @click="uploadBtn.click()">选取文件夹</el-button>
</el-upload>
</div>
<div></div>
<div class="item">
<el-upload class="upload-demo" ref="upload" action="#"
:before-upload="beforeUpload"
:on-change="onChange"
:on-remove="handleRemove"
:multiple="isMultiple"
:on-exceed="handleExceed"
:accept="acceptType"
:limit="limit"
:file-list="fileList"
:auto-upload="true"
:http-request="uploadFile"
show-file-list>
<el-button id="myButton" slot="trigger" size="small" type="primary">选取文件</el-button>
<div slot="tip" class="el-upload__tip">只能上传{{acceptType}}文件</div>
</el-upload>
<div v-show="progressFlag" class="head-img">
<el-progress :text-inside="true" :stroke-width="14" :percentage="progressPercent" status="success"></el-progress>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import sgUploadTray from "./sgUploadTray"
import {
getToken
} from "@/utils/auth";
export default {
components: {
sgUploadTray,
},
props: {
uploadUrl: {
type: String,
required: true
},
// 是否多选
isMultiple: {
type: Boolean,
default() {
return false
}
},
// 文件类型
type: {
type: Array,
default() {
return []
}
},
//上传类型
acceptType: {
type: String,
required: true
},
// 上传数量
limit: {
type: Number,
default() {
return 1
}
},
// 文件
dataFile: {
type: [Object, Array, String],
default() {
return ''
}
},
},
data() {
return {
fileList: [],
progress: 0,
isUploading: false,
progressFlag: false, //进度条初始值隐藏
progressPercent: 0, //进度条初始值
partSize: 5 * 1024 * 1024,
headers: { kkToken: localStorage.token, }, //获取token(注意仔细看后端接受token的字段名是不是叫做“token”)
accept:`.${["png", "jpg", "jpeg", "bmp", "gif"].join(",.")}`,//允许上传的后缀名
actionURL: process.env.VUE_APP_BASE_API + "/common/initUpload",
dur: 100,
percent: 100,
uploadBtn: null,//上传按钮
uploadList: [],
showUploadTray: false,
};
},
mounted(d) {
this.$nextTick(() => {
this.uploadBtn = this.$refs.uploadFolder.$children[0].$refs.input;
this.uploadBtn.webkitdirectory = true;//让el-upload支持上传文件夹
})
},
watch: {
dataFile: {
handler(newValue, oldValue) {
if (newValue) {
this.fileList = Array.isArray(newValue) ? newValue : [newValue]
} else {
this.fileList = []
}
},
immediate: true
}
},
methods: {
showFakeLoading(file) {
file = this.uploadList.find(v => v.uid == file.uid);
clearInterval(file.interval);
file.percent = 0;
file.interval = setInterval(() => {
file.percent++;
file.percent >= 99 && this.hideFakeLoading(file);
}, this.dur);
},
hideFakeLoading(file, { type, tip, color } = {}) {
console.log('file======>');
console.log(file)
file = this.uploadList.find(v => v.uid == file.uid);
clearInterval(file.interval);
switch (type) {
case 'error':
file.percent = 0;
break;
case 'success':
default:
file.percent = 100;
}
type && (file.type = type);
tip && (file.tip = tip);
color && (file.color = color);
},
exceed(file, fileList) {
this.$message.error("上传文件数量太大,分散上传吧!");
},
stopUpload(d) {
this.$refs.uploadFolder.abort();
//console.log(`取消上传`, d);
},
beforeUploadsg(file, id) {
console.log(this.uploadList)
this.uploadList = []
console.info("this.uploadList==", JSON.stringify(this.uploadList))
this.uploadList.unshift({
interval: false,
uid: file.uid,
percent: 0,//加载进度
name: file.name,
size: file.size,
type: file.type,
webkitRelativePath: file.webkitRelativePath,
tip: '',
color: '',
});
this.showUploadTray = true;
this.accept = ["png", "jpg", "jpeg", "bmp", "gif", "txt", "json", "pdf"]
// 判断是不是特定的格式________________________
let isFile = this.accept.includes(file.name.toLocaleLowerCase().split(".").pop());
const maxSize = 50; //限制大小
const isAllowSize = file.size / 1024 / 1024 <= maxSize;
isFile || this.$message.error("上传文件只能是" + this.accept+ "格式");
isAllowSize || this.$message.error("上传文件大小不能超过" + maxSize + "MB");
let allowUpload = isFile && isAllowSize;
return allowUpload; //若返回false则停止上传
},
uploadSuccess(response, file, fileList) {
if (response.data && response.data.key) {
// 下载失败原因的描述文件
this.$d.customer_downloadImportCustomerExcel({ key: response.data.key }, {
s: (d) => {
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
this.$g.downloadFile(d, `${file.name}-上传失败原因`, '.xls');
this.$message.error(`${file.name}-上传失败,请查看失败原因`);
// this.initList();//刷新列表
//console.log('上传失败', response, file, fileList);
}
});
} else if (response.success) {
// 上传成功了
this.hideFakeLoading(file, { type: 'success', tip: "上传成功", color: "green" });
this.$message.success(`${file.name}上传成功`);
// this.initList();//刷新列表
//console.log('上传成功', response, file, fileList);
} else {
// 其他失败原因
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
this.$message.error(response.msg);
//console.log('上传失败', response, file, fileList);
}
},
//上传失败
uploadError(err, file, fileList) {
this.hideFakeLoading(file, { type: 'error', tip: "上传失败", color: "red" });
this.$message.error("上传失败");
//console.log('上传失败', err, file, fileList);
},
// 上传前
beforeUpload(file) {
/* const fileType = file.type.toLowerCase()
console.info("fileType=======", fileType)
const typeFlag = this.type.some(item => {
return fileType.indexOf(item) != -1
})
if (!typeFlag) {
this.$message.error('上传类型有误,请重新上传')
return false
}*/
},
//文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
onChange(file, fileList) {
this.fileList = fileList;
},
handleRemove(file, fileList) {
this.fileList = fileList;
},
handleExceed(files, fileList) {
this.$message.warning(
"最多之能上传"+ this.limit +"个附件"
);
},
async uploadFile({ data, file }) {
let self = this
//初始化参数
this.progress++
if (file.size < this.partSize) {
let formData = new FormData()
formData.append("file", file)
self.progressFlag = true;
axios({
url: self.uploadUrl,
method: 'post',
data: formData,
headers: {
'Authorization': 'Bearer ' + getToken(),
'Content-Type': 'multipart/form-data'
},
onUploadProgress: progressEvent => {
// progressEvent.loaded:已上传文件大小
// progressEvent.total:被上传文件的总大小
//进度条
self.progressPercent = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
}
}).then(res => {
setTimeout(() => {
if (res.data.code == 200 && self.progressPercent === 100) {
setTimeout(function () {
self.$message({
message: '上传成功!',
type: 'success',
duration: '2000'
});
self.progressFlag = false;
self.progressPercent = 0
self.handleResult(res,file);
}, 500);
} else {
self.$message({
message: '上传失败!',
type: 'error',
duration: '2000'
});
}
}, 1000);
}).catch(error => {
console.error(error)
self.progressFlag = false;
self.progressPercent = 0
self.$refs.upload.clearFiles();
self.$message({
message: '上传失败!',
type: 'error',
duration: '2000'
});
})
} else {
file._shardCount = Math.ceil(file.size / this.partSize) //总片数
file.uploaded = 0
let formData = new FormData()
formData.append('fileName', file.name)
let self = this
//大文件上传初始化,返回uploadId initUpload(formData)
axios({
url: process.env.VUE_APP_BASE_API + "/common/initUpload",
method: 'post',
data: formData,
headers: {
'Authorization': 'Bearer ' + getToken(),
'Content-Type': 'multipart/form-data'
},
}).then(function (res) {
if (res.status == 200) {
//从第0块开始上传
file.uploadId = res.data.uploadId
file.objectKey = res.data
file.chunkId = 0
self.uploadByChunk(file)
} else {
this.progress--
self.$message.error(res.msg)
}
}).catch(error => {
self.progressPercent = 0
self.progressFlag = false;
console.error(error)
})
}
},
//分片上传大文件
uploadByChunk(file) {
this._start = file.chunkId * this.partSize
this._end = Math.min(file.size, this._start + this.partSize)//结束时总大小,和 开始的大小+之前的大小比较
let self = this
let fileData = file.slice(this._start, this._end)
//获取文件块MD5
let reader = new FileReader()
reader.readAsBinaryString(fileData)
let form1 = new FormData()//new一个form的实例可以进行键值对的添加
form1.append('chunkFile', fileData) //slice方法用于切出文件的一部分
form1.append('uploadId', file.uploadId)
form1.append('chunkId', (file.chunkId + 1).toString())
form1.append('shardCount', file._shardCount.toString()) //是否最后一片
self.progressFlag = true;
//上传大文件的Chunk 返回chunk的MD5 uploadChunk(form1)
axios({
url: process.env.VUE_APP_BASE_API + "/common/uploadChunk",
method: 'post',
data: form1,
headers: {
'Authorization': 'Bearer ' + getToken(),
'Content-Type': 'multipart/form-data'
},
onUploadProgress: progressEvent => {
// progressEvent.loaded:已上传文件大小
// progressEvent.total:被上传文件的总大小
//进度条
self.progressPercent = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
}
}).then(response => {
if (response.status == 200) {
//判断返回的MD5值是否一致一致继续传下一块否则重传本块这里目前前后端MD5一直不一致暂时先注释掉有时间了我再研究一下
// self.md5Str[index] === response.msg ||
if (true) {
// this.$message.success('第' + (index + 1).toString() + '块文件上传成功')
file.uploaded++
self.percentageSend(file)
//如果没上传完成,继续上传一下块
file.chunkId++
if (file.chunkId < file._shardCount) {
this.uploadByChunk(file)
}
} else {
//不一致,重新传本块
this.$message.success('第' + (file.chunkId + 1).toString() + '块文件上传不成功,重新上传')
this.uploadByChunk(file.chunkId)
}
} else {
//出错,跳出循环显示错误
this.progress--
this.$message.error(response.msg)
}
})
},
//接收上传的百分值回调
percentageSend(file) {
let self = this
let perNum = Math.floor((file.uploaded / file._shardCount) * 100)
this.progressPercent = perNum
//如果上传完成,合并文件
if (perNum === 100) {
let form2 = new FormData()//new一个form的实例可以进行键值对的添加
form2.append('uploadId', file.uploadId)
form2.append('fileName', file.name)
// 大文件上传完成后合并
// 返回文件访问的URL
axios({
url: process.env.VUE_APP_BASE_API + "/common/mergeFile",
method: 'post',
data: form2,
headers: {
'Authorization': 'Bearer ' + getToken(),
'Content-Type': 'multipart/form-data'
},
}).then(res => {
if (res.status == 200) {
setTimeout(function () {
self.$message({
message: '上传成功!',
type: 'success',
duration: '2000'
});
self.progressFlag = false;
self.progressPercent = 0
self.handleResult(res,file);
}, 500);
} else {
self.$message({
message: '上传失败!',
type: 'error',
duration: '2000'
});
}
})
}
},
resetData() {
this.progress = 0;
},
handleResult(res, file) {
let self = this
const data = {
fileName: file.name,
fileSize: file.size,
fileUrl: res.data.url,
filePath: res.data.filePath,
fileOldName: res.data.originalFilename,
fileNewName: res.data.newFileName,
suffixType: res.data.suffixType
}
self.$emit("handleSuccess", data)
},
/** 清空文件 **/
clearFile(){
this.$refs.upload.clearFiles();
this.fileList = []
}
}
};
</script>
<style>
#myButton {
width: 90px; /* 设置按钮长度为200像素 */
}
.container {
display: flex; /* 设定为flex布局 */
}
</style>