diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/IMenuSort.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/IMenuSort.java new file mode 100644 index 000000000..eb707f5d6 --- /dev/null +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/IMenuSort.java @@ -0,0 +1,92 @@ +package org.jetlinks.community.auth.entity; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author caizz + */ +public interface IMenuSort { + String getParentId(); + + String getOwner(); + + Long getSortIndex(); + + /** + * 获取list中对应owner最小的sortIndex + * + * @param list + * @return + */ + static Map getSortIndexMap(List list) { + Map ownerMinSortIndexMap = new HashMap<>(); + for (IMenuSort menuView : list) { + String owner = menuView.getOwner(); + long sortIndex = menuView.getSortIndex(); + if (owner != null) { + ownerMinSortIndexMap.merge(owner, sortIndex, Math::min); + } + } + return ownerMinSortIndexMap; + } + + /** + * 比较两个IMenuSort对象,用于排序(考虑owner组内最小sortIndex) + * 1. 按owner组内最小sortIndex排序 + * 2. 按owner排序,确保相同owner的菜单在一起 + * 3. 按parentId排序,空值在前 + * 4. 按sortIndex排序 + * + * @param o1 第一个MenuView对象 + * @param o2 第二个MenuView对象 + * @param ownerMinSortIndexMap owner与组内最小sortIndex的映射 + * @return 比较结果 + */ + static int compareMenuViewWithOwnerMinSortIndex(IMenuSort o1, IMenuSort o2, Map ownerMinSortIndexMap) { + // 先按owner组内最小sortIndex排序 + String owner1 = o1.getOwner(); + String owner2 = o2.getOwner(); + if (owner1 != null && owner2 != null) { + long minSortIndex1 = ownerMinSortIndexMap.getOrDefault(owner1, Long.MAX_VALUE); + long minSortIndex2 = ownerMinSortIndexMap.getOrDefault(owner2, Long.MAX_VALUE); + + int minSortIndexComparison = Long.compare(minSortIndex1, minSortIndex2); + if (minSortIndexComparison != 0) { + return minSortIndexComparison; + } + + // 再按owner排序 + int ownerComparison = owner1.compareTo(owner2); + if (ownerComparison != 0) { + return ownerComparison; + } + } else if (owner1 != null) { + return -1; + } else if (owner2 != null) { + return 1; + } + + // 再按parentId排序,空值在前 + String parentId1 = o1.getParentId(); + String parentId2 = o2.getParentId(); + if (parentId1 == null && parentId2 == null) { + // 都为空,按sortIndex排序 + return Long.compare(o1.getSortIndex(), o2.getSortIndex()); + } else if (parentId1 == null) { + // 第一个为空,排在前面 + return -1; + } else if (parentId2 == null) { + // 第二个为空,排在前面 + return 1; + } else { + // 都不为空,先按parentId排序,再按sortIndex排序 + int parentComparison = parentId1.compareTo(parentId2); + if (parentComparison != 0) { + return parentComparison; + } + return Long.compare(o1.getSortIndex(), o2.getSortIndex()); + } + } +} diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuEntity.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuEntity.java index 1cfc64563..cd15e731e 100755 --- a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuEntity.java +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuEntity.java @@ -56,7 +56,7 @@ @Comment("菜单信息表") @EnableEntityEvent public class MenuEntity - extends GenericTreeSortSupportEntity implements RecordCreationEntity, MultipleI18nSupportEntity { + extends GenericTreeSortSupportEntity implements RecordCreationEntity, MultipleI18nSupportEntity, IMenuSort { /** * 在多应用集成运行时使用此字段来区分菜单属于哪个系统 diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuView.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuView.java index 89e147033..b0f446d70 100644 --- a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuView.java +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/entity/MenuView.java @@ -33,7 +33,7 @@ @Getter @Setter -public class MenuView extends GenericTreeSortSupportEntity implements MultipleI18nSupportEntity { +public class MenuView extends GenericTreeSortSupportEntity implements MultipleI18nSupportEntity, IMenuSort { /** * 在多应用集成运行时使用此字段来区分菜单属于哪个系统 diff --git a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/MenuController.java b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/MenuController.java index dbe149914..f71523bfe 100755 --- a/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/MenuController.java +++ b/jetlinks-manager/authentication-manager/src/main/java/org/jetlinks/community/auth/web/MenuController.java @@ -36,6 +36,7 @@ import org.hswebframework.web.exception.ValidationException; import org.hswebframework.web.i18n.LocaleUtils; import org.hswebframework.web.system.authorization.defaults.service.DefaultPermissionService; +import org.jetlinks.community.auth.entity.IMenuSort; import org.jetlinks.community.auth.entity.MenuEntity; import org.jetlinks.community.auth.entity.MenuView; import org.jetlinks.community.auth.service.DefaultMenuService; @@ -50,6 +51,8 @@ import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * 菜单管理 @@ -94,7 +97,14 @@ public Flux getAllMenuAsTree(@RequestBody Mono que }) .flatMapMany(defaultMenuService::query) .collectList() - .flatMapIterable(list -> TreeSupportEntity.list2tree(list, MenuEntity::setChildren)); + .flatMapIterable(list -> { + Map ownerMinSortIndexMap = IMenuSort.getSortIndexMap(list); + final List views = list + .stream() + .sorted((o1, o2) -> IMenuSort.compareMenuViewWithOwnerMinSortIndex(o1, o2, ownerMinSortIndexMap)) + .collect(Collectors.toList()); + return TreeSupportEntity.list2tree(views, MenuEntity::setChildren); + }); } /** @@ -318,7 +328,16 @@ private Mono getAuthorizationSettingDetail(Flux listToTree(Flux flux) { return flux .collectList() - .flatMapIterable(list -> TreeUtils.list2tree(list, MenuView::getId, MenuView::getParentId, MenuView::setChildren)); + .flatMapIterable(list -> { + Map ownerMinSortIndexMap = IMenuSort.getSortIndexMap(list); + final List views = list + .stream() + .sorted((o1, o2) -> IMenuSort.compareMenuViewWithOwnerMinSortIndex(o1, o2, ownerMinSortIndexMap)) + .collect(Collectors.toList()); + return TreeUtils.list2tree(views, MenuView::getId, + MenuView::getParentId, + MenuView::setChildren); + }); } @Getter