diff --git a/orgmanax-common/pom.xml b/orgmanax-common/pom.xml
index 100d46a..2ff5b46 100644
--- a/orgmanax-common/pom.xml
+++ b/orgmanax-common/pom.xml
@@ -23,6 +23,10 @@
2.0.0-SNAPSHOT
compile
+
+ cn.hutool
+ hutool-all
+
\ No newline at end of file
diff --git a/orgmanax-common/src/main/java/cn/axzo/orgmanax/common/model/IBaseTree.java b/orgmanax-common/src/main/java/cn/axzo/orgmanax/common/model/IBaseTree.java
new file mode 100644
index 0000000..54aa3cd
--- /dev/null
+++ b/orgmanax-common/src/main/java/cn/axzo/orgmanax/common/model/IBaseTree.java
@@ -0,0 +1,35 @@
+package cn.axzo.orgmanax.common.model;
+
+import java.util.List;
+
+public interface IBaseTree, O> {
+
+ /**
+ * 节点编码
+ *
+ * @return 节点编码
+ */
+ O getNodeCode();
+
+ /**
+ * 父节点编码
+ *
+ * @return 父节点编码
+ */
+ O getParentNodeCode();
+
+ /**
+ * 子节点
+ *
+ * @return 子节点
+ */
+ List getNodeChildren();
+
+ /**
+ * 设置子节点
+ *
+ * @param nodeChildren
+ */
+ void setNodeChildren(List nodeChildren);
+
+}
diff --git a/orgmanax-common/src/main/java/cn/axzo/orgmanax/common/util/TreeUtil.java b/orgmanax-common/src/main/java/cn/axzo/orgmanax/common/util/TreeUtil.java
new file mode 100644
index 0000000..54ae6df
--- /dev/null
+++ b/orgmanax-common/src/main/java/cn/axzo/orgmanax/common/util/TreeUtil.java
@@ -0,0 +1,246 @@
+package cn.axzo.orgmanax.common.util;
+
+import cn.axzo.orgmanax.common.model.IBaseTree;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.lang.Pair;
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class TreeUtil {
+
+
+ /**
+ * 合并两个树 极大合并 这里以新树为基础:
同层级树:
1).如果新树的当前节点在旧树中存在,则直接使用新树的当前节点,并保持当前节点的顺序不变
+ * 2).如果新树的当前节点在旧树中存在,在 1)的基础上,去递归比较新树的子节点
3).如果新树的当前节点在旧树中不存在,直接使用新树的当前节点,并保持当前节点的顺序不变
+ * 4).如果旧树的节点在新树中不存在,则直接附加到新树之后,并保持旧树的顺序
+ *
+ * snabbdom:https://github.com/snabbdom/snabbdom/blob/master/src/init.ts#L277
+ *
+ * @param oldTree
+ * @param newTree
+ * @return
+ */
+ public static , O> List largeMergeTree(List oldTree,
+ List newTree) {
+ return largeMergeTree(oldTree, newTree, null);
+ }
+
+ /**
+ * 合并树
+ *
+ * @param oldTree
+ * @param newTree
+ * @param oldTreeConsumer 对需要附加到新树的节点进行操作
+ * @param
+ * @return
+ */
+ public static , O> List largeMergeTree(List oldTree,
+ List newTree,
+ Consumer> oldTreeConsumer) {
+ //为空直接返回
+ if (CollectionUtils.isEmpty(oldTree)) {
+ return newTree;
+ }
+ if (CollectionUtils.isEmpty(newTree)) {
+ return oldTree;
+ }
+ //构造老树code与所在索引的map
+ Map oldTreeIndexMap = new HashMap<>(oldTree.size());
+ for (int i = 0; i < oldTree.size(); i++) {
+ oldTreeIndexMap.put(oldTree.get(i).getNodeCode(), i);
+ }
+
+ //循环新树,找到新树中的当前节点在老树中的索引
+ for (T t : newTree) {
+ Integer oldTreeIndex = oldTreeIndexMap.get(t.getNodeCode());
+ //找到了,则直接使用新树的当前节点,并保持当前节点的顺序不变
+ if (oldTreeIndex != null) {
+ t.setNodeChildren(
+ largeMergeTree(oldTree.get(oldTreeIndex).getNodeChildren(), t.getNodeChildren(),
+ oldTreeConsumer));
+ oldTreeIndexMap.put(t.getNodeCode(), null);
+ }
+ }
+ List tempOldTree = null;
+ if (oldTreeConsumer != null) {
+ tempOldTree = new ArrayList<>();
+ }
+ List finalResult = tempOldTree;
+ //将所有老树中未找到的节点附加到新树之后,并保持旧树的顺序
+ oldTreeIndexMap.values().stream().filter(Objects::nonNull).sorted().forEach(e -> {
+ T t = oldTree.get(e);
+ newTree.add(t);
+ if (oldTreeConsumer != null) {
+ finalResult.add(t);
+ }
+ });
+ if (oldTreeConsumer != null) {
+ oldTreeConsumer.accept(tempOldTree);
+ }
+ return newTree;
+ }
+
+
+ public static , O> List buildTree(List treeList) {
+ if (CollectionUtils.isEmpty(treeList)) {
+ return treeList;
+ }
+ Set codes = treeList.stream().map(IBaseTree::getNodeCode).collect(Collectors.toSet());
+ List rootList = treeList.stream().filter(e -> !codes.contains(e.getParentNodeCode()))
+ .collect(Collectors.toList());
+ List children = treeList.stream().filter(e -> codes.contains(e.getParentNodeCode()))
+ .collect(Collectors.toList());
+ for (T t : rootList) {
+ t.setNodeChildren(buildTree(children, t.getNodeCode()));
+ }
+ return rootList;
+ }
+
+ public static , O> List buildTree(List treeList, O rootCode) {
+ if (CollectionUtils.isEmpty(treeList)) {
+ return treeList;
+ }
+ //root级树
+ List rootList = treeList.stream()
+ .filter(e -> Objects.equals(e.getParentNodeCode(), rootCode))
+ .collect(Collectors.toList());
+
+ List childrenList = treeList.stream()
+ .filter(e -> !Objects.equals(e.getParentNodeCode(), rootCode))
+ .collect(Collectors.toList());
+ if (CollectionUtils.isEmpty(childrenList)) {
+ return CollectionUtils.isEmpty(rootList) ? null : rootList;
+ }
+ for (T t : rootList) {
+ t.setNodeChildren(buildTree(childrenList, t.getNodeCode()));
+ }
+ return CollectionUtils.isEmpty(rootList) ? null : rootList;
+ }
+
+ // public static , O> List buildFastTree(List treeList, O rootCode) {
+// if (CollectionUtils.isEmpty(treeList)) {
+// return treeList;
+// }
+// //root级树
+// List rootList = treeList.stream().filter(e -> Objects.equals(e.getParentNodeCode(), rootCode))
+// .collect(Collectors.toList());
+//
+// List notRootList = treeList.stream().filter(e -> !Objects.equals(e.getParentNodeCode(), rootCode))
+// .collect(Collectors.toList());
+//
+// Map> childrenMap = notRootList.stream()
+// .collect(Collectors.groupingBy(IBaseTree::getParentNodeCode));
+//
+// for (T t : rootList) {
+// List children = childrenMap.get(t.getNodeCode());
+// if(children==null){
+// children=new ArrayList<>();
+// }
+// t.setNodeChildren(children);
+// }
+// return rootList;
+// }
+
+ /**
+ * 树的扁平化操作
+ *
+ * @param trees 树列表
+ * @param maxLevel 业务场景所允许的最大的树高
+ */
+ public static , O> List flattening(List trees, int maxLevel) {
+ if (CollUtil.isEmpty(trees)) {
+ return Collections.emptyList();
+ }
+ return trees.stream()
+ .flatMap(e -> flattening(e, maxLevel).stream())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 树的扁平化操作
+ *
+ * @param tree 树
+ * @param maxLevel 业务场景所允许的最大的树高
+ */
+ public static , O> List flattening(T tree, int maxLevel) {
+ if (Objects.isNull(tree)) {
+ return Collections.emptyList();
+ }
+ List result = new ArrayList<>();
+ // 根节点放入栈中
+ LinkedList> stack = new LinkedList<>();
+ stack.push(Pair.of(1, tree));
+ Pair pointer;
+ do {
+ // 出栈
+ pointer = stack.pop();
+ // 校验当前遍历的层级是否过深
+ Assert.isTrue(pointer.getKey() <= maxLevel, "层数过深,请检查数据的准确性");
+ // 数据放入结果集
+ result.add(pointer.getValue());
+ if (CollUtil.isNotEmpty(pointer.getValue().getNodeChildren())) {
+ // 子集层级自增并入栈
+ int recursiveLevel = pointer.getKey() + 1;
+ pointer.getValue().getNodeChildren().stream()
+ .map(e -> Pair.of(recursiveLevel, e))
+ .forEach(stack::push);
+ }
+ } while (CollUtil.isNotEmpty(stack));
+ return result;
+ }
+
+ /**
+ * 树的剪枝操作
+ *
+ * @param root 树
+ * @param treeNodeCode 剪枝切入点
+ */
+ public static , O> T pruning(T root, O treeNodeCode) {
+ if (Objects.isNull(root) || Objects.isNull(treeNodeCode)) {
+ return root;
+ }
+ // 根节点放入栈中
+ LinkedList stack = new LinkedList<>();
+ stack.push(root);
+ T node;
+ do {
+ // 出栈
+ node = stack.pop();
+ if (Objects.equals(node.getNodeCode(), treeNodeCode)) {
+ return node;
+ }
+ if (CollUtil.isNotEmpty(node.getNodeChildren())) {
+ stack.addAll(node.getNodeChildren());
+ }
+ } while (CollUtil.isNotEmpty(stack));
+ return null;
+ }
+
+ public static , O> List buildTree(List treeList, Function filter) {
+ Objects.requireNonNull(filter);
+
+ if (CollectionUtils.isEmpty(treeList)) {
+ return treeList;
+ }
+
+ Set codes = treeList.stream().map(IBaseTree::getNodeCode).collect(Collectors.toSet());
+ List rootList = treeList.stream()
+ .filter(filter::apply)
+ .filter(e -> !codes.contains(e.getParentNodeCode()))
+ .collect(Collectors.toList());
+ List children = treeList.stream()
+ .filter(filter::apply)
+ .filter(e -> codes.contains(e.getParentNodeCode()))
+ .collect(Collectors.toList());
+ for (T t : rootList) {
+ t.setNodeChildren(buildTree(children, t.getNodeCode()));
+ }
+ return rootList;
+ }
+
+}
diff --git a/orgmanax-infra/src/main/java/cn/axzo/orgmanax/infra/dao/node/repository/impl/NodeQueryRepositoryImpl.java b/orgmanax-infra/src/main/java/cn/axzo/orgmanax/infra/dao/node/repository/impl/NodeQueryRepositoryImpl.java
index f8ec562..794e168 100644
--- a/orgmanax-infra/src/main/java/cn/axzo/orgmanax/infra/dao/node/repository/impl/NodeQueryRepositoryImpl.java
+++ b/orgmanax-infra/src/main/java/cn/axzo/orgmanax/infra/dao/node/repository/impl/NodeQueryRepositoryImpl.java
@@ -11,6 +11,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -28,7 +29,7 @@ import java.util.stream.Stream;
*/
@Service
@RequiredArgsConstructor
-public class NodeQueryRepositoryImpl implements NodeQueryRepository {
+public class NodeQueryRepositoryImpl extends ServiceImpl implements NodeQueryRepository {
private final NodeDao nodeDao;
@@ -58,9 +59,6 @@ public class NodeQueryRepositoryImpl implements NodeQueryRepository {
if (CollUtil.isEmpty(records)) {
return resp;
}
-
- // assemble parent node
- assembleParentNode(req, records);
return resp;
}
diff --git a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/cooperateship/service/impl/CooperateShipServiceImpl.java b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/cooperateship/service/impl/CooperateShipServiceImpl.java
index 1745409..ef6ee89 100644
--- a/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/cooperateship/service/impl/CooperateShipServiceImpl.java
+++ b/orgmanax-server/src/main/java/cn/axzo/orgmanax/server/cooperateship/service/impl/CooperateShipServiceImpl.java
@@ -166,6 +166,7 @@ public class CooperateShipServiceImpl implements CooperateShipService {
resultNodeList.addAll(ancestorShipNodes);
}
+
// 是否查询父级节点
if (BooleanUtil.isTrue(req.getIncludeAncestors())) {
Set ancestorIds = cooperateShipFoundationService.extractAncestorIds(currentNodeList);