fix: 统一上传响应与表单校验处理
- 上传组件统一解析后端响应并暴露错误事件 - AI 资源、模型提供商和工作流表单补齐程序化字段校验同步 - 修正 MinIO 对外访问域名配置
This commit is contained in:
@@ -116,7 +116,8 @@ dromara:
|
|||||||
secret-key: easyflowadmin123
|
secret-key: easyflowadmin123
|
||||||
end-point: http://127.0.0.1:39000
|
end-point: http://127.0.0.1:39000
|
||||||
bucket-name: easyflow
|
bucket-name: easyflow
|
||||||
domain: http://127.0.0.1:9000/easyflow/
|
# minio 对象对外访问链接
|
||||||
|
domain: http://127.0.0.1:39000/easyflow/
|
||||||
base-path: attachment
|
base-path: attachment
|
||||||
|
|
||||||
# 自定义节点相关配置
|
# 自定义节点相关配置
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import { useAppConfig } from '@easyflow/hooks';
|
|||||||
import { useAccessStore } from '@easyflow/stores';
|
import { useAccessStore } from '@easyflow/stores';
|
||||||
|
|
||||||
import { UploadFilled } from '@element-plus/icons-vue';
|
import { UploadFilled } from '@element-plus/icons-vue';
|
||||||
import { ElIcon, ElUpload } from 'element-plus';
|
import { ElIcon, ElMessage, ElUpload } from 'element-plus';
|
||||||
|
|
||||||
|
import { normalizeUploadError, resolveUploadPath } from '#/utils/upload-response';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
action: {
|
action: {
|
||||||
@@ -20,7 +22,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'onChange']);
|
const emit = defineEmits(['success', 'error', 'onChange']);
|
||||||
const accessStore = useAccessStore();
|
const accessStore = useAccessStore();
|
||||||
const headers = ref({
|
const headers = ref({
|
||||||
'easyflow-token': accessStore.accessToken,
|
'easyflow-token': accessStore.accessToken,
|
||||||
@@ -32,7 +34,18 @@ const uploadRef = ref<InstanceType<typeof ElUpload>>();
|
|||||||
|
|
||||||
// 上传成功回调
|
// 上传成功回调
|
||||||
const handleSuccess: UploadProps['onSuccess'] = (response) => {
|
const handleSuccess: UploadProps['onSuccess'] = (response) => {
|
||||||
emit('success', response.data.path);
|
try {
|
||||||
|
emit('success', resolveUploadPath(response));
|
||||||
|
} catch (error) {
|
||||||
|
const normalizedError = normalizeUploadError(error);
|
||||||
|
ElMessage.error(normalizedError.message);
|
||||||
|
emit('error', normalizedError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleError: UploadProps['onError'] = (error) => {
|
||||||
|
const normalizedError = normalizeUploadError(error);
|
||||||
|
ElMessage.error(normalizedError.message);
|
||||||
|
emit('error', normalizedError);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 文件状态变化回调
|
// 文件状态变化回调
|
||||||
@@ -66,6 +79,7 @@ defineExpose({
|
|||||||
:headers="headers"
|
:headers="headers"
|
||||||
:action="`${apiURL}${props.action}`"
|
:action="`${apiURL}${props.action}`"
|
||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
|
:on-error="handleError"
|
||||||
:on-change="handleChange"
|
:on-change="handleChange"
|
||||||
multiple
|
multiple
|
||||||
:style="{ display: props.visible ? 'block' : 'none' }"
|
:style="{ display: props.visible ? 'block' : 'none' }"
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import { ref } from 'vue';
|
|||||||
import { useAppConfig } from '@easyflow/hooks';
|
import { useAppConfig } from '@easyflow/hooks';
|
||||||
import { useAccessStore } from '@easyflow/stores';
|
import { useAccessStore } from '@easyflow/stores';
|
||||||
|
|
||||||
import { ElButton, ElUpload } from 'element-plus';
|
import { ElButton, ElMessage, ElUpload } from 'element-plus';
|
||||||
|
|
||||||
|
import { normalizeUploadError, resolveUploadPath } from '#/utils/upload-response';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -31,6 +32,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'success', // 文件上传成功
|
'success', // 文件上传成功
|
||||||
|
'error',
|
||||||
'handleDelete',
|
'handleDelete',
|
||||||
'handlePreview',
|
'handlePreview',
|
||||||
'beforeUpload',
|
'beforeUpload',
|
||||||
@@ -51,7 +53,18 @@ const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
|
|||||||
emit('handleDelete', file, uploadFiles);
|
emit('handleDelete', file, uploadFiles);
|
||||||
};
|
};
|
||||||
const handleSuccess: UploadProps['onSuccess'] = (response) => {
|
const handleSuccess: UploadProps['onSuccess'] = (response) => {
|
||||||
emit('success', response.data.path);
|
try {
|
||||||
|
emit('success', resolveUploadPath(response));
|
||||||
|
} catch (error) {
|
||||||
|
const normalizedError = normalizeUploadError(error);
|
||||||
|
ElMessage.error(normalizedError.message);
|
||||||
|
emit('error', normalizedError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleError: UploadProps['onError'] = (error) => {
|
||||||
|
const normalizedError = normalizeUploadError(error);
|
||||||
|
ElMessage.error(normalizedError.message);
|
||||||
|
emit('error', normalizedError);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -66,6 +79,7 @@ const handleSuccess: UploadProps['onSuccess'] = (response) => {
|
|||||||
:on-remove="handleRemove"
|
:on-remove="handleRemove"
|
||||||
:limit="props.limit"
|
:limit="props.limit"
|
||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
|
:on-error="handleError"
|
||||||
>
|
>
|
||||||
<ElButton type="primary">{{ $t('button.upload') }}</ElButton>
|
<ElButton type="primary">{{ $t('button.upload') }}</ElButton>
|
||||||
</ElUpload>
|
</ElUpload>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { Plus } from '@element-plus/icons-vue';
|
|||||||
import { ElIcon, ElImage, ElMessage, ElUpload } from 'element-plus';
|
import { ElIcon, ElImage, ElMessage, ElUpload } from 'element-plus';
|
||||||
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
import { normalizeUploadError, resolveUploadPath } from '#/utils/upload-response';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
action: {
|
action: {
|
||||||
@@ -39,7 +40,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'update:modelValue']);
|
const emit = defineEmits(['success', 'error', 'update:modelValue']);
|
||||||
const accessStore = useAccessStore();
|
const accessStore = useAccessStore();
|
||||||
const headers = ref({
|
const headers = ref({
|
||||||
'easyflow-token': accessStore.accessToken,
|
'easyflow-token': accessStore.accessToken,
|
||||||
@@ -48,12 +49,24 @@ const headers = ref({
|
|||||||
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
||||||
const localImageUrl = ref(props.modelValue);
|
const localImageUrl = ref(props.modelValue);
|
||||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (
|
const handleAvatarSuccess: UploadProps['onSuccess'] = (
|
||||||
_response,
|
response,
|
||||||
uploadFile,
|
uploadFile,
|
||||||
) => {
|
) => {
|
||||||
|
try {
|
||||||
|
const imageUrl = resolveUploadPath(response);
|
||||||
localImageUrl.value = URL.createObjectURL(uploadFile.raw!);
|
localImageUrl.value = URL.createObjectURL(uploadFile.raw!);
|
||||||
emit('success', _response.data.path);
|
emit('success', imageUrl);
|
||||||
emit('update:modelValue', _response.data.path);
|
emit('update:modelValue', imageUrl);
|
||||||
|
} catch (error) {
|
||||||
|
const normalizedError = normalizeUploadError(error);
|
||||||
|
ElMessage.error(normalizedError.message);
|
||||||
|
emit('error', normalizedError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleAvatarError: UploadProps['onError'] = (error) => {
|
||||||
|
const normalizedError = normalizeUploadError(error);
|
||||||
|
ElMessage.error(normalizedError.message);
|
||||||
|
emit('error', normalizedError);
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -98,6 +111,7 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|||||||
:headers="headers"
|
:headers="headers"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:on-success="handleAvatarSuccess"
|
:on-success="handleAvatarSuccess"
|
||||||
|
:on-error="handleAvatarError"
|
||||||
:before-upload="beforeAvatarUpload"
|
:before-upload="beforeAvatarUpload"
|
||||||
>
|
>
|
||||||
<ElImage
|
<ElImage
|
||||||
|
|||||||
25
easyflow-ui-admin/app/src/utils/form-validation.ts
Normal file
25
easyflow-ui-admin/app/src/utils/form-validation.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import type { FormInstance, FormItemProp } from 'element-plus';
|
||||||
|
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
|
||||||
|
type FormRef = Ref<FormInstance | null | undefined>;
|
||||||
|
|
||||||
|
export async function syncProgrammaticFieldValidation(
|
||||||
|
formRef: FormRef,
|
||||||
|
fields?: Array<FormItemProp>,
|
||||||
|
) {
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
if (!formRef.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fields || fields.length === 0) {
|
||||||
|
formRef.value.clearValidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
formRef.value.clearValidate(fields);
|
||||||
|
}
|
||||||
59
easyflow-ui-admin/app/src/utils/upload-response.ts
Normal file
59
easyflow-ui-admin/app/src/utils/upload-response.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
|
interface UploadResponseData {
|
||||||
|
path?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UploadResponseBody {
|
||||||
|
data?: UploadResponseData;
|
||||||
|
errorCode?: number;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMessageFromUnknown(error: unknown) {
|
||||||
|
if (typeof error === 'string' && error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error || typeof error !== 'object') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const raw = error as {
|
||||||
|
message?: unknown;
|
||||||
|
response?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof raw.message === 'string' && raw.message) {
|
||||||
|
return raw.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof raw.response === 'string' && raw.response) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw.response) as UploadResponseBody;
|
||||||
|
return parsed.message || '';
|
||||||
|
} catch {
|
||||||
|
return raw.response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeUploadError(error: unknown) {
|
||||||
|
const message = getMessageFromUnknown(error);
|
||||||
|
return new Error(message || $t('cropper.message.uploadFailed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveUploadPath(response: UploadResponseBody) {
|
||||||
|
if (!response || response.errorCode !== 0) {
|
||||||
|
throw new Error(response?.message || $t('cropper.message.uploadFailed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = response.data?.path;
|
||||||
|
if (!path) {
|
||||||
|
throw new Error($t('cropper.message.notUrl'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import {ElForm, ElFormItem, ElIcon, ElInput, ElMessage, ElOption, ElSelect,} fro
|
|||||||
import {api} from '#/api/request';
|
import {api} from '#/api/request';
|
||||||
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
|
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
|
||||||
import {$t} from '#/locales';
|
import {$t} from '#/locales';
|
||||||
|
import {syncProgrammaticFieldValidation} from '#/utils/form-validation';
|
||||||
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
|
import ModelProviderBadge from '#/views/ai/model/ModelProviderBadge.vue';
|
||||||
import {getProviderPresetByValue, providerPresets,} from '#/views/ai/model/modelUtils/defaultIcon';
|
import {getProviderPresetByValue, providerPresets,} from '#/views/ai/model/modelUtils/defaultIcon';
|
||||||
|
|
||||||
@@ -132,6 +133,14 @@ const applyPreset = (value: string) => {
|
|||||||
formData.chatPath = preset.options.chatPath || '';
|
formData.chatPath = preset.options.chatPath || '';
|
||||||
formData.embedPath = preset.options.embedPath || '';
|
formData.embedPath = preset.options.embedPath || '';
|
||||||
formData.rerankPath = preset.options.rerankPath || '';
|
formData.rerankPath = preset.options.rerankPath || '';
|
||||||
|
syncProgrammaticFieldValidation(formDataRef, [
|
||||||
|
'providerType',
|
||||||
|
'providerName',
|
||||||
|
'endpoint',
|
||||||
|
'chatPath',
|
||||||
|
'embedPath',
|
||||||
|
'rerankPath',
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { api } from '#/api/request';
|
|||||||
import DictSelect from '#/components/dict/DictSelect.vue';
|
import DictSelect from '#/components/dict/DictSelect.vue';
|
||||||
import Upload from '#/components/upload/Upload.vue';
|
import Upload from '#/components/upload/Upload.vue';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
import { syncProgrammaticFieldValidation } from '#/utils/form-validation';
|
||||||
|
|
||||||
const emit = defineEmits(['reload']);
|
const emit = defineEmits(['reload']);
|
||||||
// vue
|
// vue
|
||||||
@@ -20,50 +21,50 @@ defineExpose({
|
|||||||
openDialog,
|
openDialog,
|
||||||
});
|
});
|
||||||
const saveForm = ref<FormInstance>();
|
const saveForm = ref<FormInstance>();
|
||||||
|
const createDefaultEntity = () => ({
|
||||||
|
categoryId: '',
|
||||||
|
deptId: '',
|
||||||
|
fileSize: '',
|
||||||
|
options: '',
|
||||||
|
origin: '',
|
||||||
|
resourceName: '',
|
||||||
|
resourceType: '',
|
||||||
|
resourceUrl: '',
|
||||||
|
status: 0,
|
||||||
|
suffix: '',
|
||||||
|
});
|
||||||
// variables
|
// variables
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
const isAdd = ref(true);
|
const isAdd = ref(true);
|
||||||
const entity = ref<any>({
|
const entity = ref<any>(createDefaultEntity());
|
||||||
deptId: '',
|
|
||||||
resourceType: '',
|
|
||||||
resourceName: '',
|
|
||||||
suffix: '',
|
|
||||||
resourceUrl: '',
|
|
||||||
origin: '',
|
|
||||||
status: '',
|
|
||||||
options: '',
|
|
||||||
fileSize: '',
|
|
||||||
});
|
|
||||||
const btnLoading = ref(false);
|
const btnLoading = ref(false);
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
deptId: [
|
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
|
||||||
],
|
|
||||||
resourceType: [
|
resourceType: [
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
{ required: true, message: $t('message.required'), trigger: 'change' },
|
||||||
],
|
],
|
||||||
resourceName: [
|
resourceName: [
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
{
|
||||||
],
|
required: true,
|
||||||
suffix: [
|
message: $t('message.required'),
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
resourceUrl: [
|
resourceUrl: [
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
{ required: true, message: $t('message.required'), trigger: 'change' },
|
||||||
],
|
],
|
||||||
origin: [
|
origin: [
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
{ required: true, message: $t('message.required'), trigger: 'change' },
|
||||||
],
|
|
||||||
status: [
|
|
||||||
{ required: true, message: $t('message.required'), trigger: 'blur' },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
function openDialog(row: any) {
|
function openDialog(row: any) {
|
||||||
if (row.id) {
|
isAdd.value = !row?.id;
|
||||||
isAdd.value = false;
|
entity.value = {
|
||||||
}
|
...createDefaultEntity(),
|
||||||
entity.value = row;
|
...row,
|
||||||
|
status: row?.status ?? 0,
|
||||||
|
};
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
}
|
}
|
||||||
function save() {
|
function save() {
|
||||||
@@ -92,20 +93,33 @@ function save() {
|
|||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
saveForm.value?.resetFields();
|
saveForm.value?.resetFields();
|
||||||
isAdd.value = true;
|
isAdd.value = true;
|
||||||
entity.value = {};
|
entity.value = createDefaultEntity();
|
||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
}
|
}
|
||||||
function beforeUpload(f: any) {
|
function beforeUpload(f: any) {
|
||||||
const fName = f?.name?.split('.')[0];
|
const fileName = f?.name || '';
|
||||||
const fExt = f?.name?.split('.')[1];
|
const fileNameParts = fileName.split('.');
|
||||||
|
const fExt = fileNameParts.length > 1 ? fileNameParts.at(-1) || '' : '';
|
||||||
|
const fName =
|
||||||
|
fileNameParts.length > 1 ? fileNameParts.slice(0, -1).join('.') : fileName;
|
||||||
entity.value.resourceType = getResourceType(fExt);
|
entity.value.resourceType = getResourceType(fExt);
|
||||||
entity.value.resourceName = fName;
|
entity.value.resourceName = fName;
|
||||||
entity.value.suffix = fExt;
|
entity.value.suffix = fExt;
|
||||||
entity.value.fileSize = f.size;
|
entity.value.fileSize = f.size;
|
||||||
entity.value.origin = 0;
|
entity.value.origin = 0;
|
||||||
|
syncProgrammaticFieldValidation(saveForm, [
|
||||||
|
'origin',
|
||||||
|
'resourceName',
|
||||||
|
'resourceType',
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
function uploadSuccess(res: any) {
|
function uploadSuccess(res: any) {
|
||||||
entity.value.resourceUrl = res;
|
entity.value.resourceUrl = res;
|
||||||
|
syncProgrammaticFieldValidation(saveForm, ['resourceUrl']);
|
||||||
|
}
|
||||||
|
function uploadError() {
|
||||||
|
entity.value.resourceUrl = '';
|
||||||
|
syncProgrammaticFieldValidation(saveForm, ['resourceUrl']);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -129,7 +143,11 @@ function uploadSuccess(res: any) {
|
|||||||
class="easyflow-modal-form easyflow-modal-form--compact"
|
class="easyflow-modal-form easyflow-modal-form--compact"
|
||||||
>
|
>
|
||||||
<ElFormItem prop="resourceUrl" :label="$t('aiResource.resourceUrl')">
|
<ElFormItem prop="resourceUrl" :label="$t('aiResource.resourceUrl')">
|
||||||
<Upload @before-upload="beforeUpload" @success="uploadSuccess" />
|
<Upload
|
||||||
|
@before-upload="beforeUpload"
|
||||||
|
@success="uploadSuccess"
|
||||||
|
@error="uploadError"
|
||||||
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem prop="origin" :label="$t('aiResource.origin')">
|
<ElFormItem prop="origin" :label="$t('aiResource.origin')">
|
||||||
<DictSelect v-model="entity.origin" dict-code="resourceOriginType" />
|
<DictSelect v-model="entity.origin" dict-code="resourceOriginType" />
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import DictSelect from '#/components/dict/DictSelect.vue';
|
|||||||
// import Cropper from '#/components/upload/Cropper.vue';
|
// import Cropper from '#/components/upload/Cropper.vue';
|
||||||
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
|
import UploadAvatar from '#/components/upload/UploadAvatar.vue';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
import { syncProgrammaticFieldValidation } from '#/utils/form-validation';
|
||||||
|
|
||||||
const emit = defineEmits(['reload']);
|
const emit = defineEmits(['reload']);
|
||||||
// vue
|
// vue
|
||||||
@@ -66,18 +67,18 @@ function openDialog(row: any, importMode = false) {
|
|||||||
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||||
jsonFile.value = file;
|
jsonFile.value = file;
|
||||||
uploadFileList.value = [file];
|
uploadFileList.value = [file];
|
||||||
saveForm.value?.clearValidate('jsonFile');
|
syncProgrammaticFieldValidation(saveForm, ['jsonFile']);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
const handleChange: UploadProps['onChange'] = (file, fileList) => {
|
const handleChange: UploadProps['onChange'] = (file, fileList) => {
|
||||||
jsonFile.value = file.raw;
|
jsonFile.value = file.raw;
|
||||||
uploadFileList.value = fileList.slice(-1);
|
uploadFileList.value = fileList.slice(-1);
|
||||||
saveForm.value?.clearValidate('jsonFile');
|
syncProgrammaticFieldValidation(saveForm, ['jsonFile']);
|
||||||
};
|
};
|
||||||
const handleRemove: UploadProps['onRemove'] = () => {
|
const handleRemove: UploadProps['onRemove'] = () => {
|
||||||
jsonFile.value = null;
|
jsonFile.value = null;
|
||||||
uploadFileList.value = [];
|
uploadFileList.value = [];
|
||||||
saveForm.value?.clearValidate('jsonFile');
|
syncProgrammaticFieldValidation(saveForm, ['jsonFile']);
|
||||||
};
|
};
|
||||||
function save() {
|
function save() {
|
||||||
saveForm.value?.validate((valid) => {
|
saveForm.value?.validate((valid) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user