Ver Fonte

静态指标初版

lisonglin há 3 semanas atrás
pai
commit
65eec21e09
49 ficheiros alterados com 2810 adições e 31 exclusões
  1. 1 1
      api/load-transfer-mq-api/src/main/java/com/hdkj/lt/modle/dto/indicator/IndicatorCalcMessage.java
  2. 1 1
      api/load-transfer-mq-api/src/main/java/com/hdkj/lt/modle/dto/indicator/IndicatorCompletedEvent.java
  3. 47 0
      api/load-transfer-mq-api/src/main/java/com/hdkj/lt/modle/dto/recon/ReconCalcMessage.java
  4. 13 2
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/IAlgorithmApiClient.java
  5. 31 0
      api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/IReconApiClient.java
  6. 3 0
      common/common-core/src/main/java/com/hdkj/lt/base/constants/RedisKeyConstants.java
  7. 50 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/controller/optimization/StaticGridController.java
  8. 374 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent.java
  9. 447 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/SjztPwwyyqxtPrmPdrOutageMvDs.java
  10. 84 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/staticgrid/StaticIndicatorMetric.java
  11. 77 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/staticgrid/StaticIndicatorResult.java
  12. 70 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/staticgrid/StaticProblemDetail.java
  13. 191 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/vo/StaticGridDashboardVO.java
  14. 20 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper.java
  15. 20 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/SjztPwwyyqxtPrmPdrOutageMvDsMapper.java
  16. 12 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/staticgrid/StaticIndicatorMetricMapper.java
  17. 12 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/staticgrid/StaticIndicatorResultMapper.java
  18. 12 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/staticgrid/StaticProblemDetailMapper.java
  19. 13 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventService.java
  20. 13 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/SjztPwwyyqxtPrmPdrOutageMvDsService.java
  21. 22 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventServiceImpl.java
  22. 22 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SjztPwwyyqxtPrmPdrOutageMvDsServiceImpl.java
  23. 29 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/staticgrid/StaticGridDashboardService.java
  24. 175 0
      services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/staticgrid/impl/StaticGridDashboardServiceImpl.java
  25. 91 0
      services/load-transfer-bf/src/main/resources/mapper/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper.xml
  26. 107 0
      services/load-transfer-bf/src/main/resources/mapper/SjztPwwyyqxtPrmPdrOutageMvDsMapper.xml
  27. 2 2
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/entity/indicator/AlarmEvent.java
  28. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/entity/indicator/IndicatorResult.java
  29. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/listener/IndicatorCalcConsumer.java
  30. 61 17
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/listener/IndicatorEventConsumer.java
  31. 125 0
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/listener/ReconCalcConsumer.java
  32. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/mapper/indicator/AlarmEventMapper.java
  33. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/mapper/indicator/IndicatorResultMapper.java
  34. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/AlarmEvaluateService.java
  35. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/IndicatorResultService.java
  36. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/impl/AlarmEvaluateServiceImpl.java
  37. 1 1
      services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/impl/IndicatorResultServiceImpl.java
  38. 17 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/controller/algorithm/AlgorithmController.java
  39. 12 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/dao/StaticIndicatorMetricMapper.java
  40. 12 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/dao/StaticIndicatorResultMapper.java
  41. 12 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/dao/StaticProblemDetailMapper.java
  42. 118 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/entity/staticgrid/StaticIndicatorMetric.java
  43. 104 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/entity/staticgrid/StaticIndicatorResult.java
  44. 97 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/entity/staticgrid/StaticProblemDetail.java
  45. 9 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/algorithm/AlgorithmService.java
  46. 8 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/algorithm/impl/AlgorithmServiceImpl.java
  47. 41 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/remote/impl/AlgorithmRemoteCallServiceImpl.java
  48. 22 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/staticgrid/StaticIndicatorResultService.java
  49. 225 0
      services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/staticgrid/impl/StaticIndicatorResultServiceImpl.java

+ 1 - 1
api/load-transfer-mq-api/src/main/java/com/hdkj/lt/modle/dto/indicator/IndicatorCalcMessage.java

@@ -11,7 +11,7 @@ import java.util.Map;
 /**
  * 指标计算任务消息体(indicator-calc-topic)
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Data

+ 1 - 1
api/load-transfer-mq-api/src/main/java/com/hdkj/lt/modle/dto/indicator/IndicatorCompletedEvent.java

@@ -13,7 +13,7 @@ import java.util.List;
  * <p>
  * 事件带决策数据(告警标志+超限馈线),不带展示数据(负载率数值等在库里)
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Data

+ 47 - 0
api/load-transfer-mq-api/src/main/java/com/hdkj/lt/modle/dto/recon/ReconCalcMessage.java

@@ -0,0 +1,47 @@
+package com.hdkj.lt.modle.dto.recon;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 重构计算任务消息体(reconfiguration-calc-topic)
+ * <p>
+ * 由告警事件首次写入后发送,消费端通过 Feign 调 si 的 /recon/trigger 触发重构算法。
+ * eventId = t_alarm_event.id(主键,Long),si 侧写入 fhzg_recon_result.event_id(String)。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ReconCalcMessage implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 告警事件ID(t_alarm_event 主键)
+     */
+    private Long eventId;
+
+    /**
+     * 区县短标识
+     */
+    private String countySid;
+
+    /**
+     * 区县名称
+     */
+    private String countyName;
+
+    /**
+     * 异常馈线ID列表(按馈线粒度发送,单元素列表)
+     */
+    private List<String> problemFeederIds;
+}

+ 13 - 2
api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/IAlgorithmApiClient.java

@@ -3,6 +3,9 @@ package com.hdkj.lt.feign;
 import com.hdkj.lt.base.constants.SystemGlobalConstant;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.Map;
 
 /**
  * 算法服务 Feign 客户端
@@ -11,8 +14,7 @@ import org.springframework.web.bind.annotation.PostMapping;
  * <p>
  * 返回 ApiResponse 完整 JSON 字符串,消费方用 fastjson 解析取 data 字段
  *
- * @author hermes
- * @since 2026-07-17
+ lsl * @since 2026-07-17
  */
 @FeignClient(path = "/algorithm", value = SystemGlobalConstant.SERVICE_NAME_LOAD_TRANSFER_SI,
         contextId = "IAlgorithmApiClient")
@@ -25,4 +27,13 @@ public interface IAlgorithmApiClient {
      */
     @PostMapping("/indicators")
     String queryIndicators();
+
+    /**
+     * 查询静态网架评估结果并入库
+     *
+     * @param params 含 batchId、countyId
+     * @return ApiResponse 完整 JSON 字符串,data 为主表ID
+     */
+    @PostMapping("/static-grid")
+    String queryStaticGridIndicators(@RequestBody Map<String, Object> params);
 }

+ 31 - 0
api/load-transfer-si-api/src/main/java/com/hdkj/lt/feign/IReconApiClient.java

@@ -0,0 +1,31 @@
+package com.hdkj.lt.feign;
+
+import com.hdkj.lt.base.constants.SystemGlobalConstant;
+import com.hdkj.lt.modle.vo.recon.ReconstructionParam;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * 重构方案服务 Feign 客户端
+ * <p>
+ * 供 mq 模块通过 Feign 调用 si 模块的 /recon/trigger 接口触发重构算法。
+ * <p>
+ * 返回 ApiResponse 完整 JSON 字符串,消费方用 fastjson 解析取 data 字段(ReconSaveResultVO)。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@FeignClient(path = "/recon", value = SystemGlobalConstant.SERVICE_NAME_LOAD_TRANSFER_SI,
+        contextId = "IReconApiClient")
+public interface IReconApiClient {
+
+    /**
+     * 触发重构方案计算
+     *
+     * @param param 重构参数(eventId + params{county_sid, county_name, problem_feeder_ids})
+     * @return ApiResponse 完整 JSON 字符串
+     */
+    @PostMapping("/trigger")
+    String triggerReconfiguration(@RequestBody ReconstructionParam param);
+}

+ 3 - 0
common/common-core/src/main/java/com/hdkj/lt/base/constants/RedisKeyConstants.java

@@ -41,6 +41,9 @@ public class RedisKeyConstants {
     // 指标完成事件异步队列
     public static final String ASYNC_QUEUE_INDICATOR_EVENT = "indicatorEventTicket";
 
+    // 重构计算任务异步队列
+    public static final String ASYNC_QUEUE_RECONFIGURATION_CALC = "reconfigurationCalcTicket";
+
     // 异步处理队列 end
 
     // 组织机构

+ 50 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/controller/optimization/StaticGridController.java

@@ -0,0 +1,50 @@
+package com.hdkj.lt.bf.controller.optimization;
+
+import com.hdkj.hussar.ApiResponse;
+import com.hdkj.lt.bf.entity.vo.StaticGridDashboardVO;
+import com.hdkj.lt.bf.service.staticgrid.StaticGridDashboardService;
+import com.hdkj.lt.core.mvc.BaseController;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+/**
+ * 静态网架评估仪表盘 Controller
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@Slf4j
+@RestController
+@AllArgsConstructor
+@RequestMapping("/static-grid")
+public class StaticGridController extends BaseController {
+
+    private final StaticGridDashboardService staticGridDashboardService;
+
+    /**
+     * 查询静态网架评估仪表盘
+     * <p>
+     * 入参可选:
+     * <ul>
+     *   <li>batchId — 查指定批次,为空则查最新一次</li>
+     * </ul>
+     *
+     * @param params 请求参数
+     * @return 仪表盘 VO
+     */
+    @PostMapping("/dashboard")
+    public ApiResponse<StaticGridDashboardVO> dashboard(@RequestBody Map<String, String> params) {
+        String batchId = params.get("batchId");
+        StaticGridDashboardVO vo = StringUtils.isBlank(batchId)
+                ? staticGridDashboardService.queryLatestDashboard()
+                : staticGridDashboardService.queryDashboardByBatchId(batchId);
+        return ApiResponse.success(vo);
+    }
+}

+ 374 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent.java

@@ -0,0 +1,374 @@
+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.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event
+ * @TableName sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event
+ */
+@TableName(value ="sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event")
+@Data
+public class SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent implements Serializable {
+    /**
+     * 唯一标识
+     */
+    @TableField(value = "obj_id")
+    private String objId;
+
+    /**
+     * 省公司id
+     */
+    @TableField(value = "province_id")
+    private String provinceId;
+
+    /**
+     * 省公司名称
+     */
+    @TableField(value = "province_name")
+    private String provinceName;
+
+    /**
+     * 所属地市id
+     */
+    @TableField(value = "city_org_id")
+    private String cityOrgId;
+
+    /**
+     * 所属地市
+     */
+    @TableField(value = "city_org_name")
+    private String cityOrgName;
+
+    /**
+     * 运维单位id
+     */
+    @TableField(value = "maintainer_id")
+    private String maintainerId;
+
+    /**
+     * 运维单位
+     */
+    @TableField(value = "maintainer_name")
+    private String maintainerName;
+
+    /**
+     * 维护班组id
+     */
+    @TableField(value = "maintcrew_id")
+    private String maintcrewId;
+
+    /**
+     * 维护班组名称
+     */
+    @TableField(value = "maintcrew_name")
+    private String maintcrewName;
+
+    /**
+     * 变电站id
+     */
+    @TableField(value = "substation_id")
+    private String substationId;
+
+    /**
+     * 变电站名称
+     */
+    @TableField(value = "substation_name")
+    private String substationName;
+
+    /**
+     * 母线id
+     */
+    @TableField(value = "generatrix_id")
+    private String generatrixId;
+
+    /**
+     * 母线名称
+     */
+    @TableField(value = "generatrix_name")
+    private String generatrixName;
+
+    /**
+     * 馈线ID
+     */
+    @TableField(value = "feeder_id")
+    private String feederId;
+
+    /**
+     * 馈线名称
+     */
+    @TableField(value = "feeder_name")
+    private String feederName;
+
+    /**
+     * 所属馈线10kV发电用户数
+     */
+    @TableField(value = "feeder_10kv_generation_user_count")
+    private String feeder10kvGenerationUserCount;
+
+    /**
+     * 台区编码
+     */
+    @TableField(value = "tg_no")
+    private String tgNo;
+
+    /**
+     * 配变id
+     */
+    @TableField(value = "transformer_id")
+    private String transformerId;
+
+    /**
+     * 配变名称
+     */
+    @TableField(value = "transformer_name")
+    private String transformerName;
+
+    /**
+     * 是否光伏台区
+     */
+    @TableField(value = "is_pv_tg")
+    private String isPvTg;
+
+    /**
+     * 发电类型
+     */
+    @TableField(value = "generation_type")
+    private String generationType;
+
+    /**
+     * 表箱编号
+     */
+    @TableField(value = "meas_no")
+    private String measNo;
+
+    /**
+     * 表箱资源id
+     */
+    @TableField(value = "meas_psr_id")
+    private String measPsrId;
+
+    /**
+     * 用户编号
+     */
+    @TableField(value = "cust_no")
+    private String custNo;
+
+    /**
+     * 用户名称
+     */
+    @TableField(value = "cust_name")
+    private String custName;
+
+    /**
+     * 是否发电用户
+     */
+    @TableField(value = "is_pv_cust")
+    private String isPvCust;
+
+    /**
+     * 电压等级编码
+     */
+    @TableField(value = "voltage_level_code")
+    private String voltageLevelCode;
+
+    /**
+     * 越限日期
+     */
+    @TableField(value = "over_limit_date")
+    private String overLimitDate;
+
+    /**
+     * 越限类型
+     */
+    @TableField(value = "over_limit_type")
+    private String overLimitType;
+
+    /**
+     * 越限开始时间
+     */
+    @TableField(value = "over_limit_start_time")
+    private String overLimitStartTime;
+
+    /**
+     * 越限结束时间
+     */
+    @TableField(value = "over_limit_end_time")
+    private String overLimitEndTime;
+
+    /**
+     * 越限持续时长
+     */
+    @TableField(value = "over_limit_duration")
+    private String overLimitDuration;
+
+    /**
+     * 是否存在数据质量问题
+     */
+    @TableField(value = "is_data_quality_issue")
+    private String isDataQualityIssue;
+
+    /**
+     * 溯源层级
+     */
+    @TableField(value = "traceability_level")
+    private String traceabilityLevel;
+
+    /**
+     * 越限成因
+     */
+    @TableField(value = "over_limit_cause")
+    private String overLimitCause;
+
+    /**
+     * 治理措施
+     */
+    @TableField(value = "control_measures")
+    private String controlMeasures;
+
+    /**
+     * 创建时间
+     */
+    @TableField(value = "ctime")
+    private Date ctime;
+
+    /**
+     * 修改时间
+     */
+    @TableField(value = "mtime")
+    private Date mtime;
+
+    /**
+     * 删除标识
+     */
+    @TableField(value = "is_deleted")
+    private String isDeleted;
+
+    /**
+     * A相曲线相关性系数
+     */
+    @TableField(value = "corr_coef_phase_a")
+    private String corrCoefPhaseA;
+
+    /**
+     * B相曲线相关性系数
+     */
+    @TableField(value = "corr_coef_phase_b")
+    private String corrCoefPhaseB;
+
+    /**
+     * C相曲线相关性系数
+     */
+    @TableField(value = "corr_coef_phase_c")
+    private String corrCoefPhaseC;
+
+    /**
+     * 表箱关联用户数
+     */
+    @TableField(value = "meter_box_user_count")
+    private String meterBoxUserCount;
+
+    /**
+     * 配变类型
+     */
+    @TableField(value = "trans_type")
+    private String transType;
+
+    /**
+     * 近n日内配变档位不合理天数
+     */
+    @TableField(value = "days_unreasonable_tap_position")
+    private String daysUnreasonableTapPosition;
+
+    /**
+     * 近n日内母线电压目标不合理天数
+     */
+    @TableField(value = "days_unreasonable_bus_voltage_target")
+    private String daysUnreasonableBusVoltageTarget;
+
+    /**
+     * 计量点id
+     */
+    @TableField(value = "mp_id")
+    private String mpId;
+
+    /**
+     * 电能表编号
+     */
+    @TableField(value = "meter_id")
+    private String meterId;
+
+    /**
+     * 低压线路资源id
+     */
+    @TableField(value = "lv_line_psr_id")
+    private String lvLinePsrId;
+
+    /**
+     * 电压指数
+     */
+    @TableField(value = "voltage_index_range")
+    private String voltageIndexRange;
+
+    /**
+     * 电压越上限指数
+     */
+    @TableField(value = "voltage_over_index_mild")
+    private String voltageOverIndexMild;
+
+    /**
+     * 电压越上限指数
+     */
+    @TableField(value = "voltage_over_index_severe")
+    private String voltageOverIndexSevere;
+
+    /**
+     * 电压越下限指数
+     */
+    @TableField(value = "voltage_under_index_mild")
+    private String voltageUnderIndexMild;
+
+    /**
+     * 电压越下限指数
+     */
+    @TableField(value = "voltage_under_index_severe")
+    private String voltageUnderIndexSevere;
+
+    /**
+     * 相关性最大系数
+     */
+    @TableField(value = "max_correlation_coefficient")
+    private String maxCorrelationCoefficient;
+
+    /**
+     * 是否敏感用户
+     */
+    @TableField(value = "is_sensitive_user")
+    private String isSensitiveUser;
+
+    /**
+     * 用电类别
+     */
+    @TableField(value = "user_type")
+    private String userType;
+
+    /**
+     * 当天是否发生低电压
+     */
+    @TableField(value = "is_low_voltage_day")
+    private String isLowVoltageDay;
+
+    /**
+     * 当天是否发生严重低电压
+     */
+    @TableField(value = "is_severe_overvoltage_day")
+    private String isSevereOvervoltageDay;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 447 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/SjztPwwyyqxtPrmPdrOutageMvDs.java

@@ -0,0 +1,447 @@
+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.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * un4113_02_pwwyyqxt_prm_pdr_outage_mv_ds
+ * @TableName sjzt_pwwyyqxt_prm_pdr_outage_mv_ds
+ */
+@TableName(value ="sjzt_pwwyyqxt_prm_pdr_outage_mv_ds")
+@Data
+public class SjztPwwyyqxtPrmPdrOutageMvDs implements Serializable {
+    /**
+     * 主键
+     */
+    @TableField(value = "id")
+    private String id;
+
+    /**
+     * 事件编号
+     */
+    @TableField(value = "event_no")
+    private String eventNo;
+
+    /**
+     * 省公司编码
+     */
+    @TableField(value = "province_organisation_code")
+    private String provinceOrganisationCode;
+
+    /**
+     * 可靠性单位
+     */
+    @TableField(value = "reliability_organisation")
+    private String reliabilityOrganisation;
+
+    /**
+     * 责任部门编码
+     */
+    @TableField(value = "duty_org_id")
+    private String dutyOrgId;
+
+    /**
+     * 停电时间
+     */
+    @TableField(value = "outage_stime")
+    private Date outageStime;
+
+    /**
+     * 复电时间
+     */
+    @TableField(value = "outage_etime")
+    private Date outageEtime;
+
+    /**
+     * 停电时长
+     */
+    @TableField(value = "outage_duration")
+    private BigDecimal outageDuration;
+
+    /**
+     * 停电总时户数
+     */
+    @TableField(value = "outage_hc_num")
+    private BigDecimal outageHcNum;
+
+    /**
+     * 缺供电量
+     */
+    @TableField(value = "anes")
+    private BigDecimal anes;
+
+    /**
+     * 停电线路数
+     */
+    @TableField(value = "outage_feeder_cnt")
+    private BigDecimal outageFeederCnt;
+
+    /**
+     * 停电线段数
+     */
+    @TableField(value = "outage_zonefeeder_cnt")
+    private BigDecimal outageZonefeederCnt;
+
+    /**
+     * 停电中压用户数
+     */
+    @TableField(value = "outage_mvcons_cnt")
+    private BigDecimal outageMvconsCnt;
+
+    /**
+     * 停电低压用户数
+     */
+    @TableField(value = "outage_lvcons_cnt")
+    private BigDecimal outageLvconsCnt;
+
+    /**
+     * 停电低压时户数
+     */
+    @TableField(value = "outage_lv_hcnum")
+    private BigDecimal outageLvHcnum;
+
+    /**
+     * 停电容量
+     */
+    @TableField(value = "outage_cap")
+    private BigDecimal outageCap;
+
+    /**
+     * 单位性质码
+     */
+    @TableField(value = "org_nature_code")
+    private String orgNatureCode;
+
+    /**
+     * 停电性质码
+     */
+    @TableField(value = "outage_nature_code")
+    private String outageNatureCode;
+
+    /**
+     * 责任原因码
+     */
+    @TableField(value = "outage_respon_code")
+    private String outageResponCode;
+
+    /**
+     * 设备原因码
+     */
+    @TableField(value = "outg_equipment_reason_code")
+    private String outgEquipmentReasonCode;
+
+    /**
+     * 技术原因码
+     */
+    @TableField(value = "outage_technical_code")
+    private String outageTechnicalCode;
+
+    /**
+     * 特殊分析码
+     */
+    @TableField(value = "special_analysis_code")
+    private String specialAnalysisCode;
+
+    /**
+     * 供电区域
+     */
+    @TableField(value = "supply_area")
+    private String supplyArea;
+
+    /**
+     * 地区特征码
+     */
+    @TableField(value = "area_code")
+    private String areaCode;
+
+    /**
+     * 停电来源
+     */
+    @TableField(value = "outage_source")
+    private String outageSource;
+
+    /**
+     * 备注
+     */
+    @TableField(value = "remark")
+    private String remark;
+
+    /**
+     * 操作标识
+     */
+    @TableField(value = "operate_flag")
+    private String operateFlag;
+
+    /**
+     * 网省审核时间
+     */
+    @TableField(value = "province_audit_time")
+    private Date provinceAuditTime;
+
+    /**
+     * 国网审核时间
+     */
+    @TableField(value = "headquarters_audit_time")
+    private Date headquartersAuditTime;
+
+    /**
+     * 创建时间
+     */
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField(value = "update_time")
+    private Date updateTime;
+
+    /**
+     * 上报状态
+     */
+    @TableField(value = "report_status")
+    private String reportStatus;
+
+    /**
+     * 上报时间
+     */
+    @TableField(value = "report_time")
+    private Date reportTime;
+
+    /**
+     * 是否同步ES
+     */
+    @TableField(value = "is_sync_es")
+    private String isSyncEs;
+
+    /**
+     * 是否确认
+     */
+    @TableField(value = "is_confirmed")
+    private String isConfirmed;
+
+    /**
+     * 确认时间
+     */
+    @TableField(value = "confirm_time")
+    private Date confirmTime;
+
+    /**
+     * 主停设备类型
+     */
+    @TableField(value = "outage_main_equipment_type")
+    private String outageMainEquipmentType;
+
+    /**
+     * 是否忽略
+     */
+    @TableField(value = "is_ignored")
+    private String isIgnored;
+
+    /**
+     * 停电类型
+     */
+    @TableField(value = "outage_type")
+    private String outageType;
+
+    /**
+     * 修正原因
+     */
+    @TableField(value = "modify_reason")
+    private String modifyReason;
+
+    /**
+     * 是否修正
+     */
+    @TableField(value = "is_updated")
+    private String isUpdated;
+
+    /**
+     * 网省审核状态
+     */
+    @TableField(value = "province_audit_status")
+    private String provinceAuditStatus;
+
+    /**
+     * 首次确认时间
+     */
+    @TableField(value = "first_confirm_time")
+    private Date firstConfirmTime;
+
+    /**
+     * 数据版本
+     */
+    @TableField(value = "data_version")
+    private BigDecimal dataVersion;
+
+    /**
+     * 忽略时间
+     */
+    @TableField(value = "ignore_time")
+    private Date ignoreTime;
+
+    /**
+     * 国网审核状态
+     */
+    @TableField(value = "headquarters_audit_status")
+    private String headquartersAuditStatus;
+
+    /**
+     * 校核状态
+     */
+    @TableField(value = "check_status")
+    private String checkStatus;
+
+    /**
+     * 电压等级代码
+     */
+    @TableField(value = "voltage_level")
+    private String voltageLevel;
+
+    /**
+     * 流程编号
+     */
+    @TableField(value = "proc_inst_id")
+    private String procInstId;
+
+    /**
+     * 流程审核状态
+     */
+    @TableField(value = "audit_status")
+    private String auditStatus;
+
+    /**
+     * 校验时间
+     */
+    @TableField(value = "check_time")
+    private Date checkTime;
+
+    /**
+     * 上链交易值
+     */
+    @TableField(value = "txhash")
+    private String txhash;
+
+    /**
+     * 主停设备名称
+     */
+    @TableField(value = "outage_main_equipment_name")
+    private String outageMainEquipmentName;
+
+    /**
+     * 停电线路名称
+     */
+    @TableField(value = "outage_feeder_name")
+    private String outageFeederName;
+
+    /**
+     * 是否异常
+     */
+    @TableField(value = "is_exception")
+    private String isException;
+
+    /**
+     * 网省审核意见
+     */
+    @TableField(value = "province_audit_remark")
+    private String provinceAuditRemark;
+
+    /**
+     * 国网审核意见
+     */
+    @TableField(value = "headquarters_audit_remark")
+    private String headquartersAuditRemark;
+
+    /**
+     * 数据置信度
+     */
+    @TableField(value = "data_confidence")
+    private String dataConfidence;
+
+    /**
+     * 是否有附件
+     */
+    @TableField(value = "has_attachment")
+    private String hasAttachment;
+
+    /**
+     * 是否重点故障
+     */
+    @TableField(value = "is_major_fault")
+    private String isMajorFault;
+
+    /**
+     * 附件是否合格
+     */
+    @TableField(value = "is_attachment_valid")
+    private String isAttachmentValid;
+
+    /**
+     * 操作人
+     */
+    @TableField(value = "operator")
+    private String operator;
+
+    /**
+     * 操作时间
+     */
+    @TableField(value = "operation_time")
+    private Date operationTime;
+
+    /**
+     * 区县审核人
+     */
+    @TableField(value = "county_auditor")
+    private String countyAuditor;
+
+    /**
+     * 区县审核时间
+     */
+    @TableField(value = "county_audit_time")
+    private Date countyAuditTime;
+
+    /**
+     * 地市审核人
+     */
+    @TableField(value = "city_auditor")
+    private String cityAuditor;
+
+    /**
+     * 地市审核时间
+     */
+    @TableField(value = "city_auditor_time")
+    private Date cityAuditorTime;
+
+    /**
+     * 网省审核人
+     */
+    @TableField(value = "province_auditor")
+    private String provinceAuditor;
+
+    /**
+     * 国网审核人
+     */
+    @TableField(value = "headquarters_auditor")
+    private String headquartersAuditor;
+
+    /**
+     * 修改变更时户数
+     */
+    @TableField(value = "change_hc_num")
+    private BigDecimal changeHcNum;
+
+    /**
+     * 锁定状态
+     */
+    @TableField(value = "locked_status")
+    private String lockedStatus;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 84 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/staticgrid/StaticIndicatorMetric.java

@@ -0,0 +1,84 @@
+package com.hdkj.lt.bf.entity.staticgrid;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 静态网架评估指标明细实体
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName("t_static_indicator_metric")
+@ApiModel(description = "静态网架评估指标明细")
+public class StaticIndicatorMetric implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "关联主表ID")
+    private Long resultId;
+
+    @ApiModelProperty(value = "指标级别:county/feeder")
+    private String level;
+
+    /**
+     * 馈线ID(level=county 时为 null)
+     */
+    private String feederId;
+
+    @ApiModelProperty(value = "馈线名称")
+    private String feederName;
+
+    @ApiModelProperty(value = "源变电站名称")
+    private String sourceSubstationName;
+
+    @ApiModelProperty(value = "源母线ID")
+    private String sourceBusId;
+
+    @ApiModelProperty(value = "供电区域类型")
+    private String supplyAreaType;
+
+    @ApiModelProperty(value = "分类代码")
+    private String categoryCode;
+
+    @ApiModelProperty(value = "分类名称")
+    private String categoryName;
+
+    @ApiModelProperty(value = "指标代码")
+    private String metricCode;
+
+    @ApiModelProperty(value = "指标名称")
+    private String metricName;
+
+    @ApiModelProperty(value = "指标值")
+    private String value;
+
+    @ApiModelProperty(value = "单位")
+    private String unit;
+
+    @ApiModelProperty(value = "结果分类")
+    private String resultClass;
+
+    @ApiModelProperty(value = "严重程度")
+    private String severity;
+
+    @ApiModelProperty(value = "计算状态")
+    private String calculationStatus;
+
+    @ApiModelProperty(value = "是否为问题项")
+    private Integer isProblem;
+}

+ 77 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/staticgrid/StaticIndicatorResult.java

@@ -0,0 +1,77 @@
+package com.hdkj.lt.bf.entity.staticgrid;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 静态网架评估结果主表实体
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName("t_static_indicator_result")
+@ApiModel(description = "静态网架评估结果主表")
+public class StaticIndicatorResult implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "批次ID")
+    private String batchId;
+
+    @ApiModelProperty(value = "区县ID")
+    private Integer countyId;
+
+    @ApiModelProperty(value = "区县短标识")
+    private String countySid;
+
+    @ApiModelProperty(value = "区县名称")
+    private String countyName;
+
+    @ApiModelProperty(value = "馈线ID列表")
+    private String feederIds;
+
+    @ApiModelProperty(value = "响应类型")
+    private String responseType;
+
+    @ApiModelProperty(value = "请求ID")
+    private String requestId;
+
+    @ApiModelProperty(value = "算法返回完整JSON")
+    private String rawResponse;
+
+    @ApiModelProperty(value = "算法标识")
+    private String algorithm;
+
+    @ApiModelProperty(value = "算法耗时(秒)")
+    private BigDecimal durationSec;
+
+    @ApiModelProperty(value = "算法状态")
+    private String status;
+
+    @ApiModelProperty(value = "数据质量状态")
+    private String dataQualityStatus;
+
+    @ApiModelProperty(value = "数据完整率(%)")
+    private BigDecimal dataQualityCompletenessRate;
+
+    @ApiModelProperty(value = "创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+}

+ 70 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/staticgrid/StaticProblemDetail.java

@@ -0,0 +1,70 @@
+package com.hdkj.lt.bf.entity.staticgrid;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 静态网架评估问题详情实体
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName("t_static_problem_detail")
+@ApiModel(description = "静态网架评估问题详情")
+public class StaticProblemDetail implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键ID")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "关联主表ID")
+    private Long resultId;
+
+    @ApiModelProperty(value = "问题ID")
+    private String problemId;
+
+    @ApiModelProperty(value = "馈线ID")
+    private String feederId;
+
+    @ApiModelProperty(value = "分类代码")
+    private String categoryCode;
+
+    @ApiModelProperty(value = "分类名称")
+    private String categoryName;
+
+    @ApiModelProperty(value = "指标代码")
+    private String metricCode;
+
+    @ApiModelProperty(value = "指标名称")
+    private String metricName;
+
+    @ApiModelProperty(value = "严重程度")
+    private String severity;
+
+    @ApiModelProperty(value = "对象类型")
+    private String objectType;
+
+    @ApiModelProperty(value = "对象ID")
+    private String objectId;
+
+    @ApiModelProperty(value = "实际值")
+    private String actualValue;
+
+    @ApiModelProperty(value = "问题描述")
+    private String description;
+
+    @ApiModelProperty(value = "整改建议")
+    private String suggestion;
+}

+ 191 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/entity/vo/StaticGridDashboardVO.java

@@ -0,0 +1,191 @@
+package com.hdkj.lt.bf.entity.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 静态网架评估仪表盘 VO(前端展示用)
+ * <p>
+ * 对应前端"静态网架评估"仪表盘,按4大模块分组。
+ * 部分字段不在静态网架算法返回中(属于运行态指标或外部台账),以 null 预留。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@ApiModel(description = "静态网架评估仪表盘")
+public class StaticGridDashboardVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    // ============================================================
+    // 基础信息
+    // ============================================================
+
+    @ApiModelProperty(value = "主表ID")
+    private Long resultId;
+
+    @ApiModelProperty(value = "批次ID")
+    private String batchId;
+
+    @ApiModelProperty(value = "区县ID")
+    private Integer countyId;
+
+    @ApiModelProperty(value = "区县短标识")
+    private String countySid;
+
+    @ApiModelProperty(value = "区县名称")
+    private String countyName;
+
+    @ApiModelProperty(value = "计算时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "数据质量状态")
+    private String dataQualityStatus;
+
+    @ApiModelProperty(value = "数据完整率(%)")
+    private BigDecimal dataQualityCompletenessRate;
+
+    // ============================================================
+    // 一、标准化网架
+    // ============================================================
+
+    @ApiModelProperty(value = "10kV接线标准化率(%)")
+    private BigDecimal wiringStandardizationRate;
+
+    @ApiModelProperty(value = "10kV主干线截面标准化率(%)")
+    private BigDecimal mainTrunkSectionStandardizationRate;
+
+    // ============================================================
+    // 二、供电可靠性
+    // ============================================================
+
+    @ApiModelProperty(value = "停电时户数(预留,来自运行台账)")
+    private Integer outageDurationHoursHouseholds;
+
+    @ApiModelProperty(value = "线路N-1通过率(%)")
+    private BigDecimal lineNMinus1PassRate;
+
+    @ApiModelProperty(value = "站间无联络线路数")
+    private Integer interSubstationNoConnectionCount;
+
+    @ApiModelProperty(value = "馈线同母线联络数")
+    private Integer sameBusInterconnectionIssueCount;
+
+    @ApiModelProperty(value = "联络点过多线路数")
+    private Integer excessiveTiePointFeederCount;
+
+    @ApiModelProperty(value = "无联络/单辐射线路数")
+    private Integer singleRadialFeederCount;
+
+    @ApiModelProperty(value = "存在大分支馈线数")
+    private Integer largeBranchFeederCount;
+
+    @ApiModelProperty(value = "分段数不合理线路数")
+    private Integer unreasonableSegmentCount;
+
+    @ApiModelProperty(value = "主干线分段配变密集数(预留,未在当前算法返回中)")
+    private Integer mainTrunkSegmentDenseCount;
+
+    // ============================================================
+    // 三、电压质量
+    // ============================================================
+
+    @ApiModelProperty(value = "IEC用户电压指数(预留,来源待定)")
+    private BigDecimal iecUserVoltageIndex;
+
+    @ApiModelProperty(value = "供电半径过长线路数")
+    private Integer supplyRadiusExceedFeederCount;
+
+    @ApiModelProperty(value = "超长馈线数")
+    private Integer extraLongFeederCount;
+
+    // ============================================================
+    // 四、供电能力
+    // ============================================================
+
+    @ApiModelProperty(value = "区域最大负载率(%)(预留,来自运行态指标)")
+    private BigDecimal regionalMaxLoadRate;
+
+    @ApiModelProperty(value = "区域平均负载率(%)(预留,来自运行态指标)")
+    private BigDecimal regionalAvgLoadRate;
+
+    @ApiModelProperty(value = "线路过载条数(预留,来自运行态指标)")
+    private Integer lineOverloadCount;
+
+    @ApiModelProperty(value = "主干线截面不匹配线路数(预留,来源待定)")
+    private Integer mainTrunkSectionMismatchCount;
+
+    @ApiModelProperty(value = "线路装接容量超标准线路数")
+    private Integer connectedCapacityExceedFeederCount;
+
+    @ApiModelProperty(value = "负荷组容量异常数")
+    private Integer loadGroupCapacityAnomalyCount;
+
+    @ApiModelProperty(value = "综合线损率(%)(预留,来自运行态指标)")
+    private BigDecimal comprehensiveLossRate;
+
+    @ApiModelProperty(value = "功率因数合格率(%)(预留,来自运行态指标)")
+    private BigDecimal powerFactorPassRate;
+
+    // ============================================================
+    // 问题详情列表
+    // ============================================================
+
+    @ApiModelProperty(value = "问题详情列表")
+    private List<ProblemDetailItem> problemDetails;
+
+    /**
+     * 问题详情条目
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @Builder
+    @ApiModel(description = "问题详情条目")
+    public static class ProblemDetailItem implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        @ApiModelProperty(value = "问题ID")
+        private String problemId;
+
+        @ApiModelProperty(value = "馈线ID")
+        private String feederId;
+
+        @ApiModelProperty(value = "分类名称")
+        private String categoryName;
+
+        @ApiModelProperty(value = "指标名称")
+        private String metricName;
+
+        @ApiModelProperty(value = "严重程度")
+        private String severity;
+
+        @ApiModelProperty(value = "对象类型")
+        private String objectType;
+
+        @ApiModelProperty(value = "实际值")
+        private String actualValue;
+
+        @ApiModelProperty(value = "问题描述")
+        private String description;
+
+        @ApiModelProperty(value = "整改建议")
+        private String suggestion;
+    }
+}

+ 20 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper.java

@@ -0,0 +1,20 @@
+package com.hdkj.lt.bf.mapper;
+
+import com.hdkj.lt.bf.entity.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @author lenovo
+* @description 针对表【sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event(sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event)】的数据库操作Mapper
+* @createDate 2026-07-18 14:32:38
+* @Entity com.hdkj.lt.bf.entity.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent
+*/
+@Mapper
+public interface SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper extends BaseMapper<SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent> {
+
+}
+
+
+
+

+ 20 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/SjztPwwyyqxtPrmPdrOutageMvDsMapper.java

@@ -0,0 +1,20 @@
+package com.hdkj.lt.bf.mapper;
+
+import com.hdkj.lt.bf.entity.SjztPwwyyqxtPrmPdrOutageMvDs;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @author lenovo
+* @description 针对表【sjzt_pwwyyqxt_prm_pdr_outage_mv_ds(un4113_02_pwwyyqxt_prm_pdr_outage_mv_ds)】的数据库操作Mapper
+* @createDate 2026-07-18 14:32:38
+* @Entity com.hdkj.lt.bf.entity.SjztPwwyyqxtPrmPdrOutageMvDs
+*/
+@Mapper
+public interface SjztPwwyyqxtPrmPdrOutageMvDsMapper extends BaseMapper<SjztPwwyyqxtPrmPdrOutageMvDs> {
+
+}
+
+
+
+

+ 12 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/staticgrid/StaticIndicatorMetricMapper.java

@@ -0,0 +1,12 @@
+package com.hdkj.lt.bf.mapper.staticgrid;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.bf.entity.staticgrid.StaticIndicatorMetric;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 静态网架评估指标明细 Mapper
+ */
+@Mapper
+public interface StaticIndicatorMetricMapper extends BaseMapper<StaticIndicatorMetric> {
+}

+ 12 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/staticgrid/StaticIndicatorResultMapper.java

@@ -0,0 +1,12 @@
+package com.hdkj.lt.bf.mapper.staticgrid;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.bf.entity.staticgrid.StaticIndicatorResult;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 静态网架评估结果主表 Mapper
+ */
+@Mapper
+public interface StaticIndicatorResultMapper extends BaseMapper<StaticIndicatorResult> {
+}

+ 12 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/mapper/staticgrid/StaticProblemDetailMapper.java

@@ -0,0 +1,12 @@
+package com.hdkj.lt.bf.mapper.staticgrid;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.bf.entity.staticgrid.StaticProblemDetail;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 静态网架评估问题详情 Mapper
+ */
+@Mapper
+public interface StaticProblemDetailMapper extends BaseMapper<StaticProblemDetail> {
+}

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

@@ -0,0 +1,13 @@
+package com.hdkj.lt.bf.service;
+
+import com.hdkj.lt.bf.entity.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author lenovo
+* @description 针对表【sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event(sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event)】的数据库操作Service
+* @createDate 2026-07-18 14:32:38
+*/
+public interface SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventService extends IService<SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent> {
+
+}

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

@@ -0,0 +1,13 @@
+package com.hdkj.lt.bf.service;
+
+import com.hdkj.lt.bf.entity.SjztPwwyyqxtPrmPdrOutageMvDs;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author lenovo
+* @description 针对表【sjzt_pwwyyqxt_prm_pdr_outage_mv_ds(un4113_02_pwwyyqxt_prm_pdr_outage_mv_ds)】的数据库操作Service
+* @createDate 2026-07-18 14:32:38
+*/
+public interface SjztPwwyyqxtPrmPdrOutageMvDsService extends IService<SjztPwwyyqxtPrmPdrOutageMvDs> {
+
+}

+ 22 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventServiceImpl.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.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent;
+import com.hdkj.lt.bf.service.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventService;
+import com.hdkj.lt.bf.mapper.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author lenovo
+* @description 针对表【sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event(sjzt_pddyyczdjfzzlcj_power_tech_vs_user_over_limit_event)】的数据库操作Service实现
+* @createDate 2026-07-18 14:32:38
+*/
+@Service
+public class SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventServiceImpl extends ServiceImpl<SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper, SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent>
+    implements SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventService{
+
+}
+
+
+
+

+ 22 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SjztPwwyyqxtPrmPdrOutageMvDsServiceImpl.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.SjztPwwyyqxtPrmPdrOutageMvDs;
+import com.hdkj.lt.bf.service.SjztPwwyyqxtPrmPdrOutageMvDsService;
+import com.hdkj.lt.bf.mapper.SjztPwwyyqxtPrmPdrOutageMvDsMapper;
+import org.springframework.stereotype.Service;
+
+/**
+* @author lenovo
+* @description 针对表【sjzt_pwwyyqxt_prm_pdr_outage_mv_ds(un4113_02_pwwyyqxt_prm_pdr_outage_mv_ds)】的数据库操作Service实现
+* @createDate 2026-07-18 14:32:38
+*/
+@Service
+public class SjztPwwyyqxtPrmPdrOutageMvDsServiceImpl extends ServiceImpl<SjztPwwyyqxtPrmPdrOutageMvDsMapper, SjztPwwyyqxtPrmPdrOutageMvDs>
+    implements SjztPwwyyqxtPrmPdrOutageMvDsService{
+
+}
+
+
+
+

+ 29 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/staticgrid/StaticGridDashboardService.java

@@ -0,0 +1,29 @@
+package com.hdkj.lt.bf.service.staticgrid;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.hdkj.lt.bf.entity.staticgrid.StaticIndicatorResult;
+import com.hdkj.lt.bf.entity.vo.StaticGridDashboardVO;
+
+/**
+ * 静态网架评估仪表盘服务
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+public interface StaticGridDashboardService extends IService<StaticIndicatorResult> {
+
+    /**
+     * 查询最新一次静态网架评估结果
+     *
+     * @return 仪表盘 VO
+     */
+    StaticGridDashboardVO queryLatestDashboard();
+
+    /**
+     * 按 batchId 查询指定一次静态网架评估结果
+     *
+     * @param batchId 批次ID
+     * @return 仪表盘 VO
+     */
+    StaticGridDashboardVO queryDashboardByBatchId(String batchId);
+}

+ 175 - 0
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/staticgrid/impl/StaticGridDashboardServiceImpl.java

@@ -0,0 +1,175 @@
+package com.hdkj.lt.bf.service.staticgrid.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hdkj.lt.bf.entity.staticgrid.StaticIndicatorMetric;
+import com.hdkj.lt.bf.entity.staticgrid.StaticIndicatorResult;
+import com.hdkj.lt.bf.entity.staticgrid.StaticProblemDetail;
+import com.hdkj.lt.bf.entity.vo.StaticGridDashboardVO;
+import com.hdkj.lt.bf.mapper.staticgrid.StaticIndicatorMetricMapper;
+import com.hdkj.lt.bf.mapper.staticgrid.StaticIndicatorResultMapper;
+import com.hdkj.lt.bf.mapper.staticgrid.StaticProblemDetailMapper;
+import com.hdkj.lt.bf.service.staticgrid.StaticGridDashboardService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 静态网架评估仪表盘服务实现
+ * <p>
+ * 从 t_static_indicator_result + t_static_indicator_metric + t_static_problem_detail 三张表
+ * 聚合数据,构建前端仪表盘 VO。
+ * <p>
+ * 预留字段(运行态指标/外部台账)直接返回 null,前端渲染为"-"。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StaticGridDashboardServiceImpl
+        extends ServiceImpl<StaticIndicatorResultMapper, StaticIndicatorResult>
+        implements StaticGridDashboardService {
+
+    private final StaticIndicatorMetricMapper metricMapper;
+    private final StaticProblemDetailMapper problemDetailMapper;
+
+    @Override
+    public StaticGridDashboardVO queryLatestDashboard() {
+        LambdaQueryWrapper<StaticIndicatorResult> wrapper = new LambdaQueryWrapper<StaticIndicatorResult>()
+                .orderByDesc(StaticIndicatorResult::getCreateTime)
+                .last("LIMIT 1");
+        StaticIndicatorResult result = getOne(wrapper);
+        if (result == null) {
+            log.warn("无静态网架评估数据");
+            return null;
+        }
+        return buildDashboardVO(result);
+    }
+
+    @Override
+    public StaticGridDashboardVO queryDashboardByBatchId(String batchId) {
+        if (StringUtils.isBlank(batchId)) {
+            return queryLatestDashboard();
+        }
+        LambdaQueryWrapper<StaticIndicatorResult> wrapper = new LambdaQueryWrapper<StaticIndicatorResult>()
+                .eq(StaticIndicatorResult::getBatchId, batchId)
+                .last("LIMIT 1");
+        StaticIndicatorResult result = getOne(wrapper);
+        if (result == null) {
+            log.warn("无静态网架评估数据 batchId={}", batchId);
+            return null;
+        }
+        return buildDashboardVO(result);
+    }
+
+    /**
+     * 构建仪表盘 VO
+     */
+    private StaticGridDashboardVO buildDashboardVO(StaticIndicatorResult result) {
+        Long resultId = result.getId();
+
+        // 查 county 级指标,按 metricCode 索引
+        LambdaQueryWrapper<StaticIndicatorMetric> metricWrapper = new LambdaQueryWrapper<StaticIndicatorMetric>()
+                .eq(StaticIndicatorMetric::getResultId, resultId)
+                .eq(StaticIndicatorMetric::getLevel, "county");
+        List<StaticIndicatorMetric> countyMetrics = metricMapper.selectList(metricWrapper);
+        Map<String, String> countyMetricMap = new HashMap<String, String>();
+        for (StaticIndicatorMetric m : countyMetrics) {
+            countyMetricMap.put(m.getMetricCode(), m.getValue());
+        }
+
+        // 查问题详情
+        /*LambdaQueryWrapper<StaticProblemDetail> problemWrapper = new LambdaQueryWrapper<StaticProblemDetail>()
+                .eq(StaticProblemDetail::getResultId, resultId)
+                .orderByAsc(StaticProblemDetail::getProblemId);
+        List<StaticProblemDetail> problems = problemDetailMapper.selectList(problemWrapper);
+        List<StaticGridDashboardVO.ProblemDetailItem> problemItems = new ArrayList<StaticGridDashboardVO.ProblemDetailItem>();
+        for (StaticProblemDetail p : problems) {
+            problemItems.add(StaticGridDashboardVO.ProblemDetailItem.builder()
+                    .problemId(p.getProblemId())
+                    .feederId(p.getFeederId())
+                    .categoryName(p.getCategoryName())
+                    .metricName(p.getMetricName())
+                    .severity(p.getSeverity())
+                    .objectType(p.getObjectType())
+                    .actualValue(p.getActualValue())
+                    .description(p.getDescription())
+                    .suggestion(p.getSuggestion())
+                    .build());
+        }*/
+
+        return StaticGridDashboardVO.builder()
+                .resultId(resultId)
+                .batchId(result.getBatchId())
+                .countyId(result.getCountyId())
+                .countySid(result.getCountySid())
+                .countyName(result.getCountyName())
+                .createTime(result.getCreateTime())
+                .dataQualityStatus(result.getDataQualityStatus())
+                .dataQualityCompletenessRate(result.getDataQualityCompletenessRate())
+                // 一、标准化网架
+                .wiringStandardizationRate(toBigDecimal(countyMetricMap.get("wiring_standardization_rate")))
+                .mainTrunkSectionStandardizationRate(toBigDecimal(countyMetricMap.get("main_trunk_section_standardization_rate")))
+                // 二、供电可靠性
+                .outageDurationHoursHouseholds(null)  // 预留:运行台账
+                .lineNMinus1PassRate(toBigDecimal(countyMetricMap.get("n_minus_1_pass_rate")))
+                .interSubstationNoConnectionCount(toInteger(countyMetricMap.get("inter_substation_interconnection_rate"))) // 站间联络率相关
+                .sameBusInterconnectionIssueCount(toInteger(countyMetricMap.get("same_bus_interconnection_issue_count")))
+                .excessiveTiePointFeederCount(toInteger(countyMetricMap.get("excessive_tie_point_feeder_count")))
+                .singleRadialFeederCount(toInteger(countyMetricMap.get("single_radial_feeder_count")))
+                .largeBranchFeederCount(toInteger(countyMetricMap.get("large_branch_issue_feeder_count")))
+                .unreasonableSegmentCount(toInteger(countyMetricMap.get("unreasonable_segment_count_feeder_count")))
+                .mainTrunkSegmentDenseCount(null)  // 预留
+                // 三、电压质量
+                .iecUserVoltageIndex(null)  // 预留
+                .supplyRadiusExceedFeederCount(toInteger(countyMetricMap.get("supply_radius_exceed_feeder_count")))
+                .extraLongFeederCount(toInteger(countyMetricMap.get("extra_long_feeder_count")))
+                // 四、供电能力
+                .regionalMaxLoadRate(null)  // 预留:运行态指标
+                .regionalAvgLoadRate(null)  // 预留:运行态指标
+                .lineOverloadCount(null)  // 预留:运行态指标
+                .mainTrunkSectionMismatchCount(null)  // 预留
+                .connectedCapacityExceedFeederCount(toInteger(countyMetricMap.get("connected_capacity_exceed_feeder_count")))
+                .loadGroupCapacityAnomalyCount(toInteger(countyMetricMap.get("load_group_capacity_anomaly_count")))
+                .comprehensiveLossRate(null)  // 预留:运行态指标
+                .powerFactorPassRate(null)  // 预留:运行态指标
+                // 问题详情
+                //.problemDetails(problemItems)
+                .build();
+    }
+
+    private BigDecimal toBigDecimal(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        try {
+            return new BigDecimal(value);
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    private Integer toInteger(String value) {
+        if (StringUtils.isBlank(value)) {
+            return null;
+        }
+        try {
+            return Integer.valueOf(value);
+        } catch (NumberFormatException e) {
+            try {
+                return new BigDecimal(value).intValue();
+            } catch (NumberFormatException e2) {
+                return null;
+            }
+        }
+    }
+}

+ 91 - 0
services/load-transfer-bf/src/main/resources/mapper/SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper.xml

@@ -0,0 +1,91 @@
+<?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.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEventMapper">
+
+    <resultMap id="BaseResultMap" type="com.hdkj.lt.bf.entity.SjztPddyyczdjfzzlcjPowerTechVsUserOverLimitEvent">
+            <result property="objId" column="obj_id" jdbcType="VARCHAR"/>
+            <result property="provinceId" column="province_id" jdbcType="VARCHAR"/>
+            <result property="provinceName" column="province_name" jdbcType="VARCHAR"/>
+            <result property="cityOrgId" column="city_org_id" jdbcType="VARCHAR"/>
+            <result property="cityOrgName" column="city_org_name" jdbcType="VARCHAR"/>
+            <result property="maintainerId" column="maintainer_id" jdbcType="VARCHAR"/>
+            <result property="maintainerName" column="maintainer_name" jdbcType="VARCHAR"/>
+            <result property="maintcrewId" column="maintcrew_id" jdbcType="VARCHAR"/>
+            <result property="maintcrewName" column="maintcrew_name" jdbcType="VARCHAR"/>
+            <result property="substationId" column="substation_id" jdbcType="VARCHAR"/>
+            <result property="substationName" column="substation_name" jdbcType="VARCHAR"/>
+            <result property="generatrixId" column="generatrix_id" jdbcType="VARCHAR"/>
+            <result property="generatrixName" column="generatrix_name" jdbcType="VARCHAR"/>
+            <result property="feederId" column="feeder_id" jdbcType="VARCHAR"/>
+            <result property="feederName" column="feeder_name" jdbcType="VARCHAR"/>
+            <result property="feeder10kvGenerationUserCount" column="feeder_10kv_generation_user_count" jdbcType="VARCHAR"/>
+            <result property="tgNo" column="tg_no" jdbcType="VARCHAR"/>
+            <result property="transformerId" column="transformer_id" jdbcType="VARCHAR"/>
+            <result property="transformerName" column="transformer_name" jdbcType="VARCHAR"/>
+            <result property="isPvTg" column="is_pv_tg" jdbcType="VARCHAR"/>
+            <result property="generationType" column="generation_type" jdbcType="VARCHAR"/>
+            <result property="measNo" column="meas_no" jdbcType="VARCHAR"/>
+            <result property="measPsrId" column="meas_psr_id" jdbcType="VARCHAR"/>
+            <result property="custNo" column="cust_no" jdbcType="VARCHAR"/>
+            <result property="custName" column="cust_name" jdbcType="VARCHAR"/>
+            <result property="isPvCust" column="is_pv_cust" jdbcType="VARCHAR"/>
+            <result property="voltageLevelCode" column="voltage_level_code" jdbcType="VARCHAR"/>
+            <result property="overLimitDate" column="over_limit_date" jdbcType="VARCHAR"/>
+            <result property="overLimitType" column="over_limit_type" jdbcType="VARCHAR"/>
+            <result property="overLimitStartTime" column="over_limit_start_time" jdbcType="VARCHAR"/>
+            <result property="overLimitEndTime" column="over_limit_end_time" jdbcType="VARCHAR"/>
+            <result property="overLimitDuration" column="over_limit_duration" jdbcType="VARCHAR"/>
+            <result property="isDataQualityIssue" column="is_data_quality_issue" jdbcType="VARCHAR"/>
+            <result property="traceabilityLevel" column="traceability_level" jdbcType="VARCHAR"/>
+            <result property="overLimitCause" column="over_limit_cause" jdbcType="VARCHAR"/>
+            <result property="controlMeasures" column="control_measures" jdbcType="VARCHAR"/>
+            <result property="ctime" column="ctime" jdbcType="TIMESTAMP"/>
+            <result property="mtime" column="mtime" jdbcType="TIMESTAMP"/>
+            <result property="isDeleted" column="is_deleted" jdbcType="VARCHAR"/>
+            <result property="corrCoefPhaseA" column="corr_coef_phase_a" jdbcType="VARCHAR"/>
+            <result property="corrCoefPhaseB" column="corr_coef_phase_b" jdbcType="VARCHAR"/>
+            <result property="corrCoefPhaseC" column="corr_coef_phase_c" jdbcType="VARCHAR"/>
+            <result property="meterBoxUserCount" column="meter_box_user_count" jdbcType="VARCHAR"/>
+            <result property="transType" column="trans_type" jdbcType="VARCHAR"/>
+            <result property="daysUnreasonableTapPosition" column="days_unreasonable_tap_position" jdbcType="VARCHAR"/>
+            <result property="daysUnreasonableBusVoltageTarget" column="days_unreasonable_bus_voltage_target" jdbcType="VARCHAR"/>
+            <result property="mpId" column="mp_id" jdbcType="VARCHAR"/>
+            <result property="meterId" column="meter_id" jdbcType="VARCHAR"/>
+            <result property="lvLinePsrId" column="lv_line_psr_id" jdbcType="VARCHAR"/>
+            <result property="voltageIndexRange" column="voltage_index_range" jdbcType="VARCHAR"/>
+            <result property="voltageOverIndexMild" column="voltage_over_index_mild" jdbcType="VARCHAR"/>
+            <result property="voltageOverIndexSevere" column="voltage_over_index_severe" jdbcType="VARCHAR"/>
+            <result property="voltageUnderIndexMild" column="voltage_under_index_mild" jdbcType="VARCHAR"/>
+            <result property="voltageUnderIndexSevere" column="voltage_under_index_severe" jdbcType="VARCHAR"/>
+            <result property="maxCorrelationCoefficient" column="max_correlation_coefficient" jdbcType="VARCHAR"/>
+            <result property="isSensitiveUser" column="is_sensitive_user" jdbcType="VARCHAR"/>
+            <result property="userType" column="user_type" jdbcType="VARCHAR"/>
+            <result property="isLowVoltageDay" column="is_low_voltage_day" jdbcType="VARCHAR"/>
+            <result property="isSevereOvervoltageDay" column="is_severe_overvoltage_day" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        obj_id,province_id,province_name,
+        city_org_id,city_org_name,maintainer_id,
+        maintainer_name,maintcrew_id,maintcrew_name,
+        substation_id,substation_name,generatrix_id,
+        generatrix_name,feeder_id,feeder_name,
+        feeder_10kv_generation_user_count,tg_no,transformer_id,
+        transformer_name,is_pv_tg,generation_type,
+        meas_no,meas_psr_id,cust_no,
+        cust_name,is_pv_cust,voltage_level_code,
+        over_limit_date,over_limit_type,over_limit_start_time,
+        over_limit_end_time,over_limit_duration,is_data_quality_issue,
+        traceability_level,over_limit_cause,control_measures,
+        ctime,mtime,is_deleted,
+        corr_coef_phase_a,corr_coef_phase_b,corr_coef_phase_c,
+        meter_box_user_count,trans_type,days_unreasonable_tap_position,
+        days_unreasonable_bus_voltage_target,mp_id,meter_id,
+        lv_line_psr_id,voltage_index_range,voltage_over_index_mild,
+        voltage_over_index_severe,voltage_under_index_mild,voltage_under_index_severe,
+        max_correlation_coefficient,is_sensitive_user,user_type,
+        is_low_voltage_day,is_severe_overvoltage_day
+    </sql>
+</mapper>

+ 107 - 0
services/load-transfer-bf/src/main/resources/mapper/SjztPwwyyqxtPrmPdrOutageMvDsMapper.xml

@@ -0,0 +1,107 @@
+<?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.SjztPwwyyqxtPrmPdrOutageMvDsMapper">
+
+    <resultMap id="BaseResultMap" type="com.hdkj.lt.bf.entity.SjztPwwyyqxtPrmPdrOutageMvDs">
+            <result property="id" column="id" jdbcType="VARCHAR"/>
+            <result property="eventNo" column="event_no" jdbcType="VARCHAR"/>
+            <result property="provinceOrganisationCode" column="province_organisation_code" jdbcType="VARCHAR"/>
+            <result property="reliabilityOrganisation" column="reliability_organisation" jdbcType="VARCHAR"/>
+            <result property="dutyOrgId" column="duty_org_id" jdbcType="VARCHAR"/>
+            <result property="outageStime" column="outage_stime" jdbcType="TIMESTAMP"/>
+            <result property="outageEtime" column="outage_etime" jdbcType="TIMESTAMP"/>
+            <result property="outageDuration" column="outage_duration" jdbcType="DECIMAL"/>
+            <result property="outageHcNum" column="outage_hc_num" jdbcType="DECIMAL"/>
+            <result property="anes" column="anes" jdbcType="DECIMAL"/>
+            <result property="outageFeederCnt" column="outage_feeder_cnt" jdbcType="DECIMAL"/>
+            <result property="outageZonefeederCnt" column="outage_zonefeeder_cnt" jdbcType="DECIMAL"/>
+            <result property="outageMvconsCnt" column="outage_mvcons_cnt" jdbcType="DECIMAL"/>
+            <result property="outageLvconsCnt" column="outage_lvcons_cnt" jdbcType="DECIMAL"/>
+            <result property="outageLvHcnum" column="outage_lv_hcnum" jdbcType="DECIMAL"/>
+            <result property="outageCap" column="outage_cap" jdbcType="DECIMAL"/>
+            <result property="orgNatureCode" column="org_nature_code" jdbcType="VARCHAR"/>
+            <result property="outageNatureCode" column="outage_nature_code" jdbcType="VARCHAR"/>
+            <result property="outageResponCode" column="outage_respon_code" jdbcType="VARCHAR"/>
+            <result property="outgEquipmentReasonCode" column="outg_equipment_reason_code" jdbcType="VARCHAR"/>
+            <result property="outageTechnicalCode" column="outage_technical_code" jdbcType="VARCHAR"/>
+            <result property="specialAnalysisCode" column="special_analysis_code" jdbcType="VARCHAR"/>
+            <result property="supplyArea" column="supply_area" jdbcType="VARCHAR"/>
+            <result property="areaCode" column="area_code" jdbcType="VARCHAR"/>
+            <result property="outageSource" column="outage_source" jdbcType="VARCHAR"/>
+            <result property="remark" column="remark" jdbcType="VARCHAR"/>
+            <result property="operateFlag" column="operate_flag" jdbcType="VARCHAR"/>
+            <result property="provinceAuditTime" column="province_audit_time" jdbcType="TIMESTAMP"/>
+            <result property="headquartersAuditTime" column="headquarters_audit_time" jdbcType="TIMESTAMP"/>
+            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
+            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
+            <result property="reportStatus" column="report_status" jdbcType="VARCHAR"/>
+            <result property="reportTime" column="report_time" jdbcType="TIMESTAMP"/>
+            <result property="isSyncEs" column="is_sync_es" jdbcType="VARCHAR"/>
+            <result property="isConfirmed" column="is_confirmed" jdbcType="VARCHAR"/>
+            <result property="confirmTime" column="confirm_time" jdbcType="TIMESTAMP"/>
+            <result property="outageMainEquipmentType" column="outage_main_equipment_type" jdbcType="VARCHAR"/>
+            <result property="isIgnored" column="is_ignored" jdbcType="VARCHAR"/>
+            <result property="outageType" column="outage_type" jdbcType="VARCHAR"/>
+            <result property="modifyReason" column="modify_reason" jdbcType="VARCHAR"/>
+            <result property="isUpdated" column="is_updated" jdbcType="VARCHAR"/>
+            <result property="provinceAuditStatus" column="province_audit_status" jdbcType="VARCHAR"/>
+            <result property="firstConfirmTime" column="first_confirm_time" jdbcType="TIMESTAMP"/>
+            <result property="dataVersion" column="data_version" jdbcType="DECIMAL"/>
+            <result property="ignoreTime" column="ignore_time" jdbcType="TIMESTAMP"/>
+            <result property="headquartersAuditStatus" column="headquarters_audit_status" jdbcType="VARCHAR"/>
+            <result property="checkStatus" column="check_status" jdbcType="VARCHAR"/>
+            <result property="voltageLevel" column="voltage_level" jdbcType="VARCHAR"/>
+            <result property="procInstId" column="proc_inst_id" jdbcType="VARCHAR"/>
+            <result property="auditStatus" column="audit_status" jdbcType="VARCHAR"/>
+            <result property="checkTime" column="check_time" jdbcType="TIMESTAMP"/>
+            <result property="txhash" column="txhash" jdbcType="VARCHAR"/>
+            <result property="outageMainEquipmentName" column="outage_main_equipment_name" jdbcType="VARCHAR"/>
+            <result property="outageFeederName" column="outage_feeder_name" jdbcType="VARCHAR"/>
+            <result property="isException" column="is_exception" jdbcType="VARCHAR"/>
+            <result property="provinceAuditRemark" column="province_audit_remark" jdbcType="VARCHAR"/>
+            <result property="headquartersAuditRemark" column="headquarters_audit_remark" jdbcType="VARCHAR"/>
+            <result property="dataConfidence" column="data_confidence" jdbcType="VARCHAR"/>
+            <result property="hasAttachment" column="has_attachment" jdbcType="VARCHAR"/>
+            <result property="isMajorFault" column="is_major_fault" jdbcType="VARCHAR"/>
+            <result property="isAttachmentValid" column="is_attachment_valid" jdbcType="VARCHAR"/>
+            <result property="operator" column="operator" jdbcType="VARCHAR"/>
+            <result property="operationTime" column="operation_time" jdbcType="TIMESTAMP"/>
+            <result property="countyAuditor" column="county_auditor" jdbcType="VARCHAR"/>
+            <result property="countyAuditTime" column="county_audit_time" jdbcType="TIMESTAMP"/>
+            <result property="cityAuditor" column="city_auditor" jdbcType="VARCHAR"/>
+            <result property="cityAuditorTime" column="city_auditor_time" jdbcType="TIMESTAMP"/>
+            <result property="provinceAuditor" column="province_auditor" jdbcType="VARCHAR"/>
+            <result property="headquartersAuditor" column="headquarters_auditor" jdbcType="VARCHAR"/>
+            <result property="changeHcNum" column="change_hc_num" jdbcType="DECIMAL"/>
+            <result property="lockedStatus" column="locked_status" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,event_no,province_organisation_code,
+        reliability_organisation,duty_org_id,outage_stime,
+        outage_etime,outage_duration,outage_hc_num,
+        anes,outage_feeder_cnt,outage_zonefeeder_cnt,
+        outage_mvcons_cnt,outage_lvcons_cnt,outage_lv_hcnum,
+        outage_cap,org_nature_code,outage_nature_code,
+        outage_respon_code,outg_equipment_reason_code,outage_technical_code,
+        special_analysis_code,supply_area,area_code,
+        outage_source,remark,operate_flag,
+        province_audit_time,headquarters_audit_time,create_time,
+        update_time,report_status,report_time,
+        is_sync_es,is_confirmed,confirm_time,
+        outage_main_equipment_type,is_ignored,outage_type,
+        modify_reason,is_updated,province_audit_status,
+        first_confirm_time,data_version,ignore_time,
+        headquarters_audit_status,check_status,voltage_level,
+        proc_inst_id,audit_status,check_time,
+        txhash,outage_main_equipment_name,outage_feeder_name,
+        is_exception,province_audit_remark,headquarters_audit_remark,
+        data_confidence,has_attachment,is_major_fault,
+        is_attachment_valid,operator,operation_time,
+        county_auditor,county_audit_time,city_auditor,
+        city_auditor_time,province_auditor,headquarters_auditor,
+        change_hc_num,locked_status
+    </sql>
+</mapper>

+ 2 - 2
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/entity/indicator/AlarmEvent.java

@@ -17,7 +17,7 @@ import java.time.LocalDateTime;
 /**
  * 告警事件(t_alarm_event)
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @TableName("t_alarm_event")
@@ -107,7 +107,7 @@ public class AlarmEvent implements Serializable {
     private LocalDateTime lastAlarmTime;
 
     /**
-     * 状态:0-待处理,1-重构中,2-已完成,3-已忽略
+     * 状态:0-待处理,1-重构中,2-已完成,3-已忽略,4-重构失败
      */
     private Integer status;
 

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/entity/indicator/IndicatorResult.java

@@ -16,7 +16,7 @@ import java.time.LocalDateTime;
 /**
  * 指标计算结果(t_indicator_result)
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @TableName("t_indicator_result")

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/listener/IndicatorCalcConsumer.java

@@ -31,7 +31,7 @@ import java.util.List;
  * 消费指标计算任务消息,通过 Feign 调 si 模块算法接口获取指标JSON,
  * 入库后发送指标完成事件到 indicator-event-topic。
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Slf4j

+ 61 - 17
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/listener/IndicatorEventConsumer.java

@@ -6,7 +6,12 @@ import com.aliyun.openservices.ons.api.ConsumeContext;
 import com.aliyun.openservices.ons.api.Message;
 import com.aliyun.openservices.ons.api.MessageListener;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.hdkj.lt.base.constants.RedisKeyConstants;
+import com.hdkj.lt.base.constants.RocketMQConstants;
+import com.hdkj.lt.core.mq.client.RocketMQTemplate;
+import com.hdkj.lt.core.mq.model.RocketMQMessageEntity;
 import com.hdkj.lt.modle.dto.indicator.IndicatorCompletedEvent;
+import com.hdkj.lt.modle.dto.recon.ReconCalcMessage;
 import com.hdkj.lt.mq.entity.indicator.AlarmEvent;
 import com.hdkj.lt.mq.entity.indicator.IndicatorResult;
 import com.hdkj.lt.mq.mapper.indicator.AlarmEventMapper;
@@ -20,6 +25,7 @@ import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -29,7 +35,7 @@ import java.util.Set;
  * <p>
  * 消费指标完成事件,触发告警评估,对告警事件做抑制写入(同馈线同天活跃告警合并)。
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Slf4j
@@ -40,6 +46,7 @@ public class IndicatorEventConsumer implements MessageListener {
     private final AlarmEvaluateService alarmEvaluateService;
     private final AlarmEventMapper alarmEventMapper;
     private final IndicatorResultMapper indicatorResultMapper;
+    private final RocketMQTemplate rocketMQTemplate;
 
     @Override
     public Action consume(Message message, ConsumeContext consumeContext) {
@@ -66,9 +73,12 @@ public class IndicatorEventConsumer implements MessageListener {
                 return Action.CommitMessage;
             }
 
-            // 遍历写入告警事件(抑制)
+            // 遍历写入告警事件(抑制),首次插入的告警触发重构计算
             for (AlarmEvent alarmEvent : alarmEvents) {
-                upsertAlarmEvent(alarmEvent);
+                boolean isNew = upsertAlarmEvent(alarmEvent);
+                if (isNew) {
+                    sendReconCalcMessage(alarmEvent);
+                }
             }
 
             log.info("指标完成事件消费完成 indicatorResultId={}, batchId={}, countyId={}, alarmCount={}",
@@ -82,8 +92,10 @@ public class IndicatorEventConsumer implements MessageListener {
 
     /**
      * 告警抑制写入:同馈线同天活跃告警合并,否则新增
+     *
+     * @return true=本次为新增插入(触发重构),false=更新已有告警(不触发)
      */
-    private void upsertAlarmEvent(AlarmEvent alarmEvent) {
+    private boolean upsertAlarmEvent(AlarmEvent alarmEvent) {
         LocalDate alarmDate = alarmEvent.getAlarmDate() != null ? alarmEvent.getAlarmDate() : LocalDate.now();
         LambdaQueryWrapper<AlarmEvent> wrapper = new LambdaQueryWrapper<AlarmEvent>()
                 .eq(AlarmEvent::getCountyId, alarmEvent.getCountyId())
@@ -107,19 +119,51 @@ public class IndicatorEventConsumer implements MessageListener {
             alarmEventMapper.updateById(existing);
             log.info("告警抑制-更新 alarmEventId={}, feederId={}, alarmCount={}",
                     existing.getId(), existing.getFeederId(), existing.getAlarmCount());
-        } else {
-            // 新增
-            alarmEvent.setAlarmCount(1);
-            alarmEvent.setAlarmDate(alarmDate);
-            LocalDateTime now = LocalDateTime.now();
-            alarmEvent.setAlarmTime(now);
-            alarmEvent.setLastAlarmTime(now);
-            alarmEvent.setCreateTime(now);
-            alarmEvent.setUpdateTime(now);
-            alarmEvent.setStatus(0);
-            alarmEventMapper.insert(alarmEvent);
-            log.info("告警抑制-新增 feederId={}, countyId={}, alarmTypes={}",
-                    alarmEvent.getFeederId(), alarmEvent.getCountyId(), alarmEvent.getAlarmTypes());
+            // 回填主键,便于上游必要时引用
+            alarmEvent.setId(existing.getId());
+            return false;
+        }
+        // 新增
+        alarmEvent.setAlarmCount(1);
+        alarmEvent.setAlarmDate(alarmDate);
+        LocalDateTime now = LocalDateTime.now();
+        alarmEvent.setAlarmTime(now);
+        alarmEvent.setLastAlarmTime(now);
+        alarmEvent.setCreateTime(now);
+        alarmEvent.setUpdateTime(now);
+        alarmEvent.setStatus(0);
+        alarmEventMapper.insert(alarmEvent);
+        log.info("告警抑制-新增 alarmEventId={}, feederId={}, countyId={}, alarmTypes={}",
+                alarmEvent.getId(), alarmEvent.getFeederId(), alarmEvent.getCountyId(), alarmEvent.getAlarmTypes());
+        return true;
+    }
+
+    /**
+     * 发送重构计算任务消息(仅首次插入的告警触发,避免重复告警反复重构)
+     */
+    private void sendReconCalcMessage(AlarmEvent alarmEvent) {
+        try {
+            ReconCalcMessage msg = ReconCalcMessage.builder()
+                    .eventId(alarmEvent.getId())
+                    .countySid(alarmEvent.getCountySid())
+                    .countyName(alarmEvent.getCountyName())
+                    .problemFeederIds(alarmEvent.getFeederId() != null
+                            ? Collections.singletonList(alarmEvent.getFeederId())
+                            : Collections.<String>emptyList())
+                    .build();
+            RocketMQMessageEntity messageEntity = RocketMQMessageEntity.builder()
+                    .topicId(RocketMQConstants.TOPIC_ID_RECONFIGURATION_CALC)
+                    .cacheKey(RedisKeyConstants.ASYNC_QUEUE_RECONFIGURATION_CALC)
+                    .tag(alarmEvent.getBatchId())
+                    .body(msg)
+                    .build();
+            rocketMQTemplate.sendAsyncMessage(messageEntity);
+            log.info("发送重构计算任务 alarmEventId={}, feederId={}, countySid={}",
+                    alarmEvent.getId(), alarmEvent.getFeederId(), alarmEvent.getCountySid());
+        } catch (Exception e) {
+            // MQ 发送失败不影响告警入库主流程,记录错误日志
+            log.error("发送重构计算任务失败 alarmEventId={}, feederId={}",
+                    alarmEvent.getId(), alarmEvent.getFeederId(), e);
         }
     }
 

+ 125 - 0
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/listener/ReconCalcConsumer.java

@@ -0,0 +1,125 @@
+package com.hdkj.lt.mq.listener;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyun.openservices.ons.api.Action;
+import com.aliyun.openservices.ons.api.ConsumeContext;
+import com.aliyun.openservices.ons.api.Message;
+import com.aliyun.openservices.ons.api.MessageListener;
+import com.hdkj.lt.feign.IReconApiClient;
+import com.hdkj.lt.modle.dto.recon.ReconCalcMessage;
+import com.hdkj.lt.modle.vo.recon.ReconstructionParam;
+import com.hdkj.lt.mq.entity.indicator.AlarmEvent;
+import com.hdkj.lt.mq.mapper.indicator.AlarmEventMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 重构计算任务消费者(reconfiguration-calc-topic)
+ * <p>
+ * 消费重构计算任务消息,通过 Feign 调 si 模块的 /recon/trigger 触发重构算法,
+ * 根据返回结果更新 t_alarm_event 状态:
+ * <ul>
+ *   <li>开始:status 0(待处理) → 1(重构中)</li>
+ *   <li>成功:status → 2(已完成)</li>
+ *   <li>失败:status → 4(重构失败)</li>
+ * </ul>
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ReconCalcConsumer implements MessageListener {
+
+    private final IReconApiClient reconApiClient;
+    private final AlarmEventMapper alarmEventMapper;
+
+    @Override
+    public Action consume(Message message, ConsumeContext consumeContext) {
+        try {
+            log.info("===== 重构计算任务-开始消费 =====");
+            String body = new String(message.getBody(), StandardCharsets.UTF_8);
+            ReconCalcMessage calcMessage = JSON.parseObject(body, ReconCalcMessage.class);
+            if (calcMessage == null || calcMessage.getEventId() == null) {
+                log.warn("重构计算任务消息解析失败,body={}", body);
+                return Action.ReconsumeLater;
+            }
+
+            Long eventId = calcMessage.getEventId();
+            AlarmEvent alarmEvent = alarmEventMapper.selectById(eventId);
+            if (alarmEvent == null) {
+                log.warn("告警事件不存在 eventId={}", eventId);
+                return Action.CommitMessage;
+            }
+
+            // 1. 标记重构中
+            updateStatus(eventId, 1);
+
+            // 2. 构造 si 接口入参
+            ReconstructionParam param = new ReconstructionParam();
+            param.setEventId(String.valueOf(eventId));
+            Map<String, Object> params = new HashMap<String, Object>();
+            params.put("county_sid", calcMessage.getCountySid());
+            params.put("county_name", calcMessage.getCountyName());
+            params.put("problem_feeder_ids", calcMessage.getProblemFeederIds());
+            param.setParams(params);
+
+            // 3. Feign 调 si 重构触发接口
+            String apiResponseJson;
+            try {
+                apiResponseJson = reconApiClient.triggerReconfiguration(param);
+            } catch (Exception e) {
+                log.error("调用重构触发接口异常 eventId={}", eventId, e);
+                updateStatus(eventId, 4);
+                return Action.ReconsumeLater;
+            }
+
+            if (StringUtils.isBlank(apiResponseJson)) {
+                log.error("重构触发接口返回空 eventId={}", eventId);
+                updateStatus(eventId, 4);
+                return Action.ReconsumeLater;
+            }
+
+            // 4. 解析 ApiResponse 外壳,取 data.success 判断成功
+            JSONObject apiResp = JSON.parseObject(apiResponseJson);
+            Integer code = apiResp.getInteger("code");
+            JSONObject data = apiResp.getJSONObject("data");
+            Boolean success = data != null ? data.getBoolean("success") : null;
+
+            if (code != null && code == 200 && Boolean.TRUE.equals(success)) {
+                updateStatus(eventId, 2);
+                log.info("重构计算任务完成 eventId={}, reconResult={}", eventId, data);
+            } else {
+                updateStatus(eventId, 4);
+                log.error("重构计算任务失败 eventId={}, apiResponse={}", eventId, apiResponseJson);
+                // 业务失败不重试,避免反复调用算法
+                return Action.CommitMessage;
+            }
+
+            return Action.CommitMessage;
+        } catch (Exception e) {
+            log.error("重构计算任务消费异常 topic={}", message.getTopic(), e);
+            return Action.ReconsumeLater;
+        }
+    }
+
+    /**
+     * 更新告警事件状态
+     */
+    private void updateStatus(Long eventId, Integer status) {
+        AlarmEvent update = new AlarmEvent();
+        update.setId(eventId);
+        update.setStatus(status);
+        update.setUpdateTime(LocalDateTime.now());
+        alarmEventMapper.updateById(update);
+    }
+}

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/mapper/indicator/AlarmEventMapper.java

@@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
 /**
  * 告警事件 Mapper
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Mapper

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/mapper/indicator/IndicatorResultMapper.java

@@ -7,7 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
 /**
  * 指标计算结果 Mapper
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Mapper

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/AlarmEvaluateService.java

@@ -7,7 +7,7 @@ import java.util.List;
 /**
  * 告警评估服务
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 public interface AlarmEvaluateService {

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/IndicatorResultService.java

@@ -5,7 +5,7 @@ import com.hdkj.lt.mq.entity.indicator.IndicatorResult;
 /**
  * 指标计算结果服务
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 public interface IndicatorResultService {

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/impl/AlarmEvaluateServiceImpl.java

@@ -33,7 +33,7 @@ import java.util.Map;
  *   <li>voltage_under → 电压越限</li>
  * </ul>
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Slf4j

+ 1 - 1
services/load-transfer-mq/src/main/java/com/hdkj/lt/mq/service/indicator/impl/IndicatorResultServiceImpl.java

@@ -18,7 +18,7 @@ import java.util.List;
 /**
  * 指标计算结果服务实现
  *
- * @author hermes
+ * @author lsl
  * @since 2026-07-17
  */
 @Slf4j

+ 17 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/controller/algorithm/AlgorithmController.java

@@ -6,9 +6,12 @@ import com.hdkj.lt.si.modle.algorithm.IndicatorStatusResponse;
 import com.hdkj.lt.si.service.algorithm.AlgorithmService;
 import lombok.AllArgsConstructor;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.Map;
+
 /**
  * 算法服务接口
  *
@@ -30,4 +33,18 @@ public class AlgorithmController extends BaseController {
     public ApiResponse<IndicatorStatusResponse> queryIndicators() {
         return data(algorithmService.queryIndicators());
     }
+
+    /**
+     * 查询静态网架评估结果并入库
+     * <p>
+     * 入参:batchId(批次ID)、countyId(区县ID)
+     *
+     * @return 主表ID
+     */
+    @PostMapping(value = "/static-grid")
+    public ApiResponse<Long> queryStaticGridIndicators(@RequestBody Map<String, Object> params) {
+        String batchId = params.get("batchId") != null ? String.valueOf(params.get("batchId")) : null;
+        Integer countyId = params.get("countyId") != null ? Integer.valueOf(String.valueOf(params.get("countyId"))) : null;
+        return data(algorithmService.queryStaticGridIndicators(batchId, countyId));
+    }
 }

+ 12 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/dao/StaticIndicatorMetricMapper.java

@@ -0,0 +1,12 @@
+package com.hdkj.lt.si.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorMetric;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 静态网架评估指标明细 Mapper
+ */
+@Mapper
+public interface StaticIndicatorMetricMapper extends BaseMapper<StaticIndicatorMetric> {
+}

+ 12 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/dao/StaticIndicatorResultMapper.java

@@ -0,0 +1,12 @@
+package com.hdkj.lt.si.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorResult;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 静态网架评估结果主表 Mapper
+ */
+@Mapper
+public interface StaticIndicatorResultMapper extends BaseMapper<StaticIndicatorResult> {
+}

+ 12 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/dao/StaticProblemDetailMapper.java

@@ -0,0 +1,12 @@
+package com.hdkj.lt.si.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.si.entity.staticgrid.StaticProblemDetail;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 静态网架评估问题详情 Mapper
+ */
+@Mapper
+public interface StaticProblemDetailMapper extends BaseMapper<StaticProblemDetail> {
+}

+ 118 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/entity/staticgrid/StaticIndicatorMetric.java

@@ -0,0 +1,118 @@
+package com.hdkj.lt.si.entity.staticgrid;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 静态网架评估指标明细(t_static_indicator_metric)
+ * <p>
+ * 把算法返回的 county_result.categories[].metrics[] 和 feeder_results[].categories[].metrics[]
+ * 扁平化存储,每个指标一行。level 字段区分区县级/馈线级。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@TableName("t_static_indicator_metric")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class StaticIndicatorMetric implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 关联主表ID(t_static_indicator_result.id)
+     */
+    private Long resultId;
+
+    /**
+     * 指标级别:county / feeder
+     */
+    private String level;
+
+    /**
+     * 馈线ID(level=county 时为 null)
+     */
+    private String feederId;
+
+    /**
+     * 馈线名称(level=county 时为 null)
+     */
+    private String feederName;
+
+    /**
+     * 源变电站名称(level=county 时为 null)
+     */
+    private String sourceSubstationName;
+
+    /**
+     * 源母线ID(level=county 时为 null)
+     */
+    private String sourceBusId;
+
+    /**
+     * 供电区域类型(level=county 时为 null)
+     */
+    private String supplyAreaType;
+
+    /**
+     * 分类代码(basic_statistics / grid_standardization / interconnection / supply_capability)
+     */
+    private String categoryCode;
+
+    /**
+     * 分类名称
+     */
+    private String categoryName;
+
+    /**
+     * 指标代码
+     */
+    private String metricCode;
+
+    /**
+     * 指标名称
+     */
+    private String metricName;
+
+    /**
+     * 指标值(数值/boolean/string 统一存 varchar)
+     */
+    private String value;
+
+    /**
+     * 单位
+     */
+    private String unit;
+
+    /**
+     * 结果分类:normal / warning / problem / uncomputed
+     */
+    private String resultClass;
+
+    /**
+     * 严重程度:none / warning / critical
+     */
+    private String severity;
+
+    /**
+     * 计算状态:computed / estimated / partial / uncomputed
+     */
+    private String calculationStatus;
+
+    /**
+     * 是否为问题项(0/1)
+     */
+    private Integer isProblem;
+}

+ 104 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/entity/staticgrid/StaticIndicatorResult.java

@@ -0,0 +1,104 @@
+package com.hdkj.lt.si.entity.staticgrid;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 静态网架评估结果主表(t_static_indicator_result)
+ * <p>
+ * 一次算法调用对应一行,保存算法返回的完整 JSON 以及元信息。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@TableName("t_static_indicator_result")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class StaticIndicatorResult implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 批次ID(yyyyMMddHHmmssSSS)
+     */
+    private String batchId;
+
+    /**
+     * 区县ID
+     */
+    private Integer countyId;
+
+    /**
+     * 区县短标识
+     */
+    private String countySid;
+
+    /**
+     * 区县名称
+     */
+    private String countyName;
+
+    /**
+     * 馈线ID列表(逗号分隔)
+     */
+    private String feederIds;
+
+    /**
+     * 响应类型(static_grid_indicators)
+     */
+    private String responseType;
+
+    /**
+     * 请求ID
+     */
+    private String requestId;
+
+    /**
+     * 算法返回完整 JSON(longtext)
+     */
+    private String rawResponse;
+
+    /**
+     * 算法标识
+     */
+    private String algorithm;
+
+    /**
+     * 算法耗时(秒)
+     */
+    private BigDecimal durationSec;
+
+    /**
+     * 算法状态(success)
+     */
+    private String status;
+
+    /**
+     * 数据质量状态(partial / complete)
+     */
+    private String dataQualityStatus;
+
+    /**
+     * 数据完整率(%)
+     */
+    private BigDecimal dataQualityCompletenessRate;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 97 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/entity/staticgrid/StaticProblemDetail.java

@@ -0,0 +1,97 @@
+package com.hdkj.lt.si.entity.staticgrid;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 静态网架评估问题详情(t_static_problem_detail)
+ * <p>
+ * 算法返回的 problem_details 数组,每个问题一行。
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@TableName("t_static_problem_detail")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class StaticProblemDetail implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 关联主表ID(t_static_indicator_result.id)
+     */
+    private Long resultId;
+
+    /**
+     * 问题ID(P000001)
+     */
+    private String problemId;
+
+    /**
+     * 馈线ID
+     */
+    private String feederId;
+
+    /**
+     * 分类代码
+     */
+    private String categoryCode;
+
+    /**
+     * 分类名称
+     */
+    private String categoryName;
+
+    /**
+     * 指标代码
+     */
+    private String metricCode;
+
+    /**
+     * 指标名称
+     */
+    private String metricName;
+
+    /**
+     * 严重程度
+     */
+    private String severity;
+
+    /**
+     * 对象类型(feeder / branch)
+     */
+    private String objectType;
+
+    /**
+     * 对象ID
+     */
+    private String objectId;
+
+    /**
+     * 实际值(varchar)
+     */
+    private String actualValue;
+
+    /**
+     * 问题描述
+     */
+    private String description;
+
+    /**
+     * 整改建议
+     */
+    private String suggestion;
+}

+ 9 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/algorithm/AlgorithmService.java

@@ -13,4 +13,13 @@ public interface AlgorithmService {
      * @return 指标计算结果
      */
     IndicatorStatusResponse queryIndicators();
+
+    /**
+     * 查询静态网架评估结果并入库
+     *
+     * @param batchId  批次ID
+     * @param countyId 区县ID
+     * @return 主表ID
+     */
+    Long queryStaticGridIndicators(String batchId, Integer countyId);
 }

+ 8 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/algorithm/impl/AlgorithmServiceImpl.java

@@ -3,6 +3,7 @@ package com.hdkj.lt.si.service.algorithm.impl;
 import com.hdkj.lt.si.modle.algorithm.IndicatorStatusResponse;
 import com.hdkj.lt.si.service.algorithm.AlgorithmService;
 import com.hdkj.lt.si.service.remote.impl.AlgorithmRemoteCallServiceImpl;
+import com.hdkj.lt.si.service.staticgrid.StaticIndicatorResultService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -20,8 +21,15 @@ public class AlgorithmServiceImpl implements AlgorithmService {
     @Resource(type = AlgorithmRemoteCallServiceImpl.class)
     private AlgorithmRemoteCallServiceImpl algorithmRemoteCallService;
 
+    private final StaticIndicatorResultService staticIndicatorResultService;
+
     @Override
     public IndicatorStatusResponse queryIndicators() {
         return algorithmRemoteCallService.queryIndicators();
     }
+
+    @Override
+    public Long queryStaticGridIndicators(String batchId, Integer countyId) {
+        return staticIndicatorResultService.saveStaticGridResult(batchId, countyId);
+    }
 }

+ 41 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/remote/impl/AlgorithmRemoteCallServiceImpl.java

@@ -36,6 +36,9 @@ public class AlgorithmRemoteCallServiceImpl {
     @Value("${remote.algorithm.indicators-uri}")
     private String indicatorsUri;
 
+    @Value("${remote.algorithm.static-grid-uri}")
+    private String staticGridUri;
+
     /**
      * 调用指标计算接口
      *
@@ -71,4 +74,42 @@ public class AlgorithmRemoteCallServiceImpl {
             return null;
         }
     }
+
+    /**
+     * 调用静态网架评估接口
+     * <p>
+     * 算法返回完整 JSON(含 code/message/calculation_result 外壳),此处返回原始字符串,
+     * 由 Service 层解析入库。
+     *
+     * @return 算法返回的完整 JSON 字符串
+     */
+    public String queryStaticGridIndicators() {
+        String requestUrl = requestUri.concat(staticGridUri);
+        String requestBody = "{}";
+        try {
+            HttpHeaders headers = new HttpHeaders();
+            headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+            headers.set(HttpHeaders.ACCEPT_CHARSET, Charsets.UTF_8.toString());
+            HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers);
+
+            log.info("调用算法静态网架评估接口, requestUrl: {}", requestUrl);
+            ResponseEntity<String> responseEntity = restTemplate.postForEntity(
+                    requestUrl, httpEntity, String.class);
+
+            if (!responseEntity.getStatusCode().is2xxSuccessful() || Objects.isNull(responseEntity.getBody())) {
+                String errorMsg = String.format("调用算法静态网架评估接口失败, requestUrl: %s, response: %s",
+                        requestUrl, JSON.toJSONString(responseEntity));
+                log.error(errorMsg);
+                ExceptionCast.cast(errorMsg);
+            }
+
+            String result = responseEntity.getBody();
+            log.info("调用算法静态网架评估接口成功, requestUrl: {}, length: {}", requestUrl, result.length());
+            return result;
+        } catch (Exception e) {
+            log.error("调用算法静态网架评估接口异常, requestUrl: {}, errorMsg: {}", requestUrl, e.toString());
+            ExceptionCast.cast("调用算法静态网架评估接口失败: " + e.getMessage());
+            return null;
+        }
+    }
 }

+ 22 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/staticgrid/StaticIndicatorResultService.java

@@ -0,0 +1,22 @@
+package com.hdkj.lt.si.service.staticgrid;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorResult;
+
+/**
+ * 静态网架评估结果服务
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+public interface StaticIndicatorResultService extends IService<StaticIndicatorResult> {
+
+    /**
+     * 调用算法并解析入库
+     *
+     * @param batchId  批次ID
+     * @param countyId 区县ID
+     * @return 主表ID
+     */
+    Long saveStaticGridResult(String batchId, Integer countyId);
+}

+ 225 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/staticgrid/impl/StaticIndicatorResultServiceImpl.java

@@ -0,0 +1,225 @@
+package com.hdkj.lt.si.service.staticgrid.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hdkj.lt.si.dao.StaticIndicatorMetricMapper;
+import com.hdkj.lt.si.dao.StaticIndicatorResultMapper;
+import com.hdkj.lt.si.dao.StaticProblemDetailMapper;
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorMetric;
+import com.hdkj.lt.si.entity.staticgrid.StaticIndicatorResult;
+import com.hdkj.lt.si.entity.staticgrid.StaticProblemDetail;
+import com.hdkj.lt.si.service.remote.impl.AlgorithmRemoteCallServiceImpl;
+import com.hdkj.lt.si.service.staticgrid.StaticIndicatorResultService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 静态网架评估结果服务实现
+ * <p>
+ * 调用算法接口获取完整 JSON,解析后写入 3 张表:
+ * <ol>
+ *   <li>t_static_indicator_result  — 主表(一次计算一行)</li>
+ *   <li>t_static_indicator_metric  — 指标明细(county + feeder 两级扁平化)</li>
+ *   <li>t_static_problem_detail     — 问题详情</li>
+ * </ol>
+ *
+ * @author lsl
+ * @since 2026-07-19
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class StaticIndicatorResultServiceImpl
+        extends ServiceImpl<StaticIndicatorResultMapper, StaticIndicatorResult>
+        implements StaticIndicatorResultService {
+
+    private final StaticIndicatorMetricMapper metricMapper;
+    private final StaticProblemDetailMapper problemDetailMapper;
+
+    @Resource(type = AlgorithmRemoteCallServiceImpl.class)
+    private AlgorithmRemoteCallServiceImpl algorithmRemoteCallService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long saveStaticGridResult(String batchId, Integer countyId) {
+        // 1. 调算法
+        String rawResponse = algorithmRemoteCallService.queryStaticGridIndicators();
+        if (StringUtils.isBlank(rawResponse)) {
+            log.warn("静态网架评估接口返回空 batchId={}, countyId={}", batchId, countyId);
+            return null;
+        }
+
+        // 2. 解析顶层
+        JSONObject root = JSON.parseObject(rawResponse);
+        String responseType = root.getString("response_type");
+        String requestId = root.getString("request_id");
+
+        JSONObject countyBasicInfo = root.getJSONObject("county_basic_info");
+        String countySid = countyBasicInfo != null ? countyBasicInfo.getString("county_sid") : null;
+        String countyName = countyBasicInfo != null ? countyBasicInfo.getString("county_name") : null;
+        JSONArray feederIdsArr = countyBasicInfo != null ? countyBasicInfo.getJSONArray("feeder_ids") : null;
+        String feederIds = feederIdsArr != null ? String.join(",", feederIdsArr.toJavaList(String.class)) : null;
+
+        JSONObject calcResult = root.getJSONObject("calculation_result");
+        JSONObject countyResult = calcResult != null ? calcResult.getJSONObject("county_result") : null;
+
+        JSONObject dataQuality = calcResult != null ? calcResult.getJSONObject("data_quality") : null;
+        String dataQualityStatus = dataQuality != null ? dataQuality.getString("status") : null;
+        BigDecimal completenessRate = dataQuality != null ? dataQuality.getBigDecimal("completeness_rate") : null;
+
+        JSONObject processInfo = root.getJSONObject("process_info");
+        String algorithm = processInfo != null ? processInfo.getString("algorithm") : null;
+        BigDecimal durationSec = processInfo != null ? processInfo.getBigDecimal("duration_sec") : null;
+        String status = processInfo != null ? processInfo.getString("status") : null;
+
+        // 3. 写主表
+        StaticIndicatorResult mainRecord = StaticIndicatorResult.builder()
+                .batchId(batchId)
+                .countyId(countyId)
+                .countySid(countySid)
+                .countyName(countyName)
+                .feederIds(feederIds)
+                .responseType(responseType)
+                .requestId(requestId)
+                .rawResponse(rawResponse)
+                .algorithm(algorithm)
+                .durationSec(durationSec)
+                .status(status)
+                .dataQualityStatus(dataQualityStatus)
+                .dataQualityCompletenessRate(completenessRate)
+                .createTime(LocalDateTime.now())
+                .build();
+        save(mainRecord);
+        Long resultId = mainRecord.getId();
+
+        // 4. 写指标明细 — county 级
+        List<StaticIndicatorMetric> metricList = new ArrayList<StaticIndicatorMetric>();
+        if (countyResult != null) {
+            JSONArray categories = countyResult.getJSONArray("categories");
+            if (categories != null) {
+                for (int i = 0; i < categories.size(); i++) {
+                    JSONObject category = categories.getJSONObject(i);
+                    parseCategoryMetrics(category, resultId, "county", null, null, null, null, null, metricList);
+                }
+            }
+        }
+
+        // 5. 写指标明细 — feeder 级
+        if (calcResult != null) {
+            JSONArray feederResults = calcResult.getJSONArray("feeder_results");
+            if (feederResults != null) {
+                for (int i = 0; i < feederResults.size(); i++) {
+                    JSONObject feeder = feederResults.getJSONObject(i);
+                    String feederId = feeder.getString("feeder_id");
+                    String feederName = feeder.getString("feeder_name");
+                    String sourceSubstationName = feeder.getString("source_substation_name");
+                    String sourceBusId = feeder.getString("source_bus_id");
+                    String supplyAreaType = feeder.getString("supply_area_type");
+                    JSONArray feederCategories = feeder.getJSONArray("categories");
+                    if (feederCategories != null) {
+                        for (int j = 0; j < feederCategories.size(); j++) {
+                            JSONObject category = feederCategories.getJSONObject(j);
+                            parseCategoryMetrics(category, resultId, "feeder", feederId,
+                                    feederName, sourceSubstationName, sourceBusId, supplyAreaType,
+                                    metricList);
+                        }
+                    }
+                }
+            }
+        }
+        for (StaticIndicatorMetric m : metricList) {
+            metricMapper.insert(m);
+        }
+        log.info("静态网架指标明细入库完成 resultId={}, metricCount={}", resultId, metricList.size());
+
+        // 6. 写问题详情
+        if (calcResult != null) {
+            JSONArray problemDetails = calcResult.getJSONArray("problem_details");
+            if (problemDetails != null) {
+                int problemCount = 0;
+                for (int i = 0; i < problemDetails.size(); i++) {
+                    JSONObject p = problemDetails.getJSONObject(i);
+                    JSONObject actualValues = p.getJSONObject("actual_values");
+                    String actualValue = actualValues != null
+                            ? JSON.toJSONString(actualValues.get("value")) : null;
+
+                    StaticProblemDetail detail = StaticProblemDetail.builder()
+                            .resultId(resultId)
+                            .problemId(p.getString("problem_id"))
+                            .feederId(p.getString("feeder_id"))
+                            .categoryCode(p.getString("category_code"))
+                            .categoryName(p.getString("category_name"))
+                            .metricCode(p.getString("metric_code"))
+                            .metricName(p.getString("metric_name"))
+                            .severity(p.getString("severity"))
+                            .objectType(p.getString("object_type"))
+                            .objectId(p.getString("object_id"))
+                            .actualValue(actualValue)
+                            .description(p.getString("description"))
+                            .suggestion(p.getString("suggestion"))
+                            .build();
+                    problemDetailMapper.insert(detail);
+                    problemCount++;
+                }
+                log.info("静态网架问题详情入库完成 resultId={}, problemCount={}", resultId, problemCount);
+            }
+        }
+
+        log.info("静态网架评估入库完成 batchId={}, countyId={}, resultId={}", batchId, countyId, resultId);
+        return resultId;
+    }
+
+    /**
+     * 解析一个 category 下的 metrics 数组,追加到 metricList
+     */
+    private void parseCategoryMetrics(JSONObject category, Long resultId, String level,
+                                       String feederId, String feederName,
+                                       String sourceSubstationName, String sourceBusId,
+                                       String supplyAreaType,
+                                       List<StaticIndicatorMetric> metricList) {
+        String categoryCode = category.getString("category_code");
+        String categoryName = category.getString("category_name");
+        JSONArray metrics = category.getJSONArray("metrics");
+        if (metrics == null) {
+            return;
+        }
+        for (int i = 0; i < metrics.size(); i++) {
+            JSONObject m = metrics.getJSONObject(i);
+            Object valueObj = m.get("value");
+            String valueStr = valueObj == null ? null : String.valueOf(valueObj);
+
+            StaticIndicatorMetric metric = StaticIndicatorMetric.builder()
+                    .resultId(resultId)
+                    .level(level)
+                    .feederId(feederId)
+                    .feederName(feederName)
+                    .sourceSubstationName(sourceSubstationName)
+                    .sourceBusId(sourceBusId)
+                    .supplyAreaType(supplyAreaType)
+                    .categoryCode(categoryCode)
+                    .categoryName(categoryName)
+                    .metricCode(m.getString("metric_code"))
+                    .metricName(m.getString("metric_name"))
+                    .value(valueStr)
+                    .unit(m.getString("unit"))
+                    .resultClass(m.getString("result_class"))
+                    .severity(m.getString("severity"))
+                    .calculationStatus(m.getString("calculation_status"))
+                    .isProblem(m.getBoolean("is_problem") != null && m.getBoolean("is_problem") ? 1 : 0)
+                    .build();
+            metricList.add(metric);
+        }
+    }
+}