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