ソースを参照

方案重构参数重构,状估参数时间点调整

liuaini 2 週間 前
コミット
1094a1a5a4

+ 55 - 4
common/common-core/src/main/java/com/hdkj/lt/core/bizms/modle/dto/StateEstimation.java

@@ -5,6 +5,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 @Data
@@ -26,22 +27,22 @@ public class StateEstimation {
 //    /**
 //     *  公变状估数据集合
 //     */
-//    private List<StateEstimationSwitchResult> periodMVTransSeResult;
+    private List<StateEstimationTransResult> periodMVTransSeResult;
 //
 //    /**
 //     * 中压用户估数据集合
 //     */
-//    private List<StateEstimationSwitchResult> periodEnergyConsumerSeResult;
+    private List<StateEstimationConsumerResult> periodEnergyConsumerSeResult;
 //
 //    /**
 //     * 中压光伏状估数据集合
 //     */
-//    private List<StateEstimationSwitchResult> periodPVSeResult;
+    private List<StateEstimationCommonResult> periodPVSeResult;
 //
 //    /**
 //     * 线路段状估数据集合
 //     */
-//    private List<StateEstimationSwitchResult> periodSegmentSeResult;
+    private List<StateEstimationSegmentResult> periodSegmentSeResult;
 
     /**
      * 开关状估数据集合
@@ -101,6 +102,7 @@ public class StateEstimation {
          * 开关是否为自动化开关
          */
         private String isAuto;
+        private String feederId;
 
     }
 
@@ -124,4 +126,53 @@ public class StateEstimation {
         private String isAuto;
     }
 
+    /**
+     * 配变
+     */
+    @Data
+    public static class StateEstimationTransResult extends StateEstimationCommonResult {
+        /**
+         * 所属线路ID
+         */
+        private String feederId;
+        private List<String> capacitys;
+        private List<String> ploss;
+        private List<String> qloss;
+        private List<String> seoLvUs;
+        private List<String> seiLvPs;
+        private List<String> seiLvQs;
+        private List<String> seiLvUas;
+        private List<String> seiLvUbs;
+        private List<String> seiLvUcs;
+    }
+    /**
+     * 用户
+     */
+    @Data
+    public static class StateEstimationConsumerResult extends StateEstimationCommonResult {
+        /**
+         * 所属线路ID
+         */
+        private String feederId;
+        private List<String> consumerIds;
+        private List<String> capacitys;
+    }
+    /**
+     * 线路段
+     */
+    @Data
+    public static class StateEstimationSegmentResult extends StateEstimationCommonResult {
+        /**
+         * 所属线路ID
+         */
+        private String feederId;
+        private List<String> ploss;
+        private List<String> qloss;
+        private List<String> headUs;
+        private List<String> tailUs;
+        /** 首端电压相角 */
+        private List<String> headUAngs;
+        /** 末端电压相角 */
+        private List<String> tailUAngs;
+    }
 }

+ 68 - 0
common/common-core/src/main/java/com/hdkj/lt/core/bizms/modle/po/Jxz.java

@@ -0,0 +1,68 @@
+package com.hdkj.lt.core.bizms.modle.po;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 单元接线组负荷断面
+ * @TableName t_jxz
+ */
+@TableName(value ="t_jxz")
+@Data
+public class Jxz implements Serializable {
+    /**
+     * 接线组ID
+     */
+    @TableId
+    private String jxzId;
+
+    /**
+     * 接线组名称
+     */
+    private String jxzName;
+
+    /**
+     * 地市id
+     */
+    private String city;
+
+    /**
+     * 地市名称
+     */
+    private String cityName;
+
+    /**
+     * 图id
+     */
+    private Long fileId;
+
+    /**
+     * 区县id
+     */
+    private String maintOrg;
+
+    /**
+     * 区县名称
+     */
+    private String maintOrgName;
+
+    /**
+     * 接线组类型
+     */
+    private String jxzLabel;
+
+    /**
+     * 网格编码
+     */
+    private String gridCode;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+
+    @TableField(exist = false)
+    private String feederId;
+}

+ 25 - 0
common/common-core/src/main/java/com/hdkj/lt/core/sys/dao/JxzMapper.java

@@ -0,0 +1,25 @@
+package com.hdkj.lt.core.sys.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.core.bizms.modle.po.Jxz;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+* @author Sunlit
+* @description 针对表【t_jxz(单元接线组负荷断面)】的数据库操作Mapper
+* @createDate 2026-05-22 15:19:49
+* @Entity com.hdkj.lt.bf.entity.TJxz
+*/
+@Mapper
+public interface JxzMapper extends BaseMapper<Jxz> {
+
+   List<Jxz> queryJxzXl(@Param("feederId") String feederId);
+
+}
+
+
+
+

+ 29 - 0
common/common-core/src/main/resources/mapper/JxzMapper.xml

@@ -0,0 +1,29 @@
+<?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.core.sys.dao.JxzMapper">
+
+    <resultMap id="BaseResultMap" type="com.hdkj.lt.core.bizms.modle.po.Jxz">
+            <id property="jxzId" column="jxz_id" jdbcType="VARCHAR"/>
+            <result property="jxzName" column="jxz_name" jdbcType="VARCHAR"/>
+            <result property="city" column="city" jdbcType="VARCHAR"/>
+            <result property="cityName" column="city_name" jdbcType="VARCHAR"/>
+            <result property="maintOrg" column="maint_org" jdbcType="VARCHAR"/>
+            <result property="maintOrgName" column="maint_org_name" jdbcType="VARCHAR"/>
+            <result property="jxzLabel" column="jxz_label" jdbcType="VARCHAR"/>
+            <result property="gridCode" column="grid_code" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        jxz_id,jxz_name,city,
+        city_name,maint_org,maint_org_name,
+        jxz_label,grid_code
+    </sql>
+    <select id="queryJxzXl" resultType="com.hdkj.lt.core.bizms.modle.po.Jxz">
+        select j.*, rel.xlid feederId
+        from t_jxz j join t_jxz_xl rel on j.jxz_id = rel.jxz_id
+        where
+            j.jxz_id in(select jxz_id from t_jxz_xl where xlid=#{feederId})
+    </select>
+</mapper>

+ 35 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/config/EstimationAlgorithmProp.java

@@ -0,0 +1,35 @@
+package com.hdkj.lt.si.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description:
+ * @Author: LiuAini
+ * @Date 2026/7/24 16:52
+ */
+@Component
+@ConfigurationProperties(prefix = "estimation.algorithm")
+@Data
+public class EstimationAlgorithmProp {
+    private Map<String,Object> objectiveWeights;
+    private Double penaltyVoltage;
+    private Double penaltyLoadRate;
+    private Integer maxReturnSchemes;
+    private Map<String,Object> constraints;
+
+    // 转成外层完整Map,方便你之前构建RequestMap直接使用
+    public Map<String,Object> toAlgorithmConfigMap(){
+        Map<String,Object> map = new HashMap<>();
+        map.put("objective_weights", objectiveWeights);
+        map.put("penalty_voltage", penaltyVoltage);
+        map.put("penalty_load_rate", penaltyLoadRate);
+        map.put("max_return_schemes", maxReturnSchemes);
+        map.put("constraints", constraints);
+        return map;
+    }
+}

+ 15 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/controller/estimation/StateEstimationController.java

@@ -1,6 +1,7 @@
 package com.hdkj.lt.si.controller.estimation;
 
 
+import com.hdkj.fhzg.optimization.request.MaintOrgRequest;
 import com.hdkj.lt.core.bizms.modle.dto.StateEstimation;
 import com.hdkj.lt.core.bizms.modle.po.FhzgFeederAutoSwitchMapping;
 import com.hdkj.lt.core.bizms.modle.request.StateEstimationEquipRequest;
@@ -29,6 +30,7 @@ import java.util.List;
 public class StateEstimationController extends BaseController {
 
     private final StateEstimationService stateEstimationService;
+//    private final SePeriodCollectService sePeriodCollectService;
 
     @PostMapping(value = "/queryPeriodByFeeder")
 //    @AuditLog(moduleName = "分时段查询中压线路下设备节点状估数据", eventDesc = "分时段查询中压线路下设备节点状估数据", eventGrade = AuditEventGrade.SYSTEM_LOG_TYPE, evnetType = AuditEventType.QUERY)
@@ -59,4 +61,17 @@ public class StateEstimationController extends BaseController {
     public ApiResponse<List<FhzgFeederAutoSwitchMapping>> saveAutoSwitch(@Valid @RequestBody StateEstimationRequest request) {
         return data(stateEstimationService.saveAutoSwitch(request));
     }
+
+    @PostMapping(value = "/queryEquipByCounty")
+//    @AuditLog(moduleName = "根据区县查询设备状估结果", eventDesc = "根据区县查询设备状估结果", eventGrade = AuditEventGrade.SYSTEM_LOG_TYPE, evnetType = AuditEventType.QUERY)
+    public ApiResponse<List<StateEstimation>> queryEquipByCounty(@Valid @RequestBody MaintOrgRequest request) {
+        return data(stateEstimationService.queryEquipByCounty(request));
+    }
+//    @PostMapping(value = "/queryPeriodFeederByCounty")
+////    @AuditLog(moduleName = "根据区县查询设备状估结果", eventDesc = "根据区县查询设备状估结果", eventGrade = AuditEventGrade.SYSTEM_LOG_TYPE, evnetType = AuditEventType.QUERY)
+//    public <T>ApiResponse<T> queryPeriodFeederByCounty(@Valid @RequestBody MaintOrgRequest request) {
+//        sePeriodCollectService.collectLatestPoint(request.getMaintOrg());
+//        return success();
+//    }
+
 }

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

@@ -0,0 +1,55 @@
+package com.hdkj.lt.si.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.si.modle.FhzgStateEstimationFeeder;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+* @author Annie
+* @description 针对表【fhzg_state_estimation_feeder(线路日96点时序状估数据表(各时刻存储JSON结构化数据))】的数据库操作Mapper
+* @createDate 2026-07-23 15:41:31
+* @Entity generator.stateEstimation.FhzgStateEstimationFeeder
+*
+* <p>注: 工程启动类未启用 @MapperScan, 各 Mapper 需显式标注 @Mapper 才会被扫描(与 recon/bio/td 一致).</p>
+*/
+@Mapper
+public interface FhzgStateEstimationFeederMapper extends BaseMapper<FhzgStateEstimationFeeder> {
+
+    /**
+     * 按 (feeder, data_date) 查询主键 id, 用于 upsert 存在性判断. 轻量, 不读取 96 个 JSON 列.
+     *
+     * @param feeder   线路 ID
+     * @param dataDate 数据所属日期 yyyy-MM-dd
+     * @return 主键 id, 不存在返回 null
+     */
+    Long selectIdByFeederAndDate(@Param("feeder") String feeder, @Param("dataDate") String dataDate);
+
+    /**
+     * 更新某条 (feeder, data_date) 行的单一时刻列.
+     *
+     * @param feeder       线路 ID
+     * @param dataDate     数据所属日期 yyyy-MM-dd
+     * @param pointColumn  时刻列名, 形如 point_time_1200 (调用方已做白名单校验, 仅这 96 个合法值之一)
+     * @param json         该时刻结构化数据 JSON 字符串
+     * @return 影响行数
+     */
+    int updatePointTime(@Param("feeder") String feeder,
+                        @Param("dataDate") String dataDate,
+                        @Param("pointColumn") String pointColumn,
+                        @Param("json") String json);
+
+    /**
+     * 新建一条 (feeder, data_date) 行并写入单一时刻列, 其余时刻列留 null.
+     *
+     * @param feeder       线路 ID
+     * @param dataDate     数据所属日期 yyyy-MM-dd
+     * @param pointColumn  时刻列名, 形如 point_time_1200 (调用方已做白名单校验)
+     * @param json         该时刻结构化数据 JSON 字符串
+     * @return 影响行数
+     */
+    int insertPointTime(@Param("feeder") String feeder,
+                        @Param("dataDate") String dataDate,
+                        @Param("pointColumn") String pointColumn,
+                        @Param("json") String json);
+}

+ 937 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/modle/FhzgStateEstimationFeeder.java

@@ -0,0 +1,937 @@
+package com.hdkj.lt.si.modle;
+
+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 lombok.Data;
+
+/**
+ * 线路日96点时序状估数据表(各时刻存储JSON结构化数据)
+ * @TableName fhzg_state_estimation_feeder
+ */
+@TableName(value ="fhzg_state_estimation_feeder")
+@Data
+public class FhzgStateEstimationFeeder {
+    /**
+     * 自增主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 线路ID(馈线ID/psrId)
+     */
+    @TableField(value = "feeder")
+    private String feeder;
+
+    /**
+     * 数据所属日期
+     */
+    @TableField(value = "data_date")
+    private String dataDate;
+
+    /**
+     * 00:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0000")
+    private Object pointTime0000;
+
+    /**
+     * 00:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0015")
+    private Object pointTime0015;
+
+    /**
+     * 00:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0030")
+    private Object pointTime0030;
+
+    /**
+     * 00:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0045")
+    private Object pointTime0045;
+
+    /**
+     * 01:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0100")
+    private Object pointTime0100;
+
+    /**
+     * 01:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0115")
+    private Object pointTime0115;
+
+    /**
+     * 01:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0130")
+    private Object pointTime0130;
+
+    /**
+     * 01:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0145")
+    private Object pointTime0145;
+
+    /**
+     * 02:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0200")
+    private Object pointTime0200;
+
+    /**
+     * 02:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0215")
+    private Object pointTime0215;
+
+    /**
+     * 02:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0230")
+    private Object pointTime0230;
+
+    /**
+     * 02:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0245")
+    private Object pointTime0245;
+
+    /**
+     * 03:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0300")
+    private Object pointTime0300;
+
+    /**
+     * 03:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0315")
+    private Object pointTime0315;
+
+    /**
+     * 03:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0330")
+    private Object pointTime0330;
+
+    /**
+     * 03:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0345")
+    private Object pointTime0345;
+
+    /**
+     * 04:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0400")
+    private Object pointTime0400;
+
+    /**
+     * 04:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0415")
+    private Object pointTime0415;
+
+    /**
+     * 04:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0430")
+    private Object pointTime0430;
+
+    /**
+     * 04:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0445")
+    private Object pointTime0445;
+
+    /**
+     * 05:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0500")
+    private Object pointTime0500;
+
+    /**
+     * 05:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0515")
+    private Object pointTime0515;
+
+    /**
+     * 05:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0530")
+    private Object pointTime0530;
+
+    /**
+     * 05:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0545")
+    private Object pointTime0545;
+
+    /**
+     * 06:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0600")
+    private Object pointTime0600;
+
+    /**
+     * 06:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0615")
+    private Object pointTime0615;
+
+    /**
+     * 06:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0630")
+    private Object pointTime0630;
+
+    /**
+     * 06:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0645")
+    private Object pointTime0645;
+
+    /**
+     * 07:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0700")
+    private Object pointTime0700;
+
+    /**
+     * 07:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0715")
+    private Object pointTime0715;
+
+    /**
+     * 07:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0730")
+    private Object pointTime0730;
+
+    /**
+     * 07:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0745")
+    private Object pointTime0745;
+
+    /**
+     * 08:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0800")
+    private Object pointTime0800;
+
+    /**
+     * 08:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0815")
+    private Object pointTime0815;
+
+    /**
+     * 08:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0830")
+    private Object pointTime0830;
+
+    /**
+     * 08:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0845")
+    private Object pointTime0845;
+
+    /**
+     * 09:00时刻结构化数据
+     */
+    @TableField(value = "point_time_0900")
+    private Object pointTime0900;
+
+    /**
+     * 09:15时刻结构化数据
+     */
+    @TableField(value = "point_time_0915")
+    private Object pointTime0915;
+
+    /**
+     * 09:30时刻结构化数据
+     */
+    @TableField(value = "point_time_0930")
+    private Object pointTime0930;
+
+    /**
+     * 09:45时刻结构化数据
+     */
+    @TableField(value = "point_time_0945")
+    private Object pointTime0945;
+
+    /**
+     * 10:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1000")
+    private Object pointTime1000;
+
+    /**
+     * 10:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1015")
+    private Object pointTime1015;
+
+    /**
+     * 10:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1030")
+    private Object pointTime1030;
+
+    /**
+     * 10:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1045")
+    private Object pointTime1045;
+
+    /**
+     * 11:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1100")
+    private Object pointTime1100;
+
+    /**
+     * 11:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1115")
+    private Object pointTime1115;
+
+    /**
+     * 11:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1130")
+    private Object pointTime1130;
+
+    /**
+     * 11:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1145")
+    private Object pointTime1145;
+
+    /**
+     * 12:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1200")
+    private Object pointTime1200;
+
+    /**
+     * 12:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1215")
+    private Object pointTime1215;
+
+    /**
+     * 12:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1230")
+    private Object pointTime1230;
+
+    /**
+     * 12:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1245")
+    private Object pointTime1245;
+
+    /**
+     * 13:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1300")
+    private Object pointTime1300;
+
+    /**
+     * 13:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1315")
+    private Object pointTime1315;
+
+    /**
+     * 13:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1330")
+    private Object pointTime1330;
+
+    /**
+     * 13:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1345")
+    private Object pointTime1345;
+
+    /**
+     * 14:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1400")
+    private Object pointTime1400;
+
+    /**
+     * 14:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1415")
+    private Object pointTime1415;
+
+    /**
+     * 14:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1430")
+    private Object pointTime1430;
+
+    /**
+     * 14:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1445")
+    private Object pointTime1445;
+
+    /**
+     * 15:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1500")
+    private Object pointTime1500;
+
+    /**
+     * 15:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1515")
+    private Object pointTime1515;
+
+    /**
+     * 15:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1530")
+    private Object pointTime1530;
+
+    /**
+     * 15:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1545")
+    private Object pointTime1545;
+
+    /**
+     * 16:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1600")
+    private Object pointTime1600;
+
+    /**
+     * 16:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1615")
+    private Object pointTime1615;
+
+    /**
+     * 16:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1630")
+    private Object pointTime1630;
+
+    /**
+     * 16:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1645")
+    private Object pointTime1645;
+
+    /**
+     * 17:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1700")
+    private Object pointTime1700;
+
+    /**
+     * 17:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1715")
+    private Object pointTime1715;
+
+    /**
+     * 17:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1730")
+    private Object pointTime1730;
+
+    /**
+     * 17:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1745")
+    private Object pointTime1745;
+
+    /**
+     * 18:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1800")
+    private Object pointTime1800;
+
+    /**
+     * 18:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1815")
+    private Object pointTime1815;
+
+    /**
+     * 18:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1830")
+    private Object pointTime1830;
+
+    /**
+     * 18:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1845")
+    private Object pointTime1845;
+
+    /**
+     * 19:00时刻结构化数据
+     */
+    @TableField(value = "point_time_1900")
+    private Object pointTime1900;
+
+    /**
+     * 19:15时刻结构化数据
+     */
+    @TableField(value = "point_time_1915")
+    private Object pointTime1915;
+
+    /**
+     * 19:30时刻结构化数据
+     */
+    @TableField(value = "point_time_1930")
+    private Object pointTime1930;
+
+    /**
+     * 19:45时刻结构化数据
+     */
+    @TableField(value = "point_time_1945")
+    private Object pointTime1945;
+
+    /**
+     * 20:00时刻结构化数据
+     */
+    @TableField(value = "point_time_2000")
+    private Object pointTime2000;
+
+    /**
+     * 20:15时刻结构化数据
+     */
+    @TableField(value = "point_time_2015")
+    private Object pointTime2015;
+
+    /**
+     * 20:30时刻结构化数据
+     */
+    @TableField(value = "point_time_2030")
+    private Object pointTime2030;
+
+    /**
+     * 20:45时刻结构化数据
+     */
+    @TableField(value = "point_time_2045")
+    private Object pointTime2045;
+
+    /**
+     * 21:00时刻结构化数据
+     */
+    @TableField(value = "point_time_2100")
+    private Object pointTime2100;
+
+    /**
+     * 21:15时刻结构化数据
+     */
+    @TableField(value = "point_time_2115")
+    private Object pointTime2115;
+
+    /**
+     * 21:30时刻结构化数据
+     */
+    @TableField(value = "point_time_2130")
+    private Object pointTime2130;
+
+    /**
+     * 21:45时刻结构化数据
+     */
+    @TableField(value = "point_time_2145")
+    private Object pointTime2145;
+
+    /**
+     * 22:00时刻结构化数据
+     */
+    @TableField(value = "point_time_2200")
+    private Object pointTime2200;
+
+    /**
+     * 22:15时刻结构化数据
+     */
+    @TableField(value = "point_time_2215")
+    private Object pointTime2215;
+
+    /**
+     * 22:30时刻结构化数据
+     */
+    @TableField(value = "point_time_2230")
+    private Object pointTime2230;
+
+    /**
+     * 22:45时刻结构化数据
+     */
+    @TableField(value = "point_time_2245")
+    private Object pointTime2245;
+
+    /**
+     * 23:00时刻结构化数据
+     */
+    @TableField(value = "point_time_2300")
+    private Object pointTime2300;
+
+    /**
+     * 23:15时刻结构化数据
+     */
+    @TableField(value = "point_time_2315")
+    private Object pointTime2315;
+
+    /**
+     * 23:30时刻结构化数据
+     */
+    @TableField(value = "point_time_2330")
+    private Object pointTime2330;
+
+    /**
+     * 23:45时刻结构化数据
+     */
+    @TableField(value = "point_time_2345")
+    private Object pointTime2345;
+
+    @Override
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        FhzgStateEstimationFeeder other = (FhzgStateEstimationFeeder) that;
+        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+            && (this.getFeeder() == null ? other.getFeeder() == null : this.getFeeder().equals(other.getFeeder()))
+            && (this.getDataDate() == null ? other.getDataDate() == null : this.getDataDate().equals(other.getDataDate()))
+            && (this.getPointTime0000() == null ? other.getPointTime0000() == null : this.getPointTime0000().equals(other.getPointTime0000()))
+            && (this.getPointTime0015() == null ? other.getPointTime0015() == null : this.getPointTime0015().equals(other.getPointTime0015()))
+            && (this.getPointTime0030() == null ? other.getPointTime0030() == null : this.getPointTime0030().equals(other.getPointTime0030()))
+            && (this.getPointTime0045() == null ? other.getPointTime0045() == null : this.getPointTime0045().equals(other.getPointTime0045()))
+            && (this.getPointTime0100() == null ? other.getPointTime0100() == null : this.getPointTime0100().equals(other.getPointTime0100()))
+            && (this.getPointTime0115() == null ? other.getPointTime0115() == null : this.getPointTime0115().equals(other.getPointTime0115()))
+            && (this.getPointTime0130() == null ? other.getPointTime0130() == null : this.getPointTime0130().equals(other.getPointTime0130()))
+            && (this.getPointTime0145() == null ? other.getPointTime0145() == null : this.getPointTime0145().equals(other.getPointTime0145()))
+            && (this.getPointTime0200() == null ? other.getPointTime0200() == null : this.getPointTime0200().equals(other.getPointTime0200()))
+            && (this.getPointTime0215() == null ? other.getPointTime0215() == null : this.getPointTime0215().equals(other.getPointTime0215()))
+            && (this.getPointTime0230() == null ? other.getPointTime0230() == null : this.getPointTime0230().equals(other.getPointTime0230()))
+            && (this.getPointTime0245() == null ? other.getPointTime0245() == null : this.getPointTime0245().equals(other.getPointTime0245()))
+            && (this.getPointTime0300() == null ? other.getPointTime0300() == null : this.getPointTime0300().equals(other.getPointTime0300()))
+            && (this.getPointTime0315() == null ? other.getPointTime0315() == null : this.getPointTime0315().equals(other.getPointTime0315()))
+            && (this.getPointTime0330() == null ? other.getPointTime0330() == null : this.getPointTime0330().equals(other.getPointTime0330()))
+            && (this.getPointTime0345() == null ? other.getPointTime0345() == null : this.getPointTime0345().equals(other.getPointTime0345()))
+            && (this.getPointTime0400() == null ? other.getPointTime0400() == null : this.getPointTime0400().equals(other.getPointTime0400()))
+            && (this.getPointTime0415() == null ? other.getPointTime0415() == null : this.getPointTime0415().equals(other.getPointTime0415()))
+            && (this.getPointTime0430() == null ? other.getPointTime0430() == null : this.getPointTime0430().equals(other.getPointTime0430()))
+            && (this.getPointTime0445() == null ? other.getPointTime0445() == null : this.getPointTime0445().equals(other.getPointTime0445()))
+            && (this.getPointTime0500() == null ? other.getPointTime0500() == null : this.getPointTime0500().equals(other.getPointTime0500()))
+            && (this.getPointTime0515() == null ? other.getPointTime0515() == null : this.getPointTime0515().equals(other.getPointTime0515()))
+            && (this.getPointTime0530() == null ? other.getPointTime0530() == null : this.getPointTime0530().equals(other.getPointTime0530()))
+            && (this.getPointTime0545() == null ? other.getPointTime0545() == null : this.getPointTime0545().equals(other.getPointTime0545()))
+            && (this.getPointTime0600() == null ? other.getPointTime0600() == null : this.getPointTime0600().equals(other.getPointTime0600()))
+            && (this.getPointTime0615() == null ? other.getPointTime0615() == null : this.getPointTime0615().equals(other.getPointTime0615()))
+            && (this.getPointTime0630() == null ? other.getPointTime0630() == null : this.getPointTime0630().equals(other.getPointTime0630()))
+            && (this.getPointTime0645() == null ? other.getPointTime0645() == null : this.getPointTime0645().equals(other.getPointTime0645()))
+            && (this.getPointTime0700() == null ? other.getPointTime0700() == null : this.getPointTime0700().equals(other.getPointTime0700()))
+            && (this.getPointTime0715() == null ? other.getPointTime0715() == null : this.getPointTime0715().equals(other.getPointTime0715()))
+            && (this.getPointTime0730() == null ? other.getPointTime0730() == null : this.getPointTime0730().equals(other.getPointTime0730()))
+            && (this.getPointTime0745() == null ? other.getPointTime0745() == null : this.getPointTime0745().equals(other.getPointTime0745()))
+            && (this.getPointTime0800() == null ? other.getPointTime0800() == null : this.getPointTime0800().equals(other.getPointTime0800()))
+            && (this.getPointTime0815() == null ? other.getPointTime0815() == null : this.getPointTime0815().equals(other.getPointTime0815()))
+            && (this.getPointTime0830() == null ? other.getPointTime0830() == null : this.getPointTime0830().equals(other.getPointTime0830()))
+            && (this.getPointTime0845() == null ? other.getPointTime0845() == null : this.getPointTime0845().equals(other.getPointTime0845()))
+            && (this.getPointTime0900() == null ? other.getPointTime0900() == null : this.getPointTime0900().equals(other.getPointTime0900()))
+            && (this.getPointTime0915() == null ? other.getPointTime0915() == null : this.getPointTime0915().equals(other.getPointTime0915()))
+            && (this.getPointTime0930() == null ? other.getPointTime0930() == null : this.getPointTime0930().equals(other.getPointTime0930()))
+            && (this.getPointTime0945() == null ? other.getPointTime0945() == null : this.getPointTime0945().equals(other.getPointTime0945()))
+            && (this.getPointTime1000() == null ? other.getPointTime1000() == null : this.getPointTime1000().equals(other.getPointTime1000()))
+            && (this.getPointTime1015() == null ? other.getPointTime1015() == null : this.getPointTime1015().equals(other.getPointTime1015()))
+            && (this.getPointTime1030() == null ? other.getPointTime1030() == null : this.getPointTime1030().equals(other.getPointTime1030()))
+            && (this.getPointTime1045() == null ? other.getPointTime1045() == null : this.getPointTime1045().equals(other.getPointTime1045()))
+            && (this.getPointTime1100() == null ? other.getPointTime1100() == null : this.getPointTime1100().equals(other.getPointTime1100()))
+            && (this.getPointTime1115() == null ? other.getPointTime1115() == null : this.getPointTime1115().equals(other.getPointTime1115()))
+            && (this.getPointTime1130() == null ? other.getPointTime1130() == null : this.getPointTime1130().equals(other.getPointTime1130()))
+            && (this.getPointTime1145() == null ? other.getPointTime1145() == null : this.getPointTime1145().equals(other.getPointTime1145()))
+            && (this.getPointTime1200() == null ? other.getPointTime1200() == null : this.getPointTime1200().equals(other.getPointTime1200()))
+            && (this.getPointTime1215() == null ? other.getPointTime1215() == null : this.getPointTime1215().equals(other.getPointTime1215()))
+            && (this.getPointTime1230() == null ? other.getPointTime1230() == null : this.getPointTime1230().equals(other.getPointTime1230()))
+            && (this.getPointTime1245() == null ? other.getPointTime1245() == null : this.getPointTime1245().equals(other.getPointTime1245()))
+            && (this.getPointTime1300() == null ? other.getPointTime1300() == null : this.getPointTime1300().equals(other.getPointTime1300()))
+            && (this.getPointTime1315() == null ? other.getPointTime1315() == null : this.getPointTime1315().equals(other.getPointTime1315()))
+            && (this.getPointTime1330() == null ? other.getPointTime1330() == null : this.getPointTime1330().equals(other.getPointTime1330()))
+            && (this.getPointTime1345() == null ? other.getPointTime1345() == null : this.getPointTime1345().equals(other.getPointTime1345()))
+            && (this.getPointTime1400() == null ? other.getPointTime1400() == null : this.getPointTime1400().equals(other.getPointTime1400()))
+            && (this.getPointTime1415() == null ? other.getPointTime1415() == null : this.getPointTime1415().equals(other.getPointTime1415()))
+            && (this.getPointTime1430() == null ? other.getPointTime1430() == null : this.getPointTime1430().equals(other.getPointTime1430()))
+            && (this.getPointTime1445() == null ? other.getPointTime1445() == null : this.getPointTime1445().equals(other.getPointTime1445()))
+            && (this.getPointTime1500() == null ? other.getPointTime1500() == null : this.getPointTime1500().equals(other.getPointTime1500()))
+            && (this.getPointTime1515() == null ? other.getPointTime1515() == null : this.getPointTime1515().equals(other.getPointTime1515()))
+            && (this.getPointTime1530() == null ? other.getPointTime1530() == null : this.getPointTime1530().equals(other.getPointTime1530()))
+            && (this.getPointTime1545() == null ? other.getPointTime1545() == null : this.getPointTime1545().equals(other.getPointTime1545()))
+            && (this.getPointTime1600() == null ? other.getPointTime1600() == null : this.getPointTime1600().equals(other.getPointTime1600()))
+            && (this.getPointTime1615() == null ? other.getPointTime1615() == null : this.getPointTime1615().equals(other.getPointTime1615()))
+            && (this.getPointTime1630() == null ? other.getPointTime1630() == null : this.getPointTime1630().equals(other.getPointTime1630()))
+            && (this.getPointTime1645() == null ? other.getPointTime1645() == null : this.getPointTime1645().equals(other.getPointTime1645()))
+            && (this.getPointTime1700() == null ? other.getPointTime1700() == null : this.getPointTime1700().equals(other.getPointTime1700()))
+            && (this.getPointTime1715() == null ? other.getPointTime1715() == null : this.getPointTime1715().equals(other.getPointTime1715()))
+            && (this.getPointTime1730() == null ? other.getPointTime1730() == null : this.getPointTime1730().equals(other.getPointTime1730()))
+            && (this.getPointTime1745() == null ? other.getPointTime1745() == null : this.getPointTime1745().equals(other.getPointTime1745()))
+            && (this.getPointTime1800() == null ? other.getPointTime1800() == null : this.getPointTime1800().equals(other.getPointTime1800()))
+            && (this.getPointTime1815() == null ? other.getPointTime1815() == null : this.getPointTime1815().equals(other.getPointTime1815()))
+            && (this.getPointTime1830() == null ? other.getPointTime1830() == null : this.getPointTime1830().equals(other.getPointTime1830()))
+            && (this.getPointTime1845() == null ? other.getPointTime1845() == null : this.getPointTime1845().equals(other.getPointTime1845()))
+            && (this.getPointTime1900() == null ? other.getPointTime1900() == null : this.getPointTime1900().equals(other.getPointTime1900()))
+            && (this.getPointTime1915() == null ? other.getPointTime1915() == null : this.getPointTime1915().equals(other.getPointTime1915()))
+            && (this.getPointTime1930() == null ? other.getPointTime1930() == null : this.getPointTime1930().equals(other.getPointTime1930()))
+            && (this.getPointTime1945() == null ? other.getPointTime1945() == null : this.getPointTime1945().equals(other.getPointTime1945()))
+            && (this.getPointTime2000() == null ? other.getPointTime2000() == null : this.getPointTime2000().equals(other.getPointTime2000()))
+            && (this.getPointTime2015() == null ? other.getPointTime2015() == null : this.getPointTime2015().equals(other.getPointTime2015()))
+            && (this.getPointTime2030() == null ? other.getPointTime2030() == null : this.getPointTime2030().equals(other.getPointTime2030()))
+            && (this.getPointTime2045() == null ? other.getPointTime2045() == null : this.getPointTime2045().equals(other.getPointTime2045()))
+            && (this.getPointTime2100() == null ? other.getPointTime2100() == null : this.getPointTime2100().equals(other.getPointTime2100()))
+            && (this.getPointTime2115() == null ? other.getPointTime2115() == null : this.getPointTime2115().equals(other.getPointTime2115()))
+            && (this.getPointTime2130() == null ? other.getPointTime2130() == null : this.getPointTime2130().equals(other.getPointTime2130()))
+            && (this.getPointTime2145() == null ? other.getPointTime2145() == null : this.getPointTime2145().equals(other.getPointTime2145()))
+            && (this.getPointTime2200() == null ? other.getPointTime2200() == null : this.getPointTime2200().equals(other.getPointTime2200()))
+            && (this.getPointTime2215() == null ? other.getPointTime2215() == null : this.getPointTime2215().equals(other.getPointTime2215()))
+            && (this.getPointTime2230() == null ? other.getPointTime2230() == null : this.getPointTime2230().equals(other.getPointTime2230()))
+            && (this.getPointTime2245() == null ? other.getPointTime2245() == null : this.getPointTime2245().equals(other.getPointTime2245()))
+            && (this.getPointTime2300() == null ? other.getPointTime2300() == null : this.getPointTime2300().equals(other.getPointTime2300()))
+            && (this.getPointTime2315() == null ? other.getPointTime2315() == null : this.getPointTime2315().equals(other.getPointTime2315()))
+            && (this.getPointTime2330() == null ? other.getPointTime2330() == null : this.getPointTime2330().equals(other.getPointTime2330()))
+            && (this.getPointTime2345() == null ? other.getPointTime2345() == null : this.getPointTime2345().equals(other.getPointTime2345()));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+        result = prime * result + ((getFeeder() == null) ? 0 : getFeeder().hashCode());
+        result = prime * result + ((getDataDate() == null) ? 0 : getDataDate().hashCode());
+        result = prime * result + ((getPointTime0000() == null) ? 0 : getPointTime0000().hashCode());
+        result = prime * result + ((getPointTime0015() == null) ? 0 : getPointTime0015().hashCode());
+        result = prime * result + ((getPointTime0030() == null) ? 0 : getPointTime0030().hashCode());
+        result = prime * result + ((getPointTime0045() == null) ? 0 : getPointTime0045().hashCode());
+        result = prime * result + ((getPointTime0100() == null) ? 0 : getPointTime0100().hashCode());
+        result = prime * result + ((getPointTime0115() == null) ? 0 : getPointTime0115().hashCode());
+        result = prime * result + ((getPointTime0130() == null) ? 0 : getPointTime0130().hashCode());
+        result = prime * result + ((getPointTime0145() == null) ? 0 : getPointTime0145().hashCode());
+        result = prime * result + ((getPointTime0200() == null) ? 0 : getPointTime0200().hashCode());
+        result = prime * result + ((getPointTime0215() == null) ? 0 : getPointTime0215().hashCode());
+        result = prime * result + ((getPointTime0230() == null) ? 0 : getPointTime0230().hashCode());
+        result = prime * result + ((getPointTime0245() == null) ? 0 : getPointTime0245().hashCode());
+        result = prime * result + ((getPointTime0300() == null) ? 0 : getPointTime0300().hashCode());
+        result = prime * result + ((getPointTime0315() == null) ? 0 : getPointTime0315().hashCode());
+        result = prime * result + ((getPointTime0330() == null) ? 0 : getPointTime0330().hashCode());
+        result = prime * result + ((getPointTime0345() == null) ? 0 : getPointTime0345().hashCode());
+        result = prime * result + ((getPointTime0400() == null) ? 0 : getPointTime0400().hashCode());
+        result = prime * result + ((getPointTime0415() == null) ? 0 : getPointTime0415().hashCode());
+        result = prime * result + ((getPointTime0430() == null) ? 0 : getPointTime0430().hashCode());
+        result = prime * result + ((getPointTime0445() == null) ? 0 : getPointTime0445().hashCode());
+        result = prime * result + ((getPointTime0500() == null) ? 0 : getPointTime0500().hashCode());
+        result = prime * result + ((getPointTime0515() == null) ? 0 : getPointTime0515().hashCode());
+        result = prime * result + ((getPointTime0530() == null) ? 0 : getPointTime0530().hashCode());
+        result = prime * result + ((getPointTime0545() == null) ? 0 : getPointTime0545().hashCode());
+        result = prime * result + ((getPointTime0600() == null) ? 0 : getPointTime0600().hashCode());
+        result = prime * result + ((getPointTime0615() == null) ? 0 : getPointTime0615().hashCode());
+        result = prime * result + ((getPointTime0630() == null) ? 0 : getPointTime0630().hashCode());
+        result = prime * result + ((getPointTime0645() == null) ? 0 : getPointTime0645().hashCode());
+        result = prime * result + ((getPointTime0700() == null) ? 0 : getPointTime0700().hashCode());
+        result = prime * result + ((getPointTime0715() == null) ? 0 : getPointTime0715().hashCode());
+        result = prime * result + ((getPointTime0730() == null) ? 0 : getPointTime0730().hashCode());
+        result = prime * result + ((getPointTime0745() == null) ? 0 : getPointTime0745().hashCode());
+        result = prime * result + ((getPointTime0800() == null) ? 0 : getPointTime0800().hashCode());
+        result = prime * result + ((getPointTime0815() == null) ? 0 : getPointTime0815().hashCode());
+        result = prime * result + ((getPointTime0830() == null) ? 0 : getPointTime0830().hashCode());
+        result = prime * result + ((getPointTime0845() == null) ? 0 : getPointTime0845().hashCode());
+        result = prime * result + ((getPointTime0900() == null) ? 0 : getPointTime0900().hashCode());
+        result = prime * result + ((getPointTime0915() == null) ? 0 : getPointTime0915().hashCode());
+        result = prime * result + ((getPointTime0930() == null) ? 0 : getPointTime0930().hashCode());
+        result = prime * result + ((getPointTime0945() == null) ? 0 : getPointTime0945().hashCode());
+        result = prime * result + ((getPointTime1000() == null) ? 0 : getPointTime1000().hashCode());
+        result = prime * result + ((getPointTime1015() == null) ? 0 : getPointTime1015().hashCode());
+        result = prime * result + ((getPointTime1030() == null) ? 0 : getPointTime1030().hashCode());
+        result = prime * result + ((getPointTime1045() == null) ? 0 : getPointTime1045().hashCode());
+        result = prime * result + ((getPointTime1100() == null) ? 0 : getPointTime1100().hashCode());
+        result = prime * result + ((getPointTime1115() == null) ? 0 : getPointTime1115().hashCode());
+        result = prime * result + ((getPointTime1130() == null) ? 0 : getPointTime1130().hashCode());
+        result = prime * result + ((getPointTime1145() == null) ? 0 : getPointTime1145().hashCode());
+        result = prime * result + ((getPointTime1200() == null) ? 0 : getPointTime1200().hashCode());
+        result = prime * result + ((getPointTime1215() == null) ? 0 : getPointTime1215().hashCode());
+        result = prime * result + ((getPointTime1230() == null) ? 0 : getPointTime1230().hashCode());
+        result = prime * result + ((getPointTime1245() == null) ? 0 : getPointTime1245().hashCode());
+        result = prime * result + ((getPointTime1300() == null) ? 0 : getPointTime1300().hashCode());
+        result = prime * result + ((getPointTime1315() == null) ? 0 : getPointTime1315().hashCode());
+        result = prime * result + ((getPointTime1330() == null) ? 0 : getPointTime1330().hashCode());
+        result = prime * result + ((getPointTime1345() == null) ? 0 : getPointTime1345().hashCode());
+        result = prime * result + ((getPointTime1400() == null) ? 0 : getPointTime1400().hashCode());
+        result = prime * result + ((getPointTime1415() == null) ? 0 : getPointTime1415().hashCode());
+        result = prime * result + ((getPointTime1430() == null) ? 0 : getPointTime1430().hashCode());
+        result = prime * result + ((getPointTime1445() == null) ? 0 : getPointTime1445().hashCode());
+        result = prime * result + ((getPointTime1500() == null) ? 0 : getPointTime1500().hashCode());
+        result = prime * result + ((getPointTime1515() == null) ? 0 : getPointTime1515().hashCode());
+        result = prime * result + ((getPointTime1530() == null) ? 0 : getPointTime1530().hashCode());
+        result = prime * result + ((getPointTime1545() == null) ? 0 : getPointTime1545().hashCode());
+        result = prime * result + ((getPointTime1600() == null) ? 0 : getPointTime1600().hashCode());
+        result = prime * result + ((getPointTime1615() == null) ? 0 : getPointTime1615().hashCode());
+        result = prime * result + ((getPointTime1630() == null) ? 0 : getPointTime1630().hashCode());
+        result = prime * result + ((getPointTime1645() == null) ? 0 : getPointTime1645().hashCode());
+        result = prime * result + ((getPointTime1700() == null) ? 0 : getPointTime1700().hashCode());
+        result = prime * result + ((getPointTime1715() == null) ? 0 : getPointTime1715().hashCode());
+        result = prime * result + ((getPointTime1730() == null) ? 0 : getPointTime1730().hashCode());
+        result = prime * result + ((getPointTime1745() == null) ? 0 : getPointTime1745().hashCode());
+        result = prime * result + ((getPointTime1800() == null) ? 0 : getPointTime1800().hashCode());
+        result = prime * result + ((getPointTime1815() == null) ? 0 : getPointTime1815().hashCode());
+        result = prime * result + ((getPointTime1830() == null) ? 0 : getPointTime1830().hashCode());
+        result = prime * result + ((getPointTime1845() == null) ? 0 : getPointTime1845().hashCode());
+        result = prime * result + ((getPointTime1900() == null) ? 0 : getPointTime1900().hashCode());
+        result = prime * result + ((getPointTime1915() == null) ? 0 : getPointTime1915().hashCode());
+        result = prime * result + ((getPointTime1930() == null) ? 0 : getPointTime1930().hashCode());
+        result = prime * result + ((getPointTime1945() == null) ? 0 : getPointTime1945().hashCode());
+        result = prime * result + ((getPointTime2000() == null) ? 0 : getPointTime2000().hashCode());
+        result = prime * result + ((getPointTime2015() == null) ? 0 : getPointTime2015().hashCode());
+        result = prime * result + ((getPointTime2030() == null) ? 0 : getPointTime2030().hashCode());
+        result = prime * result + ((getPointTime2045() == null) ? 0 : getPointTime2045().hashCode());
+        result = prime * result + ((getPointTime2100() == null) ? 0 : getPointTime2100().hashCode());
+        result = prime * result + ((getPointTime2115() == null) ? 0 : getPointTime2115().hashCode());
+        result = prime * result + ((getPointTime2130() == null) ? 0 : getPointTime2130().hashCode());
+        result = prime * result + ((getPointTime2145() == null) ? 0 : getPointTime2145().hashCode());
+        result = prime * result + ((getPointTime2200() == null) ? 0 : getPointTime2200().hashCode());
+        result = prime * result + ((getPointTime2215() == null) ? 0 : getPointTime2215().hashCode());
+        result = prime * result + ((getPointTime2230() == null) ? 0 : getPointTime2230().hashCode());
+        result = prime * result + ((getPointTime2245() == null) ? 0 : getPointTime2245().hashCode());
+        result = prime * result + ((getPointTime2300() == null) ? 0 : getPointTime2300().hashCode());
+        result = prime * result + ((getPointTime2315() == null) ? 0 : getPointTime2315().hashCode());
+        result = prime * result + ((getPointTime2330() == null) ? 0 : getPointTime2330().hashCode());
+        result = prime * result + ((getPointTime2345() == null) ? 0 : getPointTime2345().hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", feeder=").append(feeder);
+        sb.append(", dataDate=").append(dataDate);
+        sb.append(", pointTime0000=").append(pointTime0000);
+        sb.append(", pointTime0015=").append(pointTime0015);
+        sb.append(", pointTime0030=").append(pointTime0030);
+        sb.append(", pointTime0045=").append(pointTime0045);
+        sb.append(", pointTime0100=").append(pointTime0100);
+        sb.append(", pointTime0115=").append(pointTime0115);
+        sb.append(", pointTime0130=").append(pointTime0130);
+        sb.append(", pointTime0145=").append(pointTime0145);
+        sb.append(", pointTime0200=").append(pointTime0200);
+        sb.append(", pointTime0215=").append(pointTime0215);
+        sb.append(", pointTime0230=").append(pointTime0230);
+        sb.append(", pointTime0245=").append(pointTime0245);
+        sb.append(", pointTime0300=").append(pointTime0300);
+        sb.append(", pointTime0315=").append(pointTime0315);
+        sb.append(", pointTime0330=").append(pointTime0330);
+        sb.append(", pointTime0345=").append(pointTime0345);
+        sb.append(", pointTime0400=").append(pointTime0400);
+        sb.append(", pointTime0415=").append(pointTime0415);
+        sb.append(", pointTime0430=").append(pointTime0430);
+        sb.append(", pointTime0445=").append(pointTime0445);
+        sb.append(", pointTime0500=").append(pointTime0500);
+        sb.append(", pointTime0515=").append(pointTime0515);
+        sb.append(", pointTime0530=").append(pointTime0530);
+        sb.append(", pointTime0545=").append(pointTime0545);
+        sb.append(", pointTime0600=").append(pointTime0600);
+        sb.append(", pointTime0615=").append(pointTime0615);
+        sb.append(", pointTime0630=").append(pointTime0630);
+        sb.append(", pointTime0645=").append(pointTime0645);
+        sb.append(", pointTime0700=").append(pointTime0700);
+        sb.append(", pointTime0715=").append(pointTime0715);
+        sb.append(", pointTime0730=").append(pointTime0730);
+        sb.append(", pointTime0745=").append(pointTime0745);
+        sb.append(", pointTime0800=").append(pointTime0800);
+        sb.append(", pointTime0815=").append(pointTime0815);
+        sb.append(", pointTime0830=").append(pointTime0830);
+        sb.append(", pointTime0845=").append(pointTime0845);
+        sb.append(", pointTime0900=").append(pointTime0900);
+        sb.append(", pointTime0915=").append(pointTime0915);
+        sb.append(", pointTime0930=").append(pointTime0930);
+        sb.append(", pointTime0945=").append(pointTime0945);
+        sb.append(", pointTime1000=").append(pointTime1000);
+        sb.append(", pointTime1015=").append(pointTime1015);
+        sb.append(", pointTime1030=").append(pointTime1030);
+        sb.append(", pointTime1045=").append(pointTime1045);
+        sb.append(", pointTime1100=").append(pointTime1100);
+        sb.append(", pointTime1115=").append(pointTime1115);
+        sb.append(", pointTime1130=").append(pointTime1130);
+        sb.append(", pointTime1145=").append(pointTime1145);
+        sb.append(", pointTime1200=").append(pointTime1200);
+        sb.append(", pointTime1215=").append(pointTime1215);
+        sb.append(", pointTime1230=").append(pointTime1230);
+        sb.append(", pointTime1245=").append(pointTime1245);
+        sb.append(", pointTime1300=").append(pointTime1300);
+        sb.append(", pointTime1315=").append(pointTime1315);
+        sb.append(", pointTime1330=").append(pointTime1330);
+        sb.append(", pointTime1345=").append(pointTime1345);
+        sb.append(", pointTime1400=").append(pointTime1400);
+        sb.append(", pointTime1415=").append(pointTime1415);
+        sb.append(", pointTime1430=").append(pointTime1430);
+        sb.append(", pointTime1445=").append(pointTime1445);
+        sb.append(", pointTime1500=").append(pointTime1500);
+        sb.append(", pointTime1515=").append(pointTime1515);
+        sb.append(", pointTime1530=").append(pointTime1530);
+        sb.append(", pointTime1545=").append(pointTime1545);
+        sb.append(", pointTime1600=").append(pointTime1600);
+        sb.append(", pointTime1615=").append(pointTime1615);
+        sb.append(", pointTime1630=").append(pointTime1630);
+        sb.append(", pointTime1645=").append(pointTime1645);
+        sb.append(", pointTime1700=").append(pointTime1700);
+        sb.append(", pointTime1715=").append(pointTime1715);
+        sb.append(", pointTime1730=").append(pointTime1730);
+        sb.append(", pointTime1745=").append(pointTime1745);
+        sb.append(", pointTime1800=").append(pointTime1800);
+        sb.append(", pointTime1815=").append(pointTime1815);
+        sb.append(", pointTime1830=").append(pointTime1830);
+        sb.append(", pointTime1845=").append(pointTime1845);
+        sb.append(", pointTime1900=").append(pointTime1900);
+        sb.append(", pointTime1915=").append(pointTime1915);
+        sb.append(", pointTime1930=").append(pointTime1930);
+        sb.append(", pointTime1945=").append(pointTime1945);
+        sb.append(", pointTime2000=").append(pointTime2000);
+        sb.append(", pointTime2015=").append(pointTime2015);
+        sb.append(", pointTime2030=").append(pointTime2030);
+        sb.append(", pointTime2045=").append(pointTime2045);
+        sb.append(", pointTime2100=").append(pointTime2100);
+        sb.append(", pointTime2115=").append(pointTime2115);
+        sb.append(", pointTime2130=").append(pointTime2130);
+        sb.append(", pointTime2145=").append(pointTime2145);
+        sb.append(", pointTime2200=").append(pointTime2200);
+        sb.append(", pointTime2215=").append(pointTime2215);
+        sb.append(", pointTime2230=").append(pointTime2230);
+        sb.append(", pointTime2245=").append(pointTime2245);
+        sb.append(", pointTime2300=").append(pointTime2300);
+        sb.append(", pointTime2315=").append(pointTime2315);
+        sb.append(", pointTime2330=").append(pointTime2330);
+        sb.append(", pointTime2345=").append(pointTime2345);
+        sb.append("]");
+        return sb.toString();
+    }
+}

+ 3 - 0
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/estimation/StateEstimationService.java

@@ -1,5 +1,6 @@
 package com.hdkj.lt.si.service.estimation;
 
+import com.hdkj.fhzg.optimization.request.MaintOrgRequest;
 import com.hdkj.lt.core.bizms.modle.dto.StateEstimation;
 import com.hdkj.lt.core.bizms.modle.po.FhzgFeederAutoSwitchMapping;
 import com.hdkj.lt.core.bizms.modle.request.StateEstimationEquipRequest;
@@ -24,5 +25,7 @@ public interface StateEstimationService {
      */
     List<FhzgFeederAutoSwitchMapping> saveAutoSwitch(StateEstimationRequest request);
 
+    List<StateEstimation> queryEquipByCounty(MaintOrgRequest request);
 
+//    StateEstimation queryEquipByCounty(StateEstimationRequest request);
 }

+ 353 - 8
services/load-transfer-si/src/main/java/com/hdkj/lt/si/service/estimation/impl/StateEstimationServiceImpl.java

@@ -1,35 +1,48 @@
 package com.hdkj.lt.si.service.estimation.impl;
 
 import cn.hutool.core.lang.Snowflake;
-import cn.hutool.core.lang.generator.SnowflakeGenerator;
 import cn.hutool.core.util.IdUtil;
-import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Maps;
+import com.hdkj.fhzg.optimization.request.MaintOrgRequest;
 import com.hdkj.lt.base.exception.ExceptionCast;
 import com.hdkj.lt.core.bizms.modle.dto.StateEstimation;
+import com.hdkj.lt.core.bizms.modle.po.DwdShbDsFeederBase;
 import com.hdkj.lt.core.bizms.modle.po.FhzgFeederAutoSwitchMapping;
 import com.hdkj.lt.core.bizms.modle.request.StateEstimationEquipRequest;
 import com.hdkj.lt.core.bizms.modle.request.StateEstimationRequest;
 import com.hdkj.lt.core.rest.service.IRemoteCallService;
+import com.hdkj.lt.core.sys.service.DwdShbDsFeederBaseService;
 import com.hdkj.lt.si.dao.FhzgFeederAutoSwitchMappingMapper;
+import com.hdkj.lt.si.dao.FhzgStateEstimationFeederMapper;
 import com.hdkj.lt.si.service.estimation.StateEstimationService;
 import com.hdkj.lt.si.service.remote.impl.SateEstimationRemoteCallServiceImpl;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.compress.utils.Lists;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.http.HttpMethod;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StreamUtils;
 
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import java.time.format.DateTimeParseException;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -47,12 +60,52 @@ public class StateEstimationServiceImpl implements StateEstimationService {
     @Value("${remote.stateEstimation.queryPeriodByEquip-uri}")
     private String periodByEquipUri;
 
+    @Value("${remote.stateEstimation.queryPeriodByFeeder-minutes:60}")
+    private long periodMinutes;
+
+
+    /**
+     * 失败重试次数 (不含首次). 即总尝试次数 = retryCount + 1.
+     * 失败定义: 抛异常 或 远程返回 code≠000000.
+     */
+    private static final int retryCount = 2;
+
+    /**
+     * 单批 psrIds 上限 (远程接口限制 100)
+     * */
+    private static final int batchSize = 100;
     @Autowired
     private FhzgFeederAutoSwitchMappingMapper fhzgFeederAutoSwitchMappingMapper;
 
+    @Autowired
+    private DwdShbDsFeederBaseService dwdShbDsFeederBaseService;
+
     @Autowired
     private RedisTemplate<String, Object> redisTemplate;
 
+    @Autowired(required = false)
+    @Qualifier("seQueryExecutor")
+    private ExecutorService executor;
+
+    private static final DateTimeFormatter POINT_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    private static final List<String> CONTAINER_CODE = Arrays.asList("feeder", "mvTrans", "energyConsumer", "pv", "segment", "switch");
+    /** 96 个合法时刻列名白名单, 杜绝 ${pointColumn} 动态拼接的 SQL 注入风险. */
+    private static final Set<String> POINT_COLUMNS;
+    static {
+        Set<String> cols = new LinkedHashSet<>(96);
+        for (int h = 0; h < 24; h++) {
+            for (int m = 0; m < 60; m += 15) {
+                cols.add("point_time_" + String.format("%02d%02d", h, m));
+            }
+        }
+        POINT_COLUMNS = Collections.unmodifiableSet(cols);
+    }
+    @Autowired
+    private FhzgStateEstimationFeederMapper mapper;
+    /** 专用写入 mapper: BigDecimal 以 plain 文本写入, 避免科学计数法. */
+    private final ObjectMapper writeMapper = new ObjectMapper();
+
     @Override
     public StateEstimation queryByFeeder(StateEstimationRequest request) {
         try {
@@ -113,6 +166,109 @@ public class StateEstimationServiceImpl implements StateEstimationService {
         return stateEstimation;
 
     }
+    @Override
+    public List<StateEstimation> queryEquipByCounty(MaintOrgRequest request) {
+        //根据区县查询线路
+        List<DwdShbDsFeederBase> list = dwdShbDsFeederBaseService.list(new LambdaQueryWrapper<DwdShbDsFeederBase>()
+                .eq(DwdShbDsFeederBase::getPsrState, "20").eq(DwdShbDsFeederBase::getPubPrivFlag, "0")
+                .eq(DwdShbDsFeederBase::getMaintOrg, request.getMaintOrg()));
+        List<String> feederIdsList = list.stream().map(DwdShbDsFeederBase::getPsrId).collect(Collectors.toList());
+
+        // 分批 (≤ batchSize, 远程限制 100)
+//        List<List<String>> batches = partition(feederIdsList, batchSize);
+//        log.info("[SE] feederIds 总量={},  批次数={}, 批大小={}", feederIdsList.size(), batches.size(), batchSize);
+
+        // 并行调用 (有界线程池), 每批带重试, 任一批最终失败则整体失败
+        StateEstimationRequest req = buildStateEstimationReq();
+        List<CompletableFuture<StateEstimation>> futures = feederIdsList.stream()
+                .map(id -> CompletableFuture.supplyAsync(() -> callWithRetry(id, req), executor))
+                .collect(Collectors.toList());
+        List<StateEstimation> mergedList = Lists.newArrayList();
+        try {
+
+            List<String> pointTime = Lists.newArrayList();
+            for (CompletableFuture<StateEstimation> f : futures) {
+                // 任一批失败 -> 抛 CompletionException -> 整体失败
+                StateEstimation part = f.join();
+                if (pointTime.isEmpty()) {
+                    pointTime = part.getPointTime();
+                }
+                String feeder = part.getPeriodFeederSeResult().stream()
+                        .map(StateEstimation.StateEstimationCommonResult::getPsrId).collect(Collectors.toList()).get(0);
+                mergeToList(mergedList, part, feeder);
+            }
+            return mergedList;
+        } catch (CompletionException e) {
+            // 取消尚未完成的批次, 减少无效远程调用
+            for (CompletableFuture<?> f : futures) {
+                f.cancel(true);
+            }
+            log.error("[SE] 查询状估失败: {}", e.getMessage(), e);
+            ExceptionCast.cast("调用状估接口失败");
+        }
+        return mergedList;
+    }
+
+    private StateEstimationRequest buildStateEstimationReq(){
+        //当前时间前一个小时
+        ZoneId zone = ZoneId.of(ZoneId.systemDefault().getId());
+        LocalDateTime now = LocalDateTime.now(zone);
+        int slot = (now.getMinute() / 15) * 15;
+        LocalDateTime floorNow = now.withMinute(slot).withSecond(0).withNano(0);
+        LocalDateTime point = floorNow.minusMinutes(periodMinutes);
+        String s = point.format(POINT_FMT);
+        StateEstimationRequest req = new StateEstimationRequest();
+        req.setContainerCode(CONTAINER_CODE);
+        req.setStartTime(s);
+        req.setEndTime(s);
+        return req;
+    }
+//    @Override
+//    public StateEstimation queryEquipByCounty(StateEstimationRequest request) {
+//        List<String> psrIds = request.getPsrIds();
+//        // 分批 (≤ batchSize, 远程限制 100)
+////        List<List<String>> batches = partition(request.getPsrIds(), batchSize);
+////        log.info("[SE] feederIds 总量={},  批次数={}, 批大小={}", request.getPsrIds(), batches.size(), batchSize);
+//
+//        // 并行调用 (有界线程池), 每批带重试, 任一批最终失败则整体失败
+//        List<CompletableFuture<StateEstimation>> futures = psrIds.stream()
+//                .map(psrId -> CompletableFuture.supplyAsync(() -> processFeeder(psrId, request), executor))
+//                .collect(Collectors.toList());
+//        try {
+//            StateEstimation merged = emptyResult();
+////            List<String> pointTime = Lists.newArrayList();
+////            for (CompletableFuture<StateEstimation> f : futures) {
+////                // 任一批失败 -> 抛 CompletionException -> 整体失败
+////                StateEstimation part = f.join();
+////                if (pointTime.isEmpty()) {
+////                    pointTime = part.getPointTime();
+////                }
+////                String feeder = part.getPeriodFeederSeResult().stream()
+////                        .map(StateEstimation.StateEstimationCommonResult::getPsrId).collect(Collectors.toList()).get(0);
+////                merge(merged, part,feeder);
+////
+////            }
+////            merged.setPointTime(pointTime);
+//            // 2. 解析返回的JSON数据
+//            String str = StreamUtils.copyToString(new ClassPathResource("状估接口返回.txt").getInputStream(), StandardCharsets.UTF_8);
+//            StateEstimation stateEstimation = JSON.parseObject(str, StateEstimation.class);
+//            //入库
+////            saveStateEstimation(merged,pointTime,request.getPsrIds());
+//            saveStateEstimation(stateEstimation,stateEstimation.getPointTime(),request.getPsrIds());
+//            return merged;
+//        } catch (CompletionException e) {
+//            // 取消尚未完成的批次, 减少无效远程调用
+////            for (CompletableFuture<?> f : futures) {
+////                f.cancel(true);
+////            }
+//            log.error("[SE] 查询状估失败: {}", e.getMessage(), e);
+//            ExceptionCast.cast("调用状估接口失败");
+//        }catch (IOException e) {
+//            log.error("[SE] 查询状估失败: {}", e.getMessage(), e);
+//            ExceptionCast.cast("调用状估接口失败");
+//        }
+//        return emptyResult();
+//    }
 
     /**
      * 获取所有入参线路自动化开关信息
@@ -150,4 +306,193 @@ public class StateEstimationServiceImpl implements StateEstimationService {
         LocalDateTime dateTime = LocalDateTime.parse(original, dateTimeFormat);
         return dateTime.format(dateTimeFormatter);
     }
+
+    /**
+     * 分批查询
+     * @param list
+     * @param size
+     * @return
+     * @param <T>
+     */
+    private static <T> List<List<T>> partition(List<T> list, int size) {
+        if (size <= 0) {
+            size = 100;
+        }
+        List<List<T>> parts = new ArrayList<>();
+        for (int i = 0; i < list.size(); i += size) {
+            parts.add(new ArrayList<>(list.subList(i, Math.min(i + size, list.size()))));
+        }
+        return parts;
+    }
+
+    /**
+     * 带重试远程调用(单条线路)
+     * @param single
+     * @return
+     */
+    private StateEstimation callWithRetry(String single, StateEstimationRequest req) {
+        int maxAttempts = retryCount + 1;
+        Exception last = null;
+        for (int attempt = 1; attempt <= maxAttempts; attempt++) {
+            try {
+                req.setPsrIds(Collections.singletonList(single));
+                StateEstimation resp = this.queryByFeeder(req);
+                if (resp != null) {
+                    return resp;
+                }
+            } catch (Exception e) {
+                last = e;
+                log.warn("[SE] 批次异常, 第{}/{}次: {}, psrIds ={}", attempt, maxAttempts, e.getMessage(), single);
+            }
+        }
+        throw new RuntimeException("状估调用失败 (已重试 " + retryCount+ " 次), psrIds ="
+                + single + ", 最后错误: " + (last == null ? "unknown" : last.getMessage()), last);
+    }
+
+    /**
+     * 含入库查询
+     * @param single
+     * @param req
+     * @return
+     */
+    private StateEstimation processFeeder(String single,StateEstimationRequest req) {
+        int maxAttempts = retryCount + 1;
+        for (int attempt = 1; attempt <= maxAttempts; attempt++) {
+            try {
+                req.setPsrIds(Collections.singletonList(single));
+                StateEstimation resp = this.queryByFeeder(req);
+                if (resp != null) {
+                    //入库
+                    saveStateEstimation(resp,resp.getPointTime(),Collections.singletonList(single));
+                    return resp;
+                }
+            } catch (Exception e) {
+                ExceptionCast.cast("调用状估接口失败");
+            }
+        }
+        return null;
+    }
+
+
+    private static void merge(StateEstimation dst,StateEstimation src,String feeder) {
+        if (src == null) {
+            return;
+        }
+        addAll(dst.getPeriodEquipResult(), src.getPeriodEquipResult());
+        addAll(dst.getPeriodFeederSeResult(), src.getPeriodFeederSeResult());
+        addAll(dst.getPeriodSwitchSeResult(), src.getPeriodSwitchSeResult().stream().peek(p->p.setFeederId(feeder)).collect(Collectors.toList()));
+        //配变
+        addAll(dst.getPeriodMVTransSeResult(), src.getPeriodMVTransSeResult());
+        //光伏
+        addAll(dst.getPeriodPVSeResult(), src.getPeriodPVSeResult());
+        //线路段
+        addAll(dst.getPeriodSegmentSeResult(), src.getPeriodSegmentSeResult());
+        //用户
+        addAll(dst.getPeriodEnergyConsumerSeResult(),src.getPeriodEnergyConsumerSeResult());
+    }
+
+    private static void mergeToList(List<StateEstimation> dst,StateEstimation src,String feeder) {
+        if (!Objects.nonNull(src)) {
+            return;
+        }
+        src.getPeriodSwitchSeResult().forEach(p->p.setFeederId(feeder));
+        dst.add(src);
+    }
+    private static <T> void addAll(List<T> dst, List<T> src) {
+        if (src != null && !src.isEmpty()) {
+            dst.addAll(src);
+        }
+    }
+    private static StateEstimation emptyResult() {
+        StateEstimation r = new StateEstimation();
+        //线路
+        r.setPeriodFeederSeResult(new ArrayList<>());
+        //设备
+        r.setPeriodEquipResult(new ArrayList<>());
+        //开关
+        r.setPeriodSwitchSeResult(new ArrayList<>());
+        //配变
+        r.setPeriodMVTransSeResult(new ArrayList<>());
+        //光伏
+        r.setPeriodPVSeResult(new ArrayList<>());
+        //线路段
+        r.setPeriodSegmentSeResult(new ArrayList<>());
+        //用户
+        r.setPeriodEnergyConsumerSeResult(new ArrayList<>());
+        return r;
+    }
+
+    public void saveStateEstimation(StateEstimation stateEstimation,List<String> mergedPointTime,List<String> feeders) {
+        if(Objects.nonNull(stateEstimation)){
+            // 5. 按设备类型分组
+            Map<String, List<StateEstimation.StateEstimationCommonResult>> feederSeMap = Objects.nonNull(stateEstimation.getPeriodFeederSeResult())?
+                    stateEstimation.getPeriodFeederSeResult().stream().collect(Collectors.groupingBy(StateEstimation.StateEstimationCommonResult::getPsrId)): Maps.newHashMap();
+            Map<String, List<StateEstimation.StateEstimationTransResult>> transMap = Objects.nonNull(stateEstimation.getPeriodMVTransSeResult())?
+                    stateEstimation.getPeriodMVTransSeResult().stream().collect(Collectors.groupingBy(StateEstimation.StateEstimationTransResult::getFeederId)): Maps.newHashMap();
+            Map<String, List<StateEstimation.StateEstimationConsumerResult>> consumerMap = Objects.nonNull(stateEstimation.getPeriodEnergyConsumerSeResult())?
+                    stateEstimation.getPeriodEnergyConsumerSeResult().stream().collect(Collectors.groupingBy(StateEstimation.StateEstimationConsumerResult::getFeederId)): Maps.newHashMap();
+            Map<String, List<StateEstimation.StateEstimationCommonResult>> pvMap = Objects.nonNull(stateEstimation.getPeriodPVSeResult())?
+                    stateEstimation.getPeriodPVSeResult().stream().collect(Collectors.groupingBy(StateEstimation.StateEstimationCommonResult::getFeederId)): Maps.newHashMap();
+            Map<String, List<StateEstimation.StateEstimationSegmentResult>> segmentMap = Objects.nonNull(stateEstimation.getPeriodSegmentSeResult())?
+                    stateEstimation.getPeriodSegmentSeResult().stream().collect(Collectors.groupingBy(StateEstimation.StateEstimationSegmentResult::getFeederId)): Maps.newHashMap();
+            Map<String, List<StateEstimation.StateEstimationSwitchResult>> switchMap = Objects.nonNull(stateEstimation.getPeriodSwitchSeResult())?
+                    stateEstimation.getPeriodSwitchSeResult().stream().filter(f->f.getFeederId()!=null).collect(Collectors.groupingBy(StateEstimation.StateEstimationSwitchResult::getFeederId)): Maps.newHashMap();
+            Map<String, List<StateEstimation.StateEstimationCommonResult>> equipMap = Objects.nonNull(stateEstimation.getPeriodEquipResult())?
+                    stateEstimation.getPeriodEquipResult().stream().collect(Collectors.groupingBy(StateEstimation.StateEstimationCommonResult::getFeederId)): Maps.newHashMap();
+            // 6. 逐时刻: 取该索引单值组装快照并落库
+            for (int i = 0; i < mergedPointTime.size(); i++) {
+                String pointStr = mergedPointTime.get(i);
+                LocalDateTime pt;
+                try {
+                    pt = LocalDateTime.parse(pointStr, POINT_FMT);
+                } catch (DateTimeParseException e) {
+                    log.warn("[SE-Collect] 无法解析时刻 '{}', 跳过", pointStr);
+                    continue;
+                }
+                String dataDate = pt.toLocalDate().format(DATE_FMT);
+                String pointColumn = "point_time_" + String.format("%02d%02d", pt.getHour(), pt.getMinute());
+                if (!POINT_COLUMNS.contains(pointColumn)) {
+                    log.warn("[SE-Collect] 时刻 '{}' 推导出非法列名 {}, 跳过", pointStr, pointColumn);
+                    continue;
+                }
+
+                for (String feeder : feeders) {
+                    if (feederSeMap.get(feeder) == null || feederSeMap.get(feeder).isEmpty()) {
+                        // 该馈线该时刻无任何数据, 跳过(不建空行)
+                        continue;
+                    }
+                    StateEstimation params = new StateEstimation();
+                    params.setPointTime(Collections.singletonList(pointStr));
+                    params.setPeriodFeederSeResult(feederSeMap.get(feeder));
+                    params.setPeriodMVTransSeResult(transMap.get(feeder));
+                    params.setPeriodEnergyConsumerSeResult(consumerMap.get(feeder));
+                    params.setPeriodPVSeResult(pvMap.get(feeder));
+                    params.setPeriodSegmentSeResult(segmentMap.get(feeder));
+                    params.setPeriodSwitchSeResult(switchMap.get(feeder));
+                    params.setPeriodEquipResult(equipMap.get(feeder));
+                    String json;
+                    try {
+                        json = writeMapper.writeValueAsString(params);
+                    } catch (JsonProcessingException e) {
+                        log.warn("[SE-Collect] 馈线 {} 时刻 {} 序列化失败: {}", feeder, pointStr, e.getMessage());
+                        continue;
+                    }
+
+                    try {
+                        upsertPoint(feeder, dataDate, pointColumn, json);
+                    } catch (Exception e) {
+                        log.error("[SE-Collect] 馈线 {} 时刻 {} 落库失败: {}", feeder, pointStr, e.getMessage(), e);
+                    }
+                }
+            }
+        }
+    }
+    private void upsertPoint(String feeder, String dataDate, String pointColumn, String json) {
+        Long id = mapper.selectIdByFeederAndDate(feeder, dataDate);
+        if (id != null) {
+            mapper.updatePointTime(feeder, dataDate, pointColumn, json);
+        } else {
+            mapper.insertPointTime(feeder, dataDate, pointColumn, json);
+        }
+    }
 }

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

@@ -1,33 +1,43 @@
 package com.hdkj.lt.si.service.recon.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import com.hdkj.lt.base.exception.ExceptionCast;
+import com.hdkj.lt.core.bizms.modle.po.Jxz;
 import com.hdkj.lt.core.rest.config.HttpClientConfig;
+import com.hdkj.lt.core.sys.dao.JxzMapper;
 import com.hdkj.lt.modle.dto.recon.*;
 import com.hdkj.lt.modle.po.*;
 import com.hdkj.lt.modle.vo.recon.ReconSaveResultVO;
+import com.hdkj.lt.si.config.EstimationAlgorithmProp;
 import com.hdkj.lt.si.dao.*;
 import com.hdkj.lt.si.service.recon.ReconResultService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.Charsets;
+import org.apache.commons.collections.MapUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
 import org.springframework.http.*;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StreamUtils;
 import org.springframework.web.client.RestTemplate;
 
 import javax.annotation.Resource;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
 
 /**
  * 重构结果入库服务实现.
@@ -47,6 +57,8 @@ public class ReconResultServiceImpl implements ReconResultService {
     private final FhzgReconVolDetailMapper volDetailMapper;
     private final FhzgReconSwitchResultDetailMapper switchResultDetailMapper;
     private final FhzgReconMetricsMapper metricsMapper;
+    private final EstimationAlgorithmProp algorithmProp;
+    private final JxzMapper jxzMapper;
 
     private static final ObjectMapper OM = new ObjectMapper()
             .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@@ -64,12 +76,13 @@ public class ReconResultServiceImpl implements ReconResultService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public ReconSaveResultVO saveReconResult(String eventId, Map<String, Object> params) {
-        // 1. 调用远程重构接口
+        // 1. 构造请求参数
+        Map<String, Object> req = buildReconRequestParams(params);
         String requestUrl = requestUri.concat(reconUri);
         HttpHeaders headers = new HttpHeaders();
         headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
         headers.set(HttpHeaders.ACCEPT_CHARSET, Charsets.UTF_8.toString());
-        HttpEntity<Object> httpEntity = new HttpEntity<>(params, headers);
+        HttpEntity<Object> httpEntity = new HttpEntity<>(req, headers);
         String str;
         try {
             ResponseEntity<Object> restRespEntity = restTemplate.postForEntity(requestUrl, httpEntity, Object.class);
@@ -175,6 +188,51 @@ public class ReconResultServiceImpl implements ReconResultService {
         return vo;
     }
 
+    private Map<String, Object> buildReconRequestParams(Map<String, Object> params){
+        Map<String, Object> root = new HashMap<>();
+        if(Objects.nonNull(params)){
+            String feederId = MapUtils.getString(params, "feeder_id");
+            String pointTime = MapUtils.getString(params, "point_time");
+            List<Jxz> jxzList = getFeederGroup(feederId);
+            List<String> feederIds = jxzList.stream().map(Jxz::getFeederId).distinct().collect(Collectors.toList());
+            Jxz jxz = jxzList.get(0);
+            // county
+            Map<String, Object> county = new HashMap<>();
+            county.put("county_id", jxz.getMaintOrg());
+            county.put("county_sid", jxz.getMaintOrgName());
+            county.put("county_name", jxz.getMaintOrgName());
+            root.put("county", county);
+
+            // snapshot
+            Map<String, Object> snapshot = new HashMap<>();
+            snapshot.put("snapshot_id", pointTime);
+            snapshot.put("alarm_state_estimation_time", pointTime);
+            snapshot.put("point_time", pointTime);
+            root.put("snapshot", snapshot);
+
+            // problem
+            Map<String, Object> problem = new HashMap<>();
+            problem.put("problem_feeder_ids", Collections.singletonList(feederId));
+            problem.put("trigger_type", "load_rate");
+            problem.put("trigger_reason", "feeder_load_rate_over_limit");
+            problem.put("trigger_source", "customer_backend_alarm");
+            root.put("problem", problem);
+
+            // feeder_group
+            Map<String, Object> feederGroup = new HashMap<>();
+            feederGroup.put("group_id", jxz.getJxzId());
+            feederGroup.put("group_sid", jxz.getJxzId());
+            feederGroup.put("group_name", jxz.getJxzName());
+            feederGroup.put("feeder_ids", feederIds);
+            root.put("feeder_group", feederGroup);
+            // algorithm_config【外部可传入覆盖】
+            root.put("algorithm_config", algorithmProp.toAlgorithmConfigMap());
+        }
+        return root;
+    }
+    private List<Jxz> getFeederGroup(String feederId){
+         return jxzMapper.queryJxzXl(feederId);
+    }
     // ==================== 构建主表 ====================
 
     private FhzgReconResult buildMain(RawResultDTO dto) {

+ 160 - 0
services/load-transfer-si/src/main/resources/mapper/FhzgStateEstimationFeederMapper.xml

@@ -0,0 +1,160 @@
+<?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.si.dao.FhzgStateEstimationFeederMapper">
+
+    <resultMap id="BaseResultMap" type="com.hdkj.lt.si.modle.FhzgStateEstimationFeeder">
+            <id property="id" column="id" />
+            <result property="feeder" column="feeder" />
+            <result property="dataDate" column="data_date" />
+            <result property="pointTime0000" column="point_time_0000" />
+            <result property="pointTime0015" column="point_time_0015" />
+            <result property="pointTime0030" column="point_time_0030" />
+            <result property="pointTime0045" column="point_time_0045" />
+            <result property="pointTime0100" column="point_time_0100" />
+            <result property="pointTime0115" column="point_time_0115" />
+            <result property="pointTime0130" column="point_time_0130" />
+            <result property="pointTime0145" column="point_time_0145" />
+            <result property="pointTime0200" column="point_time_0200" />
+            <result property="pointTime0215" column="point_time_0215" />
+            <result property="pointTime0230" column="point_time_0230" />
+            <result property="pointTime0245" column="point_time_0245" />
+            <result property="pointTime0300" column="point_time_0300" />
+            <result property="pointTime0315" column="point_time_0315" />
+            <result property="pointTime0330" column="point_time_0330" />
+            <result property="pointTime0345" column="point_time_0345" />
+            <result property="pointTime0400" column="point_time_0400" />
+            <result property="pointTime0415" column="point_time_0415" />
+            <result property="pointTime0430" column="point_time_0430" />
+            <result property="pointTime0445" column="point_time_0445" />
+            <result property="pointTime0500" column="point_time_0500" />
+            <result property="pointTime0515" column="point_time_0515" />
+            <result property="pointTime0530" column="point_time_0530" />
+            <result property="pointTime0545" column="point_time_0545" />
+            <result property="pointTime0600" column="point_time_0600" />
+            <result property="pointTime0615" column="point_time_0615" />
+            <result property="pointTime0630" column="point_time_0630" />
+            <result property="pointTime0645" column="point_time_0645" />
+            <result property="pointTime0700" column="point_time_0700" />
+            <result property="pointTime0715" column="point_time_0715" />
+            <result property="pointTime0730" column="point_time_0730" />
+            <result property="pointTime0745" column="point_time_0745" />
+            <result property="pointTime0800" column="point_time_0800" />
+            <result property="pointTime0815" column="point_time_0815" />
+            <result property="pointTime0830" column="point_time_0830" />
+            <result property="pointTime0845" column="point_time_0845" />
+            <result property="pointTime0900" column="point_time_0900" />
+            <result property="pointTime0915" column="point_time_0915" />
+            <result property="pointTime0930" column="point_time_0930" />
+            <result property="pointTime0945" column="point_time_0945" />
+            <result property="pointTime1000" column="point_time_1000" />
+            <result property="pointTime1015" column="point_time_1015" />
+            <result property="pointTime1030" column="point_time_1030" />
+            <result property="pointTime1045" column="point_time_1045" />
+            <result property="pointTime1100" column="point_time_1100" />
+            <result property="pointTime1115" column="point_time_1115" />
+            <result property="pointTime1130" column="point_time_1130" />
+            <result property="pointTime1145" column="point_time_1145" />
+            <result property="pointTime1200" column="point_time_1200" />
+            <result property="pointTime1215" column="point_time_1215" />
+            <result property="pointTime1230" column="point_time_1230" />
+            <result property="pointTime1245" column="point_time_1245" />
+            <result property="pointTime1300" column="point_time_1300" />
+            <result property="pointTime1315" column="point_time_1315" />
+            <result property="pointTime1330" column="point_time_1330" />
+            <result property="pointTime1345" column="point_time_1345" />
+            <result property="pointTime1400" column="point_time_1400" />
+            <result property="pointTime1415" column="point_time_1415" />
+            <result property="pointTime1430" column="point_time_1430" />
+            <result property="pointTime1445" column="point_time_1445" />
+            <result property="pointTime1500" column="point_time_1500" />
+            <result property="pointTime1515" column="point_time_1515" />
+            <result property="pointTime1530" column="point_time_1530" />
+            <result property="pointTime1545" column="point_time_1545" />
+            <result property="pointTime1600" column="point_time_1600" />
+            <result property="pointTime1615" column="point_time_1615" />
+            <result property="pointTime1630" column="point_time_1630" />
+            <result property="pointTime1645" column="point_time_1645" />
+            <result property="pointTime1700" column="point_time_1700" />
+            <result property="pointTime1715" column="point_time_1715" />
+            <result property="pointTime1730" column="point_time_1730" />
+            <result property="pointTime1745" column="point_time_1745" />
+            <result property="pointTime1800" column="point_time_1800" />
+            <result property="pointTime1815" column="point_time_1815" />
+            <result property="pointTime1830" column="point_time_1830" />
+            <result property="pointTime1845" column="point_time_1845" />
+            <result property="pointTime1900" column="point_time_1900" />
+            <result property="pointTime1915" column="point_time_1915" />
+            <result property="pointTime1930" column="point_time_1930" />
+            <result property="pointTime1945" column="point_time_1945" />
+            <result property="pointTime2000" column="point_time_2000" />
+            <result property="pointTime2015" column="point_time_2015" />
+            <result property="pointTime2030" column="point_time_2030" />
+            <result property="pointTime2045" column="point_time_2045" />
+            <result property="pointTime2100" column="point_time_2100" />
+            <result property="pointTime2115" column="point_time_2115" />
+            <result property="pointTime2130" column="point_time_2130" />
+            <result property="pointTime2145" column="point_time_2145" />
+            <result property="pointTime2200" column="point_time_2200" />
+            <result property="pointTime2215" column="point_time_2215" />
+            <result property="pointTime2230" column="point_time_2230" />
+            <result property="pointTime2245" column="point_time_2245" />
+            <result property="pointTime2300" column="point_time_2300" />
+            <result property="pointTime2315" column="point_time_2315" />
+            <result property="pointTime2330" column="point_time_2330" />
+            <result property="pointTime2345" column="point_time_2345" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+        id,feeder,data_date,point_time_0000,point_time_0015,point_time_0030,
+        point_time_0045,point_time_0100,point_time_0115,point_time_0130,point_time_0145,
+        point_time_0200,point_time_0215,point_time_0230,point_time_0245,point_time_0300,
+        point_time_0315,point_time_0330,point_time_0345,point_time_0400,point_time_0415,
+        point_time_0430,point_time_0445,point_time_0500,point_time_0515,point_time_0530,
+        point_time_0545,point_time_0600,point_time_0615,point_time_0630,point_time_0645,
+        point_time_0700,point_time_0715,point_time_0730,point_time_0745,point_time_0800,
+        point_time_0815,point_time_0830,point_time_0845,point_time_0900,point_time_0915,
+        point_time_0930,point_time_0945,point_time_1000,point_time_1015,point_time_1030,
+        point_time_1045,point_time_1100,point_time_1115,point_time_1130,point_time_1145,
+        point_time_1200,point_time_1215,point_time_1230,point_time_1245,point_time_1300,
+        point_time_1315,point_time_1330,point_time_1345,point_time_1400,point_time_1415,
+        point_time_1430,point_time_1445,point_time_1500,point_time_1515,point_time_1530,
+        point_time_1545,point_time_1600,point_time_1615,point_time_1630,point_time_1645,
+        point_time_1700,point_time_1715,point_time_1730,point_time_1745,point_time_1800,
+        point_time_1815,point_time_1830,point_time_1845,point_time_1900,point_time_1915,
+        point_time_1930,point_time_1945,point_time_2000,point_time_2015,point_time_2030,
+        point_time_2045,point_time_2100,point_time_2115,point_time_2130,point_time_2145,
+        point_time_2200,point_time_2215,point_time_2230,point_time_2245,point_time_2300,
+        point_time_2315,point_time_2330,point_time_2345
+    </sql>
+
+    <!--
+        单点 upsert 辅助查询: 仅取主键 id 用于存在性判断, 避免读取 96 个 JSON 列.
+        (feeder, data_date) 无唯一键, 见 README 关于并发与补跑的说明.
+    -->
+    <select id="selectIdByFeederAndDate" resultType="java.lang.Long">
+        SELECT id
+        FROM fhzg_state_estimation_feeder
+        WHERE feeder = #{feeder} AND data_date = #{dataDate}
+        LIMIT 1
+    </select>
+
+    <!--
+        更新单一时刻列. ${pointColumn} 为列名(动态), 调用方 SePeriodCollectServiceImpl 已做 96 个列名白名单校验,
+        杜绝 SQL 注入. #{json} 为 JSON 字符串参数, MySQL JSON 列接受合法 JSON 字符串.
+    -->
+    <update id="updatePointTime">
+        UPDATE fhzg_state_estimation_feeder
+        SET ${pointColumn} = #{json}
+        WHERE feeder = #{feeder} AND data_date = #{dataDate}
+    </update>
+
+    <!--
+        新建行并写入单一时刻列, 其余时刻列留 null, id 自增.
+    -->
+    <insert id="insertPointTime">
+        INSERT INTO fhzg_state_estimation_feeder (feeder, data_date, ${pointColumn})
+        VALUES (#{feeder}, #{dataDate}, #{json})
+    </insert>
+</mapper>