Explorar o código

1.按时间维度(结合create_time)绘制三相电压、电流的趋势曲线,分析日内 / 日间波动规律,判断是否存在周期性异常(如特定时段电压骤降)。
2.结合total_electricity(总用电量)及分时电量(sharp_active_power_consumption尖、peak峰、average平、valley谷),统计分时电量占比,分析用电负荷的峰谷分布特征,为错峰用电策略提供依据。
3.按table_number(表号)分组,汇总其对应的用电量、功率、电压等参数

zlm hai 8 meses
pai
achega
2bd3e41088

+ 34 - 0
electricity-service/src/main/java/com/zksy/electricity/controller/MessageParseController.java

@@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.zksy.common.core.domain.Result;
 import com.zksy.common.utils.SearchUtil;
 import com.zksy.electricity.domain.MessageParseResult;
+import com.zksy.electricity.domain.vo.MessageParseVo;
+import com.zksy.electricity.domain.vo.PowerLoadDistributionVo;
+import com.zksy.electricity.domain.vo.VoltageCurrentTrendVo;
 import com.zksy.electricity.service.MessageParseResultService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -31,4 +34,35 @@ public class MessageParseController {
         List<MessageParseResult> list = service.list(SearchUtil.parseWhereSql(conditionJson));
         return Result.ok(list);
     }
+
+
+    @GetMapping("/summaryByTable")
+    @ApiOperation(value = "按表号分组汇总统计")
+    public Result getSummaryByTable() {
+        List<MessageParseVo> vo = service.getSummaryByTableNumber();
+        return Result.ok(vo);
+    }
+
+    @GetMapping("/voltageCurrentTrend")
+    @ApiOperation(value = "按时间范围查询三相电压、电流趋势")
+    public Result getVoltageCurrentTrend(
+            @RequestParam String startTime,
+            @RequestParam String endTime,
+            @RequestParam(required = false) String tableNumber
+    ) {
+        VoltageCurrentTrendVo vo = service.getVoltageCurrentTrend(startTime, endTime, tableNumber);
+        return Result.ok(vo);
+    }
+
+    @GetMapping("/powerLoadDistribution")
+    @ApiOperation(value = "分时用电负荷分布")
+    public Result getPowerLoadDistribution(
+            @RequestParam(required = false) String tableNumber,
+            @RequestParam String startTime,
+            @RequestParam String endTime) {
+
+        List<PowerLoadDistributionVo> list = service.getPowerLoadDistribution(tableNumber, startTime, endTime);
+
+        return Result.ok(list);
+    }
 }

+ 40 - 0
electricity-service/src/main/java/com/zksy/electricity/domain/vo/MessageParseVo.java

@@ -0,0 +1,40 @@
+package com.zksy.electricity.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * 按table_number(表号)分组,汇总其对应的用电量、功率、电压等参数
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MessageParseVo {
+    /**
+     * 表号
+     */
+    private String tableNumber;
+    /**
+     * 总用电量
+     */
+    private BigDecimal totalElectricity;
+    /**
+     * A相平均电压
+     */
+    private BigDecimal avgAVoltage;
+    private BigDecimal avgBVoltage;
+    private BigDecimal avgCVoltage;
+    /**
+     * A相平均电流
+     */
+    private BigDecimal avgACurrent;
+    private BigDecimal avgBCurrent;
+    private BigDecimal avgCCurrent;
+    /**
+     * 平均总有功功率
+     */
+    private BigDecimal avgTotalActivePower;
+}

+ 58 - 0
electricity-service/src/main/java/com/zksy/electricity/domain/vo/PowerLoadDistributionVo.java

@@ -0,0 +1,58 @@
+package com.zksy.electricity.domain.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * 结合total_electricity(总用电量)及分时电量(sharp_active_power_consumption尖、peak峰、average平、valley谷),统计分时电量占比,分析用电负荷的峰谷分布特征,为错峰用电策略提供依据。
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class PowerLoadDistributionVo {
+
+    /**
+     * 电表号
+     */
+    private String tableNumber;
+    /**
+     * 总用电量
+     */
+    private BigDecimal totalElectricity;
+    /**
+     * 尖时用电量
+     */
+    private BigDecimal sharp;
+    /**
+     * 峰时用电量
+     */
+    private BigDecimal peak;
+    /**
+     * 平时用电量
+     */
+    private BigDecimal average;
+    /**
+     * 谷时用电量
+     */
+    private BigDecimal valley;
+
+    /**
+     * 尖占比
+     */
+    private BigDecimal sharpRatio;
+    /**
+     * 峰占比
+     */
+    private BigDecimal peakRatio;
+    /**
+     * 平占比
+     */
+    private BigDecimal averageRatio;
+    /**
+     * 谷占比
+     */
+    private BigDecimal valleyRatio;
+}

+ 36 - 0
electricity-service/src/main/java/com/zksy/electricity/domain/vo/VoltageCurrentTrendVo.java

@@ -0,0 +1,36 @@
+package com.zksy.electricity.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 按时间维度(结合create_time)绘制三相电压、电流的趋势曲线,分析日内 / 日间波动规律,判断是否存在周期性异常(如特定时段电压骤降)。
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class VoltageCurrentTrendVo {
+    /**
+     * 时间轴
+     */
+    @JsonProperty("time")
+    private List<String> time;
+    @JsonProperty("aVoltage")
+    private List<BigDecimal> aVoltage;
+    @JsonProperty("bVoltage")
+    private List<BigDecimal> bVoltage;
+    @JsonProperty("cVoltage")
+    private List<BigDecimal> cVoltage;
+    @JsonProperty("aCurrent")
+    private List<BigDecimal> aCurrent;
+    @JsonProperty("bCurrent")
+    private List<BigDecimal> bCurrent;
+    @JsonProperty("cCurrent")
+    private List<BigDecimal> cCurrent;
+
+}

+ 11 - 0
electricity-service/src/main/java/com/zksy/electricity/service/MessageParseResultService.java

@@ -2,7 +2,18 @@ package com.zksy.electricity.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.zksy.electricity.domain.MessageParseResult;
+import com.zksy.electricity.domain.vo.MessageParseVo;
+import com.zksy.electricity.domain.vo.PowerLoadDistributionVo;
+import com.zksy.electricity.domain.vo.VoltageCurrentTrendVo;
+
+import java.util.List;
 
 public interface MessageParseResultService extends IService<MessageParseResult> {
     public Integer saveMessageParseResult(MessageParseResult result);
+
+    List<MessageParseVo> getSummaryByTableNumber();
+
+    VoltageCurrentTrendVo getVoltageCurrentTrend(String startTimeStr, String endTimeStr, String tableNumber);
+
+    List<PowerLoadDistributionVo> getPowerLoadDistribution(String tableNumber, String startTime, String endTime);
 }

+ 219 - 0
electricity-service/src/main/java/com/zksy/electricity/service/impl/MessageParseResultServiceImpl.java

@@ -1,12 +1,25 @@
 package com.zksy.electricity.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.electricity.domain.MessageParseResult;
+import com.zksy.electricity.domain.vo.MessageParseVo;
+import com.zksy.electricity.domain.vo.PowerLoadDistributionVo;
+import com.zksy.electricity.domain.vo.VoltageCurrentTrendVo;
 import com.zksy.electricity.mapper.MessageParseResultMapper;
 import com.zksy.electricity.service.MessageParseResultService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 /**
  * @author Administrator
  * @version 1.0
@@ -22,4 +35,210 @@ public class MessageParseResultServiceImpl extends ServiceImpl<MessageParseResul
     public Integer saveMessageParseResult(MessageParseResult result) {
         return messageParseResultMapper.insert(result);
     }
+
+    /**
+     * 按 tableNumber 分组统计各参数
+     */
+    @Override
+    public List<MessageParseVo> getSummaryByTableNumber() {
+        List<MessageParseResult> allData = this.list();
+
+        Map<String, List<MessageParseResult>> grouped = allData.stream()
+                .collect(Collectors.groupingBy(MessageParseResult::getTableNumber));
+
+        List<MessageParseVo> resultList = new ArrayList<>();
+
+        for (Map.Entry<String, List<MessageParseResult>> entry : grouped.entrySet()) {
+            String tableNumber = entry.getKey();
+            List<MessageParseResult> records = entry.getValue();
+
+            MessageParseVo vo = new MessageParseVo();
+            vo.setTableNumber(tableNumber);
+
+            BigDecimal totalElectricity = records.stream()
+                    .map(MessageParseResult::getTotalElectricity)
+                    .map(this::parseNumber)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            vo.setTotalElectricity(totalElectricity);
+
+            vo.setAvgAVoltage(avg(records, MessageParseResult::getAVoltage));
+            vo.setAvgBVoltage(avg(records, MessageParseResult::getBVoltage));
+            vo.setAvgCVoltage(avg(records, MessageParseResult::getCVoltage));
+            vo.setAvgACurrent(avg(records, MessageParseResult::getACurrent));
+            vo.setAvgBCurrent(avg(records, MessageParseResult::getBCurrent));
+            vo.setAvgCCurrent(avg(records, MessageParseResult::getCCurrent));
+            vo.setAvgTotalActivePower(avg(records, MessageParseResult::getTotalActivePower));
+
+            resultList.add(vo);
+        }
+
+        return resultList;
+    }
+
+    @Override
+    public VoltageCurrentTrendVo getVoltageCurrentTrend(String startTimeStr, String endTimeStr, String tableNumber) {
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date startTime;
+        Date endTime;
+        try {
+            startTime = sdf.parse(startTimeStr);
+            endTime = sdf.parse(endTimeStr);
+        } catch (ParseException e) {
+            throw new IllegalArgumentException("时间格式错误,应为 yyyy-MM-dd HH:mm:ss");
+        }
+
+
+        List<MessageParseResult> data = this.list(
+                Wrappers.<MessageParseResult>lambdaQuery()
+                        .between(MessageParseResult::getCreateTime, startTime, endTime)
+                        .eq(tableNumber != null && !tableNumber.isEmpty(), MessageParseResult::getTableNumber, tableNumber)
+                        .orderByAsc(MessageParseResult::getCreateTime)
+        );
+
+        List<String> timeList = new ArrayList<>();
+        List<BigDecimal> aVoltageList = new ArrayList<>();
+        List<BigDecimal> bVoltageList = new ArrayList<>();
+        List<BigDecimal> cVoltageList = new ArrayList<>();
+        List<BigDecimal> aCurrentList = new ArrayList<>();
+        List<BigDecimal> bCurrentList = new ArrayList<>();
+        List<BigDecimal> cCurrentList = new ArrayList<>();
+
+        SimpleDateFormat sdff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        for (MessageParseResult r : data) {
+            timeList.add(sdff.format(r.getCreateTime()));
+            aVoltageList.add(parseNumber(r.getAVoltage()));
+            bVoltageList.add(parseNumber(r.getBVoltage()));
+            cVoltageList.add(parseNumber(r.getCVoltage()));
+            aCurrentList.add(parseNumber(r.getACurrent()));
+            bCurrentList.add(parseNumber(r.getBCurrent()));
+            cCurrentList.add(parseNumber(r.getCCurrent()));
+        }
+
+        VoltageCurrentTrendVo vo = new VoltageCurrentTrendVo();
+        vo.setTime(timeList);
+        vo.setAVoltage(aVoltageList);
+        vo.setBVoltage(bVoltageList);
+        vo.setCVoltage(cVoltageList);
+        vo.setACurrent(aCurrentList);
+        vo.setBCurrent(bCurrentList);
+        vo.setCCurrent(cCurrentList);
+        return vo;
+    }
+
+    @Override
+    public List<PowerLoadDistributionVo> getPowerLoadDistribution(String tableNumber, String startTime, String endTime) {
+        List<MessageParseResult> records;
+
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            Date start = sdf.parse(startTime);
+            Date end = sdf.parse(endTime);
+
+            records = this.list(new QueryWrapper<MessageParseResult>()
+                    .eq(tableNumber != null, "table_number", tableNumber)
+                    .ge("create_time", start)
+                    .le("create_time", end)
+            );
+        } catch (ParseException e) {
+            return new ArrayList<>();
+        } catch (Exception e) {
+            return new ArrayList<>();
+        }
+
+        Map<String, List<MessageParseResult>> grouped = records.stream()
+                .collect(Collectors.groupingBy(MessageParseResult::getTableNumber));
+
+        List<PowerLoadDistributionVo> resultList = new ArrayList<>();
+
+        for (Map.Entry<String, List<MessageParseResult>> entry : grouped.entrySet()) {
+            String tn = entry.getKey();
+            List<MessageParseResult> recs = entry.getValue();
+
+            PowerLoadDistributionVo vo = new PowerLoadDistributionVo();
+            vo.setTableNumber(tn);
+
+            BigDecimal totalElectricity = recs.stream()
+                    .map(MessageParseResult::getTotalElectricity)
+                    .map(this::parseNumber)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            BigDecimal sharp = recs.stream()
+                    .map(MessageParseResult::getSharpActivePowerConsumption)
+                    .map(this::parseNumber)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            BigDecimal peak = recs.stream()
+                    .map(MessageParseResult::getPeakActivePowerConsumption)
+                    .map(this::parseNumber)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            BigDecimal average = recs.stream()
+                    .map(MessageParseResult::getAverageActivePowerConsumption)
+                    .map(this::parseNumber)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            BigDecimal valley = recs.stream()
+                    .map(MessageParseResult::getValleyActivePower)
+                    .map(this::parseNumber)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            vo.setTotalElectricity(totalElectricity);
+            vo.setSharp(sharp);
+            vo.setPeak(peak);
+            vo.setAverage(average);
+            vo.setValley(valley);
+
+            if (totalElectricity.compareTo(BigDecimal.ZERO) > 0) {
+                vo.setSharpRatio(sharp.divide(totalElectricity, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
+                vo.setPeakRatio(peak.divide(totalElectricity, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
+                vo.setAverageRatio(average.divide(totalElectricity, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
+                vo.setValleyRatio(valley.divide(totalElectricity, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
+            } else {
+                vo.setSharpRatio(BigDecimal.ZERO);
+                vo.setPeakRatio(BigDecimal.ZERO);
+                vo.setAverageRatio(BigDecimal.ZERO);
+                vo.setValleyRatio(BigDecimal.ZERO);
+            }
+
+            resultList.add(vo);
+        }
+
+        return resultList;
+    }
+    /**
+     * 将带单位的字符串解析为 BigDecimal
+     */
+    private BigDecimal parseNumber(String val) {
+        if (val == null || val.trim().isEmpty()) return BigDecimal.ZERO;
+        try {
+            // 去掉非数字、小数点、负号的字符
+            String cleaned = val.trim().replaceAll("[^0-9.\\-]", "");
+            if (cleaned.isEmpty()) return BigDecimal.ZERO;
+            return new BigDecimal(cleaned);
+        } catch (Exception e) {
+            return BigDecimal.ZERO;
+        }
+    }
+
+    /**
+     * 计算平均值
+     */
+    private BigDecimal avg(List<MessageParseResult> records, Function<MessageParseResult, String> getter) {
+        List<BigDecimal> nums = records.stream()
+                .map(getter)
+                .map(this::parseNumber)
+                .collect(Collectors.toList());
+
+        if (nums.isEmpty()) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal sum = nums.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
+        return sum.divide(BigDecimal.valueOf(nums.size()), 2, RoundingMode.HALF_UP);
+    }
 }