Sfoglia il codice sorgente

求解器算法集成

raojiang 1 settimana fa
parent
commit
0de144e7f8
17 ha cambiato i file con 660 aggiunte e 93 eliminazioni
  1. 1 1
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/ISimulationPlatformApiClient.java
  2. 1 1
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/fallback/SimulationPlatformApiClientFallBack.java
  3. 60 0
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/recon/DnrResultV24DTO.java
  4. 51 0
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/recon/DnrResultV24GroupDTO.java
  5. 74 0
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/recon/DnrResultV24SolnDTO.java
  6. 16 0
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/simulation/OperationModeDTO.java
  7. 104 2
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/listener/ReconTriggerListener.java
  8. 46 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/bf/entity/FhzgReconSimulationTask.java
  9. 17 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/bf/mapper/FhzgReconSimulationTaskMapper.java
  10. 13 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/bf/service/FhzgReconSimulationTaskService.java
  11. 22 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/bf/service/impl/FhzgReconSimulationTaskServiceImpl.java
  12. 1 1
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/controller/simulation/SimulationController.java
  13. 12 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/recon/ReconResultService.java
  14. 136 36
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/recon/impl/ReconResultServiceImpl.java
  15. 1 1
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/simulation/ISimulationService.java
  16. 87 51
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/simulation/impl/SimulationServiceImpl.java
  17. 18 0
      services/load-transfer-si/src/main/resources/mapper/FhzgReconSimulationTaskMapper.xml

+ 1 - 1
api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/ISimulationPlatformApiClient.java

@@ -33,7 +33,7 @@ public interface ISimulationPlatformApiClient {
 
     @ApiOperation(value = "执行调优算法计算,启动网络重构")
     @PostMapping("/operationMode/startOperationCalTask")
-    ApiResponse<String> startOperationCalTask(@RequestBody OperationModeStartDTO dto);
+    ApiResponse<String> startOperationCalTask(@RequestBody OperationModeDTO dto);
 
     @ApiOperation(value = "查询调优计算结果")
     @GetMapping("/operationMode/queryOperationResult")

+ 1 - 1
api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/fallback/SimulationPlatformApiClientFallBack.java

@@ -41,7 +41,7 @@ public class SimulationPlatformApiClientFallBack implements FallbackFactory<ISim
             }
 
             @Override
-            public ApiResponse<String> startOperationCalTask(OperationModeStartDTO dto) {
+            public ApiResponse<String> startOperationCalTask(OperationModeDTO dto) {
                 log.error("执行调优算法计算-远程调用服务异常, 参数:{},异常:{}", dto, cause.getMessage());
                 return ApiResponse.fail("执行调优算法计算服务异常");
             }

+ 60 - 0
api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/recon/DnrResultV24DTO.java

@@ -0,0 +1,60 @@
+package com.hdkj.lt.modle.dto.recon;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * DNR 结果 v2.4 格式 — 顶层结构.
+ * <p>
+ * 对应 dnr_result_v2.4.json 的顶层结构:
+ * <pre>
+ * { "summary": {...}, "data": [...] }
+ * </pre>
+ */
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class DnrResultV24DTO {
+
+    @JsonProperty("summary")
+    private DnrResultV24SummaryDTO summary;
+
+    @JsonProperty("data")
+    private List<DnrResultV24GroupDTO> data;
+
+    /**
+     * summary 对象.
+     */
+    @Data
+    @NoArgsConstructor
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    public static class DnrResultV24SummaryDTO {
+        @JsonProperty("case_name")
+        private String caseName;
+
+        @JsonProperty("algo")
+        private String algo;
+
+        @JsonProperty("total_feeder_group_count")
+        private Integer totalFeederGroupCount;
+
+        @JsonProperty("success_count")
+        private Integer successCount;
+
+        @JsonProperty("failed_count")
+        private Integer failedCount;
+
+        @JsonProperty("skipped_count")
+        private Integer skippedCount;
+
+        @JsonProperty("status")
+        private String status;
+
+        @JsonProperty("message")
+        private String message;
+    }
+}

+ 51 - 0
api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/recon/DnrResultV24GroupDTO.java

@@ -0,0 +1,51 @@
+package com.hdkj.lt.modle.dto.recon;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * DNR 结果 v2.4 格式 — data[] 中的每个馈线组.
+ * <p>
+ * 对应 JSON 结构:
+ * <pre>
+ * {
+ *   "group_id": 1,
+ *   "group_sid": "fgrp_001",
+ *   "group_name": "...",
+ *   "st_area_id": 0,
+ *   "status": "success",
+ *   "algo": "PSO",
+ *   "soln_list": [...]
+ * }
+ * </pre>
+ */
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class DnrResultV24GroupDTO {
+
+    @JsonProperty("group_id")
+    private Integer groupId;
+
+    @JsonProperty("group_sid")
+    private String groupSid;
+
+    @JsonProperty("group_name")
+    private String groupName;
+
+    @JsonProperty("st_area_id")
+    private Integer stAreaId;
+
+    @JsonProperty("status")
+    private String status;
+
+    @JsonProperty("algo")
+    private String algo;
+
+    @JsonProperty("soln_list")
+    private List<DnrResultV24SolnDTO> solnList;
+}

+ 74 - 0
api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/recon/DnrResultV24SolnDTO.java

@@ -0,0 +1,74 @@
+package com.hdkj.lt.modle.dto.recon;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * DNR 结果 v2.4 格式 — soln_list[] 中的每个方案.
+ * <p>
+ * 对应 JSON 结构:
+ * <pre>
+ * {
+ *   "rank": 1,
+ *   "soln_id": "solution_1",
+ *   "soln_name": "solution_1",
+ *   "soln_desc": "...",
+ *   "algo": "PSO",
+ *   "objective": "default",
+ *   "computeResult": "computeOK",
+ *   "detalDesc": "...",
+ *   "SwitchOp": { "listSwitchOp": [...] },
+ *   "switchSeq": { "listSwitchOp": [...] },
+ *   "feederResult": { "listFeeder": [...] },
+ *   "volResult": { "summary": {...}, "details": [...] },
+ *   "switchResult": { "summary": "...", "details": [...] },
+ *   "finalCheck": { "is_safe": true, "details": "ok" },
+ *   "metrics": { "metrics_before": {...}, "metrics_after": {...}, ... }
+ * }
+ * </pre>
+ */
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class DnrResultV24SolnDTO {
+
+    private Integer rank;
+
+    @JsonProperty("soln_id")
+    private String solnId;
+
+    @JsonProperty("soln_name")
+    private String solnName;
+
+    @JsonProperty("computeResult")
+    private String computeResult;
+
+    @JsonProperty("detalDesc")
+    private String detalDesc;
+
+    private JsonNode objective;
+
+    @JsonProperty("SwitchOp")
+    private SwitchOpDTO switchOp;
+
+    @JsonProperty("switchSeq")
+    private SwitchSeqDTO switchSeq;
+
+    @JsonProperty("feederResult")
+    private FeederResultDTO feederResult;
+
+    @JsonProperty("volResult")
+    private VolResultDTO volResult;
+
+    @JsonProperty("switchResult")
+    private SwitchResultDTO switchResult;
+
+    @JsonProperty("finalCheck")
+    private FinalCheckDTO finalCheck;
+
+    @JsonProperty("metrics")
+    private MetricsDTO metrics;
+}

+ 16 - 0
api/load-transfer-si-api/src/main/java/com/hdkj/lt/modle/dto/simulation/OperationModeDTO.java

@@ -0,0 +1,16 @@
+package com.hdkj.lt.modle.dto.simulation;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 执行调优算法计算 — 请求参数.
+ */
+@Data
+@NoArgsConstructor
+public class OperationModeDTO {
+
+    private String eventId;
+
+    private OperationModeStartDTO operationModeStartDTO;
+}

+ 104 - 2
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/listener/ReconTriggerListener.java

@@ -1,12 +1,25 @@
 package com.hdkj.lt.bf.listener;
 
 import com.alibaba.fastjson.JSONObject;
+import com.hdkj.hussar.ApiResponse;
 import com.hdkj.lt.bf.entity.FhzgSeCurrentEvent;
 import com.hdkj.lt.bf.entity.FhzgSeVoltageEvent;
+import com.hdkj.lt.bf.entity.dto.XlRelDTO;
+import com.hdkj.lt.bf.entity.vo.XlRelVO;
 import com.hdkj.lt.bf.event.ReconTriggerEvent;
 import com.hdkj.lt.bf.mapper.FhzgSeCurrentEventMapper;
 import com.hdkj.lt.bf.mapper.FhzgSeVoltageEventMapper;
+import com.hdkj.lt.bf.mapper.XlRelMapper;
+import com.hdkj.lt.core.bizms.modle.po.DwdShbDsFeederBase;
+import com.hdkj.lt.core.bizms.modle.po.Jxz;
+import com.hdkj.lt.core.sys.dao.DwdShbDsFeederBaseMapper;
+import com.hdkj.lt.core.sys.dao.JxzMapper;
 import com.hdkj.lt.feign.IReconApiClient;
+import com.hdkj.lt.feign.ISimulationPlatformApiClient;
+import com.hdkj.lt.modle.dto.simulation.EacFeederDTO;
+import com.hdkj.lt.modle.dto.simulation.OperationModeDTO;
+import com.hdkj.lt.modle.dto.simulation.OperationModeStartDTO;
+import com.hdkj.lt.modle.dto.simulation.SwitchFeederDTO;
 import com.hdkj.lt.modle.vo.recon.ReconstructionParam;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -15,8 +28,9 @@ import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
 import java.time.format.DateTimeFormatter;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
 
 /**
  * 重构算法触发监听器
@@ -41,6 +55,10 @@ import java.util.Map;
 public class ReconTriggerListener {
 
     private final IReconApiClient reconApiClient;
+    private final ISimulationPlatformApiClient simulationPlatformApiClient;
+    private final JxzMapper jxzMapper;
+    private final XlRelMapper xlRelMapper;
+    private final DwdShbDsFeederBaseMapper feederBaseMapper;
     private final FhzgSeCurrentEventMapper currentEventMapper;
     private final FhzgSeVoltageEventMapper voltageEventMapper;
 
@@ -68,6 +86,9 @@ public class ReconTriggerListener {
         log.info("重构触发: eventId={}, feederId={}, alarmType={}, pointTime={}",
                 event.getEventId(), event.getFeederId(), event.getAlarmType(), event.getPointTime());
 
+        // 异步调用求解器,不阻塞后续重构请求
+        CompletableFuture.runAsync(() -> callSolver(event));
+
         try {
             String resp = reconApiClient.triggerReconfiguration(param);
             log.info("重构接口调用成功: eventId={}, response={}", event.getEventId(), resp);
@@ -81,6 +102,87 @@ public class ReconTriggerListener {
         }
     }
 
+    /**
+     * 调用求解器(startOperationCalTask).
+     * <p>
+     * 从 t_jxz_xl 获取接线组线路,从 dwd_shb_ds_feeder_base 获取 orgId,
+     * 从 ct_xl_rel 获取联络开关数据,组装参数后远程调用。
+     */
+    private void callSolver(ReconTriggerEvent event) {
+        try {
+            // 1. 查询接线组线路
+            List<Jxz> jxzList = jxzMapper.queryJxzXl(event.getFeederId());
+            List<String> groupFeederIds = jxzList.stream()
+                    .map(Jxz::getFeederId)
+                    .filter(Objects::nonNull)
+                    .distinct()
+                    .collect(Collectors.toList());
+
+            if (groupFeederIds.isEmpty()) {
+                log.warn("求解器: 未找到接线组线路, feederId={}", event.getFeederId());
+                return;
+            }
+
+            // 2. 批量查询馈线台账,构建 orgId 映射
+            Map<String, String> feederOrgMap = new HashMap<>();
+            List<DwdShbDsFeederBase> feederBases = feederBaseMapper.selectBatchIds(groupFeederIds);
+            for (DwdShbDsFeederBase base : feederBases) {
+                if (base != null) {
+                    feederOrgMap.put(base.getPsrId(), base.getMaintOrg());
+                }
+            }
+            List<EacFeederDTO> feeders = groupFeederIds.stream().map(fid -> {
+                EacFeederDTO f = new EacFeederDTO();
+                f.setPsrId(fid);
+                f.setOrgId(feederOrgMap.get(fid));
+                return f;
+            }).collect(Collectors.toList());
+
+            // 3. 查询联络开关数据
+            Map<String, List<EacFeederDTO>> switchFeederMap = new LinkedHashMap<>();
+            for (String fid : groupFeederIds) {
+                XlRelDTO xlRelDTO = new XlRelDTO(fid, null, null, null);
+                List<XlRelVO> contactSwitches = xlRelMapper.getContactSwitchListByFeeder(xlRelDTO);
+                for (XlRelVO sw : contactSwitches) {
+                    switchFeederMap.computeIfAbsent(sw.getLlsbId(), k -> new ArrayList<>());
+                    // 对侧线路
+                    String oppId = fid.equals(sw.getXlIdOne()) ? sw.getXlIdTwo() : sw.getXlIdOne();
+                    String oppName = fid.equals(sw.getXlIdOne()) ? sw.getXlNameTwo() : sw.getXlNameOne();
+                    EacFeederDTO oppFeeder = new EacFeederDTO();
+                    oppFeeder.setPsrId(oppId);
+                    oppFeeder.setName(oppName);
+                    oppFeeder.setOrgId(feederOrgMap.get(oppId));
+                    switchFeederMap.get(sw.getLlsbId()).add(oppFeeder);
+                }
+            }
+            List<SwitchFeederDTO> switchFeeders = switchFeederMap.entrySet().stream().map(entry -> {
+                SwitchFeederDTO sf = new SwitchFeederDTO();
+                sf.setSwitchPsrId(entry.getKey());
+                sf.setFeeders(entry.getValue());
+                return sf;
+            }).collect(Collectors.toList());
+
+            // 4. 构建请求参数
+            OperationModeStartDTO startDTO = new OperationModeStartDTO();
+            startDTO.setFeeders(feeders);
+            startDTO.setSwitchFeeders(switchFeeders);
+            startDTO.setSectionTime(event.getPointTime() != null
+                    ? event.getPointTime().format(DT_FMT) : null);
+
+            OperationModeDTO modeDTO = new OperationModeDTO();
+            modeDTO.setEventId(String.valueOf(event.getEventId()));
+            modeDTO.setOperationModeStartDTO(startDTO);
+
+            // 5. 远程调用求解器
+            ApiResponse<String> solverResp = simulationPlatformApiClient.startOperationCalTask(modeDTO);
+            log.info("求解器调用成功: eventId={}, response={}",
+                    event.getEventId(), JSONObject.toJSONString(solverResp));
+        } catch (Exception e) {
+            log.error("求解器调用失败: eventId={}, feederId={}, error={}",
+                    event.getEventId(), event.getFeederId(), e.getMessage(), e);
+        }
+    }
+
     private int parseReconResponse(String response) {
         if (response == null || response.isEmpty()) return RECON_FAILED;
         try {

+ 46 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/bf/entity/FhzgReconSimulationTask.java

@@ -0,0 +1,46 @@
+package com.hdkj.lt.bf.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 java.util.Date;
+import lombok.Data;
+
+/**
+ * 
+ * @TableName fhzg_recon_simulation_task
+ */
+@TableName(value ="fhzg_recon_simulation_task")
+@Data
+public class FhzgReconSimulationTask {
+    /**
+     * 主键
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 任务id
+     */
+    @TableField(value = "task_id")
+    private String taskId;
+
+    /**
+     * 任务id
+     */
+    @TableField(value = "event_id")
+    private String eventId;
+
+    /**
+     * 0-未请求 1-已请求
+     */
+    @TableField(value = "status")
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    @TableField(value = "create_time")
+    private Date createTime;
+}

+ 17 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/bf/mapper/FhzgReconSimulationTaskMapper.java

@@ -0,0 +1,17 @@
+package com.hdkj.lt.bf.mapper;
+
+import com.hdkj.lt.bf.entity.FhzgReconSimulationTask;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author Sunlit
+* @description 针对表【fhzg_recon_simulation_task】的数据库操作Mapper
+* @date 2026-08-02 10:02:31
+*/
+public interface FhzgReconSimulationTaskMapper extends BaseMapper<FhzgReconSimulationTask> {
+
+}
+
+
+
+

+ 13 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/bf/service/FhzgReconSimulationTaskService.java

@@ -0,0 +1,13 @@
+package com.hdkj.lt.bf.service;
+
+import com.hdkj.lt.bf.entity.FhzgReconSimulationTask;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author Sunlit
+* @description 针对表【fhzg_recon_simulation_task】的数据库操作Service
+* @date 2026-08-02 10:02:31
+*/
+public interface FhzgReconSimulationTaskService extends IService<FhzgReconSimulationTask> {
+
+}

+ 22 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/bf/service/impl/FhzgReconSimulationTaskServiceImpl.java

@@ -0,0 +1,22 @@
+package com.hdkj.lt.bf.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hdkj.lt.bf.entity.FhzgReconSimulationTask;
+import com.hdkj.lt.bf.service.FhzgReconSimulationTaskService;
+import com.hdkj.lt.bf.mapper.FhzgReconSimulationTaskMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author Sunlit
+* @description 针对表【fhzg_recon_simulation_task】的数据库操作Service实现
+* @date 2026-08-02 10:02:31
+*/
+@Service
+public class FhzgReconSimulationTaskServiceImpl extends ServiceImpl<FhzgReconSimulationTaskMapper, FhzgReconSimulationTask>
+    implements FhzgReconSimulationTaskService{
+
+}
+
+
+
+

+ 1 - 1
services/load-transfer-si/src/main/java/com/hdkj/lt/si/controller/simulation/SimulationController.java

@@ -49,7 +49,7 @@ public class SimulationController implements ISimulationPlatformApiClient {
      */
     @Override
     @PostMapping("/operationMode/startOperationCalTask")
-    public ApiResponse<String> startOperationCalTask(@RequestBody OperationModeStartDTO dto) {
+    public ApiResponse<String> startOperationCalTask(@RequestBody OperationModeDTO dto) {
         return simulationService.startOperationCalTask(dto);
     }
 

+ 12 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/recon/ReconResultService.java

@@ -25,4 +25,16 @@ public interface ReconResultService {
      * @return 入库结果概要
      */
     ReconSaveResultVO parseAndSaveReconResult(String rawResultJson, String eventId);
+
+    /**
+     * 解析 v2.4 格式的 DNR 结果 JSON 并入库.
+     * <p>
+     * 独立反序列化 dnr_result_v2.4.json 格式({ summary, data: [...] }),
+     * 转换为内部 RawResultDTO 格式后复用 {@link #parseAndSaveReconResult} 的入库逻辑。
+     *
+     * @param jsonStr v2.4 格式的完整 JSON 字符串
+     * @param eventId 事件ID
+     * @return 入库结果概要
+     */
+    ReconSaveResultVO parseAndSaveDnrResultV24(String jsonStr, String eventId);
 }

+ 136 - 36
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/recon/impl/ReconResultServiceImpl.java

@@ -142,42 +142,11 @@ public class ReconResultServiceImpl implements ReconResultService {
             Long resultId = main.getId();
             counts.merge("result", 1, Integer::sum);
 
-            // 2. 开关操作(简化版)
-            if (scheme.getSwitchOp() != null) {
-                counts.merge("switch_op", insertSwitchOp(scheme.getSwitchOp(), resultId), Integer::sum);
-            }
-
-            // 3. 开关操作序列(详细)
-            if (scheme.getSwitchSeq() != null) {
-                counts.merge("switch_seq", insertSwitchSeq(scheme.getSwitchSeq(), resultId), Integer::sum);
-            }
-
-            // 4. 馈线结果
-            if (scheme.getFeederResult() != null) {
-                counts.merge("feeder_result", insertFeederResult(scheme.getFeederResult(), resultId), Integer::sum);
-            }
-
-            // 5. 电压结果(汇总+详情)
-            if (scheme.getVolResult() != null) {
-                if (scheme.getVolResult().getSummary() != null) {
-                    volResultMapper.insert(buildVolResult(scheme.getVolResult().getSummary(), resultId));
-                    counts.merge("vol_result", 1, Integer::sum);
-                }
-                if (scheme.getVolResult().getDetails() != null) {
-                    counts.merge("vol_detail", insertVolDetail(scheme.getVolResult().getDetails(), resultId), Integer::sum);
-                }
-            }
-
-            // 6. 开关状态详情(summary 折叠进主表)
-            if (scheme.getSwitchResult() != null && scheme.getSwitchResult().getDetails() != null) {
-                counts.merge("switch_result_detail", insertSwitchResultDetail(scheme.getSwitchResult().getDetails(), resultId), Integer::sum);
-            }
-
-            // 7. 运行指标
-            if (scheme.getMetrics() != null) {
-                metricsMapper.insert(buildMetrics(scheme.getMetrics(), resultId));
-                counts.merge("metrics", 1, Integer::sum);
-            }
+            // 2-7. 子表(复用公共方法)
+            insertSubTables(scheme.getSwitchOp(), scheme.getSwitchSeq(),
+                    scheme.getFeederResult(), scheme.getVolResult(),
+                    scheme.getSwitchResult(), scheme.getMetrics(),
+                    resultId, counts);
         }
 
         log.info("重构方案counts:{}", JSON.toJSONString(counts));
@@ -249,6 +218,137 @@ public class ReconResultServiceImpl implements ReconResultService {
         return dto.getReconfigurationSchemes().getList();
     }
 
+    // ==================== v2.4 格式解析 ====================
+
+    @Override
+    public ReconSaveResultVO parseAndSaveDnrResultV24(String jsonStr, String eventId) {
+        log.info("解析 v2.4 DNR 结果, eventId: {}", eventId);
+
+        // 1. 反序列化新结构
+        DnrResultV24DTO root;
+        try {
+            root = OM.readValue(jsonStr, DnrResultV24DTO.class);
+        } catch (IOException e) {
+            throw new RuntimeException("反序列化 v2.4 DNR 结果 JSON 失败", e);
+        }
+
+        if (root.getData() == null || root.getData().isEmpty()) {
+            log.warn("v2.4 结果无 data 数据, eventId: {}", eventId);
+            ReconSaveResultVO vo = new ReconSaveResultVO();
+            vo.setSuccess(true);
+            vo.setEventId(eventId);
+            return vo;
+        }
+
+        // 2. 遍历每个 group → soln,独立处理主表,复用分表方法
+        Map<String, Integer> counts = new LinkedHashMap<>();
+        for (DnrResultV24GroupDTO group : root.getData()) {
+            if (group.getSolnList() == null || group.getSolnList().isEmpty()) {
+                continue;
+            }
+            for (DnrResultV24SolnDTO soln : group.getSolnList()) {
+                // 主表
+                FhzgReconResult main = buildMainV24(group, soln, eventId, jsonStr);
+                resultMapper.insert(main);
+                Long resultId = main.getId();
+                counts.merge("result", 1, Integer::sum);
+
+                // 以下子表直接复用公共方法(soln 的子 DTO 类型与原有一致)
+                insertSubTables(soln.getSwitchOp(), soln.getSwitchSeq(),
+                        soln.getFeederResult(), soln.getVolResult(),
+                        soln.getSwitchResult(), soln.getMetrics(),
+                        resultId, counts);
+            }
+        }
+
+        log.info("v2.4 DNR 结果入库完成, eventId: {}, counts: {}", eventId, JSON.toJSONString(counts));
+        ReconSaveResultVO result = new ReconSaveResultVO();
+        result.setSuccess(true);
+        result.setEventId(eventId);
+        result.setCounts(counts);
+        return result;
+    }
+
+    /**
+     * 构建 v2.4 格式的主表记录.
+     * <p>
+     * 字段映射: group_id, group_sid 等来自 group 层;
+     * computeResult, detalDesc, soln_id, soln_name 等来自 soln 层.
+     */
+    private FhzgReconResult buildMainV24(DnrResultV24GroupDTO group, DnrResultV24SolnDTO soln,
+                                         String eventId, String rawResultJson) {
+        FhzgReconResult m = new FhzgReconResult();
+        m.setId(IdWorker.getId());
+        m.setEventId(eventId);
+        m.setRawResult(rawResultJson);
+        m.setGroupId(String.valueOf(group.getGroupId()));
+        m.setGroupSid(group.getGroupSid());
+        m.setGroupName(group.getGroupName());
+        m.setStAreaId(group.getStAreaId());
+        m.setStatus(group.getStatus());
+        m.setAlgo(group.getAlgo());
+        m.setComputeResult(soln.getComputeResult());
+        m.setDetalDesc(soln.getDetalDesc());
+        m.setRank(soln.getRank());
+        m.setSchemeId(soln.getSolnId());
+        m.setSchemeName(soln.getSolnName());
+        m.setObjective(toJson(soln.getObjective()));
+        // finalCheck
+        if (soln.getFinalCheck() != null) {
+            m.setFinalCheckIsSafe(soln.getFinalCheck().getSafe());
+            m.setFinalCheckDetails(soln.getFinalCheck().getDetails());
+        }
+        // switchResult.summary
+        if (soln.getSwitchResult() != null) {
+            m.setSwitchResultSummary(soln.getSwitchResult().getSummary());
+        }
+        m.setSnapshotTime(LocalDateTime.now());
+        return m;
+    }
+
+    // ==================== 子表公共处理 ====================
+
+    /**
+     * 插入所有子表记录(switchOp, switchSeq, feederResult, volResult, switchResultDetail, metrics).
+     * 在 {@link #parseAndSaveReconResult} 和 {@link #parseAndSaveDnrResultV24} 中复用.
+     */
+    private void insertSubTables(SwitchOpDTO switchOp, SwitchSeqDTO switchSeq,
+                                  FeederResultDTO feederResult, VolResultDTO volResult,
+                                  SwitchResultDTO switchResult, MetricsDTO metrics,
+                                  Long resultId, Map<String, Integer> counts) {
+        // 开关操作(简化版)
+        if (switchOp != null) {
+            counts.merge("switch_op", insertSwitchOp(switchOp, resultId), Integer::sum);
+        }
+        // 开关操作序列(详细)
+        if (switchSeq != null) {
+            counts.merge("switch_seq", insertSwitchSeq(switchSeq, resultId), Integer::sum);
+        }
+        // 馈线结果
+        if (feederResult != null) {
+            counts.merge("feeder_result", insertFeederResult(feederResult, resultId), Integer::sum);
+        }
+        // 电压结果(汇总+详情)
+        if (volResult != null) {
+            if (volResult.getSummary() != null) {
+                volResultMapper.insert(buildVolResult(volResult.getSummary(), resultId));
+                counts.merge("vol_result", 1, Integer::sum);
+            }
+            if (volResult.getDetails() != null) {
+                counts.merge("vol_detail", insertVolDetail(volResult.getDetails(), resultId), Integer::sum);
+            }
+        }
+        // 开关状态详情
+        if (switchResult != null && switchResult.getDetails() != null) {
+            counts.merge("switch_result_detail", insertSwitchResultDetail(switchResult.getDetails(), resultId), Integer::sum);
+        }
+        // 运行指标
+        if (metrics != null) {
+            metricsMapper.insert(buildMetrics(metrics, resultId));
+            counts.merge("metrics", 1, Integer::sum);
+        }
+    }
+
     private FhzgReconResult buildMain(RawResultDTO dto, ReconfigurationSchemeDTO scheme,int i) {
         FhzgReconResult m = new FhzgReconResult();
         // 共享标量(每个方案主记录重复)

+ 1 - 1
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/simulation/ISimulationService.java

@@ -27,7 +27,7 @@ public interface ISimulationService {
      * @param dto 请求参数
      * @return 任务ID
      */
-    ApiResponse<String> startOperationCalTask(OperationModeStartDTO dto);
+    ApiResponse<String> startOperationCalTask(OperationModeDTO dto);
 
     /**
      * 查询调优结果.

+ 87 - 51
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/simulation/impl/SimulationServiceImpl.java

@@ -7,10 +7,13 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.hdkj.hussar.ApiResponse;
 import com.hdkj.lt.base.constants.ErrorLogConstant;
 import com.hdkj.lt.base.enums.EventTypeEnum;
 import com.hdkj.lt.base.enums.OperationStepEnum;
 import com.hdkj.lt.base.exception.ExceptionCast;
+import com.hdkj.lt.bf.entity.FhzgReconSimulationTask;
+import com.hdkj.lt.bf.service.FhzgReconSimulationTaskService;
 import com.hdkj.lt.core.bizms.modle.po.fault.FaultAwaitTransferAreaResult;
 import com.hdkj.lt.core.bizms.modle.po.fault.FaultPowerCut;
 import com.hdkj.lt.core.bizms.modle.po.operationAbnormality.FhzgOperationAbnormalityTransferAreaResult;
@@ -20,14 +23,11 @@ import com.hdkj.lt.core.bizms.modle.po.plan.PlanAwaitTransferAreaResultPO;
 import com.hdkj.lt.core.log.exception.ExceptionErrorLogCast;
 import com.hdkj.lt.core.log.model.param.ErrorLogParam;
 import com.hdkj.lt.core.rest.config.HttpClientConfig;
-import com.hdkj.lt.modle.dto.recon.RawResultDTO;
 import com.hdkj.lt.modle.dto.simulation.*;
-import com.hdkj.lt.modle.po.FhzgReconResult;
 import com.hdkj.lt.si.dao.*;
 import com.hdkj.lt.si.service.recon.ReconResultService;
 import com.hdkj.lt.si.service.simulation.ISimulationService;
 import com.hdkj.lt.si.service.simulation.TyptResponseEntity;
-import com.hdkj.hussar.ApiResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -43,7 +43,7 @@ import org.springframework.web.client.RestTemplate;
 import javax.annotation.Resource;
 import java.io.IOException;
 import java.time.LocalDateTime;
-import java.util.UUID;
+import java.util.Date;
 
 /**
  * @author rj
@@ -61,8 +61,8 @@ public class SimulationServiceImpl implements ISimulationService {
     private final PlanAwaitTransferAreaResultMapper planAwaitTransferAreaResultMapper;
     private final FaultAwaitTransferAreaResultMapper faultAwaitTransferAreaResultMapper;
     private final FhzgOperationAbnormalityTransferAreaResultMapper operationAbnormalityTransferAreaResultMapper;
-    private final FhzgReconResultMapper fhzgReconResultMapper;
     private final ReconResultService reconResultService;
+    private final FhzgReconSimulationTaskService reconSimulationTaskService;
     private final String BASE_URL = "http://25.91.83.252:28081";
 
     private static final ObjectMapper OM = new ObjectMapper();
@@ -70,12 +70,6 @@ public class SimulationServiceImpl implements ISimulationService {
     @Value("${simulation.xToken}")
     private String xToken;
 
-    @Value("${remote.recon.request-uri}")
-    private String reconRequestUri;
-
-    @Value("${remote.recon.recon-uri}")
-    private String reconUri;
-
     @Autowired
     @Qualifier("simpleRestTemplate")
     private RestTemplate simpleRestTemplate;
@@ -206,7 +200,7 @@ public class SimulationServiceImpl implements ISimulationService {
         httpHeaders.setContentType(MediaType.APPLICATION_JSON);
         httpHeaders.set("x-token", xToken);
         HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
-        TyptResponseEntity rs = simpleRestTemplate.exchange(url, HttpMethod.GET,httpEntity,TyptResponseEntity.class,operationSchemeDTO.getId()).getBody();
+        TyptResponseEntity rs = simpleRestTemplate.exchange(url, HttpMethod.GET, httpEntity, TyptResponseEntity.class, operationSchemeDTO.getId()).getBody();
         log.info("调优-推演平台结果:{}", JSONObject.toJSONString(rs.getSuccess()));
         if (rs.getSuccess()) {
             operationAbnormalityTransferAreaResultMapper.delete(new LambdaUpdateWrapper<FhzgOperationAbnormalityTransferAreaResult>().eq(FhzgOperationAbnormalityTransferAreaResult::getOaId, operationSchemeDTO.getId()));
@@ -272,69 +266,111 @@ public class SimulationServiceImpl implements ISimulationService {
     }
 
     @Override
-    public ApiResponse<String> startOperationCalTask(OperationModeStartDTO dto) {
-        // 1. 生成任务ID
-        String taskId = UUID.randomUUID().toString();
-        log.info("启动重构计算, taskId: {}, request: {}", taskId, JSON.toJSONString(dto));
+    public ApiResponse<String> startOperationCalTask(OperationModeDTO dto) {
+        OperationModeStartDTO operationModeStartDTO = dto.getOperationModeStartDTO();
+        log.info("启动重构计算, request: {}", JSON.toJSONString(operationModeStartDTO));
 
-        // 2. 调用远程重构接口
-        String requestUrl = reconRequestUri.concat(reconUri);
+        // 1. 调用远程接口启动重构计算任务
+        String requestUrl = BASE_URL + "/api/eac-operation/operationMode/startOperationCalTask";
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_JSON);
-        HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(dto), headers);
+        headers.set("x-token", xToken);
+        HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(operationModeStartDTO), headers);
         String responseStr;
         try {
             responseStr = connPoolRestTemplate.postForObject(requestUrl, httpEntity, String.class);
-            log.info("重构计算接口返回, taskId: {}, response: {}", taskId, responseStr);
+            log.info("重构计算启动接口返回, response: {}", responseStr);
         } catch (Exception e) {
-            log.error("调用重构算法接口失败, taskId: {}", taskId, e);
-            return ApiResponse.fail("调用重构算法接口失败: " + e.getMessage());
+            log.error("调用重构计算启动接口失败", e);
+            return ApiResponse.fail("调用重构计算启动接口失败: " + e.getMessage());
         }
 
-        // 3. 提取 raw_result 节点并入库
+        // 2. 解析响应,提取任务ID
         try {
             JsonNode root = OM.readTree(responseStr);
-            JsonNode rawNode = root.get("raw_result");
-            if (rawNode == null || rawNode.isNull()) {
-                log.error("算法响应缺少 raw_result 节点, taskId: {}", taskId);
-                return ApiResponse.fail("算法响应缺少 raw_result 节点");
+            int code = root.get("code").asInt();
+            boolean success = root.get("success").asBoolean();
+            if (code != 0 || !success) {
+                String msg = root.has("msg") ? root.get("msg").asText() : "";
+                log.error("重构计算启动失败, code: {}, msg: {}", code, msg);
+                return ApiResponse.fail("重构计算启动失败: " + msg);
+            }
+            JsonNode dataNode = root.get("data");
+            if (dataNode == null || dataNode.isNull()) {
+                return ApiResponse.fail("重构计算启动响应缺少任务ID");
             }
-            String rawResultJson = OM.writeValueAsString(rawNode);
-            reconResultService.parseAndSaveReconResult(rawResultJson, taskId);
+            String taskId = dataNode.asText();
+
+            // 3. 保存任务ID和状态到任务追踪表
+            FhzgReconSimulationTask task = new FhzgReconSimulationTask();
+            task.setTaskId(taskId);
+            task.setEventId(dto.getEventId());
+            task.setStatus(0);
+            task.setCreateTime(new Date());
+            reconSimulationTaskService.save(task);
+
+            log.info("重构计算任务已启动, taskId: {}", taskId);
+            return ApiResponse.success(taskId);
         } catch (IOException e) {
-            log.error("解析算法响应失败, taskId: {}", taskId, e);
-            return ApiResponse.fail("解析算法响应失败: " + e.getMessage());
+            log.error("解析重构计算启动响应失败", e);
+            return ApiResponse.fail("解析重构计算启动响应失败: " + e.getMessage());
         }
-
-        return ApiResponse.success(taskId);
     }
 
     @Override
     public ApiResponse<QueryOperationModeDTO> queryOperationResult(String taskId) {
         log.info("查询重构结果, taskId: {}", taskId);
 
-        // 查询主表
-        FhzgReconResult reconResult = fhzgReconResultMapper.selectOne(
-                new LambdaQueryWrapper<FhzgReconResult>().eq(FhzgReconResult::getEventId, taskId));
-        if (reconResult == null) {
-            return ApiResponse.fail("任务不存在或未完成: " + taskId);
+        // 1. 调用远程接口查询重构结果
+        String requestUrl = BASE_URL + "/api/eac-operation/operationMode/queryOperationResult?id={taskId}";
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("x-token", xToken);
+        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
+        String responseStr;
+        try {
+            responseStr = connPoolRestTemplate.exchange(requestUrl, HttpMethod.GET, httpEntity, String.class, taskId).getBody();
+            log.info("重构结果查询接口返回, taskId: {}", taskId);
+        } catch (Exception e) {
+            log.error("调用重构结果查询接口失败, taskId: {}", taskId, e);
+            return ApiResponse.fail("调用重构结果查询接口失败: " + e.getMessage());
         }
 
-        // 反序列化 rawResult JSON -> RawResultDTO
-        RawResultDTO rawResultDTO = null;
-        String rawResultJson = reconResult.getRawResult();
-        if (rawResultJson != null && !rawResultJson.isEmpty()) {
-            try {
-                rawResultDTO = OM.readValue(rawResultJson, RawResultDTO.class);
-            } catch (IOException e) {
-                log.error("反序列化 rawResult 失败, taskId: {}", taskId, e);
+        FhzgReconSimulationTask one = reconSimulationTaskService.getOne(new LambdaQueryWrapper<FhzgReconSimulationTask>().eq(FhzgReconSimulationTask::getTaskId, taskId));
+
+
+        // 2. 解析响应
+        try {
+            JsonNode root = OM.readTree(responseStr);
+            int code = root.get("code").asInt();
+            boolean success = root.get("success").asBoolean();
+            if (code != 0 || !success) {
+                String msg = root.has("msg") ? root.get("msg").asText() : "";
+                log.error("重构结果查询失败, taskId: {}, code: {}, msg: {}", taskId, code, msg);
+                return ApiResponse.fail("重构结果查询失败: " + msg);
             }
-        }
+            JsonNode dataNode = root.get("data");
+            if (dataNode == null || dataNode.isNull()) {
+                return ApiResponse.fail("重构结果查询响应数据为空");
+            }
+            QueryOperationModeDTO resultDTO = OM.treeToValue(dataNode, QueryOperationModeDTO.class);
 
-        QueryOperationModeDTO resultDTO = new QueryOperationModeDTO();
-        resultDTO.setId(taskId);
-        resultDTO.setResult(rawResultDTO);
-        return ApiResponse.success(resultDTO);
+            // 3. 保存结果到数据库
+            if (resultDTO.getResult() != null) {
+                // 将 result 序列化为 rawResult JSON 并入库
+                String rawResultJson = OM.writeValueAsString(resultDTO.getResult());
+                reconResultService.parseAndSaveDnrResultV24(rawResultJson, one.getEventId());
+            }
+
+            if (one != null) {
+                one.setStatus(1);
+                reconSimulationTaskService.saveOrUpdate(one);
+            }
+
+            return ApiResponse.success(resultDTO);
+        } catch (IOException e) {
+            log.error("解析重构结果查询响应失败, taskId: {}", taskId, e);
+            return ApiResponse.fail("解析重构结果查询响应失败: " + e.getMessage());
+        }
     }
 
 }

+ 18 - 0
services/load-transfer-si/src/main/resources/mapper/FhzgReconSimulationTaskMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.hdkj.lt.bf.mapper.FhzgReconSimulationTaskMapper">
+
+    <resultMap id="BaseResultMap" type="com.hdkj.lt.bf.entity.FhzgReconSimulationTask">
+            <id property="id" column="id" jdbcType="BIGINT"/>
+            <result property="taskId" column="task_id" jdbcType="VARCHAR"/>
+            <result property="status" column="status" jdbcType="INTEGER"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,task_id,status,
+        create_time
+    </sql>
+</mapper>