浏览代码

电网小时供电产出计算

learshaw 1 周之前
父节点
当前提交
f8b16a59e8

+ 8 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/BaseDevHandler.java

@@ -22,7 +22,9 @@ import com.ruoyi.ems.model.AbilityPayload;
 import com.ruoyi.ems.model.CallResponse;
 import com.ruoyi.ems.model.MqttCacheMsg;
 import com.ruoyi.ems.service.IElecMeterHService;
+import com.ruoyi.ems.service.IElecPgSupplyHService;
 import com.ruoyi.ems.service.IEmsDeviceService;
+import com.ruoyi.ems.service.IEmsFacsService;
 import com.ruoyi.ems.service.IEmsObjAbilityCallLogService;
 import com.ruoyi.ems.service.IEmsObjAttrValueService;
 import com.ruoyi.ems.service.IEmsObjEventLogService;
@@ -51,6 +53,9 @@ public abstract class BaseDevHandler {
     protected RedisService redisService;
 
     @Autowired
+    protected IEmsFacsService facsService;
+
+    @Autowired
     protected IEmsDeviceService deviceService;
 
     @Autowired
@@ -77,6 +82,9 @@ public abstract class BaseDevHandler {
     @Autowired
     protected IEmsObjEventLogService objEventLogService;
 
+    @Autowired
+    protected IElecPgSupplyHService pgSupplyHService;
+
     /**
      * 抽象方法,用于能力调用
      *

+ 11 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/BaseMeterDevHandler.java

@@ -311,4 +311,15 @@ public abstract class BaseMeterDevHandler extends BaseDevHandler {
         int hour = calendar.get(Calendar.HOUR_OF_DAY);
         return hour + 1;
     }
+
+    /**
+     * 格式化数值为指定小数位数
+     *
+     * @param value 原始值
+     * @param decimalPlaces 小数位数
+     * @return 格式化后的值
+     */
+    protected double formatToDecimalPlaces(double value, int decimalPlaces) {
+        return Math.round(value * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces);
+    }
 }

+ 297 - 34
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/InDoorEnergyHandler.java

@@ -1,15 +1,6 @@
-/*
- * 文 件 名:  InDoorEnergyHandler
- * 版    权:  华设设计集团股份有限公司
- * 描    述:  <描述>
- * 修 改 人:  lvwenbin
- * 修改时间:  2025/8/15
- * 跟踪单号:  <跟踪单号>
- * 修改单号:  <修改单号>
- * 修改内容:  <修改内容>
- */
 package com.ruoyi.ems.handle;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.huashe.common.exception.Assert;
 import com.huashe.common.utils.DateUtils;
@@ -17,21 +8,22 @@ import com.ruoyi.common.redis.service.RedisService;
 import com.ruoyi.ems.config.InDoorEnergyConfig;
 import com.ruoyi.ems.core.InDoorEnergyTemplate;
 import com.ruoyi.ems.domain.ElecMeterH;
+import com.ruoyi.ems.domain.ElecPgSupplyH;
 import com.ruoyi.ems.domain.EmsDevice;
 import com.ruoyi.ems.domain.EmsObjAbility;
+import com.ruoyi.ems.domain.EmsObjAttrValue;
 import com.ruoyi.ems.domain.FdEnergyPriceConfig;
 import com.ruoyi.ems.domain.MeterDevice;
 import com.ruoyi.ems.domain.WaterMeterH;
 import com.ruoyi.ems.model.AbilityPayload;
+import com.ruoyi.ems.model.BoundaryObj;
 import com.ruoyi.ems.model.CallResponse;
 import com.ruoyi.ems.model.ObjAttrTableItem;
 import com.ruoyi.ems.model.Price;
 import com.ruoyi.ems.model.QueryDevice;
 import com.ruoyi.ems.model.idenergy.CodesVal;
 import com.ruoyi.ems.model.idenergy.CodesValReq;
-import com.ruoyi.ems.domain.EmsObjAttrValue;
 import com.ruoyi.ems.service.IEmsObjAttrValueService;
-import com.alibaba.fastjson.JSON;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
@@ -66,6 +58,13 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
     // 设备模型代码
     private static final String MODE_CODE = "M_W2_SM_INDOOR_ENERGY";
 
+    // 单小时最大增长量(度)
+    private static final double MAX_HOUR_INCREASE_RATE = 1000.0;
+    // 允许的最小负增长(考虑精度误差)
+    private static final double MIN_REASONABLE_DECREASE_RATE = -0.1;
+    // 异常数据连续确认次数
+    private static final int ABNORMAL_DATA_CONFIRM_COUNT = 3;
+
     @Resource
     private IEmsObjAttrValueService objAttrValueService;
 
@@ -226,16 +225,27 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
                         CodesVal syncCodesVal = codesValMap.get(pointId);
 
                         if (null != syncCodesVal) {
-                            // 更新缓存中的数据
-                            String hKey = NEW_HOUR_READING + "-" + pointId;
-                            redisService.setCacheMapValue(dbAttr.getObjCode(), hKey, syncCodesVal.getValue());
-
-                            if (!StringUtils.equals(syncCodesVal.getValue(), dbItem.getValue()) || !StringUtils.equals(
-                                syncCodesVal.getTime(), dbItem.getUpdateTime())) {
-                                dbNeedUpdate = true;
-
-                                dbItem.setValue(syncCodesVal.getValue());
-                                dbItem.setUpdateTime(syncCodesVal.getTime());
+                            // 数据验证和处理
+                            DataValidationResult validationResult = validateMeterData(dbAttr.getObjCode(),
+                                pointId, dbItem.getValue(), syncCodesVal.getValue());
+
+                            if (validationResult.isValid()) {
+                                // 更新缓存中的数据
+                                String hKey = NEW_HOUR_READING + "-" + pointId;
+                                redisService.setCacheMapValue(dbAttr.getObjCode(), hKey, validationResult.getValidValue());
+
+                                if (!StringUtils.equals(validationResult.getValidValue(), dbItem.getValue()) ||
+                                    !StringUtils.equals(syncCodesVal.getTime(), dbItem.getUpdateTime())) {
+                                    dbNeedUpdate = true;
+
+                                    dbItem.setValue(validationResult.getValidValue());
+                                    dbItem.setUpdateTime(syncCodesVal.getTime());
+                                }
+                            } else {
+                                // 记录异常数据但不更新
+                                log.warn("检测到异常抄表数据 - 设备:{}, 测点:{}, 旧值:{}, 新值:{}, 原因:{}",
+                                    dbAttr.getObjCode(), pointId, dbItem.getValue(),
+                                    syncCodesVal.getValue(), validationResult.getReason());
                             }
                         }
                     }
@@ -255,7 +265,7 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
     }
 
     /**
-     * 能耗数据抄报
+     * 能耗数据抄报(扩展支持市电计量)
      */
     @Override
     public int meterHourProd() {
@@ -265,11 +275,29 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
             // 获取所有能源设备列表
             List<EmsDevice> deviceList = getDeviceList();
             List<MeterDevice> meterDeviceList = getMeterDeviceList();
+            List<ElecMeterH> allElecMeterHList = new ArrayList<>();
 
             // 遍历每个能源设备
             if (CollectionUtils.isNotEmpty(deviceList)) {
                 for (EmsDevice emsDevice : deviceList) {
-                    cnt += meterDevHourProd(emsDevice, meterDeviceList);
+                    // 产出表计小时计量数据
+                    MeterHourProdResult result = meterDevHourProd(emsDevice, meterDeviceList);
+
+                    if (CollectionUtils.isNotEmpty(result.getElecMeterHList())) {
+                        elecMeterHService.insertBatch(result.getElecMeterHList());
+                        allElecMeterHList.addAll(result.getElecMeterHList());
+                    }
+
+                    if (CollectionUtils.isNotEmpty(result.getWaterMeterHList())) {
+                        waterMeterHService.insertBatch(result.getWaterMeterHList());
+                    }
+
+                    cnt += result.getElecMeterHList().size() + result.getWaterMeterHList().size();
+                }
+
+                // 统一处理市电供应数据(避免重复)
+                if (CollectionUtils.isNotEmpty(allElecMeterHList)) {
+                    generatePgSupplyData(allElecMeterHList);
                 }
             }
         }
@@ -280,8 +308,11 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
         return cnt;
     }
 
-    private int meterDevHourProd(EmsDevice emsDevice, List<MeterDevice> meterDeviceList) {
-        int cnt = 0;
+    /**
+     * 修改后的单设备计量产出方法,返回详细结果
+     */
+    private MeterHourProdResult meterDevHourProd(EmsDevice emsDevice, List<MeterDevice> meterDeviceList) {
+        MeterHourProdResult result = new MeterHourProdResult();
 
         try {
             // 查询当前设备的接口属性值
@@ -302,7 +333,8 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
 
             // 电表抄表数据保存
             if (CollectionUtils.isNotEmpty(elecDevs)) {
-                cnt += saveElecMeterReading(emsDevice, elecDevs);
+                List<ElecMeterH> elecMeterHList = saveElecMeterReading(emsDevice, elecDevs);
+                result.setElecMeterHList(elecMeterHList);
             }
 
             // 水表过滤
@@ -312,17 +344,18 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
 
             // 水表抄表数据保存
             if (CollectionUtils.isNotEmpty(waterDevs)) {
-                cnt += saveWaterMeterReading(emsDevice, waterDevs);
+                List<WaterMeterH> waterMeterHList = saveWaterMeterReading(emsDevice, waterDevs);
+                result.setWaterMeterHList(waterMeterHList);
             }
         }
         catch (Exception e) {
             log.error("meterDevHourProd error! deviceCode:{}", emsDevice.getDeviceCode(), e);
         }
 
-        return cnt;
+        return result;
     }
 
-    private int saveElecMeterReading(EmsDevice gwDevice, List<MeterDevice> deviceList) {
+    private List<ElecMeterH> saveElecMeterReading(EmsDevice gwDevice, List<MeterDevice> deviceList) {
         Map<String, Price> priceMap = new ConcurrentHashMap<>();
         List<ElecMeterH> meterHList = new ArrayList<>();
         Date date = DateUtils.adjustHour(new Date(), -1);
@@ -350,7 +383,7 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
             }
         }
 
-        return CollectionUtils.isNotEmpty(meterHList) ? elecMeterHService.insertBatch(meterHList) : 0;
+        return meterHList;
     }
 
     @Override
@@ -386,7 +419,7 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
         return elecMeterH;
     }
 
-    private int saveWaterMeterReading(EmsDevice gwDevice, List<MeterDevice> deviceList) {
+    private List<WaterMeterH> saveWaterMeterReading(EmsDevice gwDevice, List<MeterDevice> deviceList) {
         Map<String, FdEnergyPriceConfig> priceMap = new ConcurrentHashMap<>();
         List<WaterMeterH> meterHList = new ArrayList<>();
 
@@ -402,7 +435,8 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
                 String lastMeterReading = redisService.getCacheMapValue(gwDevice.getDeviceCode(), lastCacheKey);
 
                 // 组装水表抄报数据
-                WaterMeterH waterMeterH = getWaterMeterH(gwDevice.getDeviceCode(), meterDevice, lastMeterReading, newMeterReading);
+                WaterMeterH waterMeterH = getWaterMeterH(gwDevice.getDeviceCode(), meterDevice, lastMeterReading,
+                    newMeterReading);
 
                 if (null != waterMeterH) {
                     FdEnergyPriceConfig price = priceMap.computeIfAbsent(gwDevice.getAreaCode(),
@@ -413,7 +447,7 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
             }
         }
 
-        return CollectionUtils.isNotEmpty(meterHList) ? waterMeterHService.insertBatch(meterHList) : 0;
+        return meterHList;
     }
 
     @Override
@@ -451,6 +485,108 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
         return waterMeterH;
     }
 
+    /**
+     * 产出市电供应计量数据(优化版)
+     */
+    private void generatePgSupplyData(List<ElecMeterH> allElecMeterHList) {
+        try {
+            // 生成市电供应数据
+            List<ElecPgSupplyH> pgSupplyHList = new ArrayList<>();
+
+            // 获取所有区域的市电设施及其绑定的计量设备
+            Set<String> areaCodeSet = allElecMeterHList.stream().map(ElecMeterH::getAreaCode)
+                .collect(Collectors.toSet());
+
+            Map<String, Price> priceMap = new ConcurrentHashMap<>();
+            Date recordTime = DateUtils.adjustHour(new Date(), -1);
+
+            // 按区域查询市电设施
+            for (String areaCode : areaCodeSet) {
+                // 查询区域下市电的供应设施(同时获取了设施绑定的表计)
+                List<BoundaryObj> facsMeterBinds = facsService.getFacsWithMeterDev(areaCode, "W", "W2");
+
+                if (CollectionUtils.isNotEmpty(facsMeterBinds)) {
+                    for (BoundaryObj facsMeterBind : facsMeterBinds) {
+                        // 过滤出当前设施绑定表计对应的小时计量数据
+                        List<ElecMeterH> subElecMeterHs = filterBindElecMeterDevs(facsMeterBind, allElecMeterHList);
+
+                        if (CollectionUtils.isNotEmpty(subElecMeterHs)) {
+                            // 直接累加同一设施下的所有电表数据(同一小时电价类型相同)
+                            double totalQuantity = subElecMeterHs.stream()
+                                .mapToDouble(ElecMeterH::getElecQuantity)
+                                .sum();
+
+                            double totalCost = subElecMeterHs.stream()
+                                .mapToDouble(ElecMeterH::getUseElecCost)
+                                .sum();
+
+                            // 精度控制:用量保留1位小数,金额保留2位小数
+                            totalQuantity = formatToDecimalPlaces(totalQuantity, 1);
+                            totalCost = formatToDecimalPlaces(totalCost, 2);
+
+                            // 获取电价信息(同一小时所有表计的电价类型和单价都相同,取第一个即可)
+                            ElecMeterH firstMeter = subElecMeterHs.get(0);
+                            Integer meterType = firstMeter.getMeterType();
+                            Double unitPrice = firstMeter.getMeterUnitPrice();
+
+                            // 创建市电供应记录
+                            ElecPgSupplyH pgSupplyH = new ElecPgSupplyH();
+                            pgSupplyH.setAreaCode(areaCode);
+                            pgSupplyH.setFacsCode(facsMeterBind.getObjCode());
+                            pgSupplyH.setRecordTime(recordTime);
+                            pgSupplyH.setDate(recordTime);
+                            pgSupplyH.setTime(recordTime);
+                            pgSupplyH.setTimeIndex(getHourIndex(recordTime));
+                            pgSupplyH.setMeterType(meterType);
+                            pgSupplyH.setMeterUnitPrice(unitPrice);
+                            pgSupplyH.setUseElecQuantity(totalQuantity);
+                            pgSupplyH.setUseElecCost(totalCost);
+                            pgSupplyHList.add(pgSupplyH);
+
+                        }
+                        else {
+                            Price price = priceMap.computeIfAbsent(areaCode,
+                                k -> priceService.getElecHourPrice(areaCode, recordTime));
+
+                            ElecPgSupplyH pgSupplyH = new ElecPgSupplyH();
+                            pgSupplyH.setAreaCode(areaCode);
+                            pgSupplyH.setFacsCode(facsMeterBind.getObjCode());
+                            pgSupplyH.setRecordTime(recordTime);
+                            pgSupplyH.setDate(recordTime);
+                            pgSupplyH.setTime(recordTime);
+                            pgSupplyH.setTimeIndex(getHourIndex(recordTime));
+                            pgSupplyH.setMeterType(price.getMeterType());
+                            pgSupplyH.setMeterUnitPrice(price.getPriceValue());
+                            pgSupplyH.setUseElecQuantity(0.0);
+                            pgSupplyH.setUseElecCost(0.0);
+                            pgSupplyHList.add(pgSupplyH);
+                        }
+                    }
+                }
+                else {
+                    log.warn("未找到市电设施配置,无法产出市电供应数据");
+                }
+            }
+
+            if (CollectionUtils.isNotEmpty(pgSupplyHList)) {
+                pgSupplyHService.insertBatch(pgSupplyHList);
+            }
+        }
+        catch (Exception e) {
+            log.error("产出市电供应计量数据异常", e);
+        }
+    }
+
+    private List<ElecMeterH> filterBindElecMeterDevs(BoundaryObj facsMeterBind, List<ElecMeterH> allElecMeterHList) {
+        Set<String> bindElecMeterDevs = facsMeterBind.getBindElecMeterDevs();
+        if (CollectionUtils.isEmpty(bindElecMeterDevs)) {
+            return new ArrayList<>();
+        }
+        return allElecMeterHList.stream()
+            .filter(elecMeterH -> bindElecMeterDevs.contains(elecMeterH.getDeviceCode()))
+            .collect(Collectors.toList());
+    }
+
     private Set<String> getPointIds(List<EmsObjAttrValue> attrValues) {
         Set<String> pointIds = new HashSet<>();
 
@@ -469,4 +605,131 @@ public class InDoorEnergyHandler extends BaseMeterDevHandler {
 
         return pointIds;
     }
+
+    /**
+     * 验证抄表数据的合理性
+     */
+    private DataValidationResult validateMeterData(String deviceCode, String pointId, String oldValue, String newValue) {
+        try {
+            // 新数据为空或无效
+            if (StringUtils.isBlank(newValue)) {
+                return DataValidationResult.invalid("新值为空");
+            }
+
+            double newVal = Double.parseDouble(newValue);
+
+            // 首次数据,直接接受
+            if (StringUtils.isBlank(oldValue)) {
+                return DataValidationResult.valid(newValue);
+            }
+
+            double oldVal = Double.parseDouble(oldValue);
+            double difference = newVal - oldVal;
+
+            // 1. 检查是否为明显的向后跳变(新值比旧值小很多)
+            if (difference < MIN_REASONABLE_DECREASE_RATE) {
+                // 检查是否可能是表计重置(新值很小,旧值很大)
+                if (newVal < 100 && oldVal > 10000) {
+                    log.info("检测到可能的表计重置 - 设备:{}, 测点:{}, 旧值:{}, 新值:{}",
+                        deviceCode, pointId, oldVal, newVal);
+                    // 表计重置的情况,需要人工确认,暂时不更新
+                    return DataValidationResult.invalid("疑似表计重置,需人工确认");
+                } else {
+                    return DataValidationResult.invalid(String.format("数据向后跳变,差值:%.2f", difference));
+                }
+            }
+
+            // 2. 检查是否增长过快(可能是数据错误)
+            if (difference > MAX_HOUR_INCREASE_RATE) {
+                return DataValidationResult.invalid(String.format("增长过快,差值:%.2f", difference));
+            }
+
+            // 3. 连续异常数据确认机制
+            if (Math.abs(difference) > MAX_HOUR_INCREASE_RATE * 0.1) { // 超过正常增长的10%认为需要关注
+                String abnormalKey = "ABNORMAL_COUNT_" + pointId;
+                String countStr = redisService.getCacheMapValue(deviceCode, abnormalKey);
+                int abnormalCount = StringUtils.isNotBlank(countStr) ? Integer.parseInt(countStr) : 0;
+
+                abnormalCount++;
+                redisService.setCacheMapValue(deviceCode, abnormalKey, String.valueOf(abnormalCount));
+
+                // 如果连续异常次数太多,需要告警但仍然更新数据
+                if (abnormalCount >= ABNORMAL_DATA_CONFIRM_COUNT) {
+                    log.warn("连续异常数据 - 设备:{}, 测点:{}, 连续{}次异常, 当前差值:%.2f",
+                        deviceCode, pointId, abnormalCount, difference);
+                    // 重置计数
+                    redisService.setCacheMapValue(deviceCode, abnormalKey, "0");
+                }
+            } else {
+                // 数据正常,清除异常计数
+                String abnormalKey = "ABNORMAL_COUNT_" + pointId;
+                redisService.setCacheMapValue(deviceCode, abnormalKey, "0");
+            }
+
+            return DataValidationResult.valid(newValue);
+
+        } catch (NumberFormatException e) {
+            return DataValidationResult.invalid("数据格式错误: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 单个设备的计量数据产出结果
+     */
+    private static class MeterHourProdResult {
+        private List<ElecMeterH> elecMeterHList = new ArrayList<>();
+
+        private List<WaterMeterH> waterMeterHList = new ArrayList<>();
+
+        public List<ElecMeterH> getElecMeterHList() {
+            return elecMeterHList;
+        }
+
+        public void setElecMeterHList(List<ElecMeterH> elecMeterHList) {
+            this.elecMeterHList = elecMeterHList;
+        }
+
+        public List<WaterMeterH> getWaterMeterHList() {
+            return waterMeterHList;
+        }
+
+        public void setWaterMeterHList(List<WaterMeterH> waterMeterHList) {
+            this.waterMeterHList = waterMeterHList;
+        }
+    }
+
+    /**
+     * 数据验证结果内部类
+     */
+    private static class DataValidationResult {
+        private final boolean valid;
+        private final String validValue;
+        private final String reason;
+
+        private DataValidationResult(boolean valid, String validValue, String reason) {
+            this.valid = valid;
+            this.validValue = validValue;
+            this.reason = reason;
+        }
+
+        public static DataValidationResult valid(String value) {
+            return new DataValidationResult(true, value, null);
+        }
+
+        public static DataValidationResult invalid(String reason) {
+            return new DataValidationResult(false, null, reason);
+        }
+
+        public boolean isValid() {
+            return valid;
+        }
+
+        public String getValidValue() {
+            return validValue;
+        }
+
+        public String getReason() {
+            return reason;
+        }
+    }
 }

+ 3 - 4
ems/ems-core/src/main/java/com/ruoyi/ems/domain/ElecPgSupplyH.java

@@ -6,7 +6,6 @@ import com.huashe.common.domain.BaseEntity;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 
-import java.sql.Time;
 import java.util.Date;
 
 /**
@@ -51,7 +50,7 @@ public class ElecPgSupplyH extends BaseEntity
     /** 时间 */
     @JsonFormat(pattern = "HH:mm:ss")
     @Excel(name = "时间", width = 30, dateFormat = "HH:mm:ss")
-    private Time time;
+    private Date time;
 
     /** 时间序列 */
     @Excel(name = "时间序列")
@@ -137,11 +136,11 @@ public class ElecPgSupplyH extends BaseEntity
         this.date = date;
     }
 
-    public Time getTime() {
+    public Date getTime() {
         return time;
     }
 
-    public void setTime(Time time) {
+    public void setTime(Date time) {
         this.time = time;
     }
 

+ 7 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/ElecPgSupplyHMapper.java

@@ -55,6 +55,13 @@ public interface ElecPgSupplyHMapper {
     int insertPgSupplyH(ElecPgSupplyH elecPgSupplyH);
 
     /**
+     * 批量新增电网供应计量-小时
+     * @param list 电网供应计量-小时集合
+     * @return 结果
+     */
+    int insertBatch(List<ElecPgSupplyH> list);
+
+    /**
      * 修改电网供应计量-小时
      *
      * @param elecPgSupplyH 电网供应计量-小时

+ 7 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IElecPgSupplyHService.java

@@ -49,6 +49,13 @@ public interface IElecPgSupplyHService {
     int insertPgSupplyH(ElecPgSupplyH pgSupplyH);
 
     /**
+     * 批量新增电网供应计量-小时
+     * @param list 电网供应计量-小时集合
+     * @return
+     */
+    int insertBatch(List<ElecPgSupplyH> list);
+
+    /**
      * 修改电网供应计量-小时
      *
      * @param pgSupplyH 电网供应计量-小时

+ 5 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/ElecPgSupplyHServiceImpl.java

@@ -72,6 +72,11 @@ public class ElecPgSupplyHServiceImpl implements IElecPgSupplyHService {
         return pgSupplyHMapper.insertPgSupplyH(elecPgSupplyH);
     }
 
+    @Override
+    public int insertBatch(List<ElecPgSupplyH> list) {
+        return pgSupplyHMapper.insertBatch(list);
+    }
+
     /**
      * 修改电网供应计量-小时
      *

+ 2 - 2
ems/ems-core/src/main/resources/mapper/ems/ElecMeterHMapper.xml

@@ -68,8 +68,8 @@
         '${objCode}' as device_code,
         '${objName}' as device_name,
         m.area_code, m.record_time, m.`date`, m.`time`, m.time_index,
-        sum(m.elec_quantity) as elec_quantity,
-        sum(m.use_elec_cost) as use_elec_cost
+        round(sum(m.elec_quantity),2) as elec_quantity,
+        round(sum(m.use_elec_cost),2) as use_elec_cost
         from adm_elec_meter_h m
         <where>
             <if test="areaCode != null and areaCode != '-1'">

+ 9 - 0
ems/ems-core/src/main/resources/mapper/ems/ElecPgSupplyHMapper.xml

@@ -182,6 +182,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          </trim>
     </insert>
 
+    <insert id="insertBatch" parameterType="java.util.List">
+        insert into adm_ems_pg_supply_h (area_code, facs_code, record_time, `date`, `time`, time_index, meter_type, meter_unit_price, use_elec_quantity, use_elec_cost)
+        values
+        <foreach collection="list" item="item" index="index" separator=",">
+            (#{item.areaCode}, #{item.facsCode}, #{item.recordTime}, #{item.date}, #{item.time}, #{item.timeIndex},
+            #{item.meterType}, #{item.meterUnitPrice}, #{item.useElecQuantity}, #{item.useElecCost})
+        </foreach>
+    </insert>
+
     <update id="updatePgSupplyH" parameterType="com.ruoyi.ems.domain.ElecPgSupplyH">
         update adm_ems_pg_supply_h
         <trim prefix="SET" suffixOverrides=",">

+ 84 - 0
ems/sql/ems_init_data.sql

@@ -699,6 +699,11 @@ INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-FW-02', 45, 'C_1005_AV_0400');
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-FW-02', 45, 'C_1007_AV_0000');
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-FW-02', 45, 'C_1007_AV_0200');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0002');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0003');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0004');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0005');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0006');
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0600');
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0601');
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 45, 'C_1003_AV_0602');
@@ -721,6 +726,85 @@ INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 70, 'C_1004_AV_0200');
 INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'Z-QT-02', 70, 'C_1005_AV_0600');
 
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0001');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0000');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0206');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0214');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0222');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0230');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0238');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0246');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0254');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0262');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0270');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0278');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0286');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0294');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0302');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0310');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0318');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0326');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0334');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0342');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0350');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0406');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2005_AV_0200');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2005_AV_0201');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2005_AV_0400');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2005_AV_0401');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2006_AV_0000');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0002');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0003');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0005');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0006');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0600');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0601');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0603');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2003_AV_0604');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W201', 45, 'C_2004_AV_0400');
+
+
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0001');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0000');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0206');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0214');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0222');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0230');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0238');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0246');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0254');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0262');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0270');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0278');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0286');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0294');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0302');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0310');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0318');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0326');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0334');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0342');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0350');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0406');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1005_AV_0000');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1005_AV_0200');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1005_AV_0201');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1005_AV_0400');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1007_AV_0000');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1007_AV_0200');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0002');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0003');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0004');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0005');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0006');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0600');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0601');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0602');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0603');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1003_AV_0604');
+INSERT INTO `adm_meter_boundary_rel` (`obj_type`, `boundary_obj`, `meter_cls`, `meter_device`) VALUES (2, 'W202', 45, 'C_1004_AV_0400');
+
+
 -- 抄表demo数据
 INSERT INTO adm_meter_reading (`device_code`, `area_code`, `year`, `meter_month`, `last_reading`, `last_time`, `meter_reading`, `meter_time`, `increase`, `create_time`, `update_time`) VALUES ('J-D-B-101', '321283124S3001', '2024', '202401', 0, '2023-12-31', 100, '2024-01-31', 100, NULL, NULL);
 INSERT INTO adm_meter_reading (`device_code`, `area_code`, `year`, `meter_month`, `last_reading`, `last_time`, `meter_reading`, `meter_time`, `increase`, `create_time`, `update_time`) VALUES ('J-D-B-101', '321283124S3001', '2024', '202402', 100, '2024-01-31', 238, '2024-02-28', 138, NULL, NULL);