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

This commit is contained in:
dullathanol
2026-04-04 23:40:27 +08:00
parent 96d6f89732
commit 5211f5065d
29 changed files with 516 additions and 662 deletions

View File

@@ -6,14 +6,38 @@
/* eslint-disable vue/one-component-per-file */
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadChangeParam,
UploadFile,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
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 { Recordable } from '@vben/types';
@@ -592,6 +616,39 @@ export type ComponentType =
| 'Upload'
| 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() {
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 { VbenFormSchema } from './form-schema';
import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -39,14 +41,9 @@ async function initSetupVbenForm() {
});
}
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
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 { ComponentPropsMap, ComponentType } from './component';
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';
@@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// 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';

View File

@@ -5,11 +5,39 @@
/* 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 { BaseFormComponentType } from '@vben/common-ui';
import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import {
@@ -521,6 +549,39 @@ export type ComponentType =
| 'Upload'
| 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() {
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 { VbenFormSchema } from './form-schema';
import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -38,15 +40,9 @@ async function initSetupVbenForm() {
},
});
}
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
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 { ComponentPropsMap, ComponentType } from './component';
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';
@@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// 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';

View File

@@ -3,9 +3,29 @@
* 可用于 vben-form、vben-modal、vben-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 { BaseFormComponentType } from '@vben/common-ui';
import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
@@ -15,6 +35,9 @@ import { $t } from '@vben/locales';
import { ElNotification } from 'element-plus';
type ElTreeSelectSchemaProps = InstanceType<typeof ElTreeSelectType>['$props'];
type ElTimePickerSchemaProps = InstanceType<typeof ElTimePickerType>['$props'];
const ElButton = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/button/index'),
@@ -172,6 +195,28 @@ export type ComponentType =
| 'Upload'
| 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() {
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 { VbenFormSchema } from './form-schema';
import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -31,14 +33,9 @@ async function initSetupVbenForm() {
});
}
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
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 { ComponentPropsMap, ComponentType } from './component';
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';
@@ -63,9 +69,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// 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';

View File

@@ -3,9 +3,29 @@
* 可用于 vben-form、vben-modal、vben-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 { BaseFormComponentType } from '@vben/common-ui';
import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
@@ -118,6 +138,28 @@ export type ComponentType =
| 'Upload'
| 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() {
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 { VbenFormSchema } from './form-schema';
import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -35,14 +37,9 @@ async function initSetupVbenForm() {
});
}
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
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 { ComponentPropsMap, ComponentType } from './component';
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';
@@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// 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';

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 { BaseFormComponentType } from '@vben/common-ui';
import type {
ApiComponentSharedProps,
BaseFormComponentType,
IconPickerProps,
} from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
@@ -126,6 +152,35 @@ export type ComponentType =
| 'Upload'
| 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() {
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 { VbenFormSchema } from './form-schema';
import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -39,14 +41,9 @@ async function initSetupVbenForm() {
});
}
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
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 { ComponentPropsMap, ComponentType } from './component';
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';
@@ -62,9 +68,11 @@ setupVbenVxeTable({
// 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化
// 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';

View File

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

View File

@@ -221,6 +221,70 @@ type RenderComponentContentType = (
api: FormActions,
) => 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 = (
values: Record<string, any>,
) => Promise<void> | void;
@@ -246,41 +310,13 @@ export type ArrayToStringFields = Array<
| 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 {
required?: boolean;
}
export interface FormRenderProps<
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<
T extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> extends Omit<
FormRenderProps<T>,
FormRenderProps<T, P>,
'componentBindEventMap' | 'componentMap' | 'form'
> {
/**

View File

@@ -13,9 +13,10 @@ import VbenUseForm from './vben-use-form.vue';
export function useVbenForm<
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 api = new FormApi(options);
const api = new FormApi(options as unknown as VbenFormProps);
const extendedApi: ExtendedFormApi = api as never;
extendedApi.useStore = (selector) => {
return useStore(api.store, selector);

View File

@@ -41,6 +41,7 @@ export interface SeparatorOptions {
export interface VxeGridProps<
T extends Record<string, any> = any,
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<
D extends Record<string, any> = any,
F extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> = VxeGridApi<D> & {
useStore: <T = NoInfer<VxeGridProps<D, F>>>(
selector?: (state: NoInfer<VxeGridProps<any, any>>) => T,
) => Readonly<Ref<T>>;
useStore: <S = NoInfer<VxeGridProps<D, F, P>>>(
selector?: (state: NoInfer<VxeGridProps<any, any, any>>) => S,
) => Readonly<Ref<S>>;
};
export interface SetupVxeTable {

View File

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

View File

@@ -6,14 +6,38 @@
/* eslint-disable vue/one-component-per-file */
import type {
AutoCompleteProps,
ButtonProps,
CascaderProps,
CheckboxGroupProps,
CheckboxProps,
DatePickerProps,
DividerProps,
InputNumberProps,
InputProps,
MentionsProps,
RadioGroupProps,
RadioProps,
RateProps,
SelectProps,
SpaceProps,
SwitchProps,
TextAreaProps,
TimePickerProps,
TreeSelectProps,
UploadChangeParam,
UploadFile,
UploadProps,
} from 'ant-design-vue';
import type { RangePickerProps } from 'ant-design-vue/es/date-picker';
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 { Recordable } from '@vben/types';
@@ -594,6 +618,39 @@ export type ComponentType =
| 'Upload'
| 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() {
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 { VbenFormSchema } from './form-schema';
import type { ComponentPropsMap, ComponentType } from './component';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
@@ -38,13 +40,9 @@ async function initSetupVbenForm() {
});
}
type VbenFormProps = Omit<CoreFormProps<ComponentType>, 'schema'> & {
schema?: VbenFormSchema[];
};
function useVbenForm(options: VbenFormProps) {
return useForm<ComponentType>(options as CoreFormProps<ComponentType>);
}
const useVbenForm = useForm<ComponentType, ComponentPropsMap>;
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 { Recordable } from '@vben/types';
import type { ComponentType } from './component';
import type { ComponentPropsMap, ComponentType } from './component';
import { h } from 'vue';
@@ -282,8 +282,8 @@ setupVbenVxeTable({
});
export const useVbenVxeGrid = <T extends Record<string, any>>(
...rest: Parameters<typeof useGrid<T, ComponentType>>
) => useGrid<T, ComponentType>(...rest);
...rest: Parameters<typeof useGrid<T, ComponentType, ComponentPropsMap>>
) => useGrid<T, ComponentType, ComponentPropsMap>(...rest);
export type OnActionClickParams<T = Recordable<any>> = {
code: string;