feat: 表单 Schema 支持组件 Props 映射泛型,同步适配VxeGrid

pull/348/MERGE
dullathanol 2026-04-04 23:40:27 +08:00 committed by allen
parent cb5e7e00f1
commit 064a6a20f0
29 changed files with 516 additions and 662 deletions

View File

@ -6,14 +6,38 @@
/* eslint-disable vue/one-component-per-file */ /* eslint-disable vue/one-component-per-file */
import type { import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadChangeParam, UploadChangeParam,
UploadFile, UploadFile,
UploadProps, UploadProps,
} from 'ant-design-vue'; } from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import type { Component, Ref } from 'vue'; import type { Component, Ref } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Sortable } from '@vben/hooks'; import type { Sortable } from '@vben/hooks';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
@ -592,6 +616,39 @@ export type ComponentType =
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
export interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载

View File

@ -1,95 +0,0 @@
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
FormActions,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof ComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: ComponentProps<ComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@ -1,7 +1,9 @@
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui'; import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema,
} from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
@ -39,14 +41,9 @@ async function initSetupVbenForm() {
}); });
} }
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & { const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type { VbenFormProps, VbenFormSchema }; export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

View File

@ -1,8 +1,14 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; import { useVbenForm as useForm } from '@vben/common-ui';
import {
setupVbenVxeTable,
useVbenVxeGrid as useGrid,
} from '@vben/plugins/vxe-table';
import { Button, Image } from 'ant-design-vue'; import { Button, Image } from 'ant-design-vue';
@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// vxeUI.formats.add // vxeUI.formats.add
}, },
useVbenForm, useVbenForm: useVbenForm as typeof useForm,
}); });
export { useVbenVxeGrid }; export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type * from '@vben/plugins/vxe-table'; export type * from '@vben/plugins/vxe-table';

View File

@ -5,11 +5,39 @@
/* eslint-disable vue/one-component-per-file */ /* eslint-disable vue/one-component-per-file */
import type { UploadChangeParam, UploadFile, UploadProps } from 'antdv-next'; import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RangePickerProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadChangeParam,
UploadFile,
UploadProps,
} from 'antdv-next';
import type { Component, Ref } from 'vue'; import type { Component, Ref } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { import {
@ -521,6 +549,39 @@ export type ComponentType =
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
export interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载

View File

@ -1,95 +0,0 @@
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RangePickerProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'antdv-next';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
FormActions,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof ComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: ComponentProps<ComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@ -1,7 +1,9 @@
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui'; import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema,
} from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
@ -38,15 +40,9 @@ async function initSetupVbenForm() {
}, },
}); });
} }
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type { VbenFormProps, VbenFormSchema }; export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

View File

@ -1,8 +1,14 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; import { useVbenForm as useForm } from '@vben/common-ui';
import {
setupVbenVxeTable,
useVbenVxeGrid as useGrid,
} from '@vben/plugins/vxe-table';
import { Button, Image } from 'antdv-next'; import { Button, Image } from 'antdv-next';
@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// vxeUI.formats.add // vxeUI.formats.add
}, },
useVbenForm, useVbenForm: useVbenForm as typeof useForm,
}); });
export { useVbenVxeGrid }; export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type * from '@vben/plugins/vxe-table'; export type * from '@vben/plugins/vxe-table';

View File

@ -3,9 +3,29 @@
* vben-formvben-modalvben-drawer 使, * vben-formvben-modalvben-drawer 使,
*/ */
import type {
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
ElTimePicker as ElTimePickerType,
ElTreeSelect as ElTreeSelectType,
InputNumberProps,
InputProps,
RadioGroupProps,
SelectV2Props,
SpaceProps,
SwitchProps,
UploadProps,
} from 'element-plus';
import type { Component } from 'vue'; import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
@ -15,6 +35,9 @@ import { $t } from '@vben/locales';
import { ElNotification } from 'element-plus'; import { ElNotification } from 'element-plus';
type ElTreeSelectSchemaProps = InstanceType<typeof ElTreeSelectType>['$props'];
type ElTimePickerSchemaProps = InstanceType<typeof ElTimePickerType>['$props'];
const ElButton = defineAsyncComponent(() => const ElButton = defineAsyncComponent(() =>
Promise.all([ Promise.all([
import('element-plus/es/components/button/index'), import('element-plus/es/components/button/index'),
@ -172,6 +195,28 @@ export type ComponentType =
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
export interface ComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectV2Props;
ApiTreeSelect: ApiComponentSharedProps & ElTreeSelectSchemaProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
RadioGroup: RadioGroupProps;
Select: SelectV2Props;
Space: SpaceProps;
Switch: SwitchProps;
TimePicker: ElTimePickerSchemaProps;
TreeSelect: ElTreeSelectSchemaProps;
Upload: UploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载

View File

@ -1,79 +0,0 @@
import type {
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
ElTimePicker,
ElTreeSelect,
InputNumberProps,
InputProps,
RadioGroupProps,
SelectV2Props,
SpaceProps,
SwitchProps,
UploadProps,
} from 'element-plus';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
FormActions,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ElTreeSelectSchemaProps = InstanceType<typeof ElTreeSelect>['$props'];
type ElTimePickerSchemaProps = InstanceType<typeof ElTimePicker>['$props'];
type ComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
interface ComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectV2Props;
ApiTreeSelect: ApiComponentSharedProps & ElTreeSelectSchemaProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
RadioGroup: RadioGroupProps;
Select: SelectV2Props;
Space: SpaceProps;
Switch: SwitchProps;
TimePicker: ElTimePickerSchemaProps;
TreeSelect: ElTreeSelectSchemaProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof ComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: ComponentProps<ComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@ -1,7 +1,9 @@
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui'; import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema,
} from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
@ -31,14 +33,9 @@ async function initSetupVbenForm() {
}); });
} }
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & { const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type { VbenFormProps, VbenFormSchema }; export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

View File

@ -1,8 +1,14 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; import { useVbenForm as useForm } from '@vben/common-ui';
import {
setupVbenVxeTable,
useVbenVxeGrid as useGrid,
} from '@vben/plugins/vxe-table';
import { ElButton, ElImage } from 'element-plus'; import { ElButton, ElImage } from 'element-plus';
@ -63,9 +69,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// vxeUI.formats.add // vxeUI.formats.add
}, },
useVbenForm, useVbenForm: useVbenForm as typeof useForm,
}); });
export { useVbenVxeGrid }; export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type * from '@vben/plugins/vxe-table'; export type * from '@vben/plugins/vxe-table';

View File

@ -3,9 +3,29 @@
* vben-formvben-modalvben-drawer 使, * vben-formvben-modalvben-drawer 使,
*/ */
import type {
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
RadioGroupProps,
SelectProps,
SpaceProps,
SwitchProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'naive-ui';
import type { Component } from 'vue'; import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
@ -118,6 +138,28 @@ export type ComponentType =
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
export interface ComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
RadioGroup: RadioGroupProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载

View File

@ -1,76 +0,0 @@
import type {
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
RadioGroupProps,
SelectProps,
SpaceProps,
SwitchProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'naive-ui';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
FormActions,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
interface ComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
RadioGroup: RadioGroupProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof ComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: ComponentProps<ComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@ -1,7 +1,9 @@
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui'; import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema,
} from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
@ -35,14 +37,9 @@ async function initSetupVbenForm() {
}); });
} }
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & { const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type { VbenFormProps, VbenFormSchema }; export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

View File

@ -1,8 +1,14 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; import { useVbenForm as useForm } from '@vben/common-ui';
import {
setupVbenVxeTable,
useVbenVxeGrid as useGrid,
} from '@vben/plugins/vxe-table';
import { NButton, NImage } from 'naive-ui'; import { NButton, NImage } from 'naive-ui';
@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// vxeUI.formats.add // vxeUI.formats.add
}, },
useVbenForm, useVbenForm: useVbenForm as typeof useForm,
}); });
export { useVbenVxeGrid }; export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type * from '@vben/plugins/vxe-table'; export type * from '@vben/plugins/vxe-table';

View File

@ -1,6 +1,32 @@
import type {
AutoCompleteProps,
ButtonProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DateRangePickerProps,
DividerProps,
InputNumberProps,
InputProps,
RadioGroupProps,
RadioProps,
SelectProps,
SpaceProps,
SwitchProps,
TextareaProps,
TimePickerProps,
TreeSelectProps,
} from 'tdesign-vue-next';
import type { TdRateProps } from 'tdesign-vue-next/es/rate/type';
import type { UploadProps } from 'tdesign-vue-next/es/upload/types';
import type { Component } from 'vue'; import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue'; import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
@ -126,6 +152,35 @@ export type ComponentType =
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
export interface ComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: DateRangePickerProps;
Rate: TdRateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextareaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载

View File

@ -1,89 +0,0 @@
import type {
AutoCompleteProps,
ButtonProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DateRangePickerProps,
DividerProps,
InputNumberProps,
InputProps,
RadioGroupProps,
RadioProps,
SelectProps,
SpaceProps,
SwitchProps,
TextareaProps,
TimePickerProps,
TreeSelectProps,
} from 'tdesign-vue-next';
import type { TdRateProps } from 'tdesign-vue-next/es/rate/type';
import type { UploadProps } from 'tdesign-vue-next/es/upload/types';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
FormActions,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
interface ComponentPropsMap {
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: DateRangePickerProps;
Rate: TdRateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextareaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof ComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: ComponentProps<ComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@ -1,7 +1,9 @@
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui'; import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema,
} from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
@ -39,14 +41,9 @@ async function initSetupVbenForm() {
}); });
} }
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & { const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type { VbenFormProps, VbenFormSchema }; export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

View File

@ -1,8 +1,14 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; import { useVbenForm as useForm } from '@vben/common-ui';
import {
setupVbenVxeTable,
useVbenVxeGrid as useGrid,
} from '@vben/plugins/vxe-table';
import { Button, Image } from 'tdesign-vue-next'; import { Button, Image } from 'tdesign-vue-next';
@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// vxeUI.formats.add // vxeUI.formats.add
}, },
useVbenForm, useVbenForm: useVbenForm as typeof useForm,
}); });
export { useVbenVxeGrid }; export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type * from '@vben/plugins/vxe-table'; export type * from '@vben/plugins/vxe-table';

View File

@ -3,7 +3,6 @@ export { setupVbenForm } from './config';
export type { export type {
BaseFormComponentType, BaseFormComponentType,
ExtendedFormApi, ExtendedFormApi,
FormActions,
VbenFormProps, VbenFormProps,
FormSchema as VbenFormSchema, FormSchema as VbenFormSchema,
} from './types'; } from './types';

View File

@ -221,6 +221,70 @@ type RenderComponentContentType = (
api: FormActions, api: FormActions,
) => Record<string, any>; ) => Record<string, any>;
type MappedComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
interface FormSchemaBody extends FormCommonConfig {
/** 默认值 */
defaultValue?: any;
/** 依赖 */
dependencies?: FormItemDependencies;
/** 描述 */
description?: CustomRenderType;
/** 字段名 */
fieldName: string;
/** 帮助信息 */
help?: CustomParamsRenderType;
/** 是否隐藏表单项 */
hide?: boolean;
/** 表单项 */
label?: CustomRenderType;
// 自定义组件内部渲染
renderComponentContent?: RenderComponentContentType;
/** 字段规则 */
rules?: FormSchemaRuleType;
/** 后缀 */
suffix?: CustomRenderType;
}
type FormSchemaDiscriminated<
T extends BaseFormComponentType,
P extends Record<string, any>,
> = {
[K in Extract<keyof P, T>]: {
/** 组件 */
component: K;
/** 组件参数 */
componentProps?: MappedComponentProps<P[K]>;
} & FormSchemaBody;
}[Extract<keyof P, T>];
type FormSchemaFallback<
T extends BaseFormComponentType,
P extends Record<string, any>,
> = {
/** 组件 */
component: Component | Exclude<T, Extract<keyof P, T>>;
/** 组件参数 */
componentProps?: ComponentProps;
} & FormSchemaBody;
export type FormSchema<
T extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> = [keyof P] extends [never]
? {
/** 组件 */
component: Component | T;
/** 组件参数 */
componentProps?: ComponentProps;
} & FormSchemaBody
: FormSchemaDiscriminated<T, P> | FormSchemaFallback<T, P>;
export type HandleSubmitFn = ( export type HandleSubmitFn = (
values: Record<string, any>, values: Record<string, any>,
) => Promise<void> | void; ) => Promise<void> | void;
@ -246,41 +310,13 @@ export type ArrayToStringFields = Array<
| string[] // 简单数组格式,最后一个元素可以是分隔符 | string[] // 简单数组格式,最后一个元素可以是分隔符
>; >;
export interface FormSchema<
T extends BaseFormComponentType = BaseFormComponentType,
> extends FormCommonConfig {
/** 组件 */
component: Component | T;
/** 组件参数 */
componentProps?: ComponentProps;
/** 默认值 */
defaultValue?: any;
/** 依赖 */
dependencies?: FormItemDependencies;
/** 描述 */
description?: CustomRenderType;
/** 字段名 */
fieldName: string;
/** 帮助信息 */
help?: CustomParamsRenderType;
/** 是否隐藏表单项 */
hide?: boolean;
/** 表单项 */
label?: CustomRenderType;
// 自定义组件内部渲染
renderComponentContent?: RenderComponentContentType;
/** 字段规则 */
rules?: FormSchemaRuleType;
/** 后缀 */
suffix?: CustomRenderType;
}
export interface FormFieldProps extends FormSchema { export interface FormFieldProps extends FormSchema {
required?: boolean; required?: boolean;
} }
export interface FormRenderProps< export interface FormRenderProps<
T extends BaseFormComponentType = BaseFormComponentType, T extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> { > {
/** /**
* 使"," * 使","
@ -332,7 +368,7 @@ export interface FormRenderProps<
/** /**
* *
*/ */
schema?: FormSchema<T>[]; schema?: FormSchema<T, P>[];
/** /**
* / * /
@ -357,8 +393,9 @@ export interface ActionButtonOptions extends VbenButtonProps {
export interface VbenFormProps< export interface VbenFormProps<
T extends BaseFormComponentType = BaseFormComponentType, T extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> extends Omit< > extends Omit<
FormRenderProps<T>, FormRenderProps<T, P>,
'componentBindEventMap' | 'componentMap' | 'form' 'componentBindEventMap' | 'componentMap' | 'form'
> { > {
/** /**

View File

@ -13,9 +13,10 @@ import VbenUseForm from './vben-use-form.vue';
export function useVbenForm< export function useVbenForm<
T extends BaseFormComponentType = BaseFormComponentType, T extends BaseFormComponentType = BaseFormComponentType,
>(options: VbenFormProps<T>) { P extends Record<string, any> = Record<never, never>,
>(options: VbenFormProps<T, P>) {
const IS_REACTIVE = isReactive(options); const IS_REACTIVE = isReactive(options);
const api = new FormApi(options); const api = new FormApi(options as unknown as VbenFormProps);
const extendedApi: ExtendedFormApi = api as never; const extendedApi: ExtendedFormApi = api as never;
extendedApi.useStore = (selector) => { extendedApi.useStore = (selector) => {
return useStore(api.store, selector); return useStore(api.store, selector);

View File

@ -41,6 +41,7 @@ export interface SeparatorOptions {
export interface VxeGridProps< export interface VxeGridProps<
T extends Record<string, any> = any, T extends Record<string, any> = any,
D extends BaseFormComponentType = BaseFormComponentType, D extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> { > {
/** /**
* *
@ -73,7 +74,7 @@ export interface VxeGridProps<
/** /**
* *
*/ */
formOptions?: VbenFormProps<D>; formOptions?: VbenFormProps<D, P>;
/** /**
* *
*/ */
@ -87,10 +88,11 @@ export interface VxeGridProps<
export type ExtendedVxeGridApi< export type ExtendedVxeGridApi<
D extends Record<string, any> = any, D extends Record<string, any> = any,
F extends BaseFormComponentType = BaseFormComponentType, F extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> = VxeGridApi<D> & { > = VxeGridApi<D> & {
useStore: <T = NoInfer<VxeGridProps<D, F>>>( useStore: <S = NoInfer<VxeGridProps<D, F, P>>>(
selector?: (state: NoInfer<VxeGridProps<any, any>>) => T, selector?: (state: NoInfer<VxeGridProps<any, any, any>>) => S,
) => Readonly<Ref<T>>; ) => Readonly<Ref<S>>;
}; };
export interface SetupVxeTable { export interface SetupVxeTable {

View File

@ -22,10 +22,15 @@ type FilteredSlots<T> = {
export function useVbenVxeGrid< export function useVbenVxeGrid<
T extends Record<string, any> = any, T extends Record<string, any> = any,
D extends BaseFormComponentType = BaseFormComponentType, D extends BaseFormComponentType = BaseFormComponentType,
>(options: VxeGridProps<T, D>) { P extends Record<string, any> = Record<never, never>,
>(options: VxeGridProps<T, D, P>) {
// const IS_REACTIVE = isReactive(options); // const IS_REACTIVE = isReactive(options);
const api = new VxeGridApi(options); const api = new VxeGridApi(options as VxeGridProps);
const extendedApi: ExtendedVxeGridApi<T, D> = api as ExtendedVxeGridApi<T, D>; const extendedApi: ExtendedVxeGridApi<T, D, P> = api as ExtendedVxeGridApi<
T,
D,
P
>;
extendedApi.useStore = (selector) => { extendedApi.useStore = (selector) => {
return useStore(api.store, selector); return useStore(api.store, selector);
}; };

View File

@ -6,14 +6,38 @@
/* eslint-disable vue/one-component-per-file */ /* eslint-disable vue/one-component-per-file */
import type { import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadChangeParam, UploadChangeParam,
UploadFile, UploadFile,
UploadProps, UploadProps,
} from 'ant-design-vue'; } from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import type { Component, Ref } from 'vue'; import type { Component, Ref } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Sortable } from '@vben/hooks'; import type { Sortable } from '@vben/hooks';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
@ -594,6 +618,39 @@ export type ComponentType =
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
export interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
async function initComponentAdapter() { async function initComponentAdapter() {
const components: Partial<Record<ComponentType, Component>> = { const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载 // 如果你的组件体积比较大,可以使用异步加载

View File

@ -1,95 +0,0 @@
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
import type { Component } from 'vue';
import type {
ApiComponentSharedProps,
VbenFormSchema as CoreFormSchema,
FormActions,
IconPickerProps,
} from '@vben/common-ui';
import type { ComponentType } from './component';
type ComponentProps<P> =
| ((
value: Partial<Record<string, any>>,
actions: FormActions,
) => P & Record<string, any>)
| (P & Record<string, any>);
/**
* {@link ComponentType} 便 Schema `component` + `componentProps`
*/
interface ComponentPropsMap {
ApiCascader: ApiComponentSharedProps & CascaderProps;
ApiSelect: ApiComponentSharedProps & SelectProps;
ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
AutoComplete: AutoCompleteProps;
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
IconPicker: IconPickerProps;
Input: InputProps;
InputNumber: InputNumberProps;
InputPassword: InputProps;
Mentions: MentionsProps;
PrimaryButton: ButtonProps;
Radio: RadioProps;
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
Textarea: TextAreaProps;
TimePicker: TimePickerProps;
TreeSelect: TreeSelectProps;
Upload: UploadProps;
}
type BaseSchema = Omit<
CoreFormSchema<ComponentType>,
'component' | 'componentProps'
>;
type RegisteredName = keyof ComponentPropsMap;
type DiscriminatedFormSchema = {
[K in RegisteredName]: BaseSchema & {
component: K;
componentProps?: ComponentProps<ComponentPropsMap[K]>;
};
}[RegisteredName];
type FallbackFormSchema = BaseSchema & {
component: Component | Exclude<ComponentType, RegisteredName>;
componentProps?: CoreFormSchema<ComponentType>['componentProps'];
};
export type VbenFormSchema = DiscriminatedFormSchema | FallbackFormSchema;

View File

@ -1,7 +1,9 @@
import type { VbenFormProps as CoreFormProps } from '@vben/common-ui'; import type {
VbenFormProps as FormProps,
VbenFormSchema as FormSchema,
} from '@vben/common-ui';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import type { VbenFormSchema } from './form-schema';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
@ -38,13 +40,9 @@ async function initSetupVbenForm() {
}); });
} }
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & { const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
export { initSetupVbenForm, useVbenForm, z }; export { initSetupVbenForm, useVbenForm, z };
export type { VbenFormProps, VbenFormSchema };
export type VbenFormSchema = FormSchema<ComponentType, ComponentPropsMap>;
export type VbenFormProps = FormProps<ComponentType, ComponentPropsMap>;

View File

@ -1,7 +1,7 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import type { ComponentType } from './component'; import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue'; import { h } from 'vue';
@ -282,8 +282,8 @@ setupVbenVxeTable({
}); });
export const useVbenVxeGrid = <T extends Record<string, any>>( export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType>> ...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType>(...rest); ) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type OnActionClickParams<T = Recordable<any>> = { export type OnActionClickParams<T = Recordable<any>> = {
code: string; code: string;