fix(mall): 修复文章表单商品选择弹窗异常

- 初始化文章表单 formData,避免商品关联插槽渲染报错
- 禁用父级弹窗点击遮罩关闭,避免打开商品选择时关闭文章弹窗
- 修正文章新增默认值,热门/轮播默认 false,排序默认 0
- 同步修复 antd、antdv-next、ele 三端
pull/361/MERGE
YunaiV 2026-06-08 13:20:30 +08:00
parent 21998d8044
commit 8ed97335c9
6 changed files with 35 additions and 41 deletions

View File

@ -76,24 +76,22 @@ export function useFormSchema(): VbenFormSchema[] {
label: '是否热门', label: '是否热门',
component: 'RadioGroup', component: 'RadioGroup',
componentProps: { componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid', buttonStyle: 'solid',
optionType: 'button', optionType: 'button',
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
}, },
rules: 'required', rules: z.boolean().default(false),
defaultValue: true,
}, },
{ {
fieldName: 'recommendBanner', fieldName: 'recommendBanner',
label: '是否轮播图', label: '是否轮播图',
component: 'RadioGroup', component: 'RadioGroup',
componentProps: { componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid', buttonStyle: 'solid',
optionType: 'button', optionType: 'button',
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
}, },
rules: 'required', rules: z.boolean().default(false),
defaultValue: true,
}, },
{ {
fieldName: 'spuId', fieldName: 'spuId',
@ -110,7 +108,7 @@ export function useFormSchema(): VbenFormSchema[] {
min: 0, min: 0,
placeholder: '请输入排序', placeholder: '请输入排序',
}, },
rules: 'required', rules: z.number().default(0),
}, },
{ {
fieldName: 'status', fieldName: 'status',

View File

@ -20,7 +20,7 @@ import { useFormSchema } from '../data';
const emit = defineEmits(['success']); const emit = defineEmits(['success']);
const formData = ref<MallArticleApi.Article>(); const formData = ref<Partial<MallArticleApi.Article>>({});
const getTitle = computed(() => { const getTitle = computed(() => {
return formData.value?.id return formData.value?.id
? $t('ui.actionTitle.edit', ['文章']) ? $t('ui.actionTitle.edit', ['文章'])
@ -43,7 +43,7 @@ const [Form, formApi] = useVbenForm({
const [Modal, modalApi] = useVbenModal({ const [Modal, modalApi] = useVbenModal({
async onConfirm() { async onConfirm() {
// //
if (formData.value?.spuId) { if (formData.value.spuId) {
await formApi.setFieldValue('spuId', formData.value.spuId); await formApi.setFieldValue('spuId', formData.value.spuId);
} }
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
@ -65,7 +65,7 @@ const [Modal, modalApi] = useVbenModal({
}, },
async onOpenChange(isOpen: boolean) { async onOpenChange(isOpen: boolean) {
if (!isOpen) { if (!isOpen) {
formData.value = undefined; formData.value = {};
return; return;
} }
// //
@ -86,11 +86,11 @@ const [Modal, modalApi] = useVbenModal({
</script> </script>
<template> <template>
<Modal :title="getTitle" class="w-2/5"> <Modal :title="getTitle" class="w-2/5" :close-on-click-modal="false">
<Form class="mx-4"> <Form class="mx-4">
<!-- 自定义插槽商品选择 --> <!-- 自定义插槽商品选择 -->
<template #spuId> <template #spuId>
<SpuShowcase v-model="formData!.spuId" :limit="1" /> <SpuShowcase v-model="formData.spuId" :limit="1" />
</template> </template>
</Form> </Form>
</Modal> </Modal>

View File

@ -76,24 +76,22 @@ export function useFormSchema(): VbenFormSchema[] {
label: '是否热门', label: '是否热门',
component: 'RadioGroup', component: 'RadioGroup',
componentProps: { componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid', buttonStyle: 'solid',
optionType: 'button', optionType: 'button',
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
}, },
rules: 'required', rules: z.boolean().default(false),
defaultValue: true,
}, },
{ {
fieldName: 'recommendBanner', fieldName: 'recommendBanner',
label: '是否轮播图', label: '是否轮播图',
component: 'RadioGroup', component: 'RadioGroup',
componentProps: { componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid', buttonStyle: 'solid',
optionType: 'button', optionType: 'button',
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
}, },
rules: 'required', rules: z.boolean().default(false),
defaultValue: true,
}, },
{ {
fieldName: 'spuId', fieldName: 'spuId',
@ -110,7 +108,7 @@ export function useFormSchema(): VbenFormSchema[] {
min: 0, min: 0,
placeholder: '请输入排序', placeholder: '请输入排序',
}, },
rules: 'required', rules: z.number().default(0),
}, },
{ {
fieldName: 'status', fieldName: 'status',

View File

@ -20,7 +20,7 @@ import { useFormSchema } from '../data';
const emit = defineEmits(['success']); const emit = defineEmits(['success']);
const formData = ref<MallArticleApi.Article>(); const formData = ref<Partial<MallArticleApi.Article>>({});
const getTitle = computed(() => { const getTitle = computed(() => {
return formData.value?.id return formData.value?.id
? $t('ui.actionTitle.edit', ['文章']) ? $t('ui.actionTitle.edit', ['文章'])
@ -43,7 +43,7 @@ const [Form, formApi] = useVbenForm({
const [Modal, modalApi] = useVbenModal({ const [Modal, modalApi] = useVbenModal({
async onConfirm() { async onConfirm() {
// //
if (formData.value?.spuId) { if (formData.value.spuId) {
await formApi.setFieldValue('spuId', formData.value.spuId); await formApi.setFieldValue('spuId', formData.value.spuId);
} }
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
@ -65,7 +65,7 @@ const [Modal, modalApi] = useVbenModal({
}, },
async onOpenChange(isOpen: boolean) { async onOpenChange(isOpen: boolean) {
if (!isOpen) { if (!isOpen) {
formData.value = undefined; formData.value = {};
return; return;
} }
// //
@ -86,11 +86,11 @@ const [Modal, modalApi] = useVbenModal({
</script> </script>
<template> <template>
<Modal :title="getTitle" class="w-2/5"> <Modal :title="getTitle" class="w-2/5" :close-on-click-modal="false">
<Form class="mx-4"> <Form class="mx-4">
<!-- 自定义插槽商品选择 --> <!-- 自定义插槽商品选择 -->
<template #spuId> <template #spuId>
<SpuShowcase v-model="formData!.spuId" :limit="1" /> <SpuShowcase v-model="formData.spuId" :limit="1" />
</template> </template>
</Form> </Form>
</Modal> </Modal>

View File

@ -78,8 +78,7 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: { componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
}, },
rules: 'required', rules: z.boolean().default(false),
defaultValue: true,
}, },
{ {
fieldName: 'recommendBanner', fieldName: 'recommendBanner',
@ -88,8 +87,7 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: { componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
}, },
rules: 'required', rules: z.boolean().default(false),
defaultValue: true,
}, },
{ {
fieldName: 'spuId', fieldName: 'spuId',
@ -102,12 +100,12 @@ export function useFormSchema(): VbenFormSchema[] {
label: '排序', label: '排序',
component: 'InputNumber', component: 'InputNumber',
componentProps: { componentProps: {
class: '!w-full',
controlsPosition: 'right',
min: 0, min: 0,
placeholder: '请输入排序', placeholder: '请输入排序',
controlsPosition: 'right',
class: '!w-full',
}, },
rules: 'required', rules: z.number().default(0),
}, },
{ {
fieldName: 'status', fieldName: 'status',
@ -137,10 +135,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'ApiSelect', component: 'ApiSelect',
componentProps: { componentProps: {
api: getSimpleArticleCategoryList, api: getSimpleArticleCategoryList,
clearable: true,
labelField: 'name', labelField: 'name',
valueField: 'id',
placeholder: '请选择文章分类', placeholder: '请选择文章分类',
allowClear: true, valueField: 'id',
}, },
}, },
{ {
@ -148,8 +146,8 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '文章标题', label: '文章标题',
component: 'Input', component: 'Input',
componentProps: { componentProps: {
clearable: true,
placeholder: '请输入文章标题', placeholder: '请输入文章标题',
allowClear: true,
}, },
}, },
{ {
@ -157,9 +155,9 @@ export function useGridFormSchema(): VbenFormSchema[] {
label: '状态', label: '状态',
component: 'Select', component: 'Select',
componentProps: { componentProps: {
clearable: true,
options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
placeholder: '请选择状态', placeholder: '请选择状态',
allowClear: true,
}, },
}, },
{ {
@ -168,7 +166,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker', component: 'RangePicker',
componentProps: { componentProps: {
...getRangePickerDefaultProps(), ...getRangePickerDefaultProps(),
allowClear: true, clearable: true,
}, },
}, },
]; ];

View File

@ -20,7 +20,7 @@ import { useFormSchema } from '../data';
const emit = defineEmits(['success']); const emit = defineEmits(['success']);
const formData = ref<MallArticleApi.Article>(); const formData = ref<Partial<MallArticleApi.Article>>({});
const getTitle = computed(() => { const getTitle = computed(() => {
return formData.value?.id return formData.value?.id
? $t('ui.actionTitle.edit', ['文章']) ? $t('ui.actionTitle.edit', ['文章'])
@ -43,7 +43,7 @@ const [Form, formApi] = useVbenForm({
const [Modal, modalApi] = useVbenModal({ const [Modal, modalApi] = useVbenModal({
async onConfirm() { async onConfirm() {
// //
if (formData.value?.spuId) { if (formData.value.spuId) {
await formApi.setFieldValue('spuId', formData.value.spuId); await formApi.setFieldValue('spuId', formData.value.spuId);
} }
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
@ -65,7 +65,7 @@ const [Modal, modalApi] = useVbenModal({
}, },
async onOpenChange(isOpen: boolean) { async onOpenChange(isOpen: boolean) {
if (!isOpen) { if (!isOpen) {
formData.value = undefined; formData.value = {};
return; return;
} }
// //
@ -86,11 +86,11 @@ const [Modal, modalApi] = useVbenModal({
</script> </script>
<template> <template>
<Modal :title="getTitle" class="w-2/5"> <Modal :title="getTitle" class="w-2/5" :close-on-click-modal="false">
<Form class="mx-4"> <Form class="mx-4">
<!-- 自定义插槽商品选择 --> <!-- 自定义插槽商品选择 -->
<template #spuId> <template #spuId>
<SpuShowcase v-model="formData!.spuId" :limit="1" /> <SpuShowcase v-model="formData.spuId" :limit="1" />
</template> </template>
</Form> </Form>
</Modal> </Modal>