问题:antd自定义上传customRequest时,无法正常显示上传成功状态,一直在上传的loading状态中。
查看customRequest参数
解决方法:调用onSuccess事件,解决loading一直加载的问题。
<template>
<a-upload
ref="filesUpload"
:class="['isbm-files-upload', { 'hidden-upload-button': !showUploadButton }]"
v-model:file-list="innerFileList"
:action="action"
:data="data"
:accept="accept"
:disabled="disabled"
:multiple="multiple"
:maxCount="maxCount"
:show-upload-list="{ showPreviewIcon: true, showDownloadIcon: true, showRemoveIcon: true }"
:beforeUpload="beforeUpload"
:customRequest="customRequest"
@preview="handlePreview"
@change="handleChange"
@download="handleDownload"
@remove="handleRemove"
>
<div>
<a-button :type="buttonType" :disabled="disabled">
<template #icon><upload-outlined></upload-outlined></template>
上传附件
</a-button>
</div>
<template #downloadIcon>下载</template>
<template #removeIcon>删除</template>
</a-upload>
</template>
<script setup>
import { ref, computed, getCurrentInstance } from 'vue';
import { UploadOutlined } from '@ant-design/icons-vue';
import fileRequest from '@/config/fileRequest.js';
import { getFileType, downloadNormal } from '@/utils';
const props = defineProps({
action: {
// 自定义上传的地址
type: String,
default: '/system/file/upload' // 默认上传地址
},
data: {
type: Object,
default() {
return {
bizType: ''
};
}
},
fileList: {
type: Array,
default() {
return [];
}
},
disabled: {
// 是否禁用
type: Boolean,
default: false
},
showUploadButton: {
// 是否显示上传按钮
type: Boolean,
default: true
},
multiple: {
// 是否支持多选文件
type: Boolean,
default: false
},
maxCount: {
// 限制上传数量
type: Number,
default: undefined
},
maxSize: {
type: Number,
default: 200 //单位:M
},
accept: {
// 接受上传的文件类型
type: String,
default:
'.bmp, .jpg, .jpeg, .png, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt, .rar, .zip, .3gpp, .mp4, .mpeg, .mov, .m4v, .mng, .avi, .mid, .midi, .mp3, .m4a, .dwg, .pdf, .mpp, .wav, .wps'
},
uploadNotice: {
// 下标提示
type: String,
default:
'支持扩展名:.bmp, .jpg, .jpeg, .png, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt, .rar, .zip, .3gpp, .mp4, .mpeg, .mov, .m4v, .mng, .avi, .mid, .midi, .mp3, .m4a, .dwg, .pdf, .mpp, .wav, .wps'
},
customActionConfig: {
// 使用自定义上传的相关配置,目前主要是请求参数,后期可以拓展,在watch中初始化参数
type: Object,
// default(rawProps) {
// return { message: 'hello' }
// }
default() {
return {};
}
},
visible: {
type: Boolean,
default: false
},
buttonType: {
type: String,
default: 'primary'
}
});
const emit = defineEmits(['update:fileList', 'onExceed', 'remove']);
const { proxy } = getCurrentInstance();
const filesUpload = ref(null);
const innerFileList = computed({
get() {
return props.fileList;
},
set(value) {
emit('update:fileList', value);
}
});
// 上传文件之前的钩子
const beforeUpload = (file, fileList) => {
// fileList 只包含了当次上传的文件列表,不包含已上传的文件列表
if (props.maxCount && innerFileList.value.length + fileList.length > props.maxCount) {
console.log(innerFileList.value.length);
proxy.$message.error(`上传文件数量超出最大限制${props.maxCount}个`);
emit('onExceed', file);
return false;
}
if (file.size / 1024 / 1024 > props.maxSize) {
proxy.$message.error(`上传文件超出最大限制${props.maxSize}M`);
emit('onExceed', file);
return false;
}
const suffix = getFileType(file.name); // 获取文件后缀名
if (props.accept.indexOf(suffix) === -1 && props.accept.indexOf('image') === -1) {
proxy.$message.error('文件格式错误');
return false;
}
// return false 时status为undefined
return true;
};
// 自定义上传
const customRequest = (event) => {
const formData = new FormData();
if (event.data) {
Object.keys(event.data).forEach((key) => {
formData.append(key, event.data[key]);
});
}
formData.append(event.filename, event.file);
fileRequest
.post(event.action, formData, { withCredentials: event.withCredentials })
.then((res) => {
event.onSuccess(res, event.file); //上传成功监听事件
})
.catch((err) => {
event.onError(err, err, event.file); //上传失败监听事件,onError 第二个参数要是字符串才能显示错误原因
proxy.$message.error(event.file.name + err);
});
};
const handleChange = (event) => {
const fileList = event.fileList;
// const file = event.file;
// const status = file.status; // 状态有:uploading done error removed; 另外beforeUpload钩子函数中return false 时,status为undefined
// if (status === 'uploading') {
// loading.value = true;
// } else if (status === 'done') {
// loading.value = false;
// } else if (status === 'error') {
// loading.value = false;
// } else if (status === 'removed') {
// console.log('removed');
// } else if (status === undefined) {
// console.log('reject');
// }
innerFileList.value = fileList.filter((file) => ['uploading', 'done'].includes(file.status));
};
const handleDownload = (file) => {
downloadNormal(file.response.pk, file.response.name);
};
const handlePreview = (file) => {
window.open(file.response.url);
};
const handleRemove = (file) => {
emit('remove', file);
return true;
};
</script>
<style lang="less" scoped>
.isbm-files-upload {
&.hidden-upload-button {
:deep(.ant-upload.ant-upload-select) {
display: none;
}
}
.file-question-circle {
margin-left: 6px;
color: var(--isbm-disabled-color);
}
:deep(span.ant-upload-list-item-name) {
color: #1890ff;
background-color: transparent;
cursor: pointer;
}
}
</style>