feat(upload prop:maxSize): from Upload component accept prop maxSize (AI prompt fixed) (#7059)

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize

* feat(upload prop:maxSize): from component accept prop maxSize
This commit is contained in:
JyQAQ
2026-01-03 13:19:40 +08:00
committed by GitHub
parent 7d2bc2e885
commit 81a61558cb
5 changed files with 323 additions and 293 deletions

View File

@@ -29,7 +29,7 @@ import { IconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { isEmpty } from '@vben/utils'; import { isEmpty } from '@vben/utils';
import { notification } from 'ant-design-vue'; import { message, notification } from 'ant-design-vue';
const AutoComplete = defineAsyncComponent( const AutoComplete = defineAsyncComponent(
() => import('ant-design-vue/es/auto-complete'), () => import('ant-design-vue/es/auto-complete'),
@@ -119,75 +119,7 @@ const withDefaultPlaceholder = <T extends Component>(
}; };
const withPreviewUpload = () => { const withPreviewUpload = () => {
return defineComponent({ // 创建默认的上传按钮插槽
name: Upload.name,
emits: ['change', 'update:modelValue'],
setup: (
props: any,
{ attrs, slots, emit }: { attrs: any; emit: any; slots: any },
) => {
const previewVisible = ref<boolean>(false);
const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`);
const listType = attrs?.listType || attrs?.['list-type'] || 'text';
const fileList = ref<UploadProps['fileList']>(
attrs?.fileList || attrs?.['file-list'] || [],
);
const handleChange = async (event: UploadChangeParam) => {
fileList.value = event.fileList;
emit('change', event);
emit(
'update:modelValue',
event.fileList?.length ? fileList.value : undefined,
);
};
const handlePreview = async (file: UploadFile) => {
previewVisible.value = true;
await previewImage(file, previewVisible, fileList);
};
const renderUploadButton = (): any => {
const isDisabled = attrs.disabled;
// 如果禁用,不渲染上传按钮
if (isDisabled) {
return null;
}
// 否则渲染默认上传按钮
return isEmpty(slots)
? createDefaultSlotsWithUpload(listType, placeholder)
: slots;
};
// 可以监听到表单API设置的值
watch(
() => attrs.modelValue,
(res) => {
fileList.value = res;
},
);
return () =>
h(
Upload,
{
...props,
...attrs,
fileList: fileList.value,
onChange: handleChange,
onPreview: handlePreview,
},
renderUploadButton(),
);
},
});
};
const createDefaultSlotsWithUpload = ( const createDefaultSlotsWithUpload = (
listType: string, listType: string,
placeholder: string, placeholder: string,
@@ -215,7 +147,7 @@ const createDefaultSlotsWithUpload = (
} }
} }
}; };
// 构建预览图片组
const previewImage = async ( const previewImage = async (
file: UploadFile, file: UploadFile,
visible: Ref<boolean>, visible: Ref<boolean>,
@@ -249,7 +181,7 @@ const previewImage = async (
} else if (file.preview) { } else if (file.preview) {
window.open(file.preview, '_blank'); window.open(file.preview, '_blank');
} else { } else {
console.warn('无法打开文件没有可用的URL或预览地址'); message.error($t('ui.formRules.previewWarning'));
} }
return; return;
} }
@@ -327,6 +259,85 @@ const previewImage = async (
render(h(PreviewWrapper), container); render(h(PreviewWrapper), container);
}; };
return defineComponent({
name: Upload.name,
emits: ['update:modelValue'],
setup: (
props: any,
{ attrs, slots, emit }: { attrs: any; emit: any; slots: any },
) => {
const previewVisible = ref<boolean>(false);
const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`);
const listType = attrs?.listType || attrs?.['list-type'] || 'text';
const fileList = ref<UploadProps['fileList']>(
attrs?.fileList || attrs?.['file-list'] || [],
);
const handleBeforeUpload = (file: UploadFile) => {
if (attrs.maxSize && (file.size || 0) / 1024 / 1024 > attrs.maxSize) {
message.error($t('ui.formRules.sizeLimit', [attrs.maxSize]));
file.status = 'removed';
return false;
}
return attrs.beforeUpload?.(file) ?? true;
};
const handleChange = async (event: UploadChangeParam) => {
fileList.value = event.fileList.filter(
(file) => file.status !== 'removed',
);
emit(
'update:modelValue',
event.fileList?.length ? fileList.value : undefined,
);
};
const handlePreview = async (file: UploadFile) => {
previewVisible.value = true;
await previewImage(file, previewVisible, fileList);
};
const renderUploadButton = (): any => {
const isDisabled = attrs.disabled;
// 如果禁用,不渲染上传按钮
if (isDisabled) {
return null;
}
// 否则渲染默认上传按钮
return isEmpty(slots)
? createDefaultSlotsWithUpload(listType, placeholder)
: slots;
};
// 可以监听到表单API设置的值
watch(
() => attrs.modelValue,
(res) => {
fileList.value = res;
},
);
return () =>
h(
Upload,
{
...props,
...attrs,
fileList: fileList.value,
beforeUpload: handleBeforeUpload,
onChange: handleChange,
onPreview: handlePreview,
},
renderUploadButton(),
);
},
});
};
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType = export type ComponentType =

View File

@@ -7,7 +7,9 @@
"length": "{0} must be {1} characters long", "length": "{0} must be {1} characters long",
"alreadyExists": "{0} `{1}` already exists", "alreadyExists": "{0} `{1}` already exists",
"startWith": "{0} must start with `{1}`", "startWith": "{0} must start with `{1}`",
"invalidURL": "Please input a valid URL" "invalidURL": "Please input a valid URL",
"sizeLimit": "The file size cannot exceed {0}MB",
"previewWarning": "Unable to open the file, there is no available URL or preview address"
}, },
"actionTitle": { "actionTitle": {
"edit": "Modify {0}", "edit": "Modify {0}",
@@ -24,7 +26,8 @@
}, },
"placeholder": { "placeholder": {
"input": "Please enter", "input": "Please enter",
"select": "Please select" "select": "Please select",
"upload": "Click to upload"
}, },
"captcha": { "captcha": {
"title": "Please complete the security verification", "title": "Please complete the security verification",

View File

@@ -7,7 +7,9 @@
"length": "{0}长度必须为{1}个字符", "length": "{0}长度必须为{1}个字符",
"alreadyExists": "{0} `{1}` 已存在", "alreadyExists": "{0} `{1}` 已存在",
"startWith": "{0}必须以 {1} 开头", "startWith": "{0}必须以 {1} 开头",
"invalidURL": "请输入有效的链接" "invalidURL": "请输入有效的链接",
"sizeLimit": "文件大小不能超过 {0}MB",
"previewWarning": "无法打开文件没有可用的URL或预览地址"
}, },
"actionTitle": { "actionTitle": {
"edit": "修改{0}", "edit": "修改{0}",
@@ -24,7 +26,8 @@
}, },
"placeholder": { "placeholder": {
"input": "请输入", "input": "请输入",
"select": "请选择" "select": "请选择",
"upload": "点击上传"
}, },
"captcha": { "captcha": {
"title": "请完成安全验证", "title": "请完成安全验证",

View File

@@ -29,7 +29,7 @@ import { IconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { isEmpty } from '@vben/utils'; import { isEmpty } from '@vben/utils';
import { notification } from 'ant-design-vue'; import { message, notification } from 'ant-design-vue';
const AutoComplete = defineAsyncComponent( const AutoComplete = defineAsyncComponent(
() => import('ant-design-vue/es/auto-complete'), () => import('ant-design-vue/es/auto-complete'),
@@ -128,75 +128,7 @@ const withDefaultPlaceholder = <T extends Component>(
}; };
const withPreviewUpload = () => { const withPreviewUpload = () => {
return defineComponent({ // 创建默认的上传按钮插槽
name: Upload.name,
emits: ['change', 'update:modelValue'],
setup: (
props: any,
{ attrs, slots, emit }: { attrs: any; emit: any; slots: any },
) => {
const previewVisible = ref<boolean>(false);
const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`);
const listType = attrs?.listType || attrs?.['list-type'] || 'text';
const fileList = ref<UploadProps['fileList']>(
attrs?.fileList || attrs?.['file-list'] || [],
);
const handleChange = async (event: UploadChangeParam) => {
fileList.value = event.fileList;
emit('change', event);
emit(
'update:modelValue',
event.fileList?.length ? fileList.value : undefined,
);
};
const handlePreview = async (file: UploadFile) => {
previewVisible.value = true;
await previewImage(file, previewVisible, fileList);
};
const renderUploadButton = (): any => {
const isDisabled = attrs.disabled;
// 如果禁用,不渲染上传按钮
if (isDisabled) {
return null;
}
// 否则渲染默认上传按钮
return isEmpty(slots)
? createDefaultSlotsWithUpload(listType, placeholder)
: slots;
};
// 可以监听到表单API设置的值
watch(
() => attrs.modelValue,
(res) => {
fileList.value = res;
},
);
return () =>
h(
Upload,
{
...props,
...attrs,
fileList: fileList.value,
onChange: handleChange,
onPreview: handlePreview,
},
renderUploadButton(),
);
},
});
};
const createDefaultSlotsWithUpload = ( const createDefaultSlotsWithUpload = (
listType: string, listType: string,
placeholder: string, placeholder: string,
@@ -224,7 +156,7 @@ const createDefaultSlotsWithUpload = (
} }
} }
}; };
// 构建预览图片组
const previewImage = async ( const previewImage = async (
file: UploadFile, file: UploadFile,
visible: Ref<boolean>, visible: Ref<boolean>,
@@ -258,7 +190,7 @@ const previewImage = async (
} else if (file.preview) { } else if (file.preview) {
window.open(file.preview, '_blank'); window.open(file.preview, '_blank');
} else { } else {
console.warn('无法打开文件没有可用的URL或预览地址'); message.error($t('ui.formRules.previewWarning'));
} }
return; return;
} }
@@ -336,6 +268,85 @@ const previewImage = async (
render(h(PreviewWrapper), container); render(h(PreviewWrapper), container);
}; };
return defineComponent({
name: Upload.name,
emits: ['update:modelValue'],
setup: (
props: any,
{ attrs, slots, emit }: { attrs: any; emit: any; slots: any },
) => {
const previewVisible = ref<boolean>(false);
const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`);
const listType = attrs?.listType || attrs?.['list-type'] || 'text';
const fileList = ref<UploadProps['fileList']>(
attrs?.fileList || attrs?.['file-list'] || [],
);
const handleBeforeUpload = (file: UploadFile) => {
if (attrs.maxSize && (file.size || 0) / 1024 / 1024 > attrs.maxSize) {
message.error($t('ui.formRules.sizeLimit', [attrs.maxSize]));
file.status = 'removed';
return false;
}
return attrs.beforeUpload?.(file) ?? true;
};
const handleChange = async (event: UploadChangeParam) => {
fileList.value = event.fileList.filter(
(file) => file.status !== 'removed',
);
emit(
'update:modelValue',
event.fileList?.length ? fileList.value : undefined,
);
};
const handlePreview = async (file: UploadFile) => {
previewVisible.value = true;
await previewImage(file, previewVisible, fileList);
};
const renderUploadButton = (): any => {
const isDisabled = attrs.disabled;
// 如果禁用,不渲染上传按钮
if (isDisabled) {
return null;
}
// 否则渲染默认上传按钮
return isEmpty(slots)
? createDefaultSlotsWithUpload(listType, placeholder)
: slots;
};
// 可以监听到表单API设置的值
watch(
() => attrs.modelValue,
(res) => {
fileList.value = res;
},
);
return () =>
h(
Upload,
{
...props,
...attrs,
fileList: fileList.value,
beforeUpload: handleBeforeUpload,
onChange: handleChange,
onPreview: handlePreview,
},
renderUploadButton(),
);
},
});
};
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType = export type ComponentType =

View File

@@ -342,6 +342,8 @@ const [BaseForm, baseFormApi] = useVbenForm({
customRequest: upload_file, customRequest: upload_file,
disabled: false, disabled: false,
maxCount: 1, maxCount: 1,
// 单位MB
maxSize: 2,
multiple: false, multiple: false,
showUploadList: true, showUploadList: true,
// 上传列表的内建样式,支持四种基本样式 text, picture, picture-card 和 picture-circle // 上传列表的内建样式,支持四种基本样式 text, picture, picture-card 和 picture-circle
@@ -354,7 +356,7 @@ const [BaseForm, baseFormApi] = useVbenForm({
default: () => $t('examples.form.upload-image'), default: () => $t('examples.form.upload-image'),
}; };
}, },
rules: 'required', rules: 'selectRequired',
}, },
], ],
// 大屏一行显示3个中屏一行显示2个小屏一行显示1个 // 大屏一行显示3个中屏一行显示2个小屏一行显示1个