fix: 修复 Vben5.0 form-create 多图上传校验拒绝 png/jpeg/gif,isImage 兼容 MIME 与扩展名两种 accept 写法

dev
YunaiV 2026-05-02 22:56:38 +08:00
parent 897220e19a
commit e385823d46
9 changed files with 120 additions and 152 deletions

View File

@ -6,18 +6,36 @@ export function useImagesUpload() {
return defineComponent({ return defineComponent({
name: 'ImagesUpload', name: 'ImagesUpload',
props: { props: {
multiple: { accept: {
type: Array,
default: () => ['image/jpeg', 'image/png', 'image/gif'],
},
disabled: {
type: Boolean, type: Boolean,
default: true, default: false,
}, },
maxNumber: { maxNumber: {
type: Number, type: Number,
default: 5, default: 5,
}, },
maxSize: {
type: Number,
default: 5,
},
multiple: {
type: Boolean,
default: true,
},
}, },
setup(props) { setup(props) {
return () => ( return () => (
<ImageUpload maxNumber={props.maxNumber} multiple={props.multiple} /> <ImageUpload
accept={props.accept as string[]}
disabled={props.disabled}
maxNumber={props.maxNumber}
maxSize={props.maxSize}
multiple={props.multiple}
/>
); );
}, },
}); });

View File

@ -26,7 +26,7 @@ export function useUploadFileRule() {
makeRequiredRule(), makeRequiredRule(),
{ {
type: 'select', type: 'select',
field: 'fileType', field: 'accept',
title: '文件类型', title: '文件类型',
value: ['doc', 'xls', 'ppt', 'txt', 'pdf'], value: ['doc', 'xls', 'ppt', 'txt', 'pdf'],
options: [ options: [
@ -40,12 +40,6 @@ export function useUploadFileRule() {
mode: 'multiple', mode: 'multiple',
}, },
}, },
{
type: 'switch',
field: 'autoUpload',
title: '是否在选取文件后立即进行上传',
value: true,
},
{ {
type: 'switch', type: 'switch',
field: 'drag', field: 'drag',
@ -54,23 +48,23 @@ export function useUploadFileRule() {
}, },
{ {
type: 'switch', type: 'switch',
field: 'isShowTip', field: 'showDescription',
title: '是否显示提示', title: '是否显示提示',
value: true, value: true,
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'fileSize', field: 'maxSize',
title: '大小限制(MB)', title: '大小限制(MB)',
value: 5, value: 5,
props: { min: 0 }, props: { min: 0 },
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'limit', field: 'maxNumber',
title: '数量限制', title: '数量限制',
value: 5, value: 5,
props: { min: 0 }, props: { min: 1 },
}, },
{ {
type: 'switch', type: 'switch',

View File

@ -24,15 +24,9 @@ export function useUploadImageRule() {
props(_: any, { t }: any) { props(_: any, { t }: any) {
return localeProps(t, `${name}.props`, [ return localeProps(t, `${name}.props`, [
makeRequiredRule(), makeRequiredRule(),
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false,
},
{ {
type: 'select', type: 'select',
field: 'fileType', field: 'accept',
title: '图片类型限制', title: '图片类型限制',
value: ['image/jpeg', 'image/png', 'image/gif'], value: ['image/jpeg', 'image/png', 'image/gif'],
options: [ options: [
@ -52,40 +46,16 @@ export function useUploadImageRule() {
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'fileSize', field: 'maxSize',
title: '大小限制(MB)', title: '大小限制(MB)',
value: 5, value: 5,
props: { min: 0 }, props: { min: 0 },
}, },
{
type: 'input',
field: 'height',
title: '组件高度',
value: '150px',
},
{
type: 'input',
field: 'width',
title: '组件宽度',
value: '150px',
},
{
type: 'input',
field: 'borderradius',
title: '组件边框圆角',
value: '8px',
},
{ {
type: 'switch', type: 'switch',
field: 'disabled', field: 'disabled',
title: '是否显示删除按钮', title: '是否禁用',
value: true, value: false,
},
{
type: 'switch',
field: 'showBtnText',
title: '是否显示按钮文字',
value: true,
}, },
]); ]);
}, },

View File

@ -24,15 +24,9 @@ export function useUploadImagesRule() {
props(_: any, { t }: any) { props(_: any, { t }: any) {
return localeProps(t, `${name}.props`, [ return localeProps(t, `${name}.props`, [
makeRequiredRule(), makeRequiredRule(),
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false,
},
{ {
type: 'select', type: 'select',
field: 'fileType', field: 'accept',
title: '图片类型限制', title: '图片类型限制',
value: ['image/jpeg', 'image/png', 'image/gif'], value: ['image/jpeg', 'image/png', 'image/gif'],
options: [ options: [
@ -48,40 +42,27 @@ export function useUploadImagesRule() {
], ],
props: { props: {
mode: 'multiple', mode: 'multiple',
maxNumber: 5,
}, },
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'fileSize', field: 'maxSize',
title: '大小限制(MB)', title: '大小限制(MB)',
value: 5, value: 5,
props: { min: 0 }, props: { min: 0 },
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'limit', field: 'maxNumber',
title: '数量限制', title: '数量限制',
value: 5, value: 5,
props: { min: 0 }, props: { min: 1 },
}, },
{ {
type: 'input', type: 'switch',
field: 'height', field: 'disabled',
title: '组件高度', title: '是否禁用',
value: '150px', value: false,
},
{
type: 'input',
field: 'width',
title: '组件宽度',
value: '150px',
},
{
type: 'input',
field: 'borderradius',
title: '组件边框圆角',
value: '8px',
}, },
]); ]);
}, },

View File

@ -6,18 +6,36 @@ export function useImagesUpload() {
return defineComponent({ return defineComponent({
name: 'ImagesUpload', name: 'ImagesUpload',
props: { props: {
multiple: { accept: {
type: Array,
default: () => ['image/jpeg', 'image/png', 'image/gif'],
},
disabled: {
type: Boolean, type: Boolean,
default: true, default: false,
}, },
maxNumber: { maxNumber: {
type: Number, type: Number,
default: 5, default: 5,
}, },
maxSize: {
type: Number,
default: 5,
},
multiple: {
type: Boolean,
default: true,
},
}, },
setup(props) { setup(props) {
return () => ( return () => (
<ImageUpload maxNumber={props.maxNumber} multiple={props.multiple} /> <ImageUpload
accept={props.accept as string[]}
disabled={props.disabled}
maxNumber={props.maxNumber}
maxSize={props.maxSize}
multiple={props.multiple}
/>
); );
}, },
}); });

View File

@ -26,7 +26,7 @@ export function useUploadFileRule() {
makeRequiredRule(), makeRequiredRule(),
{ {
type: 'select', type: 'select',
field: 'fileType', field: 'accept',
title: '文件类型', title: '文件类型',
value: ['doc', 'xls', 'ppt', 'txt', 'pdf'], value: ['doc', 'xls', 'ppt', 'txt', 'pdf'],
options: [ options: [
@ -40,12 +40,6 @@ export function useUploadFileRule() {
multiple: true, multiple: true,
}, },
}, },
{
type: 'switch',
field: 'autoUpload',
title: '是否在选取文件后立即进行上传',
value: true,
},
{ {
type: 'switch', type: 'switch',
field: 'drag', field: 'drag',
@ -54,23 +48,23 @@ export function useUploadFileRule() {
}, },
{ {
type: 'switch', type: 'switch',
field: 'isShowTip', field: 'showDescription',
title: '是否显示提示', title: '是否显示提示',
value: true, value: true,
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'fileSize', field: 'maxSize',
title: '大小限制(MB)', title: '大小限制(MB)',
value: 5, value: 5,
props: { min: 0 }, props: { min: 0 },
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'limit', field: 'maxNumber',
title: '数量限制', title: '数量限制',
value: 5, value: 5,
props: { min: 0 }, props: { min: 1 },
}, },
{ {
type: 'switch', type: 'switch',

View File

@ -24,15 +24,9 @@ export function useUploadImageRule() {
props(_: any, { t }: any) { props(_: any, { t }: any) {
return localeProps(t, `${name}.props`, [ return localeProps(t, `${name}.props`, [
makeRequiredRule(), makeRequiredRule(),
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false,
},
{ {
type: 'select', type: 'select',
field: 'fileType', field: 'accept',
title: '图片类型限制', title: '图片类型限制',
value: ['image/jpeg', 'image/png', 'image/gif'], value: ['image/jpeg', 'image/png', 'image/gif'],
options: [ options: [
@ -52,40 +46,16 @@ export function useUploadImageRule() {
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'fileSize', field: 'maxSize',
title: '大小限制(MB)', title: '大小限制(MB)',
value: 5, value: 5,
props: { min: 0 }, props: { min: 0 },
}, },
{
type: 'input',
field: 'height',
title: '组件高度',
value: '150px',
},
{
type: 'input',
field: 'width',
title: '组件宽度',
value: '150px',
},
{
type: 'input',
field: 'borderradius',
title: '组件边框圆角',
value: '8px',
},
{ {
type: 'switch', type: 'switch',
field: 'disabled', field: 'disabled',
title: '是否显示删除按钮', title: '是否禁用',
value: true, value: false,
},
{
type: 'switch',
field: 'showBtnText',
title: '是否显示按钮文字',
value: true,
}, },
]); ]);
}, },

View File

@ -24,15 +24,9 @@ export function useUploadImagesRule() {
props(_: any, { t }: any) { props(_: any, { t }: any) {
return localeProps(t, `${name}.props`, [ return localeProps(t, `${name}.props`, [
makeRequiredRule(), makeRequiredRule(),
{
type: 'switch',
field: 'drag',
title: '拖拽上传',
value: false,
},
{ {
type: 'select', type: 'select',
field: 'fileType', field: 'accept',
title: '图片类型限制', title: '图片类型限制',
value: ['image/jpeg', 'image/png', 'image/gif'], value: ['image/jpeg', 'image/png', 'image/gif'],
options: [ options: [
@ -48,40 +42,27 @@ export function useUploadImagesRule() {
], ],
props: { props: {
multiple: true, multiple: true,
maxNumber: 5,
}, },
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'fileSize', field: 'maxSize',
title: '大小限制(MB)', title: '大小限制(MB)',
value: 5, value: 5,
props: { min: 0 }, props: { min: 0 },
}, },
{ {
type: 'inputNumber', type: 'inputNumber',
field: 'limit', field: 'maxNumber',
title: '数量限制', title: '数量限制',
value: 5, value: 5,
props: { min: 0 }, props: { min: 1 },
}, },
{ {
type: 'input', type: 'switch',
field: 'height', field: 'disabled',
title: '组件高度', title: '是否禁用',
value: '150px', value: false,
},
{
type: 'input',
field: 'width',
title: '组件宽度',
value: '150px',
},
{
type: 'input',
field: 'borderradius',
title: '组件边框圆角',
value: '8px',
}, },
]); ]);
}, },

View File

@ -103,11 +103,37 @@ export const defaultImageAccepts = [
'webp', 'webp',
]; ];
/**
* MIME
*/
const IMAGE_MIME_SUBTYPE_ALIASES: Record<string, string[]> = {
apng: ['apng', 'png'],
jpeg: ['jpeg', 'jpg'],
pjpeg: ['jpeg', 'jpg'],
'svg+xml': ['svg'],
tiff: ['tif', 'tiff'],
'x-icon': ['ico'],
};
/**
* MIME image/*
*/
function matchMimeSubtype(subtype: string, ext: string): boolean {
if (subtype === '*') {
return defaultImageAccepts.includes(ext);
}
const aliases = IMAGE_MIME_SUBTYPE_ALIASES[subtype];
if (aliases) {
return aliases.includes(ext);
}
return subtype === ext;
}
/** /**
* *
* *
* @param filename * @param filename
* @param accepts * @param accepts MIME image/png.ext .png png
* @returns * @returns
*/ */
export function isImage( export function isImage(
@ -118,7 +144,23 @@ export function isImage(
return false; return false;
} }
const ext = filename.split('.').pop()?.toLowerCase() || ''; const ext = filename.split('.').pop()?.toLowerCase() || '';
return accepts.includes(ext); if (!ext) {
return false;
}
return accepts.some((accept) => {
const lower = accept.toLowerCase();
// MIME 类型,例如 image/png image/* 仅放行已知图片扩展
if (lower.includes('/')) {
const subtype = lower.split('/').pop() || '';
return matchMimeSubtype(subtype, ext);
}
// 以点号开头的扩展名,例如 .png
if (lower.startsWith('.')) {
return lower.slice(1) === ext;
}
// 纯后缀
return lower === ext;
});
} }
/** /**