From 0408c9752eb06406380e465d8c6249228b8bea41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Mon, 31 Aug 2026 01:21:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=8F=9C=E5=8D=95=E6=8E=92=E5=BA=8F=20a?= =?UTF-8?q?pp=20=E5=88=86=E7=BB=84=E4=BC=98=E5=85=88=E4=BA=8E=20admin?= =?UTF-8?q?=EF=BC=8Csort=5Forder=20=E6=8C=89=20menuType=20=E4=BD=9C?= =?UTF-8?q?=E7=94=A8=E5=9F=9F=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - menuComparator 增加 menuType 排序维度(app → admin → 其他) - resolveSortOrder 查询限定同 menuType,避免跨类型尾部误判 - 抽出 loadRawMenus 保持原始 SQL 与比较器语义一致 --- .../service/PermissionMenuService.java | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/backend-java/src/main/java/com/nanri/aiimage/modules/permission/service/PermissionMenuService.java b/backend-java/src/main/java/com/nanri/aiimage/modules/permission/service/PermissionMenuService.java index 14a2f985..de1c6f58 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/modules/permission/service/PermissionMenuService.java +++ b/backend-java/src/main/java/com/nanri/aiimage/modules/permission/service/PermissionMenuService.java @@ -85,7 +85,7 @@ public class PermissionMenuService { entity.setParentId(parentId); entity.setMenuType(menuType); entity.setRoutePath(routePath); - entity.setSortOrder(resolveSortOrder(request.getSortOrder(), null)); + entity.setSortOrder(resolveSortOrder(menuType, request.getSortOrder(), null)); permissionMenuMapper.insert(entity); return toItemVo(getMenuById(entity.getId())); } @@ -118,7 +118,7 @@ public class PermissionMenuService { entity.setParentId(parentId); entity.setMenuType(menuType); entity.setRoutePath(routePath); - entity.setSortOrder(resolveSortOrder(request.getSortOrder(), id)); + entity.setSortOrder(resolveSortOrder(menuType, request.getSortOrder(), id)); permissionMenuMapper.updateById(entity); return toItemVo(getMenuById(id)); } @@ -410,12 +410,7 @@ public class PermissionMenuService { } private List loadMenus(String menuType) { - String normalizedType = normalizeMenuType(menuType); - LambdaQueryWrapper query = new LambdaQueryWrapper() - .eq(normalizedType != null, PermissionMenuEntity::getMenuType, normalizedType) - .orderByAsc(PermissionMenuEntity::getSortOrder) - .orderByAsc(PermissionMenuEntity::getId); - List rows = permissionMenuMapper.selectList(query); + List rows = loadRawMenus(menuType); if (rows == null || rows.isEmpty()) { return List.of(); } @@ -425,6 +420,20 @@ public class PermissionMenuService { .toList(); } + /** + * Fetches every menu (optionally scoped to one type) in insertion order. + * Sorting happens in {@link #loadMenus(String)} and only for hierarchies + * that actually need one, keeping raw SQL and comparator semantics in sync. + */ + private List loadRawMenus(String menuType) { + String normalizedType = normalizeMenuType(menuType); + LambdaQueryWrapper query = new LambdaQueryWrapper() + .eq(normalizedType != null, PermissionMenuEntity::getMenuType, normalizedType) + .orderByAsc(PermissionMenuEntity::getSortOrder) + .orderByAsc(PermissionMenuEntity::getId); + return permissionMenuMapper.selectList(query); + } + private List loadDirectColumnIds(Long userId) { List rows = userColumnPermissionMapper.selectByUserId(userId); if (rows == null || rows.isEmpty()) { @@ -751,12 +760,30 @@ public class PermissionMenuService { return new ArrayList<>(uniqueIds); } + /** app 分组排在 admin 分组之前;组内按 sort_order, id 排。 */ private Comparator menuComparator() { return Comparator - .comparing(PermissionMenuEntity::getSortOrder, Comparator.nullsLast(Integer::compareTo)) + .comparing(PermissionMenuEntity::getMenuType, Comparator.nullsLast(menuTypeRank())) + .thenComparing(PermissionMenuEntity::getSortOrder, Comparator.nullsLast(Integer::compareTo)) .thenComparing(PermissionMenuEntity::getId, Comparator.nullsLast(Long::compareTo)); } + private Comparator menuTypeRank() { + return Comparator.comparing(this::menuTypePriority); + } + + /** App 菜单优先展示在 admin 菜单之前。 */ + private int menuTypePriority(String menuType) { + if (MENU_TYPE_APP.equals(menuType)) { + return 0; + } + if (MENU_TYPE_ADMIN.equals(menuType)) { + return 1; + } + // Internal/legacy rows stay out of the way of both user-facing groups. + return 2; + } + private List toItemVos(List visibleMenus, List hierarchyMenus) { Map menuMap = hierarchyMenus.stream() @@ -800,11 +827,18 @@ public class PermissionMenuService { return root.getColumnKey(); } - private Integer resolveSortOrder(Integer sortOrder, Long excludeId) { + /** + * Resolves the default sort order when none is supplied, scoped to the + * menu's own type (parent takes precedence, then hierarchy ancestors). + * The DB query mirrors {@link #loadMenus(String)} ordering so the last row + * is the true tail of the type's ordering. + */ + private Integer resolveSortOrder(String menuType, Integer sortOrder, Long excludeId) { if (sortOrder != null) { return sortOrder; } PermissionMenuEntity tail = permissionMenuMapper.selectOne(new LambdaQueryWrapper() + .eq(PermissionMenuEntity::getMenuType, normalizeMenuType(menuType)) .ne(excludeId != null, PermissionMenuEntity::getId, excludeId) .orderByDesc(PermissionMenuEntity::getSortOrder) .orderByDesc(PermissionMenuEntity::getId)