From 63486c527b01c459110a88930d9cda1ded633aee Mon Sep 17 00:00:00 2001
From: “djh” <“3298565835@qq.com”>
Date: Tue, 11 Nov 2025 10:32:30 +0800
Subject: [PATCH] 修改新增气象数据统计

---
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/DataReceiveServiceImpl.java                |   43 ++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/SummaryStatsRepository.java                  |   14 
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/SummaryStatsServiceImpl.java               |  112 ++++++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/MonitorDataServiceImpl.java                |    5 
 src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/resp/SummaryStatsPageRespDTO.java                |   74 ++++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/enums/StatsTypeEnum.java                                |   43 ++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/GasConcentrationRepository.java              |   36 ++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/SummaryStats.java                                |  255 +++++++++++++++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/utils/SummaryUtils.java                                 |  191 +++++++++++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/SummaryStatsReqDTO.java                      |   17 +
 src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/UploadGasConcentrationReqDTO.java            |    9 
 src/main/java/com/gkhy/fourierSpecialGasMonitor/controller/GasMonitorDataController.java                |   16 
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/MonitorDataService.java                         |    2 
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/GasConcentrationService.java                    |    7 
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/GasConcentrationServiceImpl.java           |   67 +++
 src/main/java/com/gkhy/fourierSpecialGasMonitor/domain/sysAdmin/service/impl/MenuDomainServiceImpl.java |   69 ++-
 src/main/java/com/gkhy/fourierSpecialGasMonitor/service/SummaryStatsService.java                        |   12 
 17 files changed, 943 insertions(+), 29 deletions(-)

diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/controller/GasMonitorDataController.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/controller/GasMonitorDataController.java
index d318878..189465a 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/controller/GasMonitorDataController.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/controller/GasMonitorDataController.java
@@ -8,6 +8,7 @@
 import com.gkhy.fourierSpecialGasMonitor.entity.query.GasPageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.req.*;
 import com.gkhy.fourierSpecialGasMonitor.service.MonitorDataService;
+import com.gkhy.fourierSpecialGasMonitor.service.SummaryStatsService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -25,6 +26,9 @@
 
     @Autowired
     private MonitorDataService monitorDataService;
+
+    @Autowired
+    private SummaryStatsService summaryStatsService;
 
     @PostMapping("/gas/lineChart")
     public Result gasLineChart(@RequestBody GasLineChartReqDTO reqDto){
@@ -74,4 +78,16 @@
         Result result = monitorDataService.gasConcentrationExport(gasConcentrationExportBO);
         return result;
     }
+
+    @PostMapping("/gasAtmosphere/stats")
+    public Result gasAtmosphereStats(@RequestBody PageQuery<SummaryStatsReqDTO> pageQuery){
+        Result result = summaryStatsService.listSummaryStats(pageQuery);
+        return result;
+    }
+
+    @PostMapping("/gasAtmosphere/extremum")
+    public Result gasAtmosphereExtremum(@RequestBody SummaryStatsReqDTO reqDTO){
+        Result result = monitorDataService.gasAtmosphereExtremum(reqDTO);
+        return result;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/domain/sysAdmin/service/impl/MenuDomainServiceImpl.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/domain/sysAdmin/service/impl/MenuDomainServiceImpl.java
index ddbff4f..bb7266c 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/domain/sysAdmin/service/impl/MenuDomainServiceImpl.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/domain/sysAdmin/service/impl/MenuDomainServiceImpl.java
@@ -340,33 +340,60 @@
         return parantList;
     }
 
-    /**
-     * 递归解析菜单数据,获取菜单树状结构
-     * @param parantItem
-     * @param childItemList
-     * @return
-     */
-    private List<MenuItemDomainDTO> praseChildMenuItems(MenuItemDomainDTO parantItem, List<MenuItemDomainDTO> childItemList){
-        if(childItemList == null || childItemList.size() == 0 || parantItem == null)
-            return null;
-        List<MenuItemDomainDTO> resultList = new ArrayList<>();
-//        childItemList.forEach(child -> {
+
+//    private List<MenuItemDomainDTO> praseChildMenuItems(MenuItemDomainDTO parantItem, List<MenuItemDomainDTO> childItemList){
+//        if(childItemList == null || childItemList.size() == 0 || parantItem == null)
+//            return null;
+//        List<MenuItemDomainDTO> resultList = new ArrayList<>();
+////        childItemList.forEach(child -> {
+////            if(parantItem.getId().equals(child.getParentId())){
+////                resultList.add(child);
+////            }
+////        });
+//        for(MenuItemDomainDTO child : childItemList){
 //            if(parantItem.getId().equals(child.getParentId())){
 //                resultList.add(child);
 //            }
-//        });
-        for(MenuItemDomainDTO child : childItemList){
-            if(parantItem.getId().equals(child.getParentId())){
-                resultList.add(child);
+//        }
+//        if(resultList.size() > 0){
+//            for (MenuItemDomainDTO child : childItemList){
+//                List<MenuItemDomainDTO> childList = praseChildMenuItems(child,childItemList);
+//                if(childList != null && childList.size() > 0)
+//                    child.setSubMenuItemList(childList);
+//            }
+//        }
+//        return resultList;
+//    }
+
+    /**
+     * 递归解析菜单数据,获取菜单树状结构
+     * @param parentItem
+     * @param allItems
+     * @return
+     */
+    private List<MenuItemDomainDTO> praseChildMenuItems(MenuItemDomainDTO parentItem, List<MenuItemDomainDTO> allItems) {
+        if (allItems == null || allItems.isEmpty() || parentItem == null) {
+            return null;
+        }
+        List<MenuItemDomainDTO> directChildren = new ArrayList<>();
+        // 1. 先找出当前父菜单的直接子菜单(parentId等于当前父菜单的id)
+        for (MenuItemDomainDTO item : allItems) {
+            if (parentItem.getId().equals(item.getParentId())) {
+                directChildren.add(item);
             }
         }
-        if(resultList.size() > 0){
-            for (MenuItemDomainDTO child : childItemList){
-                List<MenuItemDomainDTO> childList = praseChildMenuItems(child,childItemList);
-                if(childList != null && childList.size() > 0)
-                    child.setSubMenuItemList(childList);
+        // 2. 只对直接子菜单递归,找它们的子菜单(孙菜单)
+        if (!directChildren.isEmpty()) {
+            for (MenuItemDomainDTO child : directChildren) { // 关键:遍历directChildren而非allItems
+                List<MenuItemDomainDTO> grandChildren = praseChildMenuItems(child, allItems);
+                if (grandChildren != null && !grandChildren.isEmpty()) {
+                    child.setSubMenuItemList(grandChildren);
+                }
             }
         }
-        return resultList;
+        return directChildren;
     }
+
+
+
 }
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/SummaryStats.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/SummaryStats.java
new file mode 100644
index 0000000..ff06a9e
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/SummaryStats.java
@@ -0,0 +1,255 @@
+package com.gkhy.fourierSpecialGasMonitor.entity;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "summary_stats")
+@Data
+public class SummaryStats {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    private LocalDateTime time;
+
+    //温度
+    private Double tempMin;
+    private Double tempMax;
+    private Double tempAvg;
+    private Double temp;
+
+    //湿度
+    private Double  humidityMin;
+    private Double  humidityMax;
+    private Double  humidityAvg;
+    private Double  humidity;
+
+    //风速
+    private Double windSpeedMin;
+    private Double windSpeedMax;
+    private Double windSpeedAvg;
+    private Double windSpeed;
+
+    //风向
+    private Integer windDirectionMin;
+    private Integer windDirectionMax;
+    private Double windDirectionAvg;
+    private int windDirection;
+
+    //压力
+    private Double pressureMin;
+    private Double pressureMax;
+    private Double pressureAvg;
+    private Double pressure;
+
+    public SummaryStats(Double tempMin, Double tempMax, Double tempAvg,
+                        Double humidityMin, Double humidityMax, Double humidityAvg,
+                        Double windSpeedMin, Double windSpeedMax, Double windSpeedAvg,
+                        Integer windDirectionMin, Integer windDirectionMax, Double windDirectionAvg,
+                        Double pressureMin, Double pressureMax, Double pressureAvg) {
+        this.tempMin = tempMin;
+        this.tempMax = tempMax;
+        this.tempAvg = tempAvg;
+        this.humidityMin = humidityMin;
+        this.humidityMax = humidityMax;
+        this.humidityAvg = humidityAvg;
+        this.windSpeedMin = windSpeedMin;
+        this.windSpeedMax = windSpeedMax;
+        this.windSpeedAvg = windSpeedAvg;
+        this.windDirectionMin = windDirectionMin;
+        this.windDirectionMax = windDirectionMax;
+        this.windDirectionAvg = windDirectionAvg;
+        this.pressureMin = pressureMin;
+        this.pressureMax = pressureMax;
+        this.pressureAvg = pressureAvg;
+    }
+
+    public SummaryStats() {
+
+    }
+
+
+    public boolean isEmpty(){
+        return tempMin == null&&humidityMin==null&&windSpeedMin==null&&pressureMin==null&& windDirectionMin == null;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public LocalDateTime getTime() {
+        return time;
+    }
+
+    public void setTime(LocalDateTime time) {
+        this.time = time;
+    }
+
+    public Double getTempMin() {
+        return tempMin;
+    }
+
+    public void setTempMin(Double tempMin) {
+        this.tempMin = tempMin;
+    }
+
+    public Double getTempMax() {
+        return tempMax;
+    }
+
+    public void setTempMax(Double tempMax) {
+        this.tempMax = tempMax;
+    }
+
+    public Double getTempAvg() {
+        return tempAvg;
+    }
+
+    public void setTempAvg(Double tempAvg) {
+        this.tempAvg = tempAvg;
+    }
+
+    public Double getTemp() {
+        return temp;
+    }
+
+    public void setTemp(Double temp) {
+        this.temp = temp;
+    }
+
+    public Double getHumidityMin() {
+        return humidityMin;
+    }
+
+    public void setHumidityMin(Double humidityMin) {
+        this.humidityMin = humidityMin;
+    }
+
+    public Double getHumidityMax() {
+        return humidityMax;
+    }
+
+    public void setHumidityMax(Double humidityMax) {
+        this.humidityMax = humidityMax;
+    }
+
+    public Double getHumidityAvg() {
+        return humidityAvg;
+    }
+
+    public void setHumidityAvg(Double humidityAvg) {
+        this.humidityAvg = humidityAvg;
+    }
+
+    public Double getHumidity() {
+        return humidity;
+    }
+
+    public void setHumidity(Double humidity) {
+        this.humidity = humidity;
+    }
+
+    public Double getWindSpeedMin() {
+        return windSpeedMin;
+    }
+
+    public void setWindSpeedMin(Double windSpeedMin) {
+        this.windSpeedMin = windSpeedMin;
+    }
+
+    public Double getWindSpeedMax() {
+        return windSpeedMax;
+    }
+
+    public void setWindSpeedMax(Double windSpeedMax) {
+        this.windSpeedMax = windSpeedMax;
+    }
+
+    public Double getWindSpeedAvg() {
+        return windSpeedAvg;
+    }
+
+    public void setWindSpeedAvg(Double windSpeedAvg) {
+        this.windSpeedAvg = windSpeedAvg;
+    }
+
+    public Double getWindSpeed() {
+        return windSpeed;
+    }
+
+    public void setWindSpeed(Double windSpeed) {
+        this.windSpeed = windSpeed;
+    }
+
+    public int getWindDirectionMin() {
+        return windDirectionMin;
+    }
+
+    public void setWindDirectionMin(int windDirectionMin) {
+        this.windDirectionMin = windDirectionMin;
+    }
+
+    public int getWindDirectionMax() {
+        return windDirectionMax;
+    }
+
+    public void setWindDirectionMax(int windDirectionMax) {
+        this.windDirectionMax = windDirectionMax;
+    }
+
+    public Double getWindDirectionAvg() {
+        return windDirectionAvg;
+    }
+
+    public void setWindDirectionAvg(Double windDirectionAvg) {
+        this.windDirectionAvg = windDirectionAvg;
+    }
+
+    public int getWindDirection() {
+        return windDirection;
+    }
+
+    public void setWindDirection(int windDirection) {
+        this.windDirection = windDirection;
+    }
+
+    public Double getPressureMin() {
+        return pressureMin;
+    }
+
+    public void setPressureMin(Double pressureMin) {
+        this.pressureMin = pressureMin;
+    }
+
+    public Double getPressureMax() {
+        return pressureMax;
+    }
+
+    public void setPressureMax(Double pressureMax) {
+        this.pressureMax = pressureMax;
+    }
+
+    public Double getPressureAvg() {
+        return pressureAvg;
+    }
+
+    public void setPressureAvg(Double pressureAvg) {
+        this.pressureAvg = pressureAvg;
+    }
+
+    public Double getPressure() {
+        return pressure;
+    }
+
+    public void setPressure(Double pressure) {
+        this.pressure = pressure;
+    }
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/SummaryStatsReqDTO.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/SummaryStatsReqDTO.java
new file mode 100644
index 0000000..e640de7
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/SummaryStatsReqDTO.java
@@ -0,0 +1,17 @@
+package com.gkhy.fourierSpecialGasMonitor.entity.req;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class SummaryStatsReqDTO {
+    private LocalDateTime startTime;
+
+    private LocalDateTime endTime;
+
+    private String type;
+
+    private Integer dateType;
+    private String date;
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/UploadGasConcentrationReqDTO.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/UploadGasConcentrationReqDTO.java
index 7833003..60ba9a7 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/UploadGasConcentrationReqDTO.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/req/UploadGasConcentrationReqDTO.java
@@ -28,14 +28,15 @@
 
     private String angle;
 
+    //温度
     private Double temp;
-
+    //湿度
     private Double  humidity;
-
+    //风速
     private Double windSpeed;
-
+    //风向
     private int windDirection;
-
+    //压力
     private Double pressure;
 
     private int gasName01;
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/resp/SummaryStatsPageRespDTO.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/resp/SummaryStatsPageRespDTO.java
new file mode 100644
index 0000000..09ca0e4
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/entity/resp/SummaryStatsPageRespDTO.java
@@ -0,0 +1,74 @@
+package com.gkhy.fourierSpecialGasMonitor.entity.resp;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class SummaryStatsPageRespDTO {
+
+    private Long id;
+    private LocalDateTime time;
+    private Object value;
+    private Object min;
+    private Object max;
+    private Object avg;
+
+    public SummaryStatsPageRespDTO( Object max,Object min, Object avg) {
+        this.min = min;
+        this.max = max;
+        this.avg = avg;
+    }
+
+    public SummaryStatsPageRespDTO() {
+
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public LocalDateTime getTime() {
+        return time;
+    }
+
+    public void setTime(LocalDateTime time) {
+        this.time = time;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    public Object getMin() {
+        return min;
+    }
+
+    public void setMin(Object min) {
+        this.min = min;
+    }
+
+    public Object getMax() {
+        return max;
+    }
+
+    public void setMax(Object max) {
+        this.max = max;
+    }
+
+    public Object getAvg() {
+        return avg;
+    }
+
+    public void setAvg(Object avg) {
+        this.avg = avg;
+    }
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/enums/StatsTypeEnum.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/enums/StatsTypeEnum.java
new file mode 100644
index 0000000..0a68700
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/enums/StatsTypeEnum.java
@@ -0,0 +1,43 @@
+package com.gkhy.fourierSpecialGasMonitor.enums;
+
+public enum StatsTypeEnum {
+    TEMP("temp", "temp", "tempMin", "tempMax", "tempAvg"),
+    HUMIDITY("humidity", "humidity", "humidityMin", "humidityMax", "humidityAvg"),
+    WIND_SPEED("windSpeed", "windSpeed", "windSpeedMin", "windSpeedMax", "windSpeedAvg"),
+    WIND_DIRECTION("windDirection", "windDirection", "windDirectionMin", "windDirectionMax", "windDirectionAvg"),
+    PRESSURE("pressure", "pressure", "pressureMin", "pressureMax", "pressureAvg");
+
+    private  String type; // 与传入的 type 字符串对应
+    private  String valueField; // 对应 value 的字段名
+    private  String minField;   // 最小值字段名
+    private  String maxField;   // 最大值字段名
+    private  String avgField;   // 平均值字段名
+
+    StatsTypeEnum(String type, String valueField, String minField, String maxField, String avgField) {
+        this.type = type;
+        this.valueField = valueField;
+        this.minField = minField;
+        this.maxField = maxField;
+        this.avgField = avgField;
+    }
+
+    // 根据 type 字符串获取枚举
+    public static StatsTypeEnum getByType(String type) {
+        if (type == null) {
+            return null;
+        }
+        for (StatsTypeEnum mapper : values()) {
+            if (mapper.type.equalsIgnoreCase(type)) { // 忽略大小写(可选,根据需求调整)
+                return mapper;
+            }
+        }
+        return null;
+    }
+
+    // getter 方法
+    public String getType() { return type; }
+    public String getValueField() { return valueField; }
+    public String getMinField() { return minField; }
+    public String getMaxField() { return maxField; }
+    public String getAvgField() { return avgField; }
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/GasConcentrationRepository.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/GasConcentrationRepository.java
index a90d38e..d43c1b6 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/GasConcentrationRepository.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/GasConcentrationRepository.java
@@ -3,8 +3,14 @@
 
 import com.gkhy.fourierSpecialGasMonitor.entity.GasCategory;
 import com.gkhy.fourierSpecialGasMonitor.entity.GasConcentration;
+import com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats;
+import com.gkhy.fourierSpecialGasMonitor.entity.req.SummaryStatsReqDTO;
+import com.gkhy.fourierSpecialGasMonitor.entity.resp.SummaryStatsPageRespDTO;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.security.core.parameters.P;
 import org.springframework.stereotype.Repository;
 
 import javax.persistence.OrderBy;
@@ -18,4 +24,34 @@
     GasConcentration findTopByOrderByDataReceivingTimeDesc();
 
     List<GasConcentration> findAllByDataReceivingTimeBetweenOrderByDataReceivingTimeDesc(LocalDateTime startTime, LocalDateTime endTime);
+
+    //分别查询temp,humidity,windSpeed,windDirection,pressure的平均值,最小值,最大值
+    @Query("SELECT new com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats(MIN(g.temp), MAX(g.temp), FUNCTION('ROUND', AVG(g.temp), 2)," +
+            "MIN(g.humidity), MAX(g.humidity), FUNCTION('ROUND', AVG(g.humidity), 2), " +
+            "MIN(g.windSpeed), MAX(g.windSpeed), FUNCTION('ROUND', AVG(g.windSpeed), 2), " +
+            "MIN(g.windDirection), MAX(g.windDirection), FUNCTION('ROUND', AVG(g.windDirection), 2), " +
+            "MIN(g.pressure), MAX(g.pressure), FUNCTION('ROUND', AVG(g.pressure), 2) " +
+            ") FROM GasConcentration g WHERE g.time BETWEEN :startTime AND :endTime")
+    SummaryStats findStats(@Param("startTime") LocalDateTime startTime,@Param("endTime") LocalDateTime endTime);
+
+
+    @Query("SELECT new com.gkhy.fourierSpecialGasMonitor.entity.resp.SummaryStatsPageRespDTO( " +
+            "MAX(CASE WHEN :type = 'temp' THEN g.temp " +
+            "WHEN :type = 'humidity' THEN g.humidity " +
+            "WHEN :type = 'windSpeed' THEN g.windSpeed " +
+            "WHEN :type = 'windDirection' THEN g.windDirection " +
+            "WHEN :type = 'pressure' THEN g.pressure END), " +
+            "MIN(CASE WHEN :type = 'temp' THEN g.temp " +
+            "WHEN :type = 'humidity' THEN g.humidity " +
+            "WHEN :type = 'windSpeed' THEN g.windSpeed " +
+            "WHEN :type = 'windDirection' THEN g.windDirection " +
+            "WHEN :type = 'pressure' THEN g.pressure END), " +
+            "FUNCTION('ROUND', AVG(CASE WHEN :type = 'temp' THEN g.temp " +
+            "WHEN :type = 'humidity' THEN g.humidity " +
+            "WHEN :type = 'windSpeed' THEN g.windSpeed " +
+            "WHEN :type = 'windDirection' THEN g.windDirection " +
+            "WHEN :type = 'pressure' THEN g.pressure END), 2) " +
+            ") FROM GasConcentration g " +
+            "WHERE g.time BETWEEN :startTime AND :endTime")
+    SummaryStatsPageRespDTO findSummaryStatsByTypeAndTimeRange(@Param("type")String type,@Param("startTime") LocalDateTime startTime,@Param("endTime") LocalDateTime endTime);
 }
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/SummaryStatsRepository.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/SummaryStatsRepository.java
new file mode 100644
index 0000000..9f46dd4
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/repository/SummaryStatsRepository.java
@@ -0,0 +1,14 @@
+package com.gkhy.fourierSpecialGasMonitor.repository;
+
+import com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+
+@Repository
+public interface SummaryStatsRepository extends JpaRepository<SummaryStats,Long>, JpaSpecificationExecutor<SummaryStats> {
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/GasConcentrationService.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/GasConcentrationService.java
index 5b54be5..f30d7e8 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/GasConcentrationService.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/GasConcentrationService.java
@@ -1,12 +1,15 @@
 package com.gkhy.fourierSpecialGasMonitor.service;
 
 
+import com.gkhy.fourierSpecialGasMonitor.commons.domain.Result;
 import com.gkhy.fourierSpecialGasMonitor.commons.model.PageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.GasConcentration;
 import com.gkhy.fourierSpecialGasMonitor.entity.GasWarnUser;
+import com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats;
 import com.gkhy.fourierSpecialGasMonitor.entity.query.GasAtmospherePageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.query.GasPageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.req.GasConcentrationExportBO;
+import com.gkhy.fourierSpecialGasMonitor.entity.req.SummaryStatsReqDTO;
 import org.springframework.data.domain.Page;
 
 import java.time.LocalDateTime;
@@ -26,4 +29,8 @@
     List<GasConcentration> listDatabyTimeSlotAndPosition(LocalDateTime startTime, LocalDateTime endTime, Integer position);
 
     List<GasConcentration> gasConcentrationExport(GasConcentrationExportBO gasConcentrationExportBO);
+
+    SummaryStats findStats(LocalDateTime startTime,LocalDateTime endTime);
+
+    Result gasAtmosphereExtremum(SummaryStatsReqDTO reqDTO);
 }
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/MonitorDataService.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/MonitorDataService.java
index a10c6d7..7d4ebe7 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/MonitorDataService.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/MonitorDataService.java
@@ -28,4 +28,6 @@
     Result gasFluxExport(GasFluxExportBO gasFluxExportBO);
 
     Result gasConcentrationExport(GasConcentrationExportBO gasConcentrationExportBO);
+
+    Result gasAtmosphereExtremum(SummaryStatsReqDTO reqDTO);
 }
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/SummaryStatsService.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/SummaryStatsService.java
new file mode 100644
index 0000000..ee8e0f4
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/SummaryStatsService.java
@@ -0,0 +1,12 @@
+package com.gkhy.fourierSpecialGasMonitor.service;
+
+import com.gkhy.fourierSpecialGasMonitor.commons.domain.Result;
+import com.gkhy.fourierSpecialGasMonitor.commons.model.PageQuery;
+import com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats;
+import com.gkhy.fourierSpecialGasMonitor.entity.req.SummaryStatsReqDTO;
+
+public interface SummaryStatsService {
+    void save(SummaryStats stats);
+
+    Result listSummaryStats(PageQuery<SummaryStatsReqDTO> pageQuery);
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/DataReceiveServiceImpl.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/DataReceiveServiceImpl.java
index 598a24f..9de5cd1 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/DataReceiveServiceImpl.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/DataReceiveServiceImpl.java
@@ -17,6 +17,7 @@
 import com.gkhy.fourierSpecialGasMonitor.repository.GasConcentrationRepository;
 import com.gkhy.fourierSpecialGasMonitor.service.*;
 import com.gkhy.fourierSpecialGasMonitor.utils.SendMessageUtil;
+import com.gkhy.fourierSpecialGasMonitor.utils.SummaryUtils;
 import com.gkhy.fourierSpecialGasMonitor.websocket.GasConcentrationExcWebsocketServer;
 import com.gkhy.fourierSpecialGasMonitor.websocket.GasConcentrationWebsocketServer;
 import com.gkhy.fourierSpecialGasMonitor.websocket.GasDeviceExcWebsocketServer;
@@ -39,6 +40,7 @@
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.text.MessageFormat;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -90,6 +92,9 @@
 
     @Autowired
     private GasFluxWebsocketServer gasFluxWebsocketServer;
+
+    @Autowired
+    private SummaryStatsService summaryStatsService;
 
     private static final ReentrantLock lock = new ReentrantLock();
 
@@ -268,11 +273,49 @@
         GasConcentration save = gasConcentrationService.save(gasConcentration);
         if (save == null)
             throw new DataReceiveException(this.getClass(), ForeignResultCode.SYSTEM_ERROR_DATABASE_FAIL.getCode(),"气体实时数据保存失败");
+        //计算平局值,最大值,最小值
+        computeAndSaveDailySummaryStats(save);
         dataCacheAndPush(save);
         execDataCountAndPush(reqDto);
         return ForeignResult.success();
     }
 
+    /**
+     * 计算并保存当天的气体浓度统计数据(若统计为空则初始化,否则更新)
+     * @param newData 新插入的气体浓度数据
+     */
+    private void computeAndSaveDailySummaryStats(GasConcentration newData) {
+        //  定义当天时间范围(00:00:00 至当前时间)
+        LocalDateTime todayStart = LocalDate.now().atStartOfDay();
+        LocalDateTime now = LocalDateTime.now();
+
+        //  查询当天已有的统计数据
+        SummaryStats dailyStats = gasConcentrationService.findStats(todayStart, now);
+
+        // 若统计数据为空,创建新对象并初始化(用新数据作为初始值)
+        if (dailyStats == null || dailyStats.isEmpty()) {
+            dailyStats = new SummaryStats();
+            SummaryUtils.initSummaryStats(dailyStats, newData);
+        } else {
+            // 若统计数据已存在,更新统计值(根据新数据重新计算 min/max/avg)
+            SummaryUtils.updateSummaryStats(dailyStats, newData);
+        }
+
+
+        dailyStats.setTemp(newData.getTemp());
+        dailyStats.setHumidity(newData.getHumidity());
+        dailyStats.setWindSpeed(newData.getWindSpeed());
+        dailyStats.setWindDirection(newData.getWindDirection());
+        dailyStats.setPressure(newData.getPressure());
+        // 补充通用字段(时间取最新数据的时间)
+        dailyStats.setTime(newData.getTime());
+
+        //  保存统计结果
+        summaryStatsService.save(dailyStats);
+    }
+
+
+
 
     private  void execDataCountAndPush(UploadGasConcentrationReqDTO reqDto){
         RBucket<List<GasCategory>> bucket = redissonClient.getBucket(SystemCacheKeyEnum.KEY_GAS_CATEGORY.getKey());
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/GasConcentrationServiceImpl.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/GasConcentrationServiceImpl.java
index a094e91..67ed5fb 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/GasConcentrationServiceImpl.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/GasConcentrationServiceImpl.java
@@ -1,22 +1,23 @@
 package com.gkhy.fourierSpecialGasMonitor.service.impl;
 
+import com.gkhy.fourierSpecialGasMonitor.commons.domain.Result;
 import com.gkhy.fourierSpecialGasMonitor.commons.domain.SearchResult;
 import com.gkhy.fourierSpecialGasMonitor.commons.enums.ResultCode;
 import com.gkhy.fourierSpecialGasMonitor.commons.exception.BusinessException;
 import com.gkhy.fourierSpecialGasMonitor.commons.model.PageQuery;
-import com.gkhy.fourierSpecialGasMonitor.entity.GasConcentration;
-import com.gkhy.fourierSpecialGasMonitor.entity.GasFlux;
-import com.gkhy.fourierSpecialGasMonitor.entity.GasWarnLog;
-import com.gkhy.fourierSpecialGasMonitor.entity.GasWarnUser;
+import com.gkhy.fourierSpecialGasMonitor.entity.*;
 import com.gkhy.fourierSpecialGasMonitor.entity.query.FindGasWarnLogPageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.query.FindGasWarnUserPageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.query.GasAtmospherePageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.query.GasPageQuery;
 import com.gkhy.fourierSpecialGasMonitor.entity.req.GasConcentrationExportBO;
+import com.gkhy.fourierSpecialGasMonitor.entity.req.SummaryStatsReqDTO;
 import com.gkhy.fourierSpecialGasMonitor.entity.resp.FindGasWarnUserPageRespDTO;
+import com.gkhy.fourierSpecialGasMonitor.entity.resp.SummaryStatsPageRespDTO;
 import com.gkhy.fourierSpecialGasMonitor.enums.DeleteStatusEnum;
 import com.gkhy.fourierSpecialGasMonitor.repository.GasConcentrationRepository;
 import com.gkhy.fourierSpecialGasMonitor.service.GasConcentrationService;
+import com.gkhy.fourierSpecialGasMonitor.utils.SummaryUtils;
 import io.micrometer.core.instrument.util.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
@@ -27,7 +28,11 @@
 import org.springframework.stereotype.Service;
 
 import javax.persistence.criteria.*;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -158,4 +163,58 @@
         List<GasConcentration> result = gasConcentrationRepository.findAll(specification);
         return result;
     }
+
+    @Override
+    public SummaryStats findStats(LocalDateTime startTime,LocalDateTime endTime) {
+        return gasConcentrationRepository.findStats(startTime,endTime);
+    }
+
+    @Override
+    public Result gasAtmosphereExtremum(SummaryStatsReqDTO reqDTO) {
+        Result success = Result.success();
+
+        // 1. 参数校验
+        SummaryUtils summaryUtils = new SummaryUtils();
+        summaryUtils.validateParams(reqDTO);
+
+        String type = reqDTO.getType();       // 气体类型(如 "temp"、"humidity")
+        Integer dateType = reqDTO.getDateType(); // 时间粒度(1-日、2-月、3-年)
+        String date = reqDTO.getDate();       // 日期(如 "2025-11-10"、"2025-11"、"2025")
+
+        // 2. 根据 dateType 解析时间范围
+        LocalDateTime startTime = null;
+        LocalDateTime endTime = null;
+        String formatDate = null; // 格式化后的日期(用于返回)
+
+        switch (dateType) {
+            case 1: // 日查询(date格式:yyyy-MM-dd)
+                LocalDate day = LocalDate.parse(date);
+                startTime = day.atStartOfDay(); // 当天00:00:00
+                endTime = day.atTime(23, 59, 59); // 当天23:59:59
+                formatDate = day.format(DateTimeFormatter.ISO_LOCAL_DATE);
+                break;
+            case 2: // 月查询(date格式:yyyy-MM)
+                YearMonth month = YearMonth.parse(date);
+                startTime = month.atDay(1).atStartOfDay(); // 当月1日00:00:00
+                endTime = month.atEndOfMonth().atTime(23, 59, 59); // 当月最后一天23:59:59
+                formatDate = month.format(DateTimeFormatter.ofPattern("yyyy-MM"));
+                break;
+            case 3: // 年查询(date格式:yyyy)
+                Year year = Year.parse(date);
+                startTime = year.atDay(1).atStartOfDay(); // 当年1月1日00:00:00
+                endTime = year.atMonth(12).atEndOfMonth().atTime(23, 59, 59); // 当年12月最后一天23:59:59
+                formatDate = year.toString();
+                break;
+            default:
+                throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_ILLEGAL.getCode(),"无效的dateType,必须为1(日)、2(月)、3(年)");
+        }
+
+        // 3. 动态查询指定类型和时间范围的统计值
+        SummaryStatsPageRespDTO summaryStatsByTypeAndTimeRange = gasConcentrationRepository.findSummaryStatsByTypeAndTimeRange(type, startTime, endTime);
+
+        success.setData(summaryStatsByTypeAndTimeRange);
+
+        // 5. 返回结果
+        return success;
+    }
 }
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/MonitorDataServiceImpl.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/MonitorDataServiceImpl.java
index a5fe17d..bf3e085 100644
--- a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/MonitorDataServiceImpl.java
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/MonitorDataServiceImpl.java
@@ -480,4 +480,9 @@
         result.setMsg("气体浓度数据导出成功");
         return result;
     }
+
+    @Override
+    public Result gasAtmosphereExtremum(SummaryStatsReqDTO reqDTO) {
+        return gasConcentrationService.gasAtmosphereExtremum(reqDTO);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/SummaryStatsServiceImpl.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/SummaryStatsServiceImpl.java
new file mode 100644
index 0000000..a7f1939
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/service/impl/SummaryStatsServiceImpl.java
@@ -0,0 +1,112 @@
+package com.gkhy.fourierSpecialGasMonitor.service.impl;
+
+import com.gkhy.fourierSpecialGasMonitor.commons.domain.Result;
+import com.gkhy.fourierSpecialGasMonitor.commons.domain.SearchResult;
+import com.gkhy.fourierSpecialGasMonitor.commons.enums.ResultCode;
+import com.gkhy.fourierSpecialGasMonitor.commons.exception.BusinessException;
+import com.gkhy.fourierSpecialGasMonitor.commons.model.PageQuery;
+import com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats;
+import com.gkhy.fourierSpecialGasMonitor.entity.req.SummaryStatsReqDTO;
+import com.gkhy.fourierSpecialGasMonitor.entity.resp.GasAtmospherePageRespDTO;
+import com.gkhy.fourierSpecialGasMonitor.entity.resp.SummaryStatsPageRespDTO;
+import com.gkhy.fourierSpecialGasMonitor.repository.SummaryStatsRepository;
+import com.gkhy.fourierSpecialGasMonitor.service.SummaryStatsService;
+import com.gkhy.fourierSpecialGasMonitor.utils.SummaryUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+
+@Service
+public class SummaryStatsServiceImpl implements SummaryStatsService {
+
+    @Autowired
+    private SummaryStatsRepository summaryStatsRepository;
+
+    @Override
+    public void save(SummaryStats stats) {
+        summaryStatsRepository.save(stats);
+    }
+
+    @Override
+    public Result listSummaryStats(PageQuery<SummaryStatsReqDTO> pageQuery) {
+        //  分页参数校验(复用已有逻辑,补充非空判断)
+        if (pageQuery == null || pageQuery.getPageIndex() == null || pageQuery.getPageSize() == null) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_NULL, "分页参数不能为空");
+        }
+        // 校验分页索引和大小合法性(避免负数或过大值)
+        if (pageQuery.getPageIndex() < 1 || pageQuery.getPageSize() < 1 || pageQuery.getPageSize() > 1000) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR, "分页索引必须≥1,分页大小必须在1-1000之间");
+        }
+
+        //查询参数校验(处理 searchParams 为 null 的情况)
+        SummaryStatsReqDTO searchParams = pageQuery.getSearchParams();
+        if (searchParams == null) {
+            searchParams = new SummaryStatsReqDTO(); // 避免后续调用 NPE
+        }
+        LocalDateTime startTime = searchParams.getStartTime();
+        LocalDateTime endTime = searchParams.getEndTime();
+        String type = searchParams.getType(); // type 改为 String 类型
+
+        // 校验 type 合法性(允许为 null,若不为 null 则必须是指定值)
+        List<String> validTypes = Arrays.asList("temp", "humidity", "windSpeed", "windDirection", "pressure");
+        if (type != null && !validTypes.contains(type)) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR,
+                    "type 必须为 temp、humidity、windSpeed、windDirection、pressure 中的一种");
+        }
+
+        //  初始化返回结果
+        SearchResult<List<SummaryStatsPageRespDTO>> searchResult = new SearchResult<>();
+        searchResult.setPageIndex(pageQuery.getPageIndex());
+        searchResult.setPageSize(pageQuery.getPageSize());
+        searchResult.setSuccess();
+        // 构建查询条件(使用 List 而非 Set,逻辑更清晰;补充时间范围非空判断)
+        Specification<SummaryStats> specification = (root, query, criteriaBuilder) -> {
+            List<Predicate> predicates = new ArrayList<>();
+            // 时间范围条件:仅当 start/endTime 非空时添加(避免 null 导致的查询异常)
+            if (startTime != null && endTime != null) {
+                predicates.add(criteriaBuilder.between(root.get("time"), startTime, endTime));
+            } else if (startTime != null) {
+                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("time"), startTime));
+            } else if (endTime != null) {
+                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("time"), endTime));
+            }
+            // 可扩展其他条件(如按位置、设备筛选)
+            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
+        };
+        // 构建分页参数(封装分页索引转换逻辑,避免硬编码)
+        Pageable pageable = PageRequest.of(pageQuery.getPageIndex()-1, pageQuery.getPageSize(), Sort.Direction.DESC, "time");
+        //  执行查询
+        Page<SummaryStats> statsPage = summaryStatsRepository.findAll(specification, pageable);
+        if (statsPage.isEmpty()) {
+            return searchResult; // 空结果直接返回
+        }
+
+        SummaryUtils summaryUtils = new SummaryUtils();
+        // 转换结果(使用枚举映射处理 type 逻辑)
+        List<SummaryStatsPageRespDTO> respDTOS = statsPage.getContent().stream()
+                .map(stats -> summaryUtils.convertToResp(stats, type))
+                .collect(Collectors.toList());
+
+        // 填充返回结果
+        searchResult.setTotal(statsPage.getTotalElements());
+        searchResult.setPages(statsPage.getTotalPages());
+        searchResult.setData(respDTOS);
+        return searchResult;
+    }
+}
diff --git a/src/main/java/com/gkhy/fourierSpecialGasMonitor/utils/SummaryUtils.java b/src/main/java/com/gkhy/fourierSpecialGasMonitor/utils/SummaryUtils.java
new file mode 100644
index 0000000..0fd8d9b
--- /dev/null
+++ b/src/main/java/com/gkhy/fourierSpecialGasMonitor/utils/SummaryUtils.java
@@ -0,0 +1,191 @@
+package com.gkhy.fourierSpecialGasMonitor.utils;
+
+import com.alibaba.druid.util.StringUtils;
+import com.gkhy.fourierSpecialGasMonitor.commons.enums.ResultCode;
+import com.gkhy.fourierSpecialGasMonitor.commons.exception.BusinessException;
+import com.gkhy.fourierSpecialGasMonitor.entity.GasConcentration;
+import com.gkhy.fourierSpecialGasMonitor.entity.SummaryStats;
+import com.gkhy.fourierSpecialGasMonitor.entity.req.SummaryStatsReqDTO;
+import com.gkhy.fourierSpecialGasMonitor.entity.resp.SummaryStatsPageRespDTO;
+import com.gkhy.fourierSpecialGasMonitor.enums.StatsTypeEnum;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+
+import java.lang.reflect.Field;
+import java.time.LocalDate;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.format.DateTimeParseException;
+import java.util.Arrays;
+
+public class SummaryUtils {
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+
+
+    /**
+     * 初始化统计数据(当当天无数据时,用新数据作为初始值)
+     */
+    public static void  initSummaryStats(SummaryStats stats, GasConcentration data) {
+        // 初始化 temp 相关统计(min/max/avg 均为当前数据值)
+        stats.setTempMin(data.getTemp());
+        stats.setTempMax(data.getTemp());
+        stats.setTempAvg(data.getTemp());
+
+        // 初始化 humidity 相关统计
+        stats.setHumidityMin(data.getHumidity());
+        stats.setHumidityMax(data.getHumidity());
+        stats.setHumidityAvg(data.getHumidity());
+
+        // 初始化 windSpeed 相关统计
+        Double windSpeed = data.getWindSpeed();
+        stats.setWindSpeedMin(windSpeed);
+        stats.setWindSpeedMax(windSpeed);
+        stats.setWindSpeedAvg(windSpeed);
+
+        // 初始化 windDirection 相关统计(处理可能的 null)
+        Integer windDirection = data.getWindDirection();
+        stats.setWindDirectionMin(windDirection);
+        stats.setWindDirectionMax(windDirection);
+        stats.setWindDirectionAvg(windDirection != null ? windDirection.doubleValue() : null);
+
+        // 初始化 pressure 相关统计
+        Double pressure = data.getPressure();
+        stats.setPressureMin(pressure);
+        stats.setPressureMax(pressure);
+        stats.setPressureAvg(pressure);
+    }
+
+    /**
+     * 更新统计数据(根据新数据重新计算 min/max/avg)
+     */
+    public static void updateSummaryStats(SummaryStats stats, GasConcentration newData) {
+        // 更新 temp:min 取更小值,max 取更大值,avg 重新计算(需注意:avg 不能直接用当前 avg 计算,需累计总和/数量)
+        // 注意:此处简化处理,实际 avg 需基于总样本数计算(建议在数据库查询时直接聚合,而非内存中更新)
+        Double newTemp = newData.getTemp();
+        stats.setTempMin(min(stats.getTempMin(), newTemp));
+        stats.setTempMax(max(stats.getTempMax(), newTemp));
+
+        // 更新 humidity
+        Double newHumidity = newData.getHumidity();
+        stats.setHumidityMin(min(stats.getHumidityMin(), newHumidity));
+        stats.setHumidityMax(max(stats.getHumidityMax(), newHumidity));
+
+        // 更新 windSpeed
+        Double newWindSpeed = newData.getWindSpeed();
+        stats.setWindSpeedMin(min(stats.getWindSpeedMin(), newWindSpeed));
+        stats.setWindSpeedMax(max(stats.getWindSpeedMax(), newWindSpeed));
+
+        // 更新 windDirection
+        Integer newWindDir = newData.getWindDirection();
+        stats.setWindDirectionMin(min(stats.getWindDirectionMin(), newWindDir));
+        stats.setWindDirectionMax(max(stats.getWindDirectionMax(), newWindDir));
+
+        // 更新 pressure
+        Double newPressure = newData.getPressure();
+        stats.setPressureMin(min(stats.getPressureMin(), newPressure));
+        stats.setPressureMax(max(stats.getPressureMax(), newPressure));
+    }
+
+    /**
+     * 安全计算两个 Double 的最小值(处理 null)
+     */
+    private static Double min(Double a, Double b) {
+        if (a == null) return b;
+        if (b == null) return a;
+        return Math.min(a, b);
+    }
+
+    /**
+     * 安全计算两个 Integer 的最小值(处理 null)
+     */
+    private static Integer min(Integer a, Integer b) {
+        if (a == null) return b;
+        if (b == null) return a;
+        return Math.min(a, b);
+    }
+
+    // 同理实现 max 方法(Double 和 Integer 版本)
+    private static Double max(Double a, Double b) {
+        if (a == null) return b;
+        if (b == null) return a;
+        return Math.max(a, b);
+    }
+
+    private static Integer max(Integer a, Integer b) {
+        if (a == null) return b;
+        if (b == null) return a;
+        return Math.max(a, b);
+    }
+
+    public void validateParams(SummaryStatsReqDTO reqDTO) {
+        if (reqDTO == null) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_NULL.getCode(),"请求参数不能为空");
+        }
+        if (StringUtils.isEmpty(reqDTO.getType())) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_NULL.getCode(),"气体类型(type)不能为空");
+        }
+        if (reqDTO.getDateType() == null || !Arrays.asList(1, 2, 3).contains(reqDTO.getDateType())) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_ILLEGAL.getCode(),"dateType必须为1(日)、2(月)、3(年)");
+        }
+        if (StringUtils.isEmpty(reqDTO.getDate())) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_NULL.getCode(),"日期(date)不能为空");
+        }
+        // 校验date格式(根据dateType)
+        try {
+            switch (reqDTO.getDateType()) {
+                case 1:
+                    LocalDate.parse(reqDTO.getDate()); // 校验 yyyy-MM-dd
+                    break;
+                case 2:
+                    YearMonth.parse(reqDTO.getDate()); // 校验 yyyy-MM
+                    break;
+                case 3:
+                    Year.parse(reqDTO.getDate()); // 校验 yyyy
+                    break;
+            }
+        } catch (DateTimeParseException e) {
+            throw new BusinessException(this.getClass(), ResultCode.PARAM_ERROR_ILLEGAL.getCode(),"日期格式错误,dateType=" + reqDTO.getDateType() + "时,date应为" +
+                    (reqDTO.getDateType() == 1 ? "yyyy-MM-dd" : reqDTO.getDateType() == 2 ? "yyyy-MM" : "yyyy"));
+        }
+    }
+
+
+    public SummaryStatsPageRespDTO convertToResp(SummaryStats stats, String type) {
+        SummaryStatsPageRespDTO respDTO = new SummaryStatsPageRespDTO();
+        BeanUtils.copyProperties(stats, respDTO); // 复制公共字段(如 time)
+
+        if (type == null) {
+            return respDTO; // 若 type 为 null,不设置指标相关字段
+        }
+
+        StatsTypeEnum mapper = StatsTypeEnum.getByType(type);
+        if (mapper == null) {
+            return respDTO; // 无效 type(理论上已在参数校验时拦截)
+        }
+
+        try {
+            // 反射获取字段值(通过枚举映射的字段名)
+            Field valueField = SummaryStats.class.getDeclaredField(mapper.getValueField());
+            Field minField = SummaryStats.class.getDeclaredField(mapper.getMinField());
+            Field maxField = SummaryStats.class.getDeclaredField(mapper.getMaxField());
+            Field avgField = SummaryStats.class.getDeclaredField(mapper.getAvgField());
+
+            valueField.setAccessible(true);
+            minField.setAccessible(true);
+            maxField.setAccessible(true);
+            avgField.setAccessible(true);
+
+            // 设置到响应 DTO
+            respDTO.setValue(valueField.get(stats));
+            respDTO.setMin(minField.get(stats));
+            respDTO.setMax(maxField.get(stats));
+            respDTO.setAvg(avgField.get(stats));
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            logger.error("转换 SummaryStats 到 DTO 失败,type={}, stats={}", type, stats, e);
+        }
+        return respDTO;
+    }
+}

--
Gitblit v1.9.2