<script lang="ts" setup>
import { PropType, reactive, Ref, ref, toRefs } from 'vue';
import type { UploadFile } from 'element-plus/es/components/upload/src/upload';
import { IUploadConfig } from '@/model/base-interface';
import $http from '@/utils/http-service';
import { genFileId } from 'element-plus';
const props = defineProps({
data: {
type: Object as PropType<IUploadConfig>,
required: true,
default: () => {
return {};
}
},
fileList: {
type: Array,
default: () => {
return [];
}
},
disabled: {
type: Boolean,
default: () => false
}
});
const { data, fileList } = toRefs(props);
const uploadConfig = reactive(data.value);
interface RawFile {
name: string;
url: string;
}
const fileItem: Ref<UploadFile | null> = ref(null);
const upload = ref();
const isError = ref(false);
const errorMsg = ref('');
const handleSuccess = (response: any, file: UploadFile, list: UploadFile[]) => {
if (uploadConfig.onSuccess) {
uploadConfig.onSuccess(response, file, list);
}
};
const handleError = (error: any, file: UploadFile, list: UploadFile[]) => {
isError.value = true;
if (uploadConfig.onError) {
uploadConfig.onError(error, file, list);
}
};
const handleChange = (file: UploadFile, list: UploadFile[]) => {
if (file.status === 'ready' && uploadConfig.onAddItem) {
fileItem.value = file;
isError.value = false;
errorMsg.value = '';
isError.value = !uploadConfig.onAddItem(file, list, errorMsg, upload.value);
if (isError.value) {
} else {
if (uploadConfig.onAddItemSuccess) {
uploadConfig.onAddItemSuccess(file);
}
}
}
};
const handleExceed = (files: UploadFile[]) => {
if (uploadConfig.onExceed) {
upload.value!.clearFiles();
const file = files[0] as UploadRawFile;
file.uid = genFileId();
upload.value!.handleStart(file);
uploadConfig.onExceed(files);
}
};
const handleRemove = (file: UploadFile, list: UploadFile[]) => {
if (uploadConfig.limit === 1) {
isError.value = false;
errorMsg.value = '';
}
if (uploadConfig.onRemove) {
uploadConfig.onRemove(file, list);
}
};
const handleBeforeUpload = (file: UploadFile) => {
if (uploadConfig.onBeforeUpload) {
const result = Boolean(uploadConfig.onBeforeUpload(file)) || false;
return !result;
}
return true;
};
const handleBeforeRemove = (file: UploadFile, list: UploadFile[]) => {
if (uploadConfig.onBeforeRemove) {
uploadConfig.onBeforeRemove(file, list);
}
};
const handleRequest = (param: UploadFile) => {
if (uploadConfig.onHttpRequest) {
uploadConfig.onHttpRequest(param);
}
};
const customUpload = (options: any): Promise<any> => {
return new Promise((resolve, reject) => {
let header = {
headers: {}
};
header.headers = uploadConfig.headers;
const url = uploadConfig.action as string;
const param = options.formData;
if (uploadConfig.isCustomUpload) {
$http
.post(url, param, header)
.then(res => {
resolve(res);
})
.catch(error => {
reject(error);
});
} else {
reject(new Error('failed'));
}
});
};
defineExpose({
clear: () => {
if (fileItem.value !== null) {
upload.value.handleRemove(fileItem.value);
}
},
setError: (msg: string) => {
isError.value = true;
errorMsg.value = msg;
},
clearError: () => {
isError.value = false;
errorMsg.value = '';
},
customUpload
});
</script>
<template>
<div class="multi-file-upload">
<el-upload
:id="uploadConfig.id || 'fileUpload'"
ref="upload"
:multiple="uploadConfig.multiple"
:limit="uploadConfig.limit"
:show-file-list="uploadConfig.showFileList || true"
:disabled="disabled"
:action="uploadConfig.action"
:name="uploadConfig.name"
:file-list="fileList"
:auto-upload="uploadConfig.isAutoUpload"
:accept="uploadConfig.accept"
:on-success="handleSuccess"
:on-exceed="handleExceed"
:on-error="handleError"
:on-remove="handleRemove"
:on-change="handleChange"
:before-upload="handleBeforeUpload"
:before-remove="handleBeforeRemove"
:http-request="handleRequest"
>
<div class="upload-button" :class="{ disabled: disabled }" :disabled="disabled">
{{ $t('ADD_FILE_BTN') }}
</div>
<template #tip>
<div class="el-upload__tip">{{ uploadConfig.tip }}</div>
</template>
</el-upload>
<span v-if="isError && errorMsg" :id="uploadConfig.errorMsgId" class="error-text">
{{ errorMsg }}
</span>
</div>
</template>
<style lang="scss" scoped>
.upload-button {
color: var(--o-color-primary);
&.disabled {
color: var(--o-text-color-tertiary);
}
}
.error-text {
color: var(--o-color-danger);
}
:deep(.el-upload-list__item.is-success .el-upload-list__item-status-label) {
top: 0;
}
.el-upload-list__item :hover {
background-color: #fdfeff;
}
</style>