“djh”
2025-11-11 63486c527b01c459110a88930d9cda1ded633aee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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;
    }
}