Parcourir la source

update 优化构建多根节点的树结构(支持多个顶级节点)

AprilWind il y a 1 an
Parent
commit
eea96e87d9

+ 35 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java

@@ -10,6 +10,9 @@ import lombok.NoArgsConstructor;
 import org.dromara.common.core.utils.reflect.ReflectUtils;
 import org.dromara.common.core.utils.reflect.ReflectUtils;
 
 
 import java.util.List;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
@@ -60,6 +63,38 @@ public class TreeBuildUtils extends TreeUtil {
         return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
         return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
     }
     }
 
 
+    /**
+     * 构建多根节点的树结构(支持多个顶级节点)
+     *
+     * @param list        原始数据列表
+     * @param getId       获取节点 ID 的方法引用,例如:node -> node.getId()
+     * @param getParentId 获取节点父级 ID 的方法引用,例如:node -> node.getParentId()
+     * @param parser      树节点属性映射器,用于将原始节点 T 转为 Tree 节点
+     * @param <T>         原始数据类型(如实体类、DTO 等)
+     * @param <K>         节点 ID 类型(如 Long、String)
+     * @return 构建完成的树形结构(可能包含多个顶级根节点)
+     */
+    public static <T, K> List<Tree<K>> buildMultiRoot(List<T> list, Function<T, K> getId, Function<T, K> getParentId, NodeParser<T, K> parser) {
+        if (CollUtil.isEmpty(list)) {
+            return CollUtil.newArrayList();
+        }
+
+        // 提取所有节点 ID,用于后续判断哪些节点为根节点(即 parentId 不在其中)
+        Set<K> allIds = StreamUtils.toSet(list, getId);
+
+        // 筛选出所有 parentId 不在 allIds 中的节点,这些节点的 parentId 可认为是根节点
+        Set<K> rootParentIds = list.stream()
+            .map(getParentId)
+            .filter(Objects::nonNull)
+            .filter(pid -> !allIds.contains(pid))
+            .collect(Collectors.toSet());
+
+        // 使用流处理,遍历每个顶级 parentId,构建对应树,并合并为一个列表返回
+        return rootParentIds.stream()
+            .flatMap(rootParentId -> TreeUtil.build(list, rootParentId, parser).stream())
+            .collect(Collectors.toList());
+    }
+
     /**
     /**
      * 获取节点列表中所有节点的叶子节点
      * 获取节点列表中所有节点的叶子节点
      *
      *

+ 11 - 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@@ -131,23 +131,17 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
         if (CollUtil.isEmpty(depts)) {
         if (CollUtil.isEmpty(depts)) {
             return CollUtil.newArrayList();
             return CollUtil.newArrayList();
         }
         }
-        // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点
-        List<Tree<Long>> treeList = CollUtil.newArrayList();
-        for (SysDeptVo d : depts) {
-            Long parentId = d.getParentId();
-            SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId);
-            if (ObjectUtil.isNull(sysDeptVo)) {
-                List<Tree<Long>> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) ->
-                    tree.setId(dept.getDeptId())
-                        .setParentId(dept.getParentId())
-                        .setName(dept.getDeptName())
-                        .setWeight(dept.getOrderNum())
-                        .putExtra("disabled", SystemConstants.DISABLE.equals(dept.getStatus())));
-                Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId());
-                treeList.add(tree);
-            }
-        }
-        return treeList;
+        return TreeBuildUtils.buildMultiRoot(
+            depts,
+            SysDeptVo::getDeptId,
+            SysDeptVo::getParentId,
+            (node, treeNode) -> treeNode
+                .setId(node.getDeptId())
+                .setParentId(node.getParentId())
+                .setName(node.getDeptName())
+                .setWeight(node.getOrderNum())
+                .putExtra("disabled", SystemConstants.DISABLE.equals(node.getStatus()))
+        );
     }
     }
 
 
     /**
     /**

+ 12 - 19
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java

@@ -95,27 +95,20 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService {
      */
      */
     @Override
     @Override
     public List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category) {
     public List<Tree<String>> selectCategoryTreeList(FlowCategoryBo category) {
-        LambdaQueryWrapper<FlowCategory> lqw = buildQueryWrapper(category);
-        List<FlowCategoryVo> categorys = baseMapper.selectVoList(lqw);
-        if (CollUtil.isEmpty(categorys)) {
+        List<FlowCategoryVo> categoryList = this.queryList(category);
+        if (CollUtil.isEmpty(categoryList)) {
             return CollUtil.newArrayList();
             return CollUtil.newArrayList();
         }
         }
-        // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点
-        List<Tree<String>> treeList = CollUtil.newArrayList();
-        for (FlowCategoryVo d : categorys) {
-            String parentId = d.getParentId().toString();
-            FlowCategoryVo categoryVo = StreamUtils.findFirst(categorys, it -> it.getCategoryId().toString().equals(parentId));
-            if (ObjectUtil.isNull(categoryVo)) {
-                List<Tree<String>> trees = TreeBuildUtils.build(categorys, parentId, (dept, tree) ->
-                    tree.setId(dept.getCategoryId().toString())
-                        .setParentId(dept.getParentId().toString())
-                        .setName(dept.getCategoryName())
-                        .setWeight(dept.getOrderNum()));
-                Tree<String> tree = StreamUtils.findFirst(trees, it -> it.getId().equals(d.getCategoryId().toString()));
-                treeList.add(tree);
-            }
-        }
-        return treeList;
+        return TreeBuildUtils.buildMultiRoot(
+            categoryList,
+            node -> String.valueOf(node.getCategoryId()),
+            node -> String.valueOf(node.getParentId()),
+            (node, treeNode) -> treeNode
+                .setId(String.valueOf(node.getCategoryId()))
+                .setParentId(String.valueOf(node.getParentId()))
+                .setName(node.getCategoryName())
+                .setWeight(node.getOrderNum())
+        );
     }
     }
 
 
     /**
     /**