vben-admin(2.8.0)中basicForm的使用(包含basicTable中开启searchForm中的使用)

分享一下最近使用vben-admin中basicForm的一些心得吧(鱼都摸秃了

首先确认一下您使用vben是2.8.0版本的而不是vben3(我也在学习中),其中有些不足之处也请各位大佬多多包涵,欢迎各位大佬在评论区留言指正,我也会不断学习。同时本文也会在各位大佬的指正之下不断修改。

首先是BasicForm的使用:

先看看文档的基本使用: 其中一些参数的介绍和一些表单的配置在文档中都有介绍,这里就不过多赘述了,不懂小伙伴仔细阅读一些文档,实在找不到配置的可以评论区向各位大佬请教,我能回答的也一定会去回复的。

先说一下我遇到的最多的吧,就是表单中select的数据问题,因为后端没有把返回数据统一起来label、key、value啥的都会给你,我这边最多的就是对返回数据的处理

js 复制代码
        // 这是基础的一个select
        {
            field: 'state',
            label: '状态',
            component: 'Select',
            colProps: {
              span: 12,
            },
            componentProps: {
              options: [
                {
                  label: '排队中',
                  value: 'IN_LINE',
                },
                {
                  label: '已退出',
                  value: 'HAS_EXITED',
                },
                {
                  label: '已办证',
                  value: 'HAS_CERTIFIED',
                },
                {
                  label: '待审核',
                  value: 'WAIT_REVIEWED',
                },
                {
                  label: '已驳回',
                  value: 'HAS_REJECTED',
                },
              ],
            },
            required: true,
          },

这是一个简单的Select所有选项都是由前端定死的

但是如果数据是后端给的并且数据并不是这种 [{ label:<String>, value:<String> }]形式的,我们也可以通过ApiSelect的形式去获取动态数据

js 复制代码
{
    label: '角色',
    colProps: {
      span: 8,
    },
    field: 'roleId',
    component: 'ApiSelect',
    componentProps: {
      api: (params) => Api.getRulesList({ params }),
      getPopupContainer: () => document.body,
      labelField: 'name',
      valueField: 'id',
      immediate: false,
      placeholder: '请选择角色',
    },
  },

api: (params) => Api.getRulesList({ params })是我用了axiosClient封装了一下,感兴趣的可以去npm上看一下这个,最终给我的就是接口返回的数组了

但是后端大佬又给我出难题了,给了[<string>,<string>,<string>......]这种格式的,怎么办呢?

喽一眼文档:

我悟了

js 复制代码
{
            field: 'city',
            component: 'ApiSelect',
            label: '城市',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_cityList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择城市',
                immediate: true,
              };
            },
            colProps: {
              span: 12,
            },
          },

ok,那么这个问题解决之后,又来难题了(联动)那怎么搞?再去看看文档

嗯~不错,上手

js 复制代码
  {
            field: 'city',
            component: 'ApiSelect',
            label: '城市',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_cityList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择城市',
                immediate: true,
                onChange: (e) => {
                  countyParams.value.city = e;
                  formModel.county = null;
                  formModel.street = null;
                  formModel.gridName = null;
                },
              };
            },
            colProps: {
              span: 12,
            },
          },
          {
            field: 'county',
            component: 'ApiSelect',
            label: '区县',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_countyList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择区县',
                params: countyParams.value,
                onChange: (e) => {
                  countyParams.value.county = e;
                  formModel.street = null;
                  formModel.gridName = null;
                },
                immediate: true,
              };
            },

            colProps: {
              span: 12,
            },
          },
          {
            field: 'street',
            component: 'ApiSelect',
            label: '街道',
            required: true,
            componentProps: ({ formModel }) => {
              return {
                api: async (params) => {
                  let list = await Api.get_grid_streetList({ params });
                  return Promise.resolve(
                    list.map((i) => {
                      return {
                        label: i,
                        value: i,
                      };
                    }),
                  );
                },
                placeholder: '请选择街道',
                params: countyParams.value,
                onChange: (e) => {
                  countyParams.value.street = e;
                  formModel.gridName = null;
                },
                immediate: true,
              };
            },

            colProps: {
              span: 12,
            },
          },

这里注意:params变化是基于watch来完成的,所以你要确保它能侦听到你数据的变化

其实到这里我就有点不明白了,这一个又一个选择框的干嘛不用级联呢?问了下产品,产品:"客户想要这样的"(我内心os:你*** 的 *** ** )

然后我们看下插槽的使用

js 复制代码
  {
    label: '组织',
    colProps: {
      span: 12,
    },
    field: 'organIds',
    component: 'Select',
    slot: 'organTree',
  },
html 复制代码
<template>
  <BasicModal
    v-bind="$attrs"
    @register="registerModal"
    :title="getTitle"
    width="600px"
    @ok="handleSubmit"
  >
    <BasicForm @register="registerForm">
      <template #organTree="{ model, field }">
        <TreeSelect
          v-model:value="model[field]"
          show-search
          treeCheckable
          :show-checked-strategy="SHOW_PARENT"
          style="width: 100%"
          :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
          placeholder="请选择组织"
          allow-clear
          tree-default-expand-all
          :tree-data="treeData"
          :field-names="{
            children: 'children',
            label: 'abbrName',
            value: 'id',
          }"
        />
      </template>
    </BasicForm>
  </BasicModal>
</template>

然后就是校验

js 复制代码
 {
    label: '手机',
    field: 'mobile',
    component: 'Input',
    // required: true,
    colProps: {
      span: 12,
    },
    rules: [
      {
        required: false,
        message: '请输入用户手机号',
      }, 
      {
        validator: async (_, value) => {
          if (!value) {
            return Promise.resolve();
          } else {
            const role = /^((1[3,4,5,6,8,7,9][0-9])|(14[5,7])|(17[0,6,7,8])|(19[7]))\d{8}$/;
            const regular = new RegExp(role);

            if (regular.test(value)) {
              return Promise.resolve();
            } else {
              return Promise.reject('手机号格式不正确');
            }
          }
        },
      },
    ],
  },

然后碰到了一个问题,就是这些规则是写死的还好,但是我的校验如果是动态可以配置的,那么怎么办呢?

js 复制代码
 {
    label: '密码',
    field: 'password',
    component: 'StrengthMeter',
    componentProps: ({ formModel }) => {
      return {
        placeholder: '请输入密码',
        onChange: (e) => {
          formModel.password = e;
        },
      };
    },
    colProps: {
      span: 12,
    },
    rules: [
      {
        validator: async (value) => {
          const userStore = useUserStore();
          // arr是我从登录的时候获取的一个数组里面是各种校验规则,比如必须包含特殊字符,密码长度,必须包含英文大小等等
          const arr = userStore.regularStr;
          if (!value) {
            return Promise.resolve();
          } else {
            let a: any = [];
            // 获取校验不成功的项
            a = arr.filter((i) => {
              return !i.str.test(value);
            });
            // 如果没有就抛出成功
            if (a.length == 0) {
              return Promise.resolve();
            }
            // 如果有就抛出首项
            for (let i = 0; i < a.length; i++) {
              return Promise.reject(a[i].warning);
            }
          }
        },
        // ❗❗❗ change 校验慢一步 blur 客户体验感不太好
        trigger: 'blur',
      },
    ],
  },

这样就解决了校验规则可配的问题,但是如果是chage的话就会发现value始终获取的是上一次输入的值,确定了不是async的问题,请各位大佬指教。

然后就是在BasicTable中开启searchForm后form的使用

首先,基本的一些配置是和form差不多的,只是要使用form的方法需要额外做一下引用

然后就是插槽的使用,与BasicForm中的插槽不同的是,在BasicTable中开启searchForm之后要使用表单的插槽的话就需要额外加上"form-"

话不多说上图

当然这只是这种使用插槽的方式,你也可以使用别的方式来用。

重点来了,上文介绍的那种省市县联动的形式,我们已经解决了,但是呢产品那边又来活了,产品:你能加上默认值吗? 我:可以,加时间!产品:要多久?我:一周吧!🤫

首先明确一下需求,这个默认值是用于table的表头搜索的,并且之间有联动;那么 ------ 开工......

js 复制代码
<template>
  <TitleCard>  </TitleCard>
  <Card>
    <BasicForm @register="register" />
  </Card>
 
</template>

<script setup lang="ts">
  import { ref } from 'vue';
  import { Card } from 'ant-design-vue';
  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
  import TitleCard from '../components/TitleCard/index.vue'; 
  import Api from '../api';
  const formDate: any = ref({});
  const schemas: FormSchema[] = [
    {
      field: 'year',
      component: 'Select',
      label: '年份',
      colProps: {
        span: 6,
      },
    },
    {
      field: 'month',
      component: 'Select',
      label: '月份',
      colProps: {
        span: 6,
      },
    },
  ];

  const getHeardList = async () => {
    const yearsList = await Api.market_monitor_years();
    updateSchema({
      label: '年份',
      colProps: { xl: 6 },
      field: 'year',
      component: 'Select',
      componentProps: ({ formModel }) => {
        return {
          getPopupContainer: () => document.body,
          onChange: async (e) => {
            if (formModel.month) {
              formModel.month = null;
            }
            if (e) {
              const monthOptions = await Api.common_getAllMonth({ params: { year: e } });
              // getMonthParams.value.year = e;
              updateSchema({
                label: '月份',
                colProps: {
                  span: 6,
                },
                field: 'month',
                component: 'Select',
                componentProps: ({ formModel }) => {
                  return {
                    getPopupContainer: () => document.body,
                    onChange: async (e) => {
                      if (e) {
                        formModel.month = e;
                        formDate.value = getFieldsValue();
                      }
                    },
                    options: monthOptions.map((i) => {
                      return {
                        label: i.key + '月',
                        value: i.value,
                      };
                    }),
                  };
                },
              });
              if (monthOptions.length != 0) {
                setFieldsValue({ month: monthOptions[0].value });
              }
            }
          },
          options: yearsList.map((i) => {
            return {
              label: i.key,
              value: i.value,
            };
          }),
        };
      },
    });
    setFieldsValue({
      year: yearsList[0].value,
    });
  };
  getHeardList();

  const [register, { updateSchema, setFieldsValue, getFieldsValue }] = useForm({
    labelWidth: 100,
    schemas,
    actionColOptions: {
      span: 24,
    },
    showActionButtonGroup: false,
  });
</script> 

因为要设置默认值,又要联动,所以写出来的东西一层又一层的看起来很繁琐,有没有更好的方式来写,请各位大佬指正。

还有就是表格单元格开启编辑 这个编辑就不能在schmes里面配置了,需要在BasicTable的columns里面进行配置

js 复制代码
    // 正常的columns
    {
      title: '代码',
      dataIndex: 'regularCode',
      key: 'regularCode',
      width: 100,
    },
js 复制代码
   {
      title: '方式',
      dataIndex: 'methodRevised',
      key: 'methodRevised',
      // width: 160,
      edit: true,
      editComponent: 'ApiSelect',

      editComponentProps: ({}) => {
        return {
          // 正常这样配置就会拿着当前行的id去请求下拉框数据
          // api: () => Api.getDeliveryOptionType({ pathVars: { id: record.id } }),
          // 因为后面业务变更,所以我这边需要拿着表头筛选框的数据来请求数据
          api: async () => {
            const formModel = getForm().getFieldsValue();
            if (!formModel.year || !formModel.month || !formModel.freq) {
              return;
            }
            let list = await Api.getDeliveryOptionType({ params: { ...formModel } });
            return Promise.resolve(list);
          },
          getPopupContainer: () => document.body,
          labelField: 'value',
          valueField: 'key',
        };
      },
    },

表单提交在他们示例里面已经有很详细的代码演示了,这里就不再多说了

欢迎JYM评论指正

相关推荐
Ares码农人生19 分钟前
React 前端框架简介
前端·react.js·前端框架
小汤猿人类20 分钟前
nacos-gateway动态路由
java·前端·gateway
GISer_Jing20 分钟前
前端经典面试合集(二)——Vue/React/Node/工程化工具/计算机网络
前端·vue.js·react.js·node.js
GesLuck1 小时前
C#控件开发4—仪表盘
前端·经验分享·c#
小林爱1 小时前
【Compose multiplatform教程14】【组件】LazyColumn组件
android·前端·kotlin·android studio·框架·多平台
过往记忆7 小时前
告别 Shuffle!深入探索 Spark 的 SPJ 技术
大数据·前端·分布式·ajax·spark
高兴蛋炒饭8 小时前
RouYi-Vue框架,环境搭建以及使用
前端·javascript·vue.js
m0_748240449 小时前
《通义千问AI落地—中》:前端实现
前端·人工智能·状态模式
ᥬ 小月亮9 小时前
Vue中接入萤石等直播视频(更新中ing)
前端·javascript·vue.js
神雕杨10 小时前
node js 过滤空白行
开发语言·前端·javascript