|
@@ -0,0 +1,438 @@
|
|
|
+package org.springblade.archive.service.impl;
|
|
|
+
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springblade.archive.service.IArchiveNameService;
|
|
|
+import org.springblade.manager.entity.ArchiveTreeContract;
|
|
|
+import org.springblade.manager.feign.ArchiveTreeContractClient;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@AllArgsConstructor
|
|
|
+public class ArchiveNameServiceImpl implements IArchiveNameService {
|
|
|
+
|
|
|
+ private final ArchiveTreeContractClient archiveTreeContractClient;
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public NodeHierarchy buildNodeHierarchy(List<ArchiveTreeContract> nodeList) {
|
|
|
+ if (nodeList == null || nodeList.isEmpty()) {
|
|
|
+ return new NodeHierarchy(
|
|
|
+ Collections.emptyMap(),
|
|
|
+ Collections.emptyMap(),
|
|
|
+ Collections.emptyMap(),
|
|
|
+ Collections.emptyMap()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 创建数据结构容器
|
|
|
+ Map<Long, List<ArchiveTreeContract>> hierarchyMap = new HashMap<>();
|
|
|
+ Map<Long, ArchiveTreeContract> allNodeMap = new HashMap<>();
|
|
|
+ Map<Long, List<ArchiveTreeContract>> childrenMap = new HashMap<>();
|
|
|
+ Map<Long, Integer> totalChildrenCountMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 2. 处理当前节点并加入映射
|
|
|
+ Map<Long, ArchiveTreeContract> tempNodeMap = new HashMap<>();
|
|
|
+ for (ArchiveTreeContract node : nodeList) {
|
|
|
+ Long nodeId = node.getId();
|
|
|
+ tempNodeMap.put(nodeId, node);
|
|
|
+ allNodeMap.put(nodeId, node);
|
|
|
+ childrenMap.putIfAbsent(nodeId, new ArrayList<>());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 收集缺失的祖先节点ID
|
|
|
+ Set<Long> missingAncestorIds = new HashSet<>();
|
|
|
+ for (ArchiveTreeContract node : nodeList) {
|
|
|
+ String ancestors = node.getAncestors();
|
|
|
+ if (ancestors == null || ancestors.isEmpty()) continue;
|
|
|
+
|
|
|
+ Arrays.stream(ancestors.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(id -> !id.isEmpty())
|
|
|
+ .map(Long::parseLong)
|
|
|
+ .filter(ancestorId -> !tempNodeMap.containsKey(ancestorId))
|
|
|
+ .forEach(missingAncestorIds::add);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 批量获取缺失的祖先节点
|
|
|
+ List<ArchiveTreeContract> missingAncestors = Collections.emptyList();
|
|
|
+ if (!missingAncestorIds.isEmpty()) {
|
|
|
+ // 直接使用Set<Long>,无需转换为字符串
|
|
|
+ List<Long> ancestorIdsList = new ArrayList<>(missingAncestorIds);
|
|
|
+
|
|
|
+ // 使用新方法调用
|
|
|
+ missingAncestors = archiveTreeContractClient
|
|
|
+ .getArchiveTreeContractListByList(ancestorIdsList);
|
|
|
+
|
|
|
+ for (ArchiveTreeContract ancestor : missingAncestors) {
|
|
|
+ Long ancestorId = ancestor.getId();
|
|
|
+ tempNodeMap.put(ancestorId, ancestor);
|
|
|
+ allNodeMap.put(ancestorId, ancestor);
|
|
|
+ childrenMap.putIfAbsent(ancestorId, new ArrayList<>());
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debug("成功获取 {} 个祖先节点", missingAncestors.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 合并所有节点
|
|
|
+ List<ArchiveTreeContract> allNodes = new ArrayList<>(nodeList);
|
|
|
+ allNodes.addAll(missingAncestors);
|
|
|
+
|
|
|
+ // 6. 为每个节点构建完整的层级路径
|
|
|
+ for (ArchiveTreeContract node : allNodes) {
|
|
|
+ Long nodeId = node.getId();
|
|
|
+ List<ArchiveTreeContract> hierarchyList = new ArrayList<>();
|
|
|
+
|
|
|
+ // 处理祖先路径
|
|
|
+ String ancestors = node.getAncestors();
|
|
|
+ if (ancestors != null && !ancestors.isEmpty()) {
|
|
|
+ String[] pathIds = ancestors.split(",");
|
|
|
+ for (String idStr : pathIds) {
|
|
|
+ idStr = idStr.trim();
|
|
|
+ if (!idStr.isEmpty()) {
|
|
|
+ Long id = Long.parseLong(idStr);
|
|
|
+ ArchiveTreeContract ancestor = tempNodeMap.get(id);
|
|
|
+ if (ancestor != null) {
|
|
|
+ hierarchyList.add(ancestor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加当前节点到路径末端
|
|
|
+ hierarchyList.add(node);
|
|
|
+
|
|
|
+ // 存入层级映射
|
|
|
+ hierarchyMap.put(nodeId, hierarchyList);
|
|
|
+
|
|
|
+ // 构建父子关系映射
|
|
|
+ Long parentId = node.getParentId();
|
|
|
+ if (parentId != null) {
|
|
|
+ childrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 7. 填充总子节点计数
|
|
|
+ for (Map.Entry<Long, List<ArchiveTreeContract>> entry : childrenMap.entrySet()) {
|
|
|
+ totalChildrenCountMap.put(entry.getKey(), entry.getValue().size());
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NodeHierarchy(hierarchyMap, allNodeMap, childrenMap, totalChildrenCountMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getLevelName(NodeHierarchy hierarchy, Long nodeId) {
|
|
|
+ Map<Long, ArchiveTreeContract> allNodeMap = hierarchy.getAllNodeMap();
|
|
|
+
|
|
|
+ // 1. 获取目标节点
|
|
|
+ ArchiveTreeContract targetNode = allNodeMap.get(nodeId);
|
|
|
+ if (targetNode == null) {
|
|
|
+ log.warn("无法找到节点 {} 的详细信息", nodeId);
|
|
|
+ return "未知节点";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取节点的层级路径
|
|
|
+ Map<Long, List<ArchiveTreeContract>> hierarchyMap = hierarchy.getHierarchyMap();
|
|
|
+ List<ArchiveTreeContract> hierarchyList = hierarchyMap.getOrDefault(
|
|
|
+ nodeId, Collections.emptyList()
|
|
|
+ );
|
|
|
+
|
|
|
+ // 3. 提取关键层级的节点
|
|
|
+ ArchiveTreeContract lastUnitNode = null;
|
|
|
+ ArchiveTreeContract lastDivisionNode = null;
|
|
|
+ ArchiveTreeContract lastItemNode = null;
|
|
|
+
|
|
|
+ for (ArchiveTreeContract node : hierarchyList) {
|
|
|
+ // 获取displayHierarchy值
|
|
|
+ Integer extNodeType = node.getExtNodeType();
|
|
|
+
|
|
|
+ // 处理空值或空白值
|
|
|
+ if (extNodeType == null ) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 尝试转换为
|
|
|
+
|
|
|
+ switch (extNodeType) {
|
|
|
+ case 1:
|
|
|
+ lastUnitNode = node;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ case 3:
|
|
|
+ lastDivisionNode = node;
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ case 5:
|
|
|
+ lastItemNode = node;
|
|
|
+ break;
|
|
|
+ // 其他情况不处理
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 记录格式错误但继续处理其他节点
|
|
|
+ log.warn("节点 {} 的displayHierarchy值 '{}' 无法转换为整数",
|
|
|
+ node.getNodeName(), extNodeType);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 构建层级名称
|
|
|
+ StringBuilder nameBuilder = new StringBuilder();
|
|
|
+
|
|
|
+ // 依次添加单位工程、分部工程、分项工程的名称
|
|
|
+ if (lastUnitNode != null) {
|
|
|
+ nameBuilder.append(lastUnitNode.getNodeName());
|
|
|
+ }
|
|
|
+ if (lastDivisionNode != null) {
|
|
|
+ nameBuilder.append(lastDivisionNode.getNodeName());
|
|
|
+ }
|
|
|
+ if (lastItemNode != null) {
|
|
|
+ nameBuilder.append(lastItemNode.getNodeName());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 返回结果(如果没有找到任何层级节点,则返回目标节点名称)
|
|
|
+ return nameBuilder.length() > 0 ?
|
|
|
+ nameBuilder.toString() :
|
|
|
+ targetNode.getNodeName();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String generateFullLevelName(
|
|
|
+ List<Long> nodeIds,
|
|
|
+ NodeHierarchy hierarchy,boolean useCovering
|
|
|
+ ) {
|
|
|
+ // 1. 获取输入节点
|
|
|
+ Map<Long, ArchiveTreeContract> allNodeMap = hierarchy.getAllNodeMap();
|
|
|
+ List<ArchiveTreeContract> nodes = new ArrayList<>();
|
|
|
+ for (Long nodeId : nodeIds) {
|
|
|
+ ArchiveTreeContract node = allNodeMap.get(nodeId);
|
|
|
+ if (node != null) {
|
|
|
+ nodes.add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nodes.isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 按父节点分组 (一级分组)
|
|
|
+ Map<Long, List<ArchiveTreeContract>> parentGroups = new LinkedHashMap<>();
|
|
|
+ for (ArchiveTreeContract node : nodes) {
|
|
|
+ Long parentId = node.getParentId();
|
|
|
+ if (parentId == null) {
|
|
|
+ parentGroups.put(node.getId(), Collections.singletonList(node));
|
|
|
+ } else {
|
|
|
+ parentGroups.computeIfAbsent(parentId, k -> new ArrayList<>()).add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 按祖父节点分组 (二级分组)
|
|
|
+ Map<Long, List<Map.Entry<Long, List<ArchiveTreeContract>>>> grandParentGroups = new LinkedHashMap<>();
|
|
|
+ for (Map.Entry<Long, List<ArchiveTreeContract>> entry : parentGroups.entrySet()) {
|
|
|
+ Long parentId = entry.getKey();
|
|
|
+ ArchiveTreeContract parentNode = allNodeMap.get(parentId);
|
|
|
+ Long grandParentId = (parentNode != null) ? parentNode.getParentId() : null;
|
|
|
+ grandParentGroups.computeIfAbsent(grandParentId, k -> new ArrayList<>()).add(entry);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 处理分组
|
|
|
+ List<String> nameParts = new ArrayList<>();
|
|
|
+ for (Map.Entry<Long, List<Map.Entry<Long, List<ArchiveTreeContract>>>> grandEntry : grandParentGroups.entrySet()) {
|
|
|
+ Long grandParentId = grandEntry.getKey();
|
|
|
+ List<Map.Entry<Long, List<ArchiveTreeContract>>> directParentGroups = grandEntry.getValue();
|
|
|
+
|
|
|
+ // 尝试在祖父节点级别合并
|
|
|
+ boolean canUseGrandParentName = false;
|
|
|
+ if (grandParentId != null) {
|
|
|
+ ArchiveTreeContract grandParentNode = allNodeMap.get(grandParentId);
|
|
|
+ if (grandParentNode != null) {
|
|
|
+ // 获取祖父节点的所有直接子节点
|
|
|
+ List<ArchiveTreeContract> grandChildren = hierarchy.getChildren(grandParentId);
|
|
|
+ if (grandChildren != null && !grandChildren.isEmpty()) {
|
|
|
+ // 检查是否覆盖所有直接子节点
|
|
|
+ boolean allChildrenCovered = true;
|
|
|
+ Set<Long> coveredParentIds = new HashSet<>();
|
|
|
+ for (Map.Entry<Long, List<ArchiveTreeContract>> directEntry : directParentGroups) {
|
|
|
+ coveredParentIds.add(directEntry.getKey());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证所有子节点都被覆盖
|
|
|
+ for (ArchiveTreeContract child : grandChildren) {
|
|
|
+ if (!coveredParentIds.contains(child.getId())) {
|
|
|
+ allChildrenCovered = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证每个被覆盖的子节点组是否都是全覆盖状态
|
|
|
+ if (allChildrenCovered) {
|
|
|
+ boolean allGroupsFullyCovered = true;
|
|
|
+ for (Map.Entry<Long, List<ArchiveTreeContract>> directEntry : directParentGroups) {
|
|
|
+ List<ArchiveTreeContract> groupNodes = directEntry.getValue();
|
|
|
+ // 获取该父节点的所有子节点
|
|
|
+ List<ArchiveTreeContract> childrenOfParent = hierarchy.getChildren(directEntry.getKey());
|
|
|
+ int childrenCount = (childrenOfParent != null) ? childrenOfParent.size() : 0;
|
|
|
+
|
|
|
+ // 检查是否全覆盖
|
|
|
+ if (childrenCount == 0 || groupNodes.size() != childrenCount) {
|
|
|
+ allGroupsFullyCovered = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (allGroupsFullyCovered && useCovering) {
|
|
|
+ nameParts.add(getLevelName(hierarchy, grandParentId));
|
|
|
+ canUseGrandParentName = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (canUseGrandParentName) {
|
|
|
+ continue; // 已使用祖父节点名称,跳过直接父节点处理
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理直接父节点组
|
|
|
+ boolean firstParentInGroup = true;
|
|
|
+ for (Map.Entry<Long, List<ArchiveTreeContract>> directEntry : directParentGroups) {
|
|
|
+ Long groupId = directEntry.getKey();
|
|
|
+ List<ArchiveTreeContract> groupNodes = directEntry.getValue();
|
|
|
+ ArchiveTreeContract parent = allNodeMap.get(groupId);
|
|
|
+
|
|
|
+ if (parent == null) {
|
|
|
+ // 无父节点的情况:添加所有节点名称(用顿号分隔)
|
|
|
+ String nodeNames = groupNodes.stream()
|
|
|
+ .map(ArchiveTreeContract::getNodeName)
|
|
|
+ .collect(Collectors.joining("、"));
|
|
|
+ nameParts.add(nodeNames);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取直接子节点
|
|
|
+ List<ArchiveTreeContract> allChildren = hierarchy.getChildren(groupId);
|
|
|
+ int childrenCount = (allChildren != null) ? allChildren.size() : 0;
|
|
|
+
|
|
|
+ // 检查是否全覆盖所有子节点
|
|
|
+ if (childrenCount > 0 && groupNodes.size() == childrenCount ) {
|
|
|
+ // 只有组内第一个父节点使用完整层级名称
|
|
|
+ String parentName = firstParentInGroup ?
|
|
|
+ getLevelName(hierarchy, groupId) :
|
|
|
+ parent.getNodeName();
|
|
|
+
|
|
|
+ nameParts.add(parentName);
|
|
|
+ } else {
|
|
|
+ // 获取父节点名称
|
|
|
+ String parentName = firstParentInGroup ?
|
|
|
+ getLevelName(hierarchy, groupId) :
|
|
|
+ parent.getNodeName();
|
|
|
+
|
|
|
+ // 部分覆盖:添加父节点名称+子节点名称(用顿号分隔)
|
|
|
+ String childNames = groupNodes.stream()
|
|
|
+ .map(ArchiveTreeContract::getNodeName)
|
|
|
+ .collect(Collectors.joining("、"));
|
|
|
+ // 修改点:根据条件决定添加的内容
|
|
|
+ if (!useCovering ) {
|
|
|
+ // 当 useCovering=false 且不是第一个父节点时,只添加子节点名称
|
|
|
+ nameParts.add(childNames);
|
|
|
+ } else {
|
|
|
+ // 其他情况:添加父节点名称+子节点名称
|
|
|
+ nameParts.add(parentName + childNames);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 后续节点不再是第一个
|
|
|
+ firstParentInGroup = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 拼接最终结果
|
|
|
+ return String.join("、", nameParts);
|
|
|
+ }
|
|
|
+ public String generateFullLevelName1(
|
|
|
+ List<Long> nodeIds,
|
|
|
+ NodeHierarchy hierarchy
|
|
|
+ ) {
|
|
|
+ // 1. 获取输入节点
|
|
|
+ Map<Long, ArchiveTreeContract> allNodeMap = hierarchy.getAllNodeMap();
|
|
|
+ List<ArchiveTreeContract> nodes = new ArrayList<>();
|
|
|
+
|
|
|
+ for (Long nodeId : nodeIds) {
|
|
|
+ ArchiveTreeContract node = allNodeMap.get(nodeId);
|
|
|
+ if (node != null) {
|
|
|
+ nodes.add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nodes.isEmpty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 按父节点分组
|
|
|
+ Map<Long, List<ArchiveTreeContract>> parentGroups = new LinkedHashMap<>();
|
|
|
+
|
|
|
+ for (ArchiveTreeContract node : nodes) {
|
|
|
+ Long parentId = node.getParentId();
|
|
|
+
|
|
|
+ // 如果没有父节点,单独处理
|
|
|
+ if (parentId == null) {
|
|
|
+ parentGroups.put(node.getId(), Collections.singletonList(node));
|
|
|
+ } else {
|
|
|
+ parentGroups.computeIfAbsent(parentId, k -> new ArrayList<>()).add(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 构建结果部分
|
|
|
+ List<String> nameParts = new ArrayList<>();
|
|
|
+
|
|
|
+ for (Map.Entry<Long, List<ArchiveTreeContract>> entry : parentGroups.entrySet()) {
|
|
|
+ Long groupId = entry.getKey();
|
|
|
+ List<ArchiveTreeContract> groupNodes = entry.getValue();
|
|
|
+
|
|
|
+ // 处理没有父节点的情况
|
|
|
+ if (groupId == null) {
|
|
|
+ groupId = groupNodes.get(0).getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取父节点(组代表)
|
|
|
+ ArchiveTreeContract parent = allNodeMap.get(groupId);
|
|
|
+
|
|
|
+ // 父节点不存在(特殊情况处理)
|
|
|
+ if (parent == null) {
|
|
|
+ // 可能是没有父节点的单独节点
|
|
|
+ for (ArchiveTreeContract node : groupNodes) {
|
|
|
+ nameParts.add(node.getNodeName());
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取父节点层级名称
|
|
|
+ String parentLevelName = getLevelName(hierarchy, parent.getId());
|
|
|
+
|
|
|
+ // 获取该父节点下的所有子节点(在hierarchy中)
|
|
|
+ List<ArchiveTreeContract> allChildren = hierarchy.getChildren(parent.getId());
|
|
|
+
|
|
|
+ // 获取该父节点下的所有子节点数量
|
|
|
+ int totalChildrenCount = hierarchy.getTotalChildrenCount(parent.getId());
|
|
|
+
|
|
|
+ // 判断是否涵盖所有子节点
|
|
|
+ if (groupNodes.size() == totalChildrenCount && !allChildren.isEmpty()) {
|
|
|
+ // 涵盖所有子节点,直接使用父节点层级名称
|
|
|
+ nameParts.add(parentLevelName);
|
|
|
+ } else {
|
|
|
+ // 部分子节点,添加节点名称
|
|
|
+ StringBuilder groupName = new StringBuilder(parentLevelName);
|
|
|
+ for (ArchiveTreeContract node : groupNodes) {
|
|
|
+ groupName.append(node.getNodeName());
|
|
|
+ }
|
|
|
+ nameParts.add(groupName.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 拼接最终结果
|
|
|
+ return String.join("、", nameParts);
|
|
|
+ }
|
|
|
+}
|