|
@@ -1967,13 +1967,20 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
|
|
|
}
|
|
|
|
|
|
//TODO 20250414-lhb-新增 添加祖级字段 ancestorsPId
|
|
|
- List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(needCopyNode.getContractId()));
|
|
|
- contractWbsTreeByContractId.addAll(saveList);
|
|
|
- Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
|
|
|
- saveList.forEach(node -> {
|
|
|
- String correctAncestors = createAncestorsPId(node,collect);;
|
|
|
- node.setAncestorsPId(correctAncestors);
|
|
|
- });
|
|
|
+ //因为复制选中节点,所以要查询出选中节点的父节点信息 来组装祖级节点
|
|
|
+ if(needCopyNode != null){
|
|
|
+ Long parentPKeyId = null;
|
|
|
+ String ancestorsPId = null;
|
|
|
+ if(needCopyNode.getPId() == 0L){
|
|
|
+ ancestorsPId = "0";
|
|
|
+ parentPKeyId = 0L;
|
|
|
+ }else{
|
|
|
+ WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(String.valueOf(needCopyNode.getPId()));
|
|
|
+ ancestorsPId = parentNode.getAncestorsPId();
|
|
|
+ parentPKeyId = parentNode.getPKeyId();
|
|
|
+ }
|
|
|
+ attachNodesToTarget(saveList,parentPKeyId,ancestorsPId);
|
|
|
+ }
|
|
|
}
|
|
|
needCopyNode.setNodeName(vo.getNeedCopyNodeName());
|
|
|
|
|
@@ -2141,6 +2148,26 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
|
|
|
this.addCopyTabData(needCopyNode, toCopyNode, tabOwner, resultTablesData, addTabList, vo.getIsCopyData(), addNewFileTabs);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ /*重构祖级id*/
|
|
|
+ List<WbsTreeContract> resultAll = new ArrayList<>();
|
|
|
+ resultAll.addAll(addNodeList);
|
|
|
+ resultAll.addAll(addTabList);
|
|
|
+ //因为复制选中节点,所以要查询出选中节点的父节点信息 来组装祖级节点
|
|
|
+ if(needCopyNode != null && CollectionUtil.isNotEmpty(resultAll)){
|
|
|
+ Long parentPKeyId = null;
|
|
|
+ String ancestorsPId = null;
|
|
|
+ if(needCopyNode.getPId() == 0L){
|
|
|
+ ancestorsPId = "0";
|
|
|
+ parentPKeyId = 0L;
|
|
|
+ }else{
|
|
|
+ WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(String.valueOf(toCopyVO.getPrimaryKeyId()));
|
|
|
+ ancestorsPId = parentNode.getAncestorsPId();
|
|
|
+ parentPKeyId = parentNode.getPKeyId();
|
|
|
+ }
|
|
|
+ attachNodesToTarget(resultAll,parentPKeyId,ancestorsPId);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -2150,14 +2177,6 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
|
|
|
resultAll.addAll(addNodeList);
|
|
|
resultAll.addAll(addTabList);
|
|
|
|
|
|
- //TODO 20250414-lhb-新增
|
|
|
- List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(contractId));
|
|
|
- contractWbsTreeByContractId.addAll(resultAll);
|
|
|
- Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
|
|
|
- resultAll.forEach(node -> {
|
|
|
- String correctAncestors = createAncestorsPId(node,collect);;
|
|
|
- node.setAncestorsPId(correctAncestors);
|
|
|
- });
|
|
|
|
|
|
List<WbsTreeContract> allData = this.reBuildAncestors(resultAll);
|
|
|
List<WbsTreeContract> nodes = allData.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
|
|
@@ -3966,24 +3985,20 @@ public R<Boolean> saveContractTreeNode(@RequestBody AddContractTreeNodeVO vo) {
|
|
|
saveList.addAll(customResult);
|
|
|
}
|
|
|
//找到最顶级节点设置parentId
|
|
|
- WbsTreeContract topLevelNode = findTopLevelNode(saveList);
|
|
|
- if (ObjectUtils.isNotEmpty(topLevelNode)) {
|
|
|
+ List<WbsTreeContract> topLevelNode = findTopLevelNode(saveList);
|
|
|
+ if (CollectionUtil.isNotEmpty(topLevelNode)) {
|
|
|
for (WbsTreeContract wbsTreeContract : saveList) {
|
|
|
- if (topLevelNode.getPKeyId().equals(wbsTreeContract.getPKeyId())) {
|
|
|
- wbsTreeContract.setParentId(treeContract.getId());
|
|
|
- //TODO 20250414-lhb-新增
|
|
|
- wbsTreeContract.setPId(treeContract.getPKeyId());
|
|
|
+ for (WbsTreeContract contract : topLevelNode) {
|
|
|
+ if (contract.getPKeyId().equals(wbsTreeContract.getPKeyId())) {
|
|
|
+ wbsTreeContract.setParentId(treeContract.getId());
|
|
|
+ //TODO 20250414-lhb-新增
|
|
|
+ wbsTreeContract.setPId(treeContract.getPKeyId());
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
//TODO 20250414-lhb-新增 添加ancestorsPId字段
|
|
|
- List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(treeContract.getContractId()));
|
|
|
- contractWbsTreeByContractId.addAll(saveList);
|
|
|
- Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
|
|
|
- saveList.forEach(node -> {
|
|
|
- String correctAncestors = createAncestorsPId(node,collect);;
|
|
|
- node.setAncestorsPId(correctAncestors);
|
|
|
- });
|
|
|
+ attachNodesToTarget(saveList,treeContract.getPKeyId(),treeContract.getAncestorsPId());
|
|
|
|
|
|
R<Boolean> booleanR = this.saveOrCopyNodeTree(saveList, saveLedger, 2, treeContract);
|
|
|
|
|
@@ -4009,16 +4024,20 @@ public R<String> getDICengNodeName(@RequestParam Long pKeyId,@RequestParam Long
|
|
|
return R.data("");
|
|
|
}
|
|
|
|
|
|
-public static WbsTreeContract findTopLevelNode(List<WbsTreeContract> saveList) {
|
|
|
+public static List<WbsTreeContract> findTopLevelNode(List<WbsTreeContract> saveList) {
|
|
|
Set<Long> nodeIds = new HashSet<>();
|
|
|
for (WbsTreeContract node : saveList) {
|
|
|
nodeIds.add(node.getId());
|
|
|
}
|
|
|
+ List<WbsTreeContract> parentNodes = new ArrayList<>();
|
|
|
for (WbsTreeContract node : saveList) {
|
|
|
if (!nodeIds.contains(node.getParentId())) {
|
|
|
- return node;
|
|
|
+ parentNodes.add(node);
|
|
|
}
|
|
|
}
|
|
|
+ if(CollectionUtil.isNotEmpty(parentNodes)){
|
|
|
+ return parentNodes;
|
|
|
+ }
|
|
|
return null;
|
|
|
}
|
|
|
|
|
@@ -4893,4 +4912,106 @@ public R<Object> customAddContractNode(@RequestBody CustomAddContractNodeDTO dto
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void attachNodesToTarget(List<WbsTreeContract> newNodes, Long targetId, String targetAncestors) {
|
|
|
+ // 1. 找到新数据中的顶层节点(新树的根节点)
|
|
|
+ List<WbsTreeContract> newRoot = findRootNode(newNodes);
|
|
|
+
|
|
|
+ // 2. 将新树的根节点绑定到目标节点
|
|
|
+ newRoot.forEach(f -> {
|
|
|
+ f.setPId(targetId);
|
|
|
+ f.setAncestorsPId(calculateAncestors(targetAncestors, targetId));
|
|
|
+
|
|
|
+
|
|
|
+ // 3. 构建映射关系
|
|
|
+ Map<Long, WbsTreeContract> nodeMap = new HashMap<>();
|
|
|
+ Map<Long, List<WbsTreeContract>> childrenMap = new HashMap<>();
|
|
|
+
|
|
|
+ for (WbsTreeContract node : newNodes) {
|
|
|
+ nodeMap.put(node.getPKeyId(), node);
|
|
|
+ childrenMap.computeIfAbsent(node.getPId(), k -> new ArrayList<>()).add(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 安全层序遍历(带循环检测)
|
|
|
+ List<WbsTreeContract> list = childrenMap.get(f.getPKeyId());
|
|
|
+ if(CollectionUtil.isNotEmpty(list)){
|
|
|
+ //如果是多个根节点
|
|
|
+ safeBfsTraversal(f, childrenMap, newNodes.size());
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void safeBfsTraversal(WbsTreeContract root,
|
|
|
+ Map<Long, List<WbsTreeContract>> childrenMap,
|
|
|
+ int totalNodes) {
|
|
|
+ Queue<WbsTreeContract> queue = new LinkedList<>();
|
|
|
+ Set<Long> visited = new HashSet<>(); // 已访问节点集合
|
|
|
+ queue.add(root);
|
|
|
+ visited.add(root.getPKeyId());
|
|
|
+
|
|
|
+ int processedCount = 0; // 已处理节点计数器
|
|
|
+ final int MAX_DEPTH = 100; // 最大深度保护
|
|
|
+
|
|
|
+ while (!queue.isEmpty()) {
|
|
|
+ WbsTreeContract parent = queue.poll();
|
|
|
+ processedCount++;
|
|
|
+
|
|
|
+ // 安全检测1:防止循环引用导致无限循环
|
|
|
+ if (processedCount > totalNodes * 2) {
|
|
|
+ throw new IllegalStateException("处理节点数超过预期,可能存在循环引用。已处理: "
|
|
|
+ + processedCount + ",总节点: " + totalNodes);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 安全检测2:防止路径过长
|
|
|
+ if (parent.getAncestorsPId().split(",").length > MAX_DEPTH) {
|
|
|
+ throw new IllegalStateException("祖级路径超过最大深度限制: " + MAX_DEPTH);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<WbsTreeContract> children = childrenMap.get(parent.getPKeyId());
|
|
|
+ if (children == null) continue;
|
|
|
+
|
|
|
+ for (WbsTreeContract child : children) {
|
|
|
+ // 安全检测3:检查循环引用
|
|
|
+ if (visited.contains(child.getPKeyId())) {
|
|
|
+ throw new IllegalStateException("检测到循环引用: 节点" + child.getPKeyId()
|
|
|
+ + " -> 节点" + parent.getPKeyId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新祖级路径 = 父路径 + 父ID
|
|
|
+ child.setAncestorsPId(calculateAncestors(parent.getAncestorsPId(), parent.getPKeyId()));
|
|
|
+
|
|
|
+ queue.add(child);
|
|
|
+ visited.add(child.getPKeyId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private String calculateAncestors(String parentAncestors, Long parentId) {
|
|
|
+ if (parentAncestors == null || parentAncestors.isEmpty()) {
|
|
|
+ return parentId.toString();
|
|
|
+ }
|
|
|
+ return parentAncestors + "," + parentId;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<WbsTreeContract> findRootNode(List<WbsTreeContract> nodes) {
|
|
|
+ Set<Long> nodeIds = new HashSet<>();
|
|
|
+ for (WbsTreeContract node : nodes) {
|
|
|
+ nodeIds.add(node.getPKeyId());
|
|
|
+ }
|
|
|
+ List<WbsTreeContract> parentNodes = new ArrayList<>();
|
|
|
+ for (WbsTreeContract node : nodes) {
|
|
|
+ Long parentId = node.getPId();
|
|
|
+ // 父节点为空 或 父节点不在当前新数据列表中 → 视为根节点
|
|
|
+ if (parentId == null || !nodeIds.contains(parentId)) {
|
|
|
+ parentNodes.add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (CollectionUtil.isNotEmpty(parentNodes)) {
|
|
|
+ return parentNodes;
|
|
|
+ }
|
|
|
+ throw new IllegalArgumentException("新数据中未找到根节点");
|
|
|
+ }
|
|
|
}
|