This commit is contained in:
dap
2026-04-08 10:34:35 +08:00
37 changed files with 1519 additions and 204 deletions

View File

@@ -1,7 +1,11 @@
<script setup lang="ts">
import type { ZodType } from 'zod';
import type { FormActions, FormSchema, MaybeComponentProps } from '../types';
import type {
FormActions,
FormFieldProps,
MaybeComponentProps,
} from '../types';
import { computed, nextTick, onUnmounted, useTemplateRef, watch } from 'vue';
@@ -26,7 +30,7 @@ import useDependencies from './dependencies';
import FormLabel from './form-label.vue';
import { isEventObjectLike } from './helper';
interface Props extends FormSchema {}
interface Props extends FormFieldProps {}
const {
colon,

View File

@@ -221,6 +221,60 @@ 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 Omit<FormCommonConfig, 'componentProps'> {
/** 默认值 */
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> = {
/** 组件 */
component: Component | T;
/** 组件参数 */
componentProps?: ComponentProps;
} & FormSchemaBody;
export type FormSchema<
T extends BaseFormComponentType = BaseFormComponentType,
P extends Record<string, any> = Record<never, never>,
> = FormSchemaDiscriminated<T, P> | FormSchemaFallback<T>;
export type HandleSubmitFn = (
values: Record<string, any>,
) => Promise<void> | void;
@@ -246,41 +300,18 @@ export type ArrayToStringFields = Array<
| string[] // 简单数组格式,最后一个元素可以是分隔符
>;
export interface FormSchema<
export interface FormFieldProps<
T extends BaseFormComponentType = BaseFormComponentType,
> extends FormCommonConfig {
> extends FormSchemaBody {
/** 组件 */
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 +363,7 @@ export interface FormRenderProps<
/**
* 表单定义
*/
schema?: FormSchema<T>[];
schema?: FormSchema<T, P>[];
/**
* 是否显示展开/折叠
@@ -357,8 +388,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);