lisonglin 9 цаг өмнө
parent
commit
f758fc3c76

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

@@ -0,0 +1,67 @@
+package com.hdkj.lt.bf.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 中台线路线损日统计表(T-2,DI 同步全量快照)
+ * <p>
+ * 数据来源:中台 ODPS 聚合任务 ads_grid_tqxs_line_tq_loss_daily_result(ds=T-2 分区)→ DI 同步本地表 fhzg_se_line_loss_daily_result
+ * 口径:date_cycle='DAY';剔除 rate_loss 空/非数字/&lt;0/&gt;=100(0 为合法值保留);
+ * 三档 dim_level(county/substation/feeder) + 维度 id/name + 日粒度 stat_date(yyyymmdd)。
+ * <p>
+ * 跨周期(月/年)线损率不能用 AVG(avg_rate_loss)(日简单平均不等价),
+ * 须 SUM(sum_power_loss)/SUM(sum_power_sup)×100 电量加权重算。
+ *
+ * @author lsl
+ * @since 2026-08
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("fhzg_se_line_loss_daily_result")
+public class FhzgSeLineLossDaily implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 统计日期 yyyymmdd */
+    private String statDate;
+
+    /** county=区县 / substation=变电站 / feeder=馈线 */
+    private String dimLevel;
+
+    private String orgId;
+    private String orgName;
+    private String substationId;
+    private String substationName;
+    private String feederId;
+    private String feederName;
+
+    /** 当日平均线损率(%) */
+    private BigDecimal avgRateLoss;
+
+    /** 当日输入电量合计 */
+    private BigDecimal sumPowerSup;
+
+    /** 当日损失电量合计 */
+    private BigDecimal sumPowerLoss;
+
+    /** 参与统计的线路数 */
+    private Integer lineCnt;
+
+    private LocalDateTime ctime;
+    private LocalDateTime createTime;
+}

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

@@ -0,0 +1,9 @@
+package com.hdkj.lt.bf.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hdkj.lt.bf.entity.FhzgSeLineLossDaily;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface FhzgSeLineLossDailyMapper extends BaseMapper<FhzgSeLineLossDaily> {
+}

+ 49 - 4
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SeIndicatorServiceImpl.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.hdkj.lt.bf.application.FeederGroupApplication;
 import com.hdkj.lt.bf.entity.FhzgSeCurrentEvent;
 import com.hdkj.lt.bf.entity.FhzgSeLineLossRate;
+import com.hdkj.lt.bf.entity.FhzgSeLineLossDaily;
 import com.hdkj.lt.bf.entity.FhzgDwmVoltageOverLimitDaily;
 import com.hdkj.lt.bf.entity.FhzgSeCapacityDaily;
 import com.hdkj.lt.bf.entity.FhzgSeVoltageEvent;
@@ -19,6 +20,7 @@ import com.hdkj.lt.bf.entity.vo.SeVoltageDashboardVO;
 import com.hdkj.lt.bf.entity.vo.SeVoltageIndexVO;
 import com.hdkj.lt.bf.mapper.FhzgSeCurrentEventMapper;
 import com.hdkj.lt.bf.mapper.FhzgSeLineLossRateMapper;
+import com.hdkj.lt.bf.mapper.FhzgSeLineLossDailyMapper;
 import com.hdkj.lt.bf.mapper.FhzgDwmVoltageOverLimitDailyMapper;
 import com.hdkj.lt.bf.mapper.FhzgSeCapacityDailyMapper;
 import com.hdkj.lt.bf.mapper.FhzgSeVoltageEventMapper;
@@ -62,6 +64,7 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
     private final FhzgSeConsumerCountDailyMapper consumerCountDailyMapper;
     private final FhzgSeConsumerRelationMapper consumerRelationMapper;
     private final FhzgSeLineLossRateMapper lineLossRateMapper;
+    private final FhzgSeLineLossDailyMapper lineLossDailyMapper;
     private final FeederGroupApplication feederGroupApplication;
 
     private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyyMMdd");
@@ -560,8 +563,9 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
 
     /**
      * 线损率(独立接口,从供电能力拆出):
-     * 按区间从 fhzg_se_line_loss_rate 加权平均(Σ线损功率 / Σ总功率 × 100)。
-     * today → 今日 0 点至今;month → 月初至今;year → 年初至今。
+     * today → 断面表 fhzg_se_line_loss_rate 加权平均(Σ线损功率/Σ总功率×100,今日 0 点至今);
+     * month/year → 中台日汇总表 ads_grid_tqxs_line_tq_loss_daily_result(T-2,DI 同步本地表 fhzg_se_line_loss_daily_result),
+     * 按 dim_level+维度id+stat_date 区间聚合,线损率 = Σsum_power_loss/Σsum_power_sup×100(电量加权)。
      */
     @Override
     public SeLineLossRateVO queryLineLoss(String id, Integer type, String timeScope) {
@@ -569,9 +573,9 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
             return null;
         }
 
-        // TODO 历史线损(month/year):取中台线损日汇总表(建设中,未接入),暂不返回
+        // 历史(month/year):查中台日汇总表(电量加权)
         if (!"today".equalsIgnoreCase(timeScope)) {
-            return null;
+            return queryLineLossHistory(id, type, timeScope);
         }
 
         LocalDateTime startTime = LocalDate.now().atStartOfDay();
@@ -602,6 +606,47 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
         return SeLineLossRateVO.builder().lineLossRate(rate).build();
     }
 
+    /**
+     * 历史线损率(month/year):中台日汇总表(DI 同步本地表 fhzg_se_line_loss_daily_result)
+     * <p>
+     * 分层分级过滤:dim_level 三档 —— type=2 county → org_id;type=3 substation → substation_id;type=4 feeder → feeder_id。
+     * 时间窗:month → stat_date >= 月初(yyyymmdd);year → stat_date >= 年初(yyyymmdd);至昨日(中台 T-2 数据)。
+     * 计算:线损率 = SUM(sum_power_loss)/SUM(sum_power_sup)×100(电量加权,不能 AVG 日线损率)。
+     */
+    private SeLineLossRateVO queryLineLossHistory(String id, Integer type, String timeScope) {
+        String startDate;
+        if ("month".equalsIgnoreCase(timeScope)) {
+            startDate = LocalDate.now().withDayOfMonth(1).format(DATE_FMT);
+        } else {
+            startDate = LocalDate.now().withDayOfMonth(1).withMonth(1).format(DATE_FMT);
+        }
+
+        QueryWrapper<FhzgSeLineLossDaily> qw = new QueryWrapper<>();
+        qw.select("COALESCE(SUM(sum_power_loss), 0) AS total_loss",
+                "COALESCE(SUM(sum_power_sup), 0) AS total_power")
+                .eq("dim_level", resolveDimLevel(type))
+                .ge("stat_date", startDate)
+                .le("stat_date", LocalDate.now().minusDays(1).format(DATE_FMT));
+        if (type == 2) {
+            qw.eq("org_id", id);
+        } else if (type == 3) {
+            qw.eq("substation_id", id);
+        } else if (type == 4) {
+            qw.eq("feeder_id", id);
+        }
+        List<Map<String, Object>> rows = lineLossDailyMapper.selectMaps(qw);
+        if (rows == null || rows.isEmpty() || rows.get(0).get("total_power") == null
+                || new BigDecimal(rows.get(0).get("total_power").toString()).compareTo(BigDecimal.ZERO) <= 0) {
+            return SeLineLossRateVO.builder().lineLossRate(BigDecimal.ZERO).build();
+        }
+        BigDecimal totalLoss = new BigDecimal(rows.get(0).get("total_loss").toString());
+        BigDecimal totalPower = new BigDecimal(rows.get(0).get("total_power").toString());
+        BigDecimal rate = totalLoss.multiply(BigDecimal.valueOf(100))
+                .divide(totalPower, 2, RoundingMode.HALF_UP);
+
+        return SeLineLossRateVO.builder().lineLossRate(rate).build();
+    }
+
     /**
      * 构建馈线今日96点时序(负载率+电流+电压+有功+无功)
      */