diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java index 2ab42cbc1..1f2b99c9c 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java +++ b/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 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.Stream; @@ -60,6 +63,38 @@ public class TreeBuildUtils extends TreeUtil { 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 原始数据类型(如实体类、DTO 等) + * @param 节点 ID 类型(如 Long、String) + * @return 构建完成的树形结构(可能包含多个顶级根节点) + */ + public static List> buildMultiRoot(List list, Function getId, Function getParentId, NodeParser parser) { + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + + // 提取所有节点 ID,用于后续判断哪些节点为根节点(即 parentId 不在其中) + Set allIds = StreamUtils.toSet(list, getId); + + // 筛选出所有 parentId 不在 allIds 中的节点,这些节点的 parentId 可认为是根节点 + Set 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()); + } + /** * 获取节点列表中所有节点的叶子节点 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java index 5e4904d05..fde4b875b 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java +++ b/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)) { return CollUtil.newArrayList(); } - // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 - List> 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> 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 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())) + ); } /** diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java index db1b7b7f0..dc8d6c833 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java @@ -95,27 +95,20 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService { */ @Override public List> selectCategoryTreeList(FlowCategoryBo category) { - LambdaQueryWrapper lqw = buildQueryWrapper(category); - List categorys = baseMapper.selectVoList(lqw); - if (CollUtil.isEmpty(categorys)) { + List categoryList = this.queryList(category); + if (CollUtil.isEmpty(categoryList)) { return CollUtil.newArrayList(); } - // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 - List> 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> trees = TreeBuildUtils.build(categorys, parentId, (dept, tree) -> - tree.setId(dept.getCategoryId().toString()) - .setParentId(dept.getParentId().toString()) - .setName(dept.getCategoryName()) - .setWeight(dept.getOrderNum())); - Tree 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()) + ); } /**