Skip to content

代码重写

代码生成器生成的代码,只是通过提前预制的模板,参数一定的配置参数生成的。生成的代码只具备简单的=单表增删改查=能力。若想要实现复杂的业务逻辑,还需要开发人员对生成的代码进行二次开发。

下面介绍如何重写增删改查方法。

后端

由于后端的Controller类继承了父类或实现接口,所以生成出来的Controller类虽然没有任何方法,但也具备了简单的增删改查接口。 但父类的实现很简单往往不能满足实际的业务,可以通过重写父类方法或新写一个接口等方式实现更复杂的业务逻辑。

新增

Controller

实现了SaveController,可以重写 handlerSavesave方法。

  • 不建议同时重写这2个方法。
  • 若重写了 save方法没有手动调用 handlerSave方法,handlerSave将不会被调用
java
@Override
public R<TestUser> handlerSave(TestUserSaveVO model) {
    // 可以编写在调用service.save前的代码,如验证参数

    // 若需要父类帮你调用service.save,请返回 R.successDef();
    return R.successDef();
}

@Override
public R<TestUser> save(TestUserSaveVO testUserSaveVO) {
    // 自己验证参数

    // 自己调用save方法
    return R.success(superService.save(testUserSaveVO));
}
@Override
public R<TestUser> handlerSave(TestUserSaveVO model) {
    // 可以编写在调用service.save前的代码,如验证参数

    // 若需要父类帮你调用service.save,请返回 R.successDef();
    return R.successDef();
}

@Override
public R<TestUser> save(TestUserSaveVO testUserSaveVO) {
    // 自己验证参数

    // 自己调用save方法
    return R.success(superService.save(testUserSaveVO));
}

Service

继承了SuperServiceImpl,可以重写 savesaveBeforesaveAfter方法。

  • 若重写了 save方法,就不建议同时重写 saveBeforesaveAfter方法
  • 若重写了 saveBeforesaveAfter方法,就不建议同时重写 save方法
java
@Override
@Transactional(rollbackFor = Exception.class)
public TestUser save(TestUserSaveVO testUserSaveVO) {
  	// 重写save方法后,父类的 save 方法将不会在执行。若你重写的方法中没有主动调用saveBefore、saveAfter方法,saveBefore、saveAfter方法也不会执行,所以不建议同时重写这3个方法。
    // 当然若你重写的save方法中手动调用了saveBefore、saveAfter方法,则可以同时重写!
    TestUser bean = BeanUtil.toBean(testUserSaveVO, TestUser.class);
    superManager.save(bean);
    return bean;
}

@Override
protected TestUser saveBefore(TestUserSaveVO testUserSaveVO) {
  	// 参数校验、参数初始化等逻辑
    return BeanUtil.toBean(saveVO, getEntityClass());
}

@Override
protected void saveAfter(TestUserSaveVO testUserSaveVO, TestUser entity) {
  	// 保存数据后需要执行的一些操作,如清理缓存、报错从表数据等
}
@Override
@Transactional(rollbackFor = Exception.class)
public TestUser save(TestUserSaveVO testUserSaveVO) {
  	// 重写save方法后,父类的 save 方法将不会在执行。若你重写的方法中没有主动调用saveBefore、saveAfter方法,saveBefore、saveAfter方法也不会执行,所以不建议同时重写这3个方法。
    // 当然若你重写的save方法中手动调用了saveBefore、saveAfter方法,则可以同时重写!
    TestUser bean = BeanUtil.toBean(testUserSaveVO, TestUser.class);
    superManager.save(bean);
    return bean;
}

@Override
protected TestUser saveBefore(TestUserSaveVO testUserSaveVO) {
  	// 参数校验、参数初始化等逻辑
    return BeanUtil.toBean(saveVO, getEntityClass());
}

@Override
protected void saveAfter(TestUserSaveVO testUserSaveVO, TestUser entity) {
  	// 保存数据后需要执行的一些操作,如清理缓存、报错从表数据等
}

Manager

继承了SuperManagerImpl,可以重写 save方法

java
@Override
public boolean save(TestUser entity) {
  	// 在manager层重写save方法,除了入库操作,还可以考虑操作缓存、调用第三方接口等。
    return baseMapper.insert(entity) > 0;
}
@Override
public boolean save(TestUser entity) {
  	// 在manager层重写save方法,除了入库操作,还可以考虑操作缓存、调用第三方接口等。
    return baseMapper.insert(entity) > 0;
}

Mapper

mapper层的 insert方法由mybaits-plus动态实现,若不能满足你的需求,建议自己写一个新方法。

修改

Controller

实现了UpdateController,可以重写 handlerSavesave方法。

  • 不建议同时重写这2个方法。
  • 若重写了 update方法没有手动调用 handlerUpdate方法,handlerUpdate将不会被调用
java
@Override
public R<TestUser> update(TestUserUpdateVO testUserUpdateVO) {
    // 自己验证参数

    // 自己调用updateById方法
    return R.success(superService.updateById(testUserUpdateVO));
}

@Override
public R<TestUser> handlerUpdate(TestUserUpdateVO testUserUpdateVO) {
    // 可以编写在调用service.update前的代码,如验证参数

    // 若需要父类帮你调用service.update,请返回 R.successDef();
    return R.successDef();
}
@Override
public R<TestUser> update(TestUserUpdateVO testUserUpdateVO) {
    // 自己验证参数

    // 自己调用updateById方法
    return R.success(superService.updateById(testUserUpdateVO));
}

@Override
public R<TestUser> handlerUpdate(TestUserUpdateVO testUserUpdateVO) {
    // 可以编写在调用service.update前的代码,如验证参数

    // 若需要父类帮你调用service.update,请返回 R.successDef();
    return R.successDef();
}

Service

继承了SuperServiceImpl,可以重写 updateByIdsaveBeforesaveAfter方法。

  • 若重写了 updateById方法,就不建议同时重写 saveBeforesaveAfter方法
  • 若重写了 saveBeforesaveAfter方法,就不建议同时重写 updateById方法
java
@Override
@Transactional(rollbackFor = Exception.class)
public TestUser updateById(TestUserUpdateVO testUserUpdateVO) {
    /* 重写 updateById 方法后,父类的 updateById 方法将不会在执行。若你重写的方法中没有主动调用updateBefore、updateAfter方法,updateBefore、updateAfter方法不会执行,所以不建议同时重写这3个方法。
     当然若你重写的 updateById 方法中手动调用了 updateBefore、updateAfter 方法,则可以同时重写!*/

    TestUser bean = BeanUtil.toBean(testUserUpdateVO, TestUser.class);
    superManager.updateById(bean);
    return bean;
}

@Override
protected TestUser updateBefore(TestUserUpdateVO testUserUpdateVO) {
    // 参数校验、参数初始化等逻辑
    return BeanUtil.toBean(testUserUpdateVO, getEntityClass());
}

@Override
protected void updateAfter(TestUserUpdateVO testUserUpdateVO, TestUser entity) {
    // 保存数据后需要执行的一些操作,如清理缓存、报错从表数据等
}
@Override
@Transactional(rollbackFor = Exception.class)
public TestUser updateById(TestUserUpdateVO testUserUpdateVO) {
    /* 重写 updateById 方法后,父类的 updateById 方法将不会在执行。若你重写的方法中没有主动调用updateBefore、updateAfter方法,updateBefore、updateAfter方法不会执行,所以不建议同时重写这3个方法。
     当然若你重写的 updateById 方法中手动调用了 updateBefore、updateAfter 方法,则可以同时重写!*/

    TestUser bean = BeanUtil.toBean(testUserUpdateVO, TestUser.class);
    superManager.updateById(bean);
    return bean;
}

@Override
protected TestUser updateBefore(TestUserUpdateVO testUserUpdateVO) {
    // 参数校验、参数初始化等逻辑
    return BeanUtil.toBean(testUserUpdateVO, getEntityClass());
}

@Override
protected void updateAfter(TestUserUpdateVO testUserUpdateVO, TestUser entity) {
    // 保存数据后需要执行的一些操作,如清理缓存、报错从表数据等
}

Manager

继承了SuperManagerImpl、SuperCacheManagerImpl,可以重写 updateById方法。 继承了SuperCacheManagerImpl,记得自行清理缓存。

java
@Override
public boolean updateById(TestUser entity) {
    // 在manager层重写save方法,除了入库操作,还可以考虑操作缓存、调用第三方接口等。
    return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
}
@Override
public boolean updateById(TestUser entity) {
    // 在manager层重写save方法,除了入库操作,还可以考虑操作缓存、调用第三方接口等。
    return SqlHelper.retBool(this.getBaseMapper().updateById(entity));
}

Mapper

mapper层的 updateById方法由mybaits-plus动态实现,若不能满足你的需求,建议自己写一个新方法。

复制

Controller

实现了 SaveController,可以重写 copy方法。

java
@Override
public R<TestUser> copy(Long id) {
    return R.success(superService.copy(id));
}
@Override
public R<TestUser> copy(Long id) {
    return R.success(superService.copy(id));
}

Service

java
@Override
@Transactional(rollbackFor = Exception.class)
public TestUser copy(Long id) {
    TestUser old = getById(id);
    ArgumentAssert.notNull(old, "您要复制的数据不存在或已被删除,请刷新重试");
    TestUser entity = BeanPlusUtil.toBean(old, TestUser.class);
    entity.setId(null);
    superManager.save(entity);
    return entity;
}
@Override
@Transactional(rollbackFor = Exception.class)
public TestUser copy(Long id) {
    TestUser old = getById(id);
    ArgumentAssert.notNull(old, "您要复制的数据不存在或已被删除,请刷新重试");
    TestUser entity = BeanPlusUtil.toBean(old, TestUser.class);
    entity.setId(null);
    superManager.save(entity);
    return entity;
}

删除

Controller

实现了 DeleteController,可以重写 handlerDeletedelete方法。

  • 不建议同时重写这2个方法。
  • 若重写了 delete方法没有手动调用 handlerDelete方法,handlerDelete将不会被调用
java
@Override
public R<Boolean> delete(List<Long> ids) {
    return R.success(getSuperService().removeByIds(ids));
}

@Override
public R<Boolean> handlerDelete(List<Long> ids) {
    // 删除前的操作,如验证参数
    return R.successDef();
}
@Override
public R<Boolean> delete(List<Long> ids) {
    return R.success(getSuperService().removeByIds(ids));
}

@Override
public R<Boolean> handlerDelete(List<Long> ids) {
    // 删除前的操作,如验证参数
    return R.successDef();
}

Service

java
@Override
@Transactional(rollbackFor = Exception.class)
public boolean removeByIds(Collection<Long> idList) {
  	// 可以执行其他操作,如删除从表等
    return superManager.removeByIds(idList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean removeByIds(Collection<Long> idList) {
  	// 可以执行其他操作,如删除从表等
    return superManager.removeByIds(idList);
}

Manager

java
@Override
public boolean removeByIds(Collection<?> list) {
    return baseMapper.deleteBatchIds(list) > 0;
}
@Override
public boolean removeByIds(Collection<?> list) {
    return baseMapper.deleteBatchIds(list) > 0;
}

查询

Controller

  • get:单体查询 父类SuperCacheController的 get方法是查询缓存
  • getDetail:单体查询 getDetailget的区别在于 getDetail会执行回显操作
  • query:列表查询
java
@Override
public R<TestUserResultVO> get(Long id) {
    TestUser entity = getSuperService().getById(id);
    return success(BeanPlusUtil.toBean(entity, TestUserResultVO.class));
}

@Override
public R<TestUserResultVO> getDetail(Long id) {
    TestUser entity = getSuperService().getById(id);
    TestUserResultVO resultVO = BeanPlusUtil.toBean(entity, TestUserResultVO.class);
    EchoService echoService = getEchoService();
    if (echoService != null) {
        echoService.action(resultVO);
    }
    return success(resultVO);
}

@Override
public R<List<TestUserResultVO>> query(TestUserPageQuery data) {
    TestUser entity = BeanPlusUtil.toBean(data, TestUser.class);
    QueryWrap<TestUser> wrapper = Wraps.q(entity);
    List<TestUser> list = getSuperService().list(wrapper);
    return success(BeanPlusUtil.toBeanList(list, getResultVOClass()));
}
@Override
public R<TestUserResultVO> get(Long id) {
    TestUser entity = getSuperService().getById(id);
    return success(BeanPlusUtil.toBean(entity, TestUserResultVO.class));
}

@Override
public R<TestUserResultVO> getDetail(Long id) {
    TestUser entity = getSuperService().getById(id);
    TestUserResultVO resultVO = BeanPlusUtil.toBean(entity, TestUserResultVO.class);
    EchoService echoService = getEchoService();
    if (echoService != null) {
        echoService.action(resultVO);
    }
    return success(resultVO);
}

@Override
public R<List<TestUserResultVO>> query(TestUserPageQuery data) {
    TestUser entity = BeanPlusUtil.toBean(data, TestUser.class);
    QueryWrap<TestUser> wrapper = Wraps.q(entity);
    List<TestUser> list = getSuperService().list(wrapper);
    return success(BeanPlusUtil.toBeanList(list, getResultVOClass()));
}

分页查询

controller

若实现了PageController接口,可以重写 pagequeryhandlerQueryParamshandlerWrapperhandlerResult

  • 若重写了 page,就不建议重写其他方法
  • 若重写了 query,就不建议重写 handlerQueryParamshandlerWrapper

前端

默认情况下,会将表中除了创建人、修改人等字段外的所有字段均展示在前端页面,但复杂的业务,往往不需要讲所有字段都展示在页面上。这时就需要开发人员手动调整生成的代码,将多余的字段删除或隐藏。

字典选择

想要在表单的某个字段选择字典数据,可以在component属性指定配置 ApiSelectApiRadioGroup组件,这2个组件仅在UI表现形式上不同。同时需要在componentProps属性指定 dictComponentProps方法。

提示

  • 字典类型 如:性别、民族
  • 字典条目 如:男、女、汉族、苗族
  • 扩展条目 如:后台的数据字典=性别=只配置了 男、女 2个条目,但在某些业务下,需要选择=全部、男、女=等选项,可以通过 dictComponentProps方法的 extendexetndFirst参数配置。
tsx
export const editFormSchema = (_type: Ref<ActionEnum>): FormSchema[] => {
  return [
    {
      label: t('ddd.user.testUser.education'),
      field: 'education',
      component: 'ApiRadioGroup',
      componentProps: {
        // 建议将魔法数参数移动到 DictEnum 中,并添加为: EchoDictType_Global_EDUCATION = 'EDUCATION';
        // 'EDUCATION' 需要与 后端DictType类中的参数 以及 def_dict表中的key字段 保持一致,否则无法回显!
        // ...dictComponentProps(DictEnum.EchoDictType_Global_EDUCATION),
        ...dictComponentProps('EDUCATION'),
      },
    },  
  ]
}
export const editFormSchema = (_type: Ref<ActionEnum>): FormSchema[] => {
  return [
    {
      label: t('ddd.user.testUser.education'),
      field: 'education',
      component: 'ApiRadioGroup',
      componentProps: {
        // 建议将魔法数参数移动到 DictEnum 中,并添加为: EchoDictType_Global_EDUCATION = 'EDUCATION';
        // 'EDUCATION' 需要与 后端DictType类中的参数 以及 def_dict表中的key字段 保持一致,否则无法回显!
        // ...dictComponentProps(DictEnum.EchoDictType_Global_EDUCATION),
        ...dictComponentProps('EDUCATION'),
      },
    },  
  ]
}
tsx
/**
 * @param type 					字典类型
 * @param extendFirst  	扩展条目放在第一位还是最后一位
 * @param extend  			扩展条目
 * @param excludes 			需要排除的字典条目 
 */
export const dictComponentProps = (
  type: DictEnum | string,
  extendFirst = true,
  extend?: any,
  excludes?: string | string[],
) => {
  if (excludes && isString(excludes)) {
    excludes = [excludes];
  }
  return {
    api: asyncFindDictList,
    params: { type, extend, extendFirst, excludes },
    resultField: 'data',
    showSearch: true,
    filterOption: (input: string, option: any) => {
      return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0;
    },
  };
};
/**
 * @param type 					字典类型
 * @param extendFirst  	扩展条目放在第一位还是最后一位
 * @param extend  			扩展条目
 * @param excludes 			需要排除的字典条目 
 */
export const dictComponentProps = (
  type: DictEnum | string,
  extendFirst = true,
  extend?: any,
  excludes?: string | string[],
) => {
  if (excludes && isString(excludes)) {
    excludes = [excludes];
  }
  return {
    api: asyncFindDictList,
    params: { type, extend, extendFirst, excludes },
    resultField: 'data',
    showSearch: true,
    filterOption: (input: string, option: any) => {
      return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0;
    },
  };
};

枚举选择

想要在表单的某个字段选择后台定义的枚举类型数据,可以在component属性指定配置 ApiSelectApiRadioGroup组件,这2个组件仅在UI表现形式上不同。同时需要在componentProps属性指定 enumComponentProps方法。

注意

假如你想查询到 order服务 的枚举类 OrderStatusEnum,OrderStatusEnum类存放在 acuity-order-entity模块,你必须在 acuity-oauth-controler/pom.xml文件中加入 acuity-order-entity的依赖。

xml
<dependency>
    <groupId>top.acuity.box</groupId>
    <artifactId>acuity-order-entity</artifactId>
    <version>${acuity-project.version}</version>
</dependency>
<dependency>
    <groupId>top.acuity.box</groupId>
    <artifactId>acuity-order-entity</artifactId>
    <version>${acuity-project.version}</version>
</dependency>
tsx
export const editFormSchema = (_type: Ref<ActionEnum>): FormSchema[] => {
  return [
    {
      label: t('basic.system.baseFile.storageType'),
      field: 'storageType',
      component: 'ApiSelect',
      componentProps: {
        ...enumComponentProps('FileStorageType'),
      },
    },   
  ]
}
export const editFormSchema = (_type: Ref<ActionEnum>): FormSchema[] => {
  return [
    {
      label: t('basic.system.baseFile.storageType'),
      field: 'storageType',
      component: 'ApiSelect',
      componentProps: {
        ...enumComponentProps('FileStorageType'),
      },
    },   
  ]
}
tsx
/**
 * @param type 					字典类型
 * @param extendFirst  	扩展条目放在第一位还是最后一位
 * @param extend  			扩展条目
 * @param excludes 			需要排除的字典条目 
 */
export const enumComponentProps = (
  type: EnumEnum | string,
  extendFirst = true,
  extend?: any,
  excludes?: string | string[],
) => {
  if (excludes && isString(excludes)) {
    excludes = [excludes];
  }
  return {
    api: asyncFindEnumList,
    params: { type, extendFirst, extend, excludes },
    resultField: 'data',
    showSearch: true,
    filterOption: (input: string, option: any) => {
      return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0;
    },
  };
};
/**
 * @param type 					字典类型
 * @param extendFirst  	扩展条目放在第一位还是最后一位
 * @param extend  			扩展条目
 * @param excludes 			需要排除的字典条目 
 */
export const enumComponentProps = (
  type: EnumEnum | string,
  extendFirst = true,
  extend?: any,
  excludes?: string | string[],
) => {
  if (excludes && isString(excludes)) {
    excludes = [excludes];
  }
  return {
    api: asyncFindEnumList,
    params: { type, extendFirst, extend, excludes },
    resultField: 'data',
    showSearch: true,
    filterOption: (input: string, option: any) => {
      return option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0;
    },
  };
};

表格回显

数据想要回显,后端接口一定得调用 echoService.action(page);方法。

tsx
export const columns = (): BasicColumn[] => {
  return [
    {
      title: t('ddd.user.testUser.sex'),
      dataIndex: ['echoMap', 'sex'],
      key: 'sex',
    },
  ]
}
export const columns = (): BasicColumn[] => {
  return [
    {
      title: t('ddd.user.testUser.sex'),
      dataIndex: ['echoMap', 'sex'],
      key: 'sex',
    },
  ]
}
java
@Override
@WebLog(value = "'分页列表查询:第' + #params?.current + '页, 显示' + #params?.size + '行'", response = false)
public R<IPage<TestUserResultVO>> page(@RequestBody @Validated PageParams<TestUserPageQuery> params) {
    IPage<TestUserResultVO> page = superService.findPageResultVO(params);
    echoService.action(page);
    return R.success(page);
}
@Override
@WebLog(value = "'分页列表查询:第' + #params?.current + '页, 显示' + #params?.size + '行'", response = false)
public R<IPage<TestUserResultVO>> page(@RequestBody @Validated PageParams<TestUserPageQuery> params) {
    IPage<TestUserResultVO> page = superService.findPageResultVO(params);
    echoService.action(page);
    return R.success(page);
}

按钮权限

按钮详情

下图展现了系统页面常用的几种按钮,都可以通过权限控制来使不同用户看不同的按钮。

按钮级权限的控制方式有几种:

  • 权限组件

  • 自定义指令

  • 函数方式过滤

  • 属性

  • 权限组件

权限组件使用于包装一个独立的组件,如: 等等

vue
<template>
  <div>
    <Authority :value="RoleEnum.SUPER">
      <a-button class="mx-4" type="primary"> 拥有super权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]">
      <a-button class="mx-4" color="error"> 同时拥有[test,super]权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]" :mode="PermModeEnum.HasAny">
      <a-button class="mx-4" color="success"> 拥有任意一个[test,super]权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]" :mode="PermModeEnum.Without">
      <a-button class="mx-4" color="success"> 没有所有[test,super]权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]" :mode="PermModeEnum.WithoutAny">
      <a-button class="mx-4" color="success"> 没有任意一个[test,super]权限可见 </a-button>
    </Authority>
    
  </div>
</template>
<script>
  import { Authority } from '/@/components/Authority';
  import { defineComponent } from 'vue';
  export default defineComponent({
    components: { Authority },
  });
</script>
<template>
  <div>
    <Authority :value="RoleEnum.SUPER">
      <a-button class="mx-4" type="primary"> 拥有super权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]">
      <a-button class="mx-4" color="error"> 同时拥有[test,super]权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]" :mode="PermModeEnum.HasAny">
      <a-button class="mx-4" color="success"> 拥有任意一个[test,super]权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]" :mode="PermModeEnum.Without">
      <a-button class="mx-4" color="success"> 没有所有[test,super]权限可见 </a-button>
    </Authority>
    
    <Authority :value="[RoleEnum.TEST, RoleEnum.SUPER]" :mode="PermModeEnum.WithoutAny">
      <a-button class="mx-4" color="success"> 没有任意一个[test,super]权限可见 </a-button>
    </Authority>
    
  </div>
</template>
<script>
  import { Authority } from '/@/components/Authority';
  import { defineComponent } from 'vue';
  export default defineComponent({
    components: { Authority },
  });
</script>
  • 自定义指令

自定义指令也可以作用于需要控制权限的独立组件上,如: 等等

指令集

  • withoutPermission没有所有权限时渲染该组件
  • withoutAnyPermission没有任意一个权限时渲染该组件
  • hasPermission拥有所有权限时渲染该组件
  • hasAnyPermission拥有任意一个权限时渲染该组件
vue
<template>
  <div>
 	  <a-button v-hasPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" type="primary"> 
      同时拥有[test,super]权限可见 
 	  </a-button>
    <a-button v-hasAnyPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" color="error">
      拥有任意一个[test,super]权限可见
    </a-button>    
    <a-button v-withoutPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" color="success"> 
      没有所有[test,super]权限可见
  	</a-button>
    <a-button v-withoutAnyPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" color="error">
      没有任意一个[test,super]权限可见
    </a-button>
  </div>
</template>
<script>
  import { defineComponent } from 'vue';
  export default defineComponent({
    components: {  },
  });
</script>
<template>
  <div>
 	  <a-button v-hasPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" type="primary"> 
      同时拥有[test,super]权限可见 
 	  </a-button>
    <a-button v-hasAnyPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" color="error">
      拥有任意一个[test,super]权限可见
    </a-button>    
    <a-button v-withoutPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" color="success"> 
      没有所有[test,super]权限可见
  	</a-button>
    <a-button v-withoutAnyPermission="[RoleEnum.TEST, RoleEnum.SUPER]" class="mx-4" color="error">
      没有任意一个[test,super]权限可见
    </a-button>
  </div>
</template>
<script>
  import { defineComponent } from 'vue';
  export default defineComponent({
    components: {  },
  });
</script>
  • 函数方式过滤

在能调用isPermission函数的地方,直接调用isPermission函数控制按钮权限

vue
<template>
  <div>
 	  <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.Has)" class="mx-4" type="primary"> 
      同时拥有[test,super]权限可见 
 	  </a-button>
    <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.HasAny)" class="mx-4" color="error">
      拥有任意一个[test,super]权限可见
    </a-button>    
    <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.Without)" class="mx-4" color="success"> 
      没有所有[test,super]权限可见
  	</a-button>
    <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.WithoutAny)" class="mx-4" color="error">
      没有任意一个[test,super]权限可见
    </a-button>
  </div>
</template>
<script>
  import { defineComponent } from 'vue';
  import { usePermission } from '/@/hooks/web/usePermission';
	import { RoleEnum, PermModeEnum } from '/@/enums/roleEnum';
  
  export default defineComponent({
    setup() {
      const { isPermission } = usePermission();
      
      return { isPermission, RoleEnum, PermModeEnum };
    }
  });
</script>
<template>
  <div>
 	  <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.Has)" class="mx-4" type="primary"> 
      同时拥有[test,super]权限可见 
 	  </a-button>
    <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.HasAny)" class="mx-4" color="error">
      拥有任意一个[test,super]权限可见
    </a-button>    
    <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.Without)" class="mx-4" color="success"> 
      没有所有[test,super]权限可见
  	</a-button>
    <a-button v-if="isPermission([RoleEnum.TEST, RoleEnum.SUPER], PermModeEnum.WithoutAny)" class="mx-4" color="error">
      没有任意一个[test,super]权限可见
    </a-button>
  </div>
</template>
<script>
  import { defineComponent } from 'vue';
  import { usePermission } from '/@/hooks/web/usePermission';
	import { RoleEnum, PermModeEnum } from '/@/enums/roleEnum';
  
  export default defineComponent({
    setup() {
      const { isPermission } = usePermission();
      
      return { isPermission, RoleEnum, PermModeEnum };
    }
  });
</script>
  • 属性 BasieTable操作栏、BasicTree操作栏、BasicTree右键菜单等可以通过auth属性来控制。
vue
<template>
  <div class="p-4">
    <BasicTable @register="registerTable">
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'action'">
          <TableAction
            :actions="[
              {
                label: '编辑',
                onClick: handleEdit.bind(null, record),
                auth: [RoleEnum.TEST, RoleEnum.SUPER], //同时拥有[test,super]权限可见 
                mode: PermModeEnum.Has
              },
              {
                label: '删除',
                icon: 'ic:outline-delete-outline',
                onClick: handleDelete.bind(null, record),
                auth: [RoleEnum.TEST, RoleEnum.SUPER], // 拥有任意一个[test,super]权限可见
                mode: PermModeEnum.HasAny
              },
            ]"
            :dropDownActions="[
              {
                label: '禁用',
                popConfirm: {
                  title: '是否禁用?',
                  confirm: handleOpen.bind(null, record),
                },
                auth: [RoleEnum.TEST, RoleEnum.SUPER], // 没有所有[test,super]权限可见
                mode: PermModeEnum.Without
              },
              {
                label: '同时控制',
                popConfirm: {
                  title: '是否动态显示?',
                  confirm: handleOpen.bind(null, record),
                },
                auth: [RoleEnum.TEST, RoleEnum.SUPER], // 没有任意一个[test,super]权限可见
                mode: PermModeEnum.WithoutAny
              },
            ]"
          />
        </template>
      </template>
    </BasicTable>
  </div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import { BasicTable, useTable, BasicColumn, TableAction } from '/@/components/Table';
	import { RoleEnum, PermModeEnum } from '/@/enums/roleEnum';

  import { demoListApi } from '/@/api/demo/table';
  const columns: BasicColumn[] = [
    {
      title: '编号',
      dataIndex: 'no',
      width: 100,
    },
    {
      title: '姓名',
      dataIndex: 'name',
      width: 200,
    },
    
  ];
  export default defineComponent({
    components: { BasicTable, TableAction },
    setup() {
      const [registerTable] = useTable({
        title: 'TableAction组件及固定列示例',
        api: demoListApi,
        columns: columns,
        bordered: true,
        rowKey: 'id',
        rowSelection: {
          type: 'checkbox',
        },
        actionColumn: {
          width: 250,
          title: 'Action',
          dataIndex: 'action',
        },
      });
      function handleEdit(record: Recordable) {
        console.log('点击了编辑', record);
      }
      function handleDelete(record: Recordable) {
        console.log('点击了删除', record);
      }
      function handleOpen(record: Recordable) {
        console.log('点击了启用', record);
      }
      return {
        registerTable,
        handleEdit,
        handleDelete,
        handleOpen,
        RoleEnum, 
        PermModeEnum,
      };
    },
  });
</script>
<template>
  <div class="p-4">
    <BasicTable @register="registerTable">
      <template #bodyCell="{ column, record }">
        <template v-if="column.key === 'action'">
          <TableAction
            :actions="[
              {
                label: '编辑',
                onClick: handleEdit.bind(null, record),
                auth: [RoleEnum.TEST, RoleEnum.SUPER], //同时拥有[test,super]权限可见 
                mode: PermModeEnum.Has
              },
              {
                label: '删除',
                icon: 'ic:outline-delete-outline',
                onClick: handleDelete.bind(null, record),
                auth: [RoleEnum.TEST, RoleEnum.SUPER], // 拥有任意一个[test,super]权限可见
                mode: PermModeEnum.HasAny
              },
            ]"
            :dropDownActions="[
              {
                label: '禁用',
                popConfirm: {
                  title: '是否禁用?',
                  confirm: handleOpen.bind(null, record),
                },
                auth: [RoleEnum.TEST, RoleEnum.SUPER], // 没有所有[test,super]权限可见
                mode: PermModeEnum.Without
              },
              {
                label: '同时控制',
                popConfirm: {
                  title: '是否动态显示?',
                  confirm: handleOpen.bind(null, record),
                },
                auth: [RoleEnum.TEST, RoleEnum.SUPER], // 没有任意一个[test,super]权限可见
                mode: PermModeEnum.WithoutAny
              },
            ]"
          />
        </template>
      </template>
    </BasicTable>
  </div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import { BasicTable, useTable, BasicColumn, TableAction } from '/@/components/Table';
	import { RoleEnum, PermModeEnum } from '/@/enums/roleEnum';

  import { demoListApi } from '/@/api/demo/table';
  const columns: BasicColumn[] = [
    {
      title: '编号',
      dataIndex: 'no',
      width: 100,
    },
    {
      title: '姓名',
      dataIndex: 'name',
      width: 200,
    },
    
  ];
  export default defineComponent({
    components: { BasicTable, TableAction },
    setup() {
      const [registerTable] = useTable({
        title: 'TableAction组件及固定列示例',
        api: demoListApi,
        columns: columns,
        bordered: true,
        rowKey: 'id',
        rowSelection: {
          type: 'checkbox',
        },
        actionColumn: {
          width: 250,
          title: 'Action',
          dataIndex: 'action',
        },
      });
      function handleEdit(record: Recordable) {
        console.log('点击了编辑', record);
      }
      function handleDelete(record: Recordable) {
        console.log('点击了删除', record);
      }
      function handleOpen(record: Recordable) {
        console.log('点击了启用', record);
      }
      return {
        registerTable,
        handleEdit,
        handleDelete,
        handleOpen,
        RoleEnum, 
        PermModeEnum,
      };
    },
  });
</script>
vue
<template>
  <BasicTree
    ref="treeRef"
    :actionList="actionList"
    :beforeRightClick="getRightMenuList"
    :title="t('basic.user.baseOrg.table.title')"
    :treeData="treeData"
  >
  </BasicTree>
</template>
<script lang="ts">
  import { defineComponent, h, ref, unref } from 'vue';
  import { useI18n } from '/@/hooks/web/useI18n';
  import {
    BasicTree,
    ContextMenuItem,
    TreeActionItem,
    TreeActionType,
    TreeItem,
  } from '/@/components/Tree';
  import { eachTree, findChildrenByParentId, findNodeByKey } from '/@/utils/helper/treeHelper';
  import { RoleEnum } from '/@/enums/roleEnum';
  import { OrgTypeEnum } from '/@/enums/biz/base';

  import { tree } from '/@/api/basic/user/baseOrg';

  export default defineComponent({
    name: 'BaseOrgManagement',
    components: { BasicTree },
    emits: ['select', 'add', 'edit', 'change', 'reset'],
    setup(props, { emit }) {
      const { t } = useI18n();
      const { createMessage, createConfirm } = useMessage();
      const treeRef = ref<Nullable<TreeActionType>>(null);
      const treeData = ref<TreeItem[]>([]);
      // 绑定角色
      const [registerModal, { openModal }] = useModal();

      function getTree() {
        const tree = unref(treeRef);
        if (!tree) {
          throw new Error('树结构加载失败,请刷新页面');
        }
        return tree;
      }

      // 加载数据
      async function fetch() {
        treeData.value = (await tree()) as unknown as TreeItem[];
        eachTree(treeData.value, (item) => {
          item.key = item.id;
          item.title = item.name;
          item.slots = { titleBefore: 'titleBefore' };
          return item;
        });
        setTimeout(() => {
          getTree().filterByLevel(2);
        }, 0);
      }

      let actionList: TreeActionItem[] = [];
      let getRightMenuList = (_: any): ContextMenuItem[] => {
        return [];
      };
     
        // 悬停图标
        actionList = [
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.Has,
            render: (node) => {
              return h(
                'a', {}, t('common.title.add'),
              );
            },
          },
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.HasAny,
            render: (node) => {
              return h(
                'a',{}, t('common.title.edit'),
              );
            },
          },
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.Without,
            render: (node) => {
              return h(
                'a', {}, t('common.title.delete'),
              );
            },
          },
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.WithoutAny,
            render: (node) => {
              return h(
                'a', {}, t('common.title.delete'),
              );
            },
          },
        ];

        // 右键菜单
        getRightMenuList = (node: any): ContextMenuItem[] => {
          return [
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.Has,
              label: t('common.title.addChildren'),
              icon: 'ant-design:plus-outlined',
            },
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.HasAny,
              label: t('common.title.edit'),
              icon: 'ant-design:edit-outlined',
            },
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.Without,
              label: t('common.title.delete'),
              icon: 'ant-design:delete-outlined',
            },
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.WithoutAny,
              label: t('common.title.delete'),
              icon: 'ant-design:delete-outlined',
            },
          ];
        };

      return {
        t,
        treeRef,
        treeData,
        getRightMenuList,
        actionList,
      };
    },
  });
</script>
<template>
  <BasicTree
    ref="treeRef"
    :actionList="actionList"
    :beforeRightClick="getRightMenuList"
    :title="t('basic.user.baseOrg.table.title')"
    :treeData="treeData"
  >
  </BasicTree>
</template>
<script lang="ts">
  import { defineComponent, h, ref, unref } from 'vue';
  import { useI18n } from '/@/hooks/web/useI18n';
  import {
    BasicTree,
    ContextMenuItem,
    TreeActionItem,
    TreeActionType,
    TreeItem,
  } from '/@/components/Tree';
  import { eachTree, findChildrenByParentId, findNodeByKey } from '/@/utils/helper/treeHelper';
  import { RoleEnum } from '/@/enums/roleEnum';
  import { OrgTypeEnum } from '/@/enums/biz/base';

  import { tree } from '/@/api/basic/user/baseOrg';

  export default defineComponent({
    name: 'BaseOrgManagement',
    components: { BasicTree },
    emits: ['select', 'add', 'edit', 'change', 'reset'],
    setup(props, { emit }) {
      const { t } = useI18n();
      const { createMessage, createConfirm } = useMessage();
      const treeRef = ref<Nullable<TreeActionType>>(null);
      const treeData = ref<TreeItem[]>([]);
      // 绑定角色
      const [registerModal, { openModal }] = useModal();

      function getTree() {
        const tree = unref(treeRef);
        if (!tree) {
          throw new Error('树结构加载失败,请刷新页面');
        }
        return tree;
      }

      // 加载数据
      async function fetch() {
        treeData.value = (await tree()) as unknown as TreeItem[];
        eachTree(treeData.value, (item) => {
          item.key = item.id;
          item.title = item.name;
          item.slots = { titleBefore: 'titleBefore' };
          return item;
        });
        setTimeout(() => {
          getTree().filterByLevel(2);
        }, 0);
      }

      let actionList: TreeActionItem[] = [];
      let getRightMenuList = (_: any): ContextMenuItem[] => {
        return [];
      };
     
        // 悬停图标
        actionList = [
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.Has,
            render: (node) => {
              return h(
                'a', {}, t('common.title.add'),
              );
            },
          },
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.HasAny,
            render: (node) => {
              return h(
                'a',{}, t('common.title.edit'),
              );
            },
          },
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.Without,
            render: (node) => {
              return h(
                'a', {}, t('common.title.delete'),
              );
            },
          },
          {
            auth: [RoleEnum.TEST, RoleEnum.SUPER],
            authMode: PermModeEnum.WithoutAny,
            render: (node) => {
              return h(
                'a', {}, t('common.title.delete'),
              );
            },
          },
        ];

        // 右键菜单
        getRightMenuList = (node: any): ContextMenuItem[] => {
          return [
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.Has,
              label: t('common.title.addChildren'),
              icon: 'ant-design:plus-outlined',
            },
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.HasAny,
              label: t('common.title.edit'),
              icon: 'ant-design:edit-outlined',
            },
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.Without,
              label: t('common.title.delete'),
              icon: 'ant-design:delete-outlined',
            },
            {
              auth: [RoleEnum.TEST, RoleEnum.SUPER],
              authMode: PermModeEnum.WithoutAny,
              label: t('common.title.delete'),
              icon: 'ant-design:delete-outlined',
            },
          ];
        };

      return {
        t,
        treeRef,
        treeData,
        getRightMenuList,
        actionList,
      };
    },
  });
</script>
  • 属性
vue
export interface ActionItem extends ButtonProps {
  // 权限编码
  auth?: RoleEnum | RoleEnum[] | string | string[];
  // 权限模式。Has-拥有所有,HasAny-拥有任意一个,Without-没有所有,WithoutAny-没有任意一个
  authMode?: PermModeEnum;
}
export interface ActionItem extends ButtonProps {
  // 权限编码
  auth?: RoleEnum | RoleEnum[] | string | string[];
  // 权限模式。Has-拥有所有,HasAny-拥有任意一个,Without-没有所有,WithoutAny-没有任意一个
  authMode?: PermModeEnum;
}

字段权限

[字段详情]
vue
<template>
  <div class="p-4">
    <BasicTable @register="registerTable">
    </BasicTable>
  </div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import { BasicTable, useTable, BasicColumn } from '/@/components/Table';

  import { demoListApi } from '/@/api/demo/table';
  const columns: BasicColumn[] = [
    {
      title: '编号',
      dataIndex: 'no',
      width: 100,
    },
    {
      title: '姓名1',
      dataIndex: 'name1',
      width: 200,
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.Has,
    },
    {
      title: '姓名2',
      dataIndex: 'name2',
      width: 200,
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.HasAny,
    },    
    {
      title: '姓名',
      dataIndex: 'name',
      width: 200,
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.Without,
    },
    {
      title: '地址',
      dataIndex: 'address',
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.WithoutAny,
    },
  ];
  export default defineComponent({
    components: { BasicTable },
    setup() {
      const [registerTable] = useTable({
        title: '权限列实例',
        api: demoListApi,
        columns: columns,
        bordered: true,
        rowKey: 'id',
        rowSelection: {
          type: 'checkbox',
        },
        actionColumn: {
          width: 250,
          title: 'Action',
          dataIndex: 'action',
          // slots: { customRender: 'action' },
        },
      });
      
      return {
        registerTable,
      };
    },
  });
</script>
<template>
  <div class="p-4">
    <BasicTable @register="registerTable">
    </BasicTable>
  </div>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import { BasicTable, useTable, BasicColumn } from '/@/components/Table';

  import { demoListApi } from '/@/api/demo/table';
  const columns: BasicColumn[] = [
    {
      title: '编号',
      dataIndex: 'no',
      width: 100,
    },
    {
      title: '姓名1',
      dataIndex: 'name1',
      width: 200,
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.Has,
    },
    {
      title: '姓名2',
      dataIndex: 'name2',
      width: 200,
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.HasAny,
    },    
    {
      title: '姓名',
      dataIndex: 'name',
      width: 200,
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.Without,
    },
    {
      title: '地址',
      dataIndex: 'address',
      auth: [RoleEnum.TEST, RoleEnum.SUPER],
      authMode: PermModeEnum.WithoutAny,
    },
  ];
  export default defineComponent({
    components: { BasicTable },
    setup() {
      const [registerTable] = useTable({
        title: '权限列实例',
        api: demoListApi,
        columns: columns,
        bordered: true,
        rowKey: 'id',
        rowSelection: {
          type: 'checkbox',
        },
        actionColumn: {
          width: 250,
          title: 'Action',
          dataIndex: 'action',
          // slots: { customRender: 'action' },
        },
      });
      
      return {
        registerTable,
      };
    },
  });
</script>
vue
export interface ActionItem extends ButtonProps {
  // 权限编码
  auth?: RoleEnum | RoleEnum[] | string | string[];
  // 权限模式。Has-拥有所有,HasAny-拥有任意一个,Without-没有所有,WithoutAny-没有任意一个
  authMode?: PermModeEnum;
}
export interface ActionItem extends ButtonProps {
  // 权限编码
  auth?: RoleEnum | RoleEnum[] | string | string[];
  // 权限模式。Has-拥有所有,HasAny-拥有任意一个,Without-没有所有,WithoutAny-没有任意一个
  authMode?: PermModeEnum;
}

自定义表单验证

生成的前端 Edit.vue页面已经自动封装了前后端统一校验功能,但后端返回的校验规则很有可能无法满足前端的业务,此时就需要前端进行自定义校验规则。

typescript
const [registerModel, { setModalProps: setProps, closeModal: close }] = useModalInner(async (data) => {
  setProps({ confirmLoading: false });
  await resetSchema(editFormSchema(type));
  await resetFields();
  type.value = data?.type || ActionEnum.ADD;

  if (unref(type) !== ActionEnum.ADD) {
    // 赋值
    const record = { ...data?.record };
    await setFieldsValue(record);
  }

  if (unref(type) !== ActionEnum.VIEW) {
    let validateApi = Api[VALIDATE_API[unref(type)]];
    // 先去 validateApi 接口查询后端的校验规则,在和前端自定义的校验规则 customFormSchemaRules 进行合并
    await getValidateRules(validateApi, customFormSchemaRules(type)).then(async (rules) => {
      rules && rules.length > 0 && (await updateSchema(rules));
    });
  }
});
const [registerModel, { setModalProps: setProps, closeModal: close }] = useModalInner(async (data) => {
  setProps({ confirmLoading: false });
  await resetSchema(editFormSchema(type));
  await resetFields();
  type.value = data?.type || ActionEnum.ADD;

  if (unref(type) !== ActionEnum.ADD) {
    // 赋值
    const record = { ...data?.record };
    await setFieldsValue(record);
  }

  if (unref(type) !== ActionEnum.VIEW) {
    let validateApi = Api[VALIDATE_API[unref(type)]];
    // 先去 validateApi 接口查询后端的校验规则,在和前端自定义的校验规则 customFormSchemaRules 进行合并
    await getValidateRules(validateApi, customFormSchemaRules(type)).then(async (rules) => {
      rules && rules.length > 0 && (await updateSchema(rules));
    });
  }
});
tsx
export const customFormSchemaRules = (
  type: Ref<ActionEnum>,
  getFieldsValue: () => Recordable,
): Partial<FormSchemaExt>[] => {
  return [
    {
      field: 'key',
      type: RuleType.append,   // 追加规则、覆盖规则
      rules: [
        {
          trigger: ['change', 'blur'],
          async validator(_, value) {
            if (type.value === ActionEnum.EDIT) {
              return Promise.resolve();
            }
            if (value && (await check(value, getFieldsValue()?.parentId, getFieldsValue()?.id))) {
              return Promise.reject(t('basic.base.baseDict.key') + '已经存在');
            }
            return Promise.resolve();
          },
        },
      ],
    },
  ];
};
export const customFormSchemaRules = (
  type: Ref<ActionEnum>,
  getFieldsValue: () => Recordable,
): Partial<FormSchemaExt>[] => {
  return [
    {
      field: 'key',
      type: RuleType.append,   // 追加规则、覆盖规则
      rules: [
        {
          trigger: ['change', 'blur'],
          async validator(_, value) {
            if (type.value === ActionEnum.EDIT) {
              return Promise.resolve();
            }
            if (value && (await check(value, getFieldsValue()?.parentId, getFieldsValue()?.id))) {
              return Promise.reject(t('basic.base.baseDict.key') + '已经存在');
            }
            return Promise.resolve();
          },
        },
      ],
    },
  ];
};

欢迎使用天源云Saas快速开发系统