From 4c7756ac12bc213e08b6085d7b7355c9f7deb6d1 Mon Sep 17 00:00:00 2001 From: 15195 Date: Fri, 6 Feb 2026 13:47:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=88=A9=E5=85=83?= =?UTF-8?q?=E4=BA=A8=E7=8E=B0=E5=9C=BA=EF=BC=8Cecn=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E6=9C=BA=E5=88=B6=E5=A4=87=E7=94=A8=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=BB=A3=E7=A0=81=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1-sql/2026-02-05/yang.sql | 16 +- .../entity/req/pbs/DelHpcJobsFileToolReq.java | 19 + .../outbridge/mode/LyricExceptionModel.java | 1 + .../project/dao/SimulationTaskEcnMapper.java | 25 ++ .../sdm/project/dao/SimulationTaskMapper.java | 4 + .../model/entity/SimulationTaskEcn.java | 57 +++ .../service/ISimulationTaskExtraService.java | 2 + .../service/SimulationTaskEcnService.java | 23 ++ .../impl/LyricInternalNewServiceImpl.java | 358 ++++++++++++++++++ .../impl/SimulationTaskEcnServiceImpl.java | 71 ++++ .../impl/SimulationTaskExtraServiceImpl.java | 77 +++- .../mapper/SimulationTaskEcnMapper.xml | 27 ++ .../resources/mapper/SimulationTaskMapper.xml | 13 + 13 files changed, 689 insertions(+), 4 deletions(-) create mode 100644 common/src/main/java/com/sdm/common/entity/req/pbs/DelHpcJobsFileToolReq.java create mode 100644 project/src/main/java/com/sdm/project/dao/SimulationTaskEcnMapper.java create mode 100644 project/src/main/java/com/sdm/project/model/entity/SimulationTaskEcn.java create mode 100644 project/src/main/java/com/sdm/project/service/SimulationTaskEcnService.java create mode 100644 project/src/main/java/com/sdm/project/service/impl/LyricInternalNewServiceImpl.java create mode 100644 project/src/main/java/com/sdm/project/service/impl/SimulationTaskEcnServiceImpl.java create mode 100644 project/src/main/resources/mapper/SimulationTaskEcnMapper.xml diff --git a/1-sql/2026-02-05/yang.sql b/1-sql/2026-02-05/yang.sql index 20325d26..557610ce 100644 --- a/1-sql/2026-02-05/yang.sql +++ b/1-sql/2026-02-05/yang.sql @@ -1,2 +1,16 @@ ALTER TABLE `spdm_baseline`.`simulation_job` - ADD COLUMN `del_flag` CHAR(1) NOT NULL DEFAULT 'N' COMMENT '逻辑删除标识:N-未删除,Y-已删除'; \ No newline at end of file + ADD COLUMN `del_flag` CHAR(1) NOT NULL DEFAULT 'N' COMMENT '逻辑删除标识:N-未删除,Y-已删除'; + +-- 创建任务异常信息记录表 +CREATE TABLE `simulation_task_ecn` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID,自增', + `project_code` VARCHAR(64) NOT NULL COMMENT '项目号', + `station_code` VARCHAR(64) NOT NULL COMMENT '工位号', + `ecn_info` MEDIUMTEXT NOT NULL COMMENT '异常数据,存储JSON字符串', + `source` VARCHAR(64) NOT NULL DEFAULT 'lyric' COMMENT '数据来源,默认值lyric', + `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间,自动记录插入时间', + `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间,自动记录更新时间', + PRIMARY KEY (`id`), + KEY `idx_project_station` (`project_code`, `station_code`) COMMENT '项目号+工位号联合索引,提升查询效率' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='任务异常信息记录表'; + diff --git a/common/src/main/java/com/sdm/common/entity/req/pbs/DelHpcJobsFileToolReq.java b/common/src/main/java/com/sdm/common/entity/req/pbs/DelHpcJobsFileToolReq.java new file mode 100644 index 00000000..c753f92e --- /dev/null +++ b/common/src/main/java/com/sdm/common/entity/req/pbs/DelHpcJobsFileToolReq.java @@ -0,0 +1,19 @@ +package com.sdm.common.entity.req.pbs; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class DelHpcJobsFileToolReq implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "计算任务Id,job new 生成") + private String jobId; + + @Schema(description = "任务执行输出的文件在Hpc的绝对路径,共享目录+jobName(文件回传)+uuid,下面可能有多个文件") + private String stdoutHpcFilePath; + +} diff --git a/outbridge/src/main/java/com/sdm/outbridge/mode/LyricExceptionModel.java b/outbridge/src/main/java/com/sdm/outbridge/mode/LyricExceptionModel.java index 9860dc61..96058ca5 100644 --- a/outbridge/src/main/java/com/sdm/outbridge/mode/LyricExceptionModel.java +++ b/outbridge/src/main/java/com/sdm/outbridge/mode/LyricExceptionModel.java @@ -9,6 +9,7 @@ public class LyricExceptionModel { // 异常任务的taskid private String uuid; + // 暂时没用,现在项目号+工位号下面有多个异常信息,就算存储也是List private LyricVProjectStationExcepTionToDM exceptionModel; } diff --git a/project/src/main/java/com/sdm/project/dao/SimulationTaskEcnMapper.java b/project/src/main/java/com/sdm/project/dao/SimulationTaskEcnMapper.java new file mode 100644 index 00000000..6ec516fa --- /dev/null +++ b/project/src/main/java/com/sdm/project/dao/SimulationTaskEcnMapper.java @@ -0,0 +1,25 @@ +package com.sdm.project.dao; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.sdm.outbridge.mode.SimulationTaskSyncExBo; +import com.sdm.project.model.entity.SimulationTaskEcn; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 任务异常信息记录表 Mapper 接口 + *

+ * + * @author author + * @since 2026-02-05 + */ +@Mapper +public interface SimulationTaskEcnMapper extends BaseMapper { + + List queryAllDataByProjectCodeAndStationCode(@Param("list") List list); + +} \ No newline at end of file diff --git a/project/src/main/java/com/sdm/project/dao/SimulationTaskMapper.java b/project/src/main/java/com/sdm/project/dao/SimulationTaskMapper.java index 513a28c9..e0ae26ac 100644 --- a/project/src/main/java/com/sdm/project/dao/SimulationTaskMapper.java +++ b/project/src/main/java/com/sdm/project/dao/SimulationTaskMapper.java @@ -68,4 +68,8 @@ public interface SimulationTaskMapper extends BaseMapper { int queryUnsyncedExceptionTasksTotal(); + int queryAllasksTotal(); + + List queryLyricAllTasksDatas(@Param("offset")int offset, @Param("pageSize")int pageSize); + } diff --git a/project/src/main/java/com/sdm/project/model/entity/SimulationTaskEcn.java b/project/src/main/java/com/sdm/project/model/entity/SimulationTaskEcn.java new file mode 100644 index 00000000..e88c78e3 --- /dev/null +++ b/project/src/main/java/com/sdm/project/model/entity/SimulationTaskEcn.java @@ -0,0 +1,57 @@ +package com.sdm.project.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author author + * @since 2026-02-05 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("simulation_task_ecn") +@ApiModel(value="SimulationTaskEcn对象", description="任务异常信息记录表") +public class SimulationTaskEcn implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "主键ID,自增") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty(value = "项目号") + @TableField("project_code") + private String projectCode; + + @ApiModelProperty(value = "工位号") + @TableField("station_code") + private String stationCode; + + @ApiModelProperty(value = "异常数据,JSON字符串") + @TableField("ecn_info") + private String ecnInfo; + + @ApiModelProperty(value = "数据来源,默认值 lyric ") + @TableField("source") + private String source; + + @ApiModelProperty(value = "创建时间") + @TableField("create_time") + private LocalDateTime createTime; + + @ApiModelProperty(value = "更新时间") + @TableField("update_time") + private LocalDateTime updateTime; + +} diff --git a/project/src/main/java/com/sdm/project/service/ISimulationTaskExtraService.java b/project/src/main/java/com/sdm/project/service/ISimulationTaskExtraService.java index b0b9ff78..355807ec 100644 --- a/project/src/main/java/com/sdm/project/service/ISimulationTaskExtraService.java +++ b/project/src/main/java/com/sdm/project/service/ISimulationTaskExtraService.java @@ -1,6 +1,7 @@ package com.sdm.project.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.sdm.outbridge.mode.LyricExceptionModel; import com.sdm.project.model.entity.SimulationTaskExtra; import com.sdm.project.model.req.SpdmNodeExtraReq; @@ -39,4 +40,5 @@ public interface ISimulationTaskExtraService extends IService taskExtras); + int batchRemoveAndSaveExceptionData(List exceptionModels); } diff --git a/project/src/main/java/com/sdm/project/service/SimulationTaskEcnService.java b/project/src/main/java/com/sdm/project/service/SimulationTaskEcnService.java new file mode 100644 index 00000000..a4a7a743 --- /dev/null +++ b/project/src/main/java/com/sdm/project/service/SimulationTaskEcnService.java @@ -0,0 +1,23 @@ +package com.sdm.project.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.sdm.outbridge.mode.SimulationTaskSyncExBo; +import com.sdm.project.model.entity.SimulationTaskEcn; + +import java.util.List; + +/** + *

+ * 任务异常信息记录表 服务类 + *

+ * + * @author author + * @since 2026-02-05 + */ +public interface SimulationTaskEcnService extends IService { + + List queryAllDataByProjectCodeAndStationCode(List validTasks); + + int batchRemoveSaveTaskEcns(List newTaskEcns); + +} \ No newline at end of file diff --git a/project/src/main/java/com/sdm/project/service/impl/LyricInternalNewServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/LyricInternalNewServiceImpl.java new file mode 100644 index 00000000..859acbb8 --- /dev/null +++ b/project/src/main/java/com/sdm/project/service/impl/LyricInternalNewServiceImpl.java @@ -0,0 +1,358 @@ +package com.sdm.project.service.impl; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.sdm.common.common.SdmResponse; +import com.sdm.outbridge.entity.LyricVProjectStationExcepTionToDM; +import com.sdm.outbridge.mode.LyricExceptionModel; +import com.sdm.outbridge.mode.SimulationTaskSyncExBo; +import com.sdm.outbridge.service.lyric.LyricVProjectStationExcepTionToDMService; +import com.sdm.project.dao.SimulationNodeMapper; +import com.sdm.project.dao.SimulationTaskMapper; +import com.sdm.project.model.entity.SimulationNode; +import com.sdm.project.model.entity.SimulationTaskEcn; +import com.sdm.project.service.ISimulationTaskExtraService; +import com.sdm.project.service.SimulationTaskEcnService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class LyricInternalNewServiceImpl { + + // 每批次处理的任务数量,可根据实际业务调整 + @Value("${lyric.syncException.batchSize:100}") + private Integer batchSize; + + @Autowired + private SimulationTaskMapper simulationTaskMapper; + + @Autowired + private SimulationNodeMapper simulationNodeMapper; + + @Autowired + private LyricVProjectStationExcepTionToDMService lyricVProjectStationExcepTionToDMService; + + @Autowired + private SimulationTaskEcnService simulationTaskEcnService; + + @Autowired + private ISimulationTaskExtraService simulationTaskExtraService; + + + /** + * 同步异常任务信息方法 batchSize + */ + public SdmResponse syncException() { + try { + // 1. 查询所有的 + int total = simulationTaskMapper.queryAllasksTotal(); + if (total <= 0) { + log.warn("同步异常任务:暂无需要同步的任务"); + return SdmResponse.success("同步异常任务:暂无需要同步的任务"); + } + log.info("同步异常任务:待处理总任务数为{}条,将分批次处理,每批次{}条", total, batchSize); + // 2. 初始化批次参数,循环分批处理 + int processedCount = 0; // 已处理的任务总数 + int syncTotalCount = 0; // 最终同步成功的异常数据总数 + int pageNum = 1; // 当前批次页码 + while (processedCount < total) { + log.info("同步异常任务:开始处理第{}批次,已处理{}条,剩余{}条", + pageNum, processedCount, total - processedCount); + // 计算当前批次的起始和结束索引(分页查询) + int fromIndex = processedCount; + int endIndex = Math.min(processedCount + batchSize, total); + // 3. 分批查询未同步异常任务 + List unsyncedExceptionTasks = queryAllTasks(fromIndex, endIndex); + if (CollectionUtils.isEmpty(unsyncedExceptionTasks)) { + log.warn("同步异常任务:第{}批次查询结果为空,跳过该批次", pageNum); + processedCount += batchSize; + pageNum++; + continue; + } + log.info("同步异常任务:第{}批次查询到{}条待处理任务", pageNum, unsyncedExceptionTasks.size()); + // 4. 构建标签对应的节点信息映射 + Map tag1NodeMap = buildTagNodeMap(unsyncedExceptionTasks, "tag1", "project"); + Map tag5NodeMap = buildTagNodeMap(unsyncedExceptionTasks, "tag5", "workspace"); + if (MapUtils.isEmpty(tag1NodeMap) && MapUtils.isEmpty(tag5NodeMap)) { + log.warn("同步异常任务:第{}批次标签对应的节点信息为空,跳过该批次", pageNum); + processedCount += unsyncedExceptionTasks.size(); + pageNum++; + continue; + } + // 5. 为任务赋值对应的节点编码 + assignNodeCodeToTasks(unsyncedExceptionTasks, tag1NodeMap, tag5NodeMap); + // 6. 过滤出编码完整的有效任务 + List validTasks = filterValidTasks(unsyncedExceptionTasks); + if (CollectionUtils.isEmpty(validTasks)) { + log.warn("同步异常任务:第{}批次过滤后无有效任务,跳过该批次", pageNum); + processedCount += unsyncedExceptionTasks.size(); + pageNum++; + continue; + } + log.info("同步异常任务:第{}批次过滤后剩余{}条有效任务", pageNum, validTasks.size()); + + // 7. 查询异常数据并匹配任务 +// List newExceptionModels = queryAndMatchExceptions(validTasks); + Pair, List> matchPair = queryAndMatchExceptions(validTasks); + List newExceptionModels = matchPair.getLeft(); + List newTaskEcns = matchPair.getRight(); + + if (CollectionUtils.isEmpty(newExceptionModels)) { + log.info("同步异常任务:第{}批次无新增异常数据需要入库", pageNum); + processedCount += unsyncedExceptionTasks.size(); + pageNum++; + continue; + } + + // 8. 批量入库异常数据,累加同步成功数量 + int syncCount = 0; + try { + syncCount = simulationTaskExtraService.batchRemoveAndSaveExceptionData(newExceptionModels); + } catch (Exception e) { + log.error("batchRemoveAndSaveExceptionData error:{}", e.getMessage()); + continue; + } + syncTotalCount += syncCount; + log.info("同步异常任务:第{}批次同步完成,本次同步{}条,累计同步{}条", + pageNum, syncCount, syncTotalCount); + // 更新已处理数量和页码 + processedCount += unsyncedExceptionTasks.size(); + pageNum++; + // 9. batchSaveTaskEcns,记录EP异常的编码信息 + try { + int ecnsCount = simulationTaskEcnService.batchRemoveSaveTaskEcns(newTaskEcns); + } catch (Exception e) { + log.error("batchRemoveSaveTaskEcns error:{}", e.getMessage()); + } + + } + + log.info("同步异常任务全部完成,总任务数{}条,累计同步异常数据{}条", total, syncTotalCount); + return SdmResponse.success("同步成功,总任务数" + total + "条,累计同步了" + syncTotalCount + "条异常数据"); + } catch (Exception e) { + log.error("同步异常任务执行失败,已处理部分数据", e); + return SdmResponse.failed("同步异常任务失败:" + e.getMessage()); + } + } + + + /** + * 查询所有的任务 + */ + private List queryAllTasks(int fromIndex, int endIndex) { + return simulationTaskMapper.queryLyricAllTasksDatas(fromIndex,endIndex); + } + + + + + /** + * 构建标签对应的节点信息映射 + * @param tasks 任务列表 + * @param tagField 标签字段名(tag1/tag5) + * @param nodeType 节点类型(project/workspace) + */ + private Map buildTagNodeMap(List tasks, + String tagField, + String nodeType) { + // 提取非空的标签值列表 + List tagValues = tasks.stream() + .filter(Objects::nonNull) + .map(task -> "tag1".equals(tagField) ? task.getTag1() : task.getTag5()) + .filter(StringUtils::isNotBlank) + .distinct() // 去重,减少查询次数 + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(tagValues)) { + return Collections.emptyMap(); + } + + // 查询标签对应的节点信息 + List nodes = simulationNodeMapper.queryNodeCodeByTags(tagValues, tagField, nodeType); + if (CollectionUtils.isEmpty(nodes)) { + log.warn("同步异常任务:{}类型节点查询结果为空,标签列表:{}", nodeType, tagValues); + return Collections.emptyMap(); + } + + // 转换为UUID->节点的映射(处理重复UUID,保留第一个) + return nodes.stream() + .filter(node -> node != null && StringUtils.isNotBlank(node.getUuid())) + .collect(Collectors.toMap( + SimulationNode::getUuid, + node -> node, + (existing, replacement) -> existing + )); + } + + /** + * 为任务赋值对应的节点编码 + */ + private void assignNodeCodeToTasks(List tasks, + Map tag1NodeMap, + Map tag5NodeMap) { + tasks.stream() + .filter(Objects::nonNull) + .forEach(task -> { + // 赋值tag1Code + if (MapUtils.isNotEmpty(tag1NodeMap) && StringUtils.isNotBlank(task.getTag1())) { + SimulationNode node = tag1NodeMap.get(task.getTag1()); + if (node != null) { + task.setTag1Code(node.getNodeCode()); + } + } + // 赋值tag5Code + if (MapUtils.isNotEmpty(tag5NodeMap) && StringUtils.isNotBlank(task.getTag5())) { + SimulationNode node = tag5NodeMap.get(task.getTag5()); + if (node != null) { + task.setTag5Code(node.getNodeCode()); + } + } + }); + } + + /** + * 过滤出tag1Code和tag5Code都不为空的有效任务 + */ + private List filterValidTasks(List tasks) { + return tasks.stream() + .filter(Objects::nonNull) + .filter(task -> StringUtils.isNotBlank(task.getTag1Code()) + && StringUtils.isNotBlank(task.getTag5Code())) + .collect(Collectors.toList()); + } + + /** + * 查询异常数据并匹配任务 + */ + private Pair,List> queryAndMatchExceptions(List validTasks) { + // 查询EP视图异常数据 + List exceptionList = lyricVProjectStationExcepTionToDMService + .queryExceptionsByProjectAndStation(validTasks); + // 查询 simulation_task_ecn 异常信息的表数据 + ListtaskEcnsList =simulationTaskEcnService. + queryAllDataByProjectCodeAndStationCode(validTasks); + + // 匹配异常和任务,返回新增的异常数据 + return matchExceptionAndTask(exceptionList, validTasks,taskEcnsList); + } + + + /** + * 匹配两个集合,筛选符合条件的数据并封装为 LyricExceptionModel 列表 + * @param exceptionList 异常信息列表 + * @param noSyncLists 没有同步的有异常的任务同步列表 + * @return 匹配后的异常模型列表 + */ + public Pair,List> matchExceptionAndTask(List exceptionList, + List noSyncLists, ListtaskEcnsList) { + List ingDealExceptionList = new ArrayList<>(); + List ingDealTaskEcnList = new ArrayList<>(); + // key = ProjectCode_StationCode sdpm系统已经记录的异常信息 + Map> spdmDbEcnMap=new HashMap<>(); + if(CollectionUtils.isNotEmpty(taskEcnsList)) { + spdmDbEcnMap = taskEcnsList.stream() + .collect(Collectors.toMap( + // 生成Key:projectCode + "_" + stationCode + ecn -> ecn.getProjectCode() + "_" + ecn.getStationCode(), + // 解析ecnInfo JSON字符串为List + ecn -> JSON.parseArray(ecn.getEcnInfo(), String.class), + // 解决Key冲突:若存在相同projectCode+stationCode,合并两个List + (existing, replacement) -> { + existing.addAll(replacement); + return existing; + } + )); + } + + // key = ProjectCode_StationCode ep拉回来的异常信息 + Map> epExceptionsMap = new HashMap<>(); + if(CollectionUtils.isNotEmpty(exceptionList)) { + epExceptionsMap = exceptionList.stream() + .collect(Collectors.toMap( + // 生成 Key:projectNum_stationCode + dto -> dto.getProjectNum() + "_" + dto.getStationCode(), + // 生成 Value:将单个 ecnCode 封装为 List + dto -> { + List ecnCodeList = new ArrayList<>(); + ecnCodeList.add(dto.getEcnCode()); + return ecnCodeList; + }, + // Key 冲突时,合并 List(将新的 ecnCode 添加到原有 List 中) + (existingList, newList) -> { + existingList.addAll(newList); + return existingList; + } + )); + } + // spdm db的task + Map> taskDbMap=new HashMap<>(); + if(CollectionUtils.isNotEmpty(noSyncLists)) { + taskDbMap = noSyncLists.stream() + .filter(bo -> bo != null + && bo.getTag1Code() != null && !bo.getTag1Code().trim().isEmpty() + && bo.getTag5Code() != null && !bo.getTag5Code().trim().isEmpty()) + .collect(Collectors.groupingBy( + bo -> bo.getTag1Code().trim() + "_" + bo.getTag5Code().trim() + )); + } + // 判断是否需要修改 + // 后面再次拉取异常,假如没有新增,原始的3条不动,即使spdm任务增加到4条,也不动; + //假如新增了异常,那拓展的数据需要修改+新增。 + // 遍历 任务的Map 的 entrySet,同时获取 key 和对应的 List + for (Map.Entry> entry : taskDbMap.entrySet()) { + // 获取当前键 + String key = entry.getKey(); + // ep异常和spdm task对应上了 + if(epExceptionsMap.containsKey(key)) { + // 这个任务有异常 + List epEcnCodes = epExceptionsMap.get(key); + List spdmEcnCodes = spdmDbEcnMap.get(key); + // 调用方法判断是否相等,异常是否有新增 + boolean isEqual = Objects.equals(epEcnCodes, spdmEcnCodes); + // 异常信息变了,重新维护任务异常,及异常编号的记录 + if(!isEqual) { + // 获取当前值(List 集合) + List spdmDbtaskList = entry.getValue(); + // 1. 先判断 List 是否为空(避免空指针,最佳实践) + if (CollectionUtils.isNotEmpty(spdmDbtaskList)) { + String projectCode=""; + String stationCode=""; + // 2. 处理每个任务的异常 + for (SimulationTaskSyncExBo taskDb : spdmDbtaskList) { + LyricExceptionModel model = new LyricExceptionModel(); + model.setUuid(taskDb.getUuid()); + ingDealExceptionList.add(model); + if(StringUtils.isNotBlank(projectCode)) {projectCode=taskDb.getTag1Code();} + if(StringUtils.isNotBlank(stationCode)) {stationCode=taskDb.getTag5Code();} + } + if(CollectionUtils.isNotEmpty(epEcnCodes)) { + // 处理项目+工位下的异常 + SimulationTaskEcn taskEcn = new SimulationTaskEcn(); + taskEcn.setEcnInfo(JSONObject.toJSONString(epEcnCodes)); + taskEcn.setSource("lyric"); + taskEcn.setProjectCode(projectCode); + taskEcn.setStationCode(stationCode); + taskEcn.setCreateTime(LocalDateTime.now()); + taskEcn.setUpdateTime(LocalDateTime.now()); + ingDealTaskEcnList.add(taskEcn); + } + } + } + } + } + return Pair.of(ingDealExceptionList, ingDealTaskEcnList); + } + + +} diff --git a/project/src/main/java/com/sdm/project/service/impl/SimulationTaskEcnServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/SimulationTaskEcnServiceImpl.java new file mode 100644 index 00000000..0ef6088d --- /dev/null +++ b/project/src/main/java/com/sdm/project/service/impl/SimulationTaskEcnServiceImpl.java @@ -0,0 +1,71 @@ +package com.sdm.project.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sdm.outbridge.mode.SimulationTaskSyncExBo; +import com.sdm.project.dao.SimulationTaskEcnMapper; +import com.sdm.project.model.entity.SimulationTaskEcn; +import com.sdm.project.service.SimulationTaskEcnService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + *

+ * 任务异常信息记录表 服务实现类 + *

+ * + * @author author + * @since 2026-02-05 + */ +@Slf4j +@Service +public class SimulationTaskEcnServiceImpl extends ServiceImpl implements SimulationTaskEcnService { + + @Autowired + private SimulationTaskEcnMapper simulationTaskEcnMapper; + + @Override + public List queryAllDataByProjectCodeAndStationCode(List validTasks) { + return simulationTaskEcnMapper.queryAllDataByProjectCodeAndStationCode(validTasks); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int batchRemoveSaveTaskEcns(List newTaskEcns) { + // 先删除,再插入 + // 1. 判空处理:集合为空直接返回,避免全表删除 + if (CollectionUtils.isEmpty(newTaskEcns)) { + return 0; + } + // 2. 构建 Lambda 查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + // 3. 遍历集合,拼接多组 (projectCode AND stationCode) 条件 + for (SimulationTaskEcn taskEcn : newTaskEcns) { + // 每一组条件都用 and() 包裹,确保逻辑正确 + queryWrapper.or(i -> i + .eq(SimulationTaskEcn::getProjectCode, taskEcn.getProjectCode()) + .eq(SimulationTaskEcn::getStationCode, taskEcn.getStationCode()) + ); + } + // 4. 执行删除 + boolean remove = this.remove(queryWrapper); + log.warn("batchSaveTaskEcns before delete: {}", remove); + if(!remove) { + log.error("batchSaveTaskEcns before delete failed"); + throw new RuntimeException("batchSaveTaskEcns before delete failed"); + } + boolean b = this.saveBatch(newTaskEcns); + if(!b) { + log.error("batchSaveTaskEcns after save failed"); + throw new RuntimeException("batchSaveTaskEcns after save failed"); + } + log.info("batchSaveTaskEcns after save: {}", b); + return newTaskEcns.size(); + } + +} \ No newline at end of file diff --git a/project/src/main/java/com/sdm/project/service/impl/SimulationTaskExtraServiceImpl.java b/project/src/main/java/com/sdm/project/service/impl/SimulationTaskExtraServiceImpl.java index 2e5757b7..380656f1 100644 --- a/project/src/main/java/com/sdm/project/service/impl/SimulationTaskExtraServiceImpl.java +++ b/project/src/main/java/com/sdm/project/service/impl/SimulationTaskExtraServiceImpl.java @@ -2,16 +2,19 @@ package com.sdm.project.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.sdm.outbridge.mode.LyricExceptionModel; import com.sdm.project.dao.SimulationTaskExtraMapper; import com.sdm.project.model.entity.SimulationTaskExtra; import com.sdm.project.model.req.SpdmNodeExtraReq; import com.sdm.project.service.ISimulationTaskExtraService; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -22,9 +25,13 @@ import java.util.stream.Collectors; * @author author * @since 2025-09-16 */ +@Slf4j @Service public class SimulationTaskExtraServiceImpl extends ServiceImpl implements ISimulationTaskExtraService { + @Autowired + private SimulationTaskExtraMapper simulationTaskExtraMapper; + @Override public Map> batchGetTaskExtraMap(List taskIds, List propertyNames) { if (CollectionUtils.isEmpty(taskIds) || CollectionUtils.isEmpty(propertyNames)) { @@ -68,4 +75,68 @@ public class SimulationTaskExtraServiceImpl extends ServiceImpl exceptionModels) { + // 先删除,再插入 + List taskIdList = exceptionModels.stream() + // 提取每个 LyricExceptionModel 对象的 uuid 字段 + .map(LyricExceptionModel::getUuid) + // 过滤掉 null 的 uuid(可选,根据业务需求决定是否保留) + .filter(Objects::nonNull) + // 收集为新的 List + .collect(Collectors.toList()); + // 2. 构建 Lambda 查询条件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(SimulationTaskExtra::getTaskId, taskIdList); + // 3. 执行删除 + boolean remove = this.remove(queryWrapper); + log.warn("batchSaveExceptionData before delete: {}", remove); + if(!remove) { + log.error("batchSaveExceptionData before delete failed"); + throw new RuntimeException("batchSaveExceptionData before delete failed"); + } + // 构建扩展表数据 + List abnormalExtraList = new ArrayList<>(); +// List abnormalDetailExtraList = new ArrayList<>(); + for (LyricExceptionModel model : exceptionModels) { + if (model == null || StringUtils.isBlank(model.getUuid())) { + log.warn("同步异常任务:异常模型数据无效,跳过处理,model={}", model); + continue; + } + // 构建异常标识扩展记录 + SpdmNodeExtraReq abnormalExtra = new SpdmNodeExtraReq(); + abnormalExtra.setNodeId(model.getUuid()); + abnormalExtra.setPropertyName("abnormal"); + abnormalExtra.setPropertyValue("1"); + abnormalExtraList.add(abnormalExtra); +// // 构建异常详情扩展记录 异常的详情暂时不需要 项目号+工位号 查出来的异常非常多,如果存储的话需要注意 +// SpdmNodeExtraReq detailExtra = new SpdmNodeExtraReq(); +// detailExtra.setNodeId(model.getUuid()); +// detailExtra.setPropertyName("abnormalDetail"); +// detailExtra.setPropertyValue(JSONObject.toJSONString(model)); +// abnormalDetailExtraList.add(detailExtra); + + } + // 批量插入异常标识 + if (CollectionUtils.isNotEmpty(abnormalExtraList)) { + int abnormalCount = simulationTaskExtraMapper.addTaskExtraBatch(abnormalExtraList); + if(abnormalCount <=0) { + throw new RuntimeException("batchSaveExceptionData failed"); + } + log.info("同步异常任务:批量插入异常标识{}条,成功{}条", abnormalExtraList.size(), abnormalCount); + } + +// 批量插入异常详情 +// if (CollectionUtils.isNotEmpty(abnormalDetailExtraList)) { +// int detailCount = simulationTaskExtraMapper.addTaskExtraBatch(abnormalDetailExtraList); +// log.info("同步异常任务:批量插入异常详情{}条,成功{}条", abnormalDetailExtraList.size(), detailCount); +// } + + return exceptionModels.size(); + } + } diff --git a/project/src/main/resources/mapper/SimulationTaskEcnMapper.xml b/project/src/main/resources/mapper/SimulationTaskEcnMapper.xml new file mode 100644 index 00000000..85d4fce9 --- /dev/null +++ b/project/src/main/resources/mapper/SimulationTaskEcnMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/project/src/main/resources/mapper/SimulationTaskMapper.xml b/project/src/main/resources/mapper/SimulationTaskMapper.xml index f8435ad5..35bc8808 100644 --- a/project/src/main/resources/mapper/SimulationTaskMapper.xml +++ b/project/src/main/resources/mapper/SimulationTaskMapper.xml @@ -743,5 +743,18 @@ AND t.tag5 IS NOT NULL + + + \ No newline at end of file