diff --git a/project/src/main/java/com/sdm/project/model/vo/SpdmNodeVo.java b/project/src/main/java/com/sdm/project/model/vo/SpdmNodeVo.java index 2ca8ae8d..c7874e66 100644 --- a/project/src/main/java/com/sdm/project/model/vo/SpdmNodeVo.java +++ b/project/src/main/java/com/sdm/project/model/vo/SpdmNodeVo.java @@ -104,4 +104,9 @@ public class SpdmNodeVo extends BaseEntity { * 军令状时间 */ private String commitmentDeadline; + + /** + * 当前阶段 + */ + private String currentPhase; } diff --git a/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java index c4825449..a1d97196 100644 --- a/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java +++ b/project/src/main/java/com/sdm/project/service/impl/NodeServiceImpl.java @@ -463,12 +463,162 @@ public class NodeServiceImpl extends ServiceImpl nodeList) { + // 过滤出自建和EP的项目 + // EP类型项目 + List epProjectNodeList = nodeList.stream().filter(node -> SYNC_PROJECT_SOURCE.equals(node.getProjectSource())).toList(); + // 自建类型项目 + List dmProjectNodeList = nodeList.stream().filter(node -> !SYNC_PROJECT_SOURCE.equals(node.getProjectSource())).toList(); + if (CollectionUtils.isNotEmpty(epProjectNodeList)) { + // 设置EP类型项目 + setEpCurrentPhase(dmProjectNodeList); + } + if (CollectionUtils.isNotEmpty(dmProjectNodeList)) { + // 设置自建类型项目 + setDmCurrentPhase(dmProjectNodeList); + } + } + + /** + * 设置EP类型项目当前阶段信息 + * @param dmProjectNodeList + */ + private void setEpCurrentPhase(List dmProjectNodeList) { + // 1. 提取节点编码 + List nodeCodeList = dmProjectNodeList.stream() + .map(SpdmNodeVo::getNodeCode) + // 过滤空的nodeCode,避免无效查询和后续匹配问题 + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(nodeCodeList)) { + return; + } + + // 2. 查询视图数据 + Map projectStageMap; + try { + List lyricVProjectList = lyricVProjectToDmService.lambdaQuery() + .in(LyricVProjectToDM::getProjectNum, nodeCodeList) + .list(); + // 3. 转换为Map + projectStageMap = lyricVProjectList.stream() + .collect(Collectors.toMap( + LyricVProjectToDM::getProjectNum, // key:项目编号(nodeCode) + LyricVProjectToDM::getStage, // value:当前阶段 + // 解决重复key问题:保留第一个值 + (existing, replacement) -> existing + )); + } catch (MyBatisSystemException ex) { + log.warn("查询EP项目信息并设置当前阶段发生异常,项目编号:{}", nodeCodeList, ex); + return; + } + + // 4. 设置当前阶段 + dmProjectNodeList.forEach(spdmNodeVo -> { + String nodeCode = spdmNodeVo.getNodeCode(); + if (org.apache.commons.lang3.StringUtils.isNotBlank(nodeCode)) { + spdmNodeVo.setCurrentPhase(projectStageMap.get(nodeCode)); + } + }); + } + + /** + * 工具方法:将时间字符串解析为时间戳,解析失败抛运行时异常 + * @param timeStr 时间字符串(yyyy-MM-dd HH:mm:ss) + * @param sdf 时间格式化器 + * @return 时间戳 + */ + private long parseTimeToMillis(String timeStr, SimpleDateFormat sdf) { + try { + return sdf.parse(timeStr).getTime(); + } catch (ParseException e) { + throw new RuntimeException("时间解析失败,时间字符串:" + timeStr, e); + } + } + + /** + * 工具方法:判断当前时间是否落在阶段节点的[开始时间, 结束时间]范围内 + * @param phaseNode 阶段节点 + * @param currentTime 当前时间戳 + * @param sdf 时间格式化器 + * @return true-在范围内,false-不在/解析失败 + */ + private boolean isCurrentTimeInRange(SimulationNode phaseNode, long currentTime, SimpleDateFormat sdf) { + try { + long beginTime = sdf.parse(phaseNode.getBeginTime()).getTime(); + long endTime = sdf.parse(phaseNode.getEndTime()).getTime(); + return currentTime >= beginTime && currentTime <= endTime; + } catch (ParseException e) { + throw new RuntimeException("阶段节点时间解析失败,节点ID:" + phaseNode.getId(), e); + } + } + + /** + * 设置自建项目当前阶段信息 + * @param nodeList + */ + private void setDmCurrentPhase(List nodeList) { + List nodeUuidList = nodeList.stream() + .map(SpdmNodeVo::getUuid) + .collect(Collectors.toList()); + + // 1. 初始化时间格式化器 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + // 2. 查询所有父节点为目标节点的阶段类型节点 + List allPhaseNodeList = this.lambdaQuery() + .in(SimulationNode::getParentId, nodeUuidList) + .eq(SimulationNode::getNodeType, NodeTypeEnum.PHASE.getValue()) + .list(); + if (CollectionUtils.isEmpty(allPhaseNodeList)) { + return; + } + + // 3. 按项目节点ID(tag1)分组,预处理:过滤时间为空的节点 + Map> phaseNodeByProjectIdMap = allPhaseNodeList.stream() + .filter(phaseNode -> StringUtils.isNotBlank(phaseNode.getBeginTime()) + && StringUtils.isNotBlank(phaseNode.getEndTime())) + .collect(Collectors.groupingBy(SimulationNode::getTag1)); + + // 4. 获取当前时间戳 + long currentTime = System.currentTimeMillis(); + + // 5. 遍历每个项目节点的阶段列表,判断当前生效阶段 + phaseNodeByProjectIdMap.forEach((projectNodeId, phaseNodeList) -> { + // 按开始时间升序排序 + List sortedPhaseNodeList = phaseNodeList.stream() + .sorted(Comparator.comparingLong(phaseNode -> parseTimeToMillis(phaseNode.getBeginTime(), sdf))) + .collect(Collectors.toList()); + + // 查找当前时间落在【开始时间, 结束时间】内的阶段节点 + SimulationNode currentPhaseNode = sortedPhaseNodeList.stream() + .filter(phaseNode -> isCurrentTimeInRange(phaseNode, currentTime, sdf)) + .findFirst() + .orElse(null); + + // 找到当前阶段,回写至对应的SpdmNodeVo + if (Objects.nonNull(currentPhaseNode)) { + nodeList.stream() + .filter(node -> projectNodeId.equals(node.getUuid())) + .findFirst() + .ifPresent(node -> node.setCurrentPhase(currentPhaseNode.getNodeName())); + } + }); + } + private List addNode(List addNodeList, List tagMap, Long tenantId, Long jobNumber) { log.info("addNode参数为:{}", addNodeList);