支持功能:多文件上传,单文件上传,文件类型限制,文件大小限制,文件个数限制(主要针对多文件上传)
<template>
<div>
<a-spin :spinning="spinning">
<a-upload
method="post"
:disabled="disabled"
:list-type="listType"
:data="paramObj"
:headers="headers"
:multiple="multiple"
:accept="fileFormat"
:action="action"
:fileList="imageProfile"
:remove="removeFile"
:showUploadList="showUploadList"
:before-upload="beforeUpload"
@preview="previewFile"
:customRequest="handleCustomRequest"
>
<a-button :type="uploadBtnType">
<a-icon type="upload" /> {{ uploadBtnName }}
</a-button>
</a-upload>
</a-spin>
<!-- 文件预览弹框-->
<Modal
:visible.sync="visible"
:isShowBtn="false"
width="48%"
:keyboardAndMaskClosable="true"
:title="dialogImageUrl.name"
@cancel="handlelose"
>
<template #content>
<img
:alt="dialogImageUrl.name"
:src="dialogImageUrl.url"
:title="dialogImageUrl.name"
class="modal_img"
/>
</template>
</Modal>
</div>
</template>
<script>
import { getAuthorization } from "@/utils/request";
import { getFileExtension } from "@/utils/file-util";
import { patchUpload } from "./api/fileApi";
import {Spin} from 'ant-design-vue'
export default {
name: "upload",
components: {
Modal: () => import("@/components/Modal"),
},
props: {
//按钮名称
uploadBtnName: {
type: String,
default: "上传文件",
},
// 默认按钮类型
uploadBtnType: {
type: String,
default: null,
},
//其他额外参数
params: {
type: [String, Object],
default: () => "",
},
//显示列表
listType: {
type: String,
default: "picture",
},
//用于展示的图片地址
fileList: {
type: [Array, String],
default: function () {
return [];
},
},
//是否支持多文件上传
multiple: {
type: Boolean,
default: false,
},
//允许的上传文件个数, 用于支持多文件上传 0:则表示无限制
fileNumber: {
type: Number,
default: 1,
},
//文件格式
fileFormat: {
type: String,
default: ".jpg,.jpeg,.pdf,.png,.doc,.docx,.svg",
},
//文件上传地址
action: {
type: String,
default: "/prize/uploadPic",
},
// 允许的上传文件类型的大小
fileSizeLimit: {
type: Number,
default: 50,
},
//是否禁用
disabled: {
type: Boolean,
default: false,
},
showUploadList: {
type: Boolean,
default: true,
},
},
data() {
return {
token: getAuthorization(),
imageProfile: [],
Authorization: "",
paramObj: {},
visible: false,
dialogImageUrl: "",
imageProfile: [], //文件内容
spinning: false,
};
},
watch: {
fileList: {
handler(val) {
this.imageProfile = val;
},
deep: true,
immediate: true
}
},
computed: {
headers() {
return {
Authorization: this.token,
};
},
},
created() {
// console.log("upload-created");
this.token = getAuthorization();
},
methods: {
//自定义文件上传
async handleCustomRequest(data) {
this.spinning = true;
const formData = new FormData();
formData.append("file", data.file);
let progress = { percent: 1 }; //进度条
let speed = 100 / (data.file.size / 65000);
const intervalId = setInterval(() => {
if (progress.percent < 100) {
progress.percent += speed;
data.onProgress(progress);
} else {
clearInterval(intervalId);
}
}, 100);
let res = await patchUpload(formData);
this.spinning = false
if (res.status === 200) {
data.onSuccess();
data.file.status = "done";
this.handleOnSuccess(res, data.file);
this.$message.success("文件上传成功!");
} else {
data.file.status = "error";
data.onError();
this.handleError(res, data.file);
this.$message.error("上传失败,请重试!");
}
},
//文件上传成功
handleOnSuccess({ url }, file) {
if (typeof this.imageProfile === "string") {
this.imageProfile = [];
}
let name = null;
if (url) name = url.substr(url.lastIndexOf("/") + 1, url.length);
let uid = name + new Date()
if(file && file.uid) uid = file.uid
let obj = {
uid,
name,
status: "done",
thumbUrl: url,
url,
};
if (this.multiple) {
//可以上传多张
this.imageProfile.push(obj);
} else {
//不能上传多张
if (this.imageProfile.length > 0) {
this.imageProfile.splice(0, this.imageProfile.length);
}
this.imageProfile.push(obj);
}
let errorList = this.imageProfile.filter(
(item) => item.status === "error"
);
if (errorList.length) {
this.$message.error("尚有未成功上传的文件,请删除后操作!");
return;
}
this.$emit("upload-success", { fileList: this.imageProfile });
},
//文件上传失败
handleError(err) {
if (err.status === 403 || err.status === 401) {
Modal.warning({
content: "该账号已在其他设备登录,您已被强制下线!",
closable: false,
destroyOnClose: true,
keyboard: false,
maskClosable: false,
okText: "重新登录",
title: "温馨提示",
onOk: () => {
store.dispatch("user/resetToken").then(() => {
location.reload();
});
},
});
}
},
//上传前校验
beforeUpload(file) {
// console.log("beforeUpload:", file);
//文件上传前额外参数
this.paramObj = {
...this.params,
FileName: file.name,
};
const extension = getFileExtension(file.name); //获取文件后缀名
const isRight = this.fileFormat.indexOf(extension) > -1;
const isPass = file.size / 1024 / 1024 < this.fileSizeLimit; //文件大小
if (!isRight) {
this.$message.error(
`文件上传类型不正确,请上传后缀名为 ${this.fileFormat} 的文件 !`
);
} else if (!isPass) {
this.$message.error(
`请检查上传文件大小是否超过${this.fileSizeLimit}MB`
);
return false;
} else if (this.imageProfile.length >= this.fileNumber && this.multiple && this.fileNumber > 0) {
//多文件上传,才限制文件个数
this.$message.error(
`当前限制选择 ${this.fileNumber} 个文件,请删除后再上传`
);
return false;
}
return isRight;
},
//文件移除
removeFile(file) {
// console.log("文件移除", file);
let index = this.imageProfile.findIndex((item) => item.uid === file.uid);
if(index >= 0) {
this.imageProfile.splice(index, 1);
this.$emit("upload-success", { fileList: this.imageProfile });
} else {
this.$message.error("文件移除查找index下标失败!")
}
},
//文件预览
previewFile(file) {
this.dialogImageUrl = {
name: file.name,
url: file.url || file.thumbUrl,
};
this.visible = true;
},
//预览弹框关闭
handlelose() {
this.visible = false;
},
},
};
</script>
<style lang="less" scoped>
.modal_img {
width: 100%;
object-fit: cover;
}
</style>