表单元数据配置

在本框架中,表单元数据(schema)是核心功能之一,它用于定义表单的结构、验证规则和显示逻辑。同一套元数据可以同时用于新增、编辑和详情页面,通过不同的配置实现差异化的显示效果。

基础配置结构

表单元数据配置包含以下几个主要部分:

export const formSchemas: VbenFormProps = {
  wrapperClass: 'grid-cols-12', // 12栅格布局
  commonConfig: {
    formItemClass: 'col-span-12', // 默认表单项占用12列
  },
  schema: [
    // 表单项配置数组
  ],
};

表单项基础配置

每个表单项的基本配置包括:

{
  fieldName: 'userName',        // 字段名
  label: '用户名',              // 标签
  component: 'Input',          // 组件类型
  componentProps: {            // 组件属性
    placeholder: '请输入用户名',
    allowClear: true,
  },
  formItemClass: 'col-span-6', // 表单项占用列数
  rules: 'required',           // 验证规则
  detailSpan: 6,               // 详情页占用列数
}

显示控制配置

通用显示控制

通过 ifDetail属性控制在详情页的显示:

{
  fieldName: 'id',
  label: '用户ID',
  component: 'Input',
  ifDetail: false, // 仅在详情页不显示
}

ifDetail可以是布尔值或者函数,函数返回值为布尔值。

条件显示控制

通过 dependencies 属性实现更复杂的条件显示:

{
  fieldName: 'password',
  label: '密码',
  component: 'InputPassword',
  dependencies: {
    // 当 id 不存在时显示(新增时显示)
    if({ id }) {
      return !id;
    },
    triggerFields: ['id'], // 触发字段
  },
  ifDetail: false, // 详情页不显示
}

确认密码示例

{
  fieldName: 'confirmPassword',
  label: '确认密码',
  component: 'InputPassword',
  dependencies: {
    // 当 id 不存在时显示(新增时显示)
    if({ id }) {
      return !id;
    },
    triggerFields: ['id', 'confirmPassword'],
    // 动态验证规则
    rules: (values) => {
      return z
        .string()
        .regex(/[\w!@#$%^&*]{5,18}/, '密码由5-18位数字、字母、特殊字符组成。')
        .refine(
          (confirmPassword) => {
            return confirmPassword === values.password;
          },
          {
            message: '确认密码必须与密码一致',
          },
        );
    },
  },
  ifDetail: false, // 详情页不显示
}

栅格布局系统

框架采用 12 列栅格系统,通过以下方式控制布局:

全局配置

export const formSchemas: VbenFormProps = {
  wrapperClass: 'grid-cols-12', // 设置12列栅格
  commonConfig: {
    formItemClass: 'col-span-12', // 默认表单项占用12列(整行)
  },
}

单个表单项配置

{
  fieldName: 'userName',
  label: '用户名',
  component: 'Input',
  formItemClass: 'col-span-6', // 占用6列(半行)
  detailSpan: 6,               // 详情页占用6列
}

分割线配置

{
  fieldName: 'baseinfo',
  component: 'Divider',
  label: '基础信息',
  formItemClass: 'col-span-12', // 占用整行
  hideLabel: true,              // 隐藏标签
  renderComponentContent: () => {
    return {
      default: () => {
        return '基础信息';
      },
    };
  },
}

不同场景显示控制

1. 所有场景都显示(默认)

{
  fieldName: 'userName',
  label: '用户名',
  component: 'Input',
  // 不设置 ifDetail 或 dependencies,默认所有场景显示
}

2. 仅在详情页显示

{
  fieldName: 'createTime',
  label: '创建时间',
  component: 'DatePicker',
  ifDetail: true, // 仅详情页显示
  dependencies: {
    if() {
      return false; // 新增和编辑时不显示
    },
    triggerFields: ['id'],
  },
}

3. 仅在新增时显示

{
  fieldName: 'password',
  label: '密码',
  component: 'InputPassword',
  dependencies: {
    if({ id }) {
      return !id; // id 不存在时显示(新增)
    },
    triggerFields: ['id'],
  },
  ifDetail: false, // 详情页不显示
}

4. 仅在编辑时显示

{
  fieldName: 'updateTime',
  label: '更新时间',
  component: 'DatePicker',
  dependencies: {
    if({ id }) {
      return !!id; // id 存在时显示(编辑)
    },
    triggerFields: ['id'],
  },
  ifDetail: false, // 详情页不显示
}

5. 仅新增和详情页显示

{
  fieldName: 'remark',
  label: '备注',
  component: 'Textarea',
  dependencies: {
    if({ id }) {
      return !id; // 新增时显示
    },
    triggerFields: ['id'],
  },
  // 不设置 ifDetail,默认详情页显示
}

6. 仅编辑和详情页显示

{
  fieldName: 'updateRemark',
  label: '更新备注',
  component: 'Textarea',
  dependencies: {
    if({ id }) {
      return !!id; // 编辑时显示
    },
    triggerFields: ['id'],
  },
  // 不设置 ifDetail,默认详情页显示
}

完整示例

export const formSchemas: VbenFormProps = {
  wrapperClass: 'grid-cols-12',
  commonConfig: {
    formItemClass: 'col-span-12',
  },
  schema: [
    // 仅详情页显示的ID字段
    {
      fieldName: 'id',
      label: '用户ID',
      component: 'Input',
      ifDetail: false,
      dependencies: {
        show: false,
        triggerFields: ['id'],
      },
    },
    
    // 分割线(所有场景显示)
    {
      fieldName: 'baseinfo',
      component: 'Divider',
      label: '基础信息',
      formItemClass: 'col-span-12',
      hideLabel: true,
      renderComponentContent: () => {
        return {
          default: () => '基础信息',
        };
      },
    },
    
    // 用户名(所有场景显示)
    {
      fieldName: 'userName',
      label: '用户名',
      component: 'Input',
      formItemClass: 'col-span-6',
      rules: 'required',
      detailSpan: 6,
    },
    
    // 密码(仅新增时显示)
    {
      fieldName: 'password',
      label: '密码',
      component: 'InputPassword',
      formItemClass: 'col-span-6',
      dependencies: {
        if({ id }) {
          return !id;
        },
        triggerFields: ['id'],
      },
      ifDetail: false,
    },
    
    // 更新时间(仅编辑和详情页显示)
    {
      fieldName: 'updateTime',
      label: '更新时间',
      component: 'DatePicker',
      formItemClass: 'col-span-6',
      detailSpan: 6,
      dependencies: {
        if({ id }) {
          return !!id;
        },
        triggerFields: ['id'],
      },
    },
  ],
};

最佳实践

  1. 合理使用栅格系统

    • 通过 col-span-* 控制表单项宽度
    • 保持表单布局整齐美观
  2. 条件显示控制

    • 使用 ifDetail 控制详情页显示
    • 使用 dependencies.if 实现复杂条件逻辑
  3. 表单复用

    • 同一套元数据可用于新增、编辑、详情
    • 通过配置控制不同场景的显示差异
  4. 验证规则

    • 使用字符串快捷规则(如 'required')
    • 使用 zod 实现复杂验证逻辑
    • 通过 dependencies.rules 实现动态验证

通过以上配置方式,可以灵活控制表单在不同场景下的显示效果,实现高效的表单复用。