1. 新增业务数据查询,新增 部门 数据权限规则支持

2. 补全子角色排除父角色管理菜单测试用例
This commit is contained in:
chenbowen
2025-07-15 10:01:46 +08:00
parent 7f0957d9c4
commit eaea76e955
11 changed files with 360 additions and 26 deletions

View File

@@ -34,7 +34,7 @@ public interface ErrorCodeConstants {
ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能操作类型为系统内置的角色");
ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用");
ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "标识【{}】不能使用");
ErrorCode ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE = new ErrorCode(1_002_002_006, "不能操作类型为标准的角色,除非是管理员角色");
ErrorCode ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE = new ErrorCode(1_002_002_006, "非管理员,不能操作类型为标准的角色");
ErrorCode ROLE_CAN_NOT_DELETE_HAS_CHILDREN = new ErrorCode(1_002_002_007, " 角色【{}】存在子角色,不允许删除");
ErrorCode ROLE_PARENT_IS_CHILD = new ErrorCode(1_002_002_008, "不能设置自己的子角色为父角色");

View File

@@ -157,29 +157,50 @@ public class PermissionServiceImpl implements PermissionService {
allEntries = true) // allEntries 清空所有缓存,主要一次更新涉及到的 menuIds 较多,反倒批量会更快
})
public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
RoleDO role = roleService.getRole(roleId);
Set<Long> userRoleIdListByUserId = permissionService.getUserRoleIdListByUserId(getLoginUserId());
// 如果为标准角色,只允许管理员修改菜单权限
if (RoleTypeEnum.NORMAL.getType().equals(role.getType()) && !roleService.hasAnySuperAdmin(userRoleIdListByUserId)) {
throw exception(ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE);
}
// 获得角色拥有菜单编号
Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
Set<Long> dbMenuIds = convertSet(getRoleMenuListByRoleId(roleId));
// 获取父级角色拥有的菜单编号
Set<Long> parentRoleIds = roleService.getAllParentAndSelfRoleIds(singleton(roleId));
// 移除自身角色编号
parentRoleIds.remove(roleId);
Set<Long> dbInheritedMenuIds = convertSet(roleMenuMapper.selectListByRoleId(parentRoleIds), RoleMenuDO::getMenuId);
// 计算新增和删除的菜单编号
Set<Long> menuIdList = CollUtil.emptyIfNull(menuIds);
Collection<Long> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds);
Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList);
// 执行新增和删除。对于已经授权的菜单,不用做任何处理
// 执行新增和删除。对于已经授权的菜单,不用进行新增和删除,处理排除关系即可
if (CollUtil.isNotEmpty(createMenuIds)) {
roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> {
RoleMenuDO entity = new RoleMenuDO();
entity.setRoleId(roleId);
entity.setMenuId(menuId);
return entity;
}));
Set<Long> inheritedCreateMenuIds = new HashSet<>(dbInheritedMenuIds);
inheritedCreateMenuIds.retainAll(createMenuIds);
if (CollUtil.isNotEmpty(inheritedCreateMenuIds)) {
// 不需要新增,只需要检查是否存在排除关系,如果存在,则标记排除关系失效
roleMenuExclusionMapper.deleteListByRoleIdAndMenuIds(roleId, inheritedCreateMenuIds);
createMenuIds.removeAll(inheritedCreateMenuIds);
}
if (CollUtil.isNotEmpty(createMenuIds)) {
roleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> {
RoleMenuDO entity = new RoleMenuDO();
entity.setRoleId(roleId);
entity.setMenuId(menuId);
return entity;
}));
}
}
if (CollUtil.isNotEmpty(deleteMenuIds)) {
roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds);
Set<Long> inheritedDeleteMenuIds = new HashSet<>(dbInheritedMenuIds);
inheritedDeleteMenuIds.retainAll(deleteMenuIds);
if (CollUtil.isNotEmpty(inheritedDeleteMenuIds)) {
// 标记排除
roleMenuExclusionMapper.insertBatch(CollectionUtils.convertList(inheritedDeleteMenuIds, menuId -> {
RoleMenuExclusionDO entity = new RoleMenuExclusionDO();
entity.setRoleId(roleId);
entity.setMenuId(menuId);
return entity;
}));
}
if (CollUtil.isNotEmpty(deleteMenuIds)) {
roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds);
}
}
}
@@ -303,7 +324,7 @@ public class PermissionServiceImpl implements PermissionService {
Set<Long> userRoleIdListByUserId = permissionService.getUserRoleIdListByUserId(getLoginUserId());
// 如果为标准角色,只允许管理员修改数据权限
if (RoleTypeEnum.NORMAL.getType().equals(role.getType()) && !roleService.hasAnySuperAdmin(userRoleIdListByUserId)) {
throw exception(ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
throw exception(ROLE_CAN_NOT_UPDATE_NORMAL_TYPE_ROLE);
}
roleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds);
}

View File

@@ -383,4 +383,29 @@ public class PermissionServiceTest extends BaseDbUnitTest {
assertTrue(menuIds2.contains(101L));
}
/**
* 测试子角色排除父角色菜单
* 通过 Service 方法排除,确保子角色不继承父角色的菜单
*/
@Test
public void testExcludeParentRoleMenu() {
// mock 父子关系 A->B
RoleDO parentRole = randomPojo(RoleDO.class, o -> o.setParentId(0L));
roleMapper.insert(parentRole);
RoleDO childRole = randomPojo(RoleDO.class, o -> o.setParentId(parentRole.getId()));
roleMapper.insert(childRole);
// 父角色分配菜单
RoleMenuDO parentMenu = randomPojo(RoleMenuDO.class).setRoleId(parentRole.getId()).setMenuId(101L);
roleMenuMapper.insert(parentMenu);
// 子角色排除父菜单(通过 Service 方法排除)
permissionService.assignRoleMenu(childRole.getId(), Collections.emptySet());
// 调用:获取子角色菜单(应不包含父菜单)
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(childRole.getId());
assertFalse(menuIds.contains(101L));
// 新增了子角色的排除菜单记录
List<RoleMenuExclusionDO> exclusionDOS = roleMenuExclusionMapper.selectMenuIdListByRoleId(Collections.singleton(childRole.getId()));
assertEquals(1, exclusionDOS.size());
assertEquals(101L, exclusionDOS.get(0).getMenuId());
}
}