fix(菜单权限): 后台侧边栏为部分授权用户补全祖先分组(二级菜单不再平铺)
只勾选分组内子页面、未勾选分组本身时,getUserColumnPermissions 只返回
直接授权+展开后代,分组容器节点缺失,AdminMenuTreeBuilder 把子页面当根节点,
前端侧边栏渲染成一列平铺;且子页面 sort_order 是全局值、跨分组穿插显示,
与超管的「分组+组内顺序」视图完全对不上(线上 31 个账号如此,含 uid=972 阿武)。
修复:getUserColumnPermissions 增加 includeAncestorGroups 重载(默认 false),
true 时沿 parentId 链把有可见后代的祖先并入集合——分组无页面路由,仅还原
展示层级,不构成授权扩展;只有 current-user/menus(后台侧边栏)启用。
刻意保持原语义的出口:/permission-users/{id}/column-permissions 与登录响应
(桌面端 tool-catalog「组键命中即整组放行」,补组键会误放行整组工具)、
dedupe/invalidasin 的精确 key 校验。
新增 3 个测试:祖先补全含多层链、树组装还原分组与组内顺序、默认出口不含祖先。
This commit is contained in:
+3
-1
@@ -76,8 +76,10 @@ public class AdminConsoleController {
|
||||
@Operation(summary = "当前登录管理员的可见后台菜单树")
|
||||
public ApiResponse<Map<String, Object>> currentUserMenus(HttpServletRequest request) {
|
||||
AdminUserEntity operator = adminAuthSupport.requireAdminOrInternal(request);
|
||||
// 补全祖先分组:部分授权用户(只授权了子页面)也要看到「一级分组 + 子页面」层级,
|
||||
// 与超管的菜单组织顺序一致;分组节点无页面路由,不构成权限扩展。
|
||||
List<PermissionMenuItemVo> menus = permissionMenuService.getUserColumnPermissions(
|
||||
operator, operator.getId(), PermissionMenuService.MENU_TYPE_ADMIN);
|
||||
operator, operator.getId(), PermissionMenuService.MENU_TYPE_ADMIN, true);
|
||||
menus = AdminMenuTreeBuilder.filterByMenuType(menus, PermissionMenuService.MENU_TYPE_ADMIN);
|
||||
List<Map<String, Object>> items = AdminMenuTreeBuilder.toMapList(AdminMenuTreeBuilder.build(menus));
|
||||
return ApiResponse.success(Map.of("items", items));
|
||||
|
||||
+54
-1
@@ -262,6 +262,20 @@ public class PermissionMenuService {
|
||||
public List<PermissionMenuItemVo> getUserColumnPermissions(AdminUserEntity operator,
|
||||
Long userId,
|
||||
String menuType) {
|
||||
return getUserColumnPermissions(operator, userId, menuType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller-facing variant with target-user scope checks.
|
||||
*
|
||||
* <p>includeAncestorGroups=true 时额外把「有可见后代的祖先节点」并入返回集合,仅用于
|
||||
* 后台侧边栏还原二级分组层级(分组自身无页面路由,不代表授权扩展);权限判定与客户端
|
||||
* 「组键命中即整组放行」的权限键集合语义都不受影响,默认 false 保持原行为。</p>
|
||||
*/
|
||||
public List<PermissionMenuItemVo> getUserColumnPermissions(AdminUserEntity operator,
|
||||
Long userId,
|
||||
String menuType,
|
||||
boolean includeAncestorGroups) {
|
||||
AdminUserEntity user = getUserById(userId);
|
||||
ensureTargetAccessible(operator, user);
|
||||
List<PermissionMenuEntity> menus = loadMenus(menuType);
|
||||
@@ -273,8 +287,9 @@ public class PermissionMenuService {
|
||||
return List.of();
|
||||
}
|
||||
Set<Long> effectiveIds = expandDescendantIds(directIds, menus);
|
||||
Set<Long> visibleIds = includeAncestorGroups ? includeAncestorIds(effectiveIds, menus) : effectiveIds;
|
||||
List<PermissionMenuEntity> effectiveMenus = menus.stream()
|
||||
.filter(menu -> menu.getId() != null && effectiveIds.contains(menu.getId()))
|
||||
.filter(menu -> menu.getId() != null && visibleIds.contains(menu.getId()))
|
||||
.toList();
|
||||
return toItemVos(effectiveMenus, menus);
|
||||
}
|
||||
@@ -724,6 +739,44 @@ public class PermissionMenuService {
|
||||
return effective;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把可见节点沿 parentId 链上的祖先并入集合,仅供后台侧边栏还原「一级分组 + 子页面」
|
||||
* 的展示层级:分组节点无页面路由、不代表授权扩展,权限判定另有独立方法。父链缺失
|
||||
* (孤儿数据)时截断;出现自环/成环时由 visited 兜底终止。
|
||||
*/
|
||||
private Set<Long> includeAncestorIds(Set<Long> effectiveIds, List<PermissionMenuEntity> menus) {
|
||||
Map<Long, PermissionMenuEntity> menuMap = new HashMap<>();
|
||||
for (PermissionMenuEntity menu : menus) {
|
||||
if (menu.getId() != null) {
|
||||
menuMap.put(menu.getId(), menu);
|
||||
}
|
||||
}
|
||||
Set<Long> withAncestors = new LinkedHashSet<>(effectiveIds);
|
||||
int addedCount = 0;
|
||||
for (Long id : effectiveIds) {
|
||||
PermissionMenuEntity current = menuMap.get(id);
|
||||
Set<Long> visited = new HashSet<>();
|
||||
while (current != null && current.getId() != null && visited.add(current.getId())) {
|
||||
Long parentId = current.getParentId();
|
||||
if (parentId == null) {
|
||||
break;
|
||||
}
|
||||
PermissionMenuEntity parent = menuMap.get(parentId);
|
||||
if (parent == null) {
|
||||
break;
|
||||
}
|
||||
if (withAncestors.add(parent.getId())) {
|
||||
addedCount++;
|
||||
}
|
||||
current = parent;
|
||||
}
|
||||
}
|
||||
if (addedCount > 0) {
|
||||
log.debug("[menu-tree-ancestor] 侧边栏树补充祖先分组节点 {} 个(仅展示层级,不改变授权)", addedCount);
|
||||
}
|
||||
return withAncestors;
|
||||
}
|
||||
|
||||
private PermissionMenuEntity getMenuById(Long id) {
|
||||
PermissionMenuEntity entity = permissionMenuMapper.selectById(id);
|
||||
if (entity == null) {
|
||||
|
||||
Reference in New Issue
Block a user