|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+package com.water.revenue.service.enhanced;
|
|
|
2
|
+
|
|
|
3
|
+import com.water.revenue.service.RemoteReadingService;
|
|
|
4
|
+import lombok.RequiredArgsConstructor;
|
|
|
5
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
6
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
7
|
+import org.springframework.stereotype.Service;
|
|
|
8
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
9
|
+
|
|
|
10
|
+import java.math.BigDecimal;
|
|
|
11
|
+import java.math.RoundingMode;
|
|
|
12
|
+import java.time.LocalDateTime;
|
|
|
13
|
+import java.util.*;
|
|
|
14
|
+
|
|
|
15
|
+/**
|
|
|
16
|
+ * 增强版远传集抄服务
|
|
|
17
|
+ * 集抄-58: 批量远传抄表 + 读数校验 + 大表(DN80+)专项监控 + 异常预警
|
|
|
18
|
+ */
|
|
|
19
|
+@Slf4j
|
|
|
20
|
+@Service
|
|
|
21
|
+@RequiredArgsConstructor
|
|
|
22
|
+public class EnhancedRemoteReadingService {
|
|
|
23
|
+
|
|
|
24
|
+ private final RemoteReadingService remoteReadingService;
|
|
|
25
|
+ private final JdbcTemplate jdbcTemplate;
|
|
|
26
|
+
|
|
|
27
|
+ /**
|
|
|
28
|
+ * 批量远传抄表(增强版)
|
|
|
29
|
+ * - 添加读数合理性校验
|
|
|
30
|
+ * - 支持多个区域批量处理
|
|
|
31
|
+ * - 添加异常标记和原因记录
|
|
|
32
|
+ */
|
|
|
33
|
+ @Transactional
|
|
|
34
|
+ public Map<String, Object> enhancedBatchRead(List<String> areas) {
|
|
|
35
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
36
|
+ result.put("areas", areas);
|
|
|
37
|
+ result.put("totalCount", 0);
|
|
|
38
|
+ result.put("successCount", 0);
|
|
|
39
|
+ result.put("failedCount", 0);
|
|
|
40
|
+ result.put("abnormalCount", 0);
|
|
|
41
|
+ result.put("period", java.time.YearMonth.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM")));
|
|
|
42
|
+
|
|
|
43
|
+ for (String area : areas) {
|
|
|
44
|
+ try {
|
|
|
45
|
+ log.info("开始批量抄表区域: {}", area);
|
|
|
46
|
+ Map<String, Object> areaResult = processAreaBatchRead(area);
|
|
|
47
|
+
|
|
|
48
|
+ result.put("totalCount", (Integer) result.get("totalCount") + (Integer) areaResult.get("totalCount"));
|
|
|
49
|
+ result.put("successCount", (Integer) result.get("successCount") + (Integer) areaResult.get("successCount"));
|
|
|
50
|
+ result.put("failedCount", (Integer) result.get("failedCount") + (Integer) areaResult.get("failedCount"));
|
|
|
51
|
+ result.put("abnormalCount", (Integer) result.get("abnormalCount") + (Integer) areaResult.get("abnormalCount"));
|
|
|
52
|
+
|
|
|
53
|
+ // 添加区域详细统计
|
|
|
54
|
+ result.put("area_" + area, areaResult);
|
|
|
55
|
+ } catch (Exception e) {
|
|
|
56
|
+ log.error("批量抄表区域失败: {}", area, e);
|
|
|
57
|
+ result.put("failedCount", (Integer) result.get("failedCount") + 1);
|
|
|
58
|
+ }
|
|
|
59
|
+ }
|
|
|
60
|
+
|
|
|
61
|
+ // 生成抄表报告
|
|
|
62
|
+ generateBatchReport(result);
|
|
|
63
|
+ return result;
|
|
|
64
|
+ }
|
|
|
65
|
+
|
|
|
66
|
+ /**
|
|
|
67
|
+ * 处理单个区域的批量抄表
|
|
|
68
|
+ */
|
|
|
69
|
+ private Map<String, Object> processAreaBatchRead(String area) {
|
|
|
70
|
+ Map<String, Object> areaResult = new HashMap<>();
|
|
|
71
|
+
|
|
|
72
|
+ // 获取区域内的所有水表
|
|
|
73
|
+ List<Map<String, Object>> meters = getMetersByArea(area);
|
|
|
74
|
+ areaResult.put("totalCount", meters.size());
|
|
|
75
|
+ areaResult.put("successCount", 0);
|
|
|
76
|
+ areaResult.put("failedCount", 0);
|
|
|
77
|
+ areaResult.put("abnormalCount", 0);
|
|
|
78
|
+ areaResult.put("abnormalReasons", new HashMap<>());
|
|
|
79
|
+
|
|
|
80
|
+ for (Map<String, Object> meter : meters) {
|
|
|
81
|
+ try {
|
|
|
82
|
+ Map<String, Object> readResult = readSingleMeter(meter, area);
|
|
|
83
|
+
|
|
|
84
|
+ if (readResult.get("status").equals("success")) {
|
|
|
85
|
+ areaResult.put("successCount", (Integer) areaResult.get("successCount") + 1);
|
|
|
86
|
+
|
|
|
87
|
+ // 检查是否为异常读数
|
|
|
88
|
+ if (readResult.get("isAbnormal") != null && (boolean) readResult.get("isAbnormal")) {
|
|
|
89
|
+ areaResult.put("abnormalCount", (Integer) areaResult.get("abnormalCount") + 1);
|
|
|
90
|
+ String reason = (String) readResult.get("abnormalReason");
|
|
|
91
|
+ @SuppressWarnings("unchecked")
|
|
|
92
|
+ Map<String, Integer> reasons = (Map<String, Integer>) areaResult.get("abnormalReasons");
|
|
|
93
|
+ reasons.put(reason, reasons.getOrDefault(reason, 0) + 1);
|
|
|
94
|
+ }
|
|
|
95
|
+ } else {
|
|
|
96
|
+ areaResult.put("failedCount", (Integer) areaResult.get("failedCount") + 1);
|
|
|
97
|
+ }
|
|
|
98
|
+ } catch (Exception e) {
|
|
|
99
|
+ log.warn("抄表失败,水表编号: {}", meter.get("meter_no"), e);
|
|
|
100
|
+ areaResult.put("failedCount", (Integer) areaResult.get("failedCount") + 1);
|
|
|
101
|
+ }
|
|
|
102
|
+ }
|
|
|
103
|
+
|
|
|
104
|
+ return areaResult;
|
|
|
105
|
+ }
|
|
|
106
|
+
|
|
|
107
|
+ /**
|
|
|
108
|
+ * 获取指定区域的所有水表
|
|
|
109
|
+ */
|
|
|
110
|
+ private List<Map<String, Object>> getMetersByArea(String area) {
|
|
|
111
|
+ return jdbcTemplate.queryForList(
|
|
|
112
|
+ "SELECT rm.id, rm.meter_no, rm.current_reading, rm.caliber, rm.install_date, " +
|
|
|
113
|
+ "c.customer_name, c.area, i.device_sn, i.status as device_status " +
|
|
|
114
|
+ "FROM rev_meter rm " +
|
|
|
115
|
+ "JOIN rev_customer c ON rm.customer_id = c.id " +
|
|
|
116
|
+ "LEFT JOIN iot_device i ON rm.device_id = i.id " +
|
|
|
117
|
+ "WHERE rm.status = 'active' AND c.area = ? " +
|
|
|
118
|
+ "ORDER BY rm.meter_no",
|
|
|
119
|
+ area);
|
|
|
120
|
+ }
|
|
|
121
|
+
|
|
|
122
|
+ /**
|
|
|
123
|
+ * 单个水表抄表(包含读数校验)
|
|
|
124
|
+ */
|
|
|
125
|
+ private Map<String, Object> readSingleMeter(Map<String, Object> meter, String area) {
|
|
|
126
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
127
|
+ String meterNo = (String) meter.get("meter_no");
|
|
|
128
|
+ BigDecimal prevReading = meter.get("current_reading") != null ? (BigDecimal) meter.get("current_reading") : BigDecimal.ZERO;
|
|
|
129
|
+ String deviceSn = (String) meter.get("device_sn");
|
|
|
130
|
+ String caliber = (String) meter.get("caliber");
|
|
|
131
|
+
|
|
|
132
|
+ try {
|
|
|
133
|
+ // 从 IoT 平台获取实时读数
|
|
|
134
|
+ BigDecimal currReading = getRemoteReading(meter, deviceSn);
|
|
|
135
|
+
|
|
|
136
|
+ // 读数校验
|
|
|
137
|
+ Map<String, Object> validation = validateReading(meter, prevReading, currReading);
|
|
|
138
|
+
|
|
|
139
|
+ if (validation.get("isValid").equals(true)) {
|
|
|
140
|
+ // 计算用水量
|
|
|
141
|
+ BigDecimal consumption = currReading.subtract(prevReading);
|
|
|
142
|
+ if (consumption.compareTo(BigDecimal.ZERO) < 0) consumption = BigDecimal.ZERO;
|
|
|
143
|
+
|
|
|
144
|
+ // 保存抄表记录
|
|
|
145
|
+ saveReadingRecord(meter, prevReading, currReading, consumption);
|
|
|
146
|
+
|
|
|
147
|
+ result.put("status", "success");
|
|
|
148
|
+ result.put("meterNo", meterNo);
|
|
|
149
|
+ result.put("prevReading", prevReading);
|
|
|
150
|
+ result.put("currReading", currReading);
|
|
|
151
|
+ result.put("consumption", consumption);
|
|
|
152
|
+ result.put("isAbnormal", validation.get("isAbnormal"));
|
|
|
153
|
+ result.put("abnormalReason", validation.get("abnormalReason"));
|
|
|
154
|
+
|
|
|
155
|
+ log.info("抄表成功: {} -> {}, 用量: {}", prevReading, currReading, consumption);
|
|
|
156
|
+ } else {
|
|
|
157
|
+ result.put("status", "abnormal");
|
|
|
158
|
+ result.put("meterNo", meterNo);
|
|
|
159
|
+ result.put("prevReading", prevReading);
|
|
|
160
|
+ result.put("currReading", currReading);
|
|
|
161
|
+ result.put("abnormalReason", validation.get("abnormalReason"));
|
|
|
162
|
+ result.put("isAbnormal", true);
|
|
|
163
|
+
|
|
|
164
|
+ // 记录异常但不阻止抄表
|
|
|
165
|
+ log.warn("读数异常: {}, 原因: {}", meterNo, validation.get("abnormalReason"));
|
|
|
166
|
+ }
|
|
|
167
|
+ } catch (Exception e) {
|
|
|
168
|
+ result.put("status", "failed");
|
|
|
169
|
+ result.put("meterNo", meterNo);
|
|
|
170
|
+ result.put("error", e.getMessage());
|
|
|
171
|
+ log.error("抄表失败: {}", meterNo, e);
|
|
|
172
|
+ }
|
|
|
173
|
+
|
|
|
174
|
+ return result;
|
|
|
175
|
+ }
|
|
|
176
|
+
|
|
|
177
|
+ /**
|
|
|
178
|
+ * 从 IoT 平台获取远程读数(模拟)
|
|
|
179
|
+ */
|
|
|
180
|
+ private BigDecimal getRemoteReading(Map<String, Object> meter, String deviceSn) {
|
|
|
181
|
+ // 模拟从 IoT 平台获取读数
|
|
|
182
|
+ // 实际实现应该调用真实的 IoT API
|
|
|
183
|
+ BigDecimal prevReading = meter.get("current_reading") != null ? (BigDecimal) meter.get("current_reading") : BigDecimal.ZERO;
|
|
|
184
|
+
|
|
|
185
|
+ // 添加一些随机变化(模拟真实抄表)
|
|
|
186
|
+ double variation = new Random().nextDouble() * 20; // 0-20 立方米的合理变化
|
|
|
187
|
+ BigDecimal increment = BigDecimal.valueOf(variation).setScale(2, RoundingMode.HALF_UP);
|
|
|
188
|
+ BigDecimal currReading = prevReading.add(increment);
|
|
|
189
|
+
|
|
|
190
|
+ return currReading.setScale(2, RoundingMode.HALF_UP);
|
|
|
191
|
+ }
|
|
|
192
|
+
|
|
|
193
|
+ /**
|
|
|
194
|
+ * 读数校验
|
|
|
195
|
+ */
|
|
|
196
|
+ private Map<String, Object> validateReading(Map<String, Object> meter, BigDecimal prevReading, BigDecimal currReading) {
|
|
|
197
|
+ Map<String, Object> validation = new HashMap<>();
|
|
|
198
|
+ validation.put("isValid", true);
|
|
|
199
|
+ validation.put("isAbnormal", false);
|
|
|
200
|
+ validation.put("abnormalReason", null);
|
|
|
201
|
+
|
|
|
202
|
+ String meterNo = (String) meter.get("meter_no");
|
|
|
203
|
+ String caliber = (String) meter.get("caliber");
|
|
|
204
|
+
|
|
|
205
|
+ // 1. 读数递减检查
|
|
|
206
|
+ if (currReading.compareTo(prevReading) < 0) {
|
|
|
207
|
+ validation.put("isValid", false);
|
|
|
208
|
+ validation.put("isAbnormal", true);
|
|
|
209
|
+ validation.put("abnormalReason", "读数递减");
|
|
|
210
|
+ return validation;
|
|
|
211
|
+ }
|
|
|
212
|
+
|
|
|
213
|
+ // 2. 零读数检查
|
|
|
214
|
+ if (currReading.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
215
|
+ validation.put("isAbnormal", true);
|
|
|
216
|
+ validation.put("abnormalReason", "零读数");
|
|
|
217
|
+ return validation;
|
|
|
218
|
+ }
|
|
|
219
|
+
|
|
|
220
|
+ // 3. 异常增量检查(根据管径设置合理的最大增量)
|
|
|
221
|
+ BigDecimal maxIncrement = getMaxIncrementByCaliber(caliber);
|
|
|
222
|
+ BigDecimal increment = currReading.subtract(prevReading);
|
|
|
223
|
+
|
|
|
224
|
+ if (increment.compareTo(maxIncrement) > 0) {
|
|
|
225
|
+ validation.put("isValid", false);
|
|
|
226
|
+ validation.put("isAbnormal", true);
|
|
|
227
|
+ validation.put("abnormalReason", String.format("增量异常: %s > %s", increment, maxIncrement));
|
|
|
228
|
+ return validation;
|
|
|
229
|
+ }
|
|
|
230
|
+
|
|
|
231
|
+ return validation;
|
|
|
232
|
+ }
|
|
|
233
|
+
|
|
|
234
|
+ /**
|
|
|
235
|
+ * 根据管径获取最大合理增量
|
|
|
236
|
+ */
|
|
|
237
|
+ private BigDecimal getMaxIncrementByCaliber(String caliber) {
|
|
|
238
|
+ return switch (caliber) {
|
|
|
239
|
+ case "DN15" -> BigDecimal.valueOf(10); // 小表每月最大10立方米
|
|
|
240
|
+ case "DN20" -> BigDecimal.valueOf(20);
|
|
|
241
|
+ case "DN25" -> BigDecimal.valueOf(30);
|
|
|
242
|
+ case "DN32" -> BigDecimal.valueOf(50);
|
|
|
243
|
+ case "DN40" -> BigDecimal.valueOf(80);
|
|
|
244
|
+ case "DN50" -> BigDecimal.valueOf(150);
|
|
|
245
|
+ case "DN65" -> BigDecimal.valueOf(300);
|
|
|
246
|
+ case "DN80" -> BigDecimal.valueOf(500); // DN80大表每月最多500立方米
|
|
|
247
|
+ case "DN100" -> BigDecimal.valueOf(800);
|
|
|
248
|
+ case "DN150" -> BigDecimal.valueOf(1500);
|
|
|
249
|
+ default -> BigDecimal.valueOf(1000); // 其他管径默认1000立方米
|
|
|
250
|
+ };
|
|
|
251
|
+ }
|
|
|
252
|
+
|
|
|
253
|
+ /**
|
|
|
254
|
+ * 保存抄表记录
|
|
|
255
|
+ */
|
|
|
256
|
+ private void saveReadingRecord(Map<String, Object> meter, BigDecimal prevReading,
|
|
|
257
|
+ BigDecimal currReading, BigDecimal consumption) {
|
|
|
258
|
+ String period = java.time.YearMonth.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM"));
|
|
|
259
|
+ Long meterId = (Long) meter.get("id");
|
|
|
260
|
+
|
|
|
261
|
+ jdbcTemplate.update(
|
|
|
262
|
+ "INSERT INTO rev_reading (meter_id, reading_date, reading_period, prev_reading, curr_reading, consumption, read_type) " +
|
|
|
263
|
+ "VALUES (?, CURRENT_DATE, ?, ?, ?, ?, 'enhanced_remote')",
|
|
|
264
|
+ meterId, period, prevReading, currReading, consumption);
|
|
|
265
|
+
|
|
|
266
|
+ jdbcTemplate.update("UPDATE rev_meter SET current_reading = ? WHERE id = ?", currReading, meterId);
|
|
|
267
|
+ }
|
|
|
268
|
+
|
|
|
269
|
+ /**
|
|
|
270
|
+ * 生成批量抄表报告
|
|
|
271
|
+ */
|
|
|
272
|
+ private void generateBatchReport(Map<String, Object> result) {
|
|
|
273
|
+ String period = (String) result.get("period");
|
|
|
274
|
+ String reportId = "BATCH_READ_" + period + "_" + System.currentTimeMillis();
|
|
|
275
|
+
|
|
|
276
|
+ jdbcTemplate.update(
|
|
|
277
|
+ "INSERT INTO rev_batch_report (report_id, period, total_meters, success_meters, failed_meters, abnormal_meters, created_at) " +
|
|
|
278
|
+ "VALUES (?, ?, ?, ?, ?, ?, NOW())",
|
|
|
279
|
+ reportId, period,
|
|
|
280
|
+ result.get("totalCount"),
|
|
|
281
|
+ result.get("successCount"),
|
|
|
282
|
+ result.get("failedCount"),
|
|
|
283
|
+ result.get("abnormalCount"));
|
|
|
284
|
+
|
|
|
285
|
+ result.put("reportId", reportId);
|
|
|
286
|
+ result.put("generatedAt", LocalDateTime.now());
|
|
|
287
|
+ }
|
|
|
288
|
+
|
|
|
289
|
+ /**
|
|
|
290
|
+ * 大表专项监控 (DN80+)
|
|
|
291
|
+ */
|
|
|
292
|
+ public Map<String, Object> largeMeterEnhancedMonitor() {
|
|
|
293
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
294
|
+
|
|
|
295
|
+ // 获取所有大表数据
|
|
|
296
|
+ List<Map<String, Object>> largeMeters = jdbcTemplate.queryForList(
|
|
|
297
|
+ "SELECT rm.*, c.customer_name, c.area, i.device_sn, i.status as device_status, " +
|
|
|
298
|
+ "rr.reading_date, rr.curr_reading, rr.prev_reading, rr.consumption " +
|
|
|
299
|
+ "FROM rev_meter rm " +
|
|
|
300
|
+ "JOIN rev_customer c ON rm.customer_id = c.id " +
|
|
|
301
|
+ "LEFT JOIN iot_device i ON rm.device_id = i.id " +
|
|
|
302
|
+ "LEFT JOIN rev_reading rr ON rm.id = rr.meter_id AND rr.reading_period = ? " +
|
|
|
303
|
+ "WHERE rm.caliber IN ('DN80','DN100','DN150','DN200','DN300','DN400') " +
|
|
|
304
|
+ "AND rm.status = 'active' " +
|
|
|
305
|
+ "ORDER BY rm.caliber DESC, c.area",
|
|
|
306
|
+ java.time.YearMonth.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM")));
|
|
|
307
|
+
|
|
|
308
|
+ result.put("totalCount", largeMeters.size());
|
|
|
309
|
+ result.put("monitors", new ArrayList<>());
|
|
|
310
|
+ result.put("alarms", new ArrayList<>());
|
|
|
311
|
+
|
|
|
312
|
+ for (Map<String, Object> meter : largeMeters) {
|
|
|
313
|
+ Map<String, Object> monitor = new HashMap<>();
|
|
|
314
|
+ monitor.put("meterNo", meter.get("meter_no"));
|
|
|
315
|
+ monitor.put("caliber", meter.get("caliber"));
|
|
|
316
|
+ monitor.put("customerName", meter.get("customer_name"));
|
|
|
317
|
+ monitor.put("area", meter.get("area"));
|
|
|
318
|
+ monitor.put("deviceSn", meter.get("device_sn"));
|
|
|
319
|
+ monitor.put("deviceStatus", meter.get("device_status"));
|
|
|
320
|
+ monitor.put("currentReading", meter.get("curr_reading"));
|
|
|
321
|
+ monitor.put("lastReadingDate", meter.get("reading_date"));
|
|
|
322
|
+ monitor.put("consumption", meter.get("consumption"));
|
|
|
323
|
+
|
|
|
324
|
+ // 大表监控检查
|
|
|
325
|
+ Map<String, Object> alarm = checkLargeMeterAlerts(monitor);
|
|
|
326
|
+ if (alarm != null) {
|
|
|
327
|
+ result.get("alarms").add(alarm);
|
|
|
328
|
+ }
|
|
|
329
|
+
|
|
|
330
|
+ result.get("monitors").add(monitor);
|
|
|
331
|
+ }
|
|
|
332
|
+
|
|
|
333
|
+ return result;
|
|
|
334
|
+ }
|
|
|
335
|
+
|
|
|
336
|
+ /**
|
|
|
337
|
+ * 大表监控预警检查
|
|
|
338
|
+ */
|
|
|
339
|
+ private Map<String, Object> checkLargeMeterAlerts(Map<String, Object> meter) {
|
|
|
340
|
+ Map<String, Object> alarm = null;
|
|
|
341
|
+ String meterNo = (String) meter.get("meterNo");
|
|
|
342
|
+ BigDecimal consumption = meter.get("consumption") != null ? (BigDecimal) meter.get("consumption") : BigDecimal.ZERO;
|
|
|
343
|
+
|
|
|
344
|
+ // 1. 突增预警(月用量超过管径标准值的2倍)
|
|
|
345
|
+ BigDecimal maxNormal = getMaxIncrementByCaliber((String) meter.get("caliber"));
|
|
|
346
|
+ if (consumption.compareTo(maxNormal.multiply(BigDecimal.valueOf(2))) > 0) {
|
|
|
347
|
+ alarm = createAlarm(meterNo, "突增预警", "MONITORING_HIGH_CONSUMPTION",
|
|
|
348
|
+ String.format("月用量%s异常高,建议检查水表状态", consumption));
|
|
|
349
|
+ }
|
|
|
350
|
+
|
|
|
351
|
+ // 2. 设备离线预警
|
|
|
352
|
+ if (meter.get("deviceStatus") == null || "offline".equals(meter.get("deviceStatus"))) {
|
|
|
353
|
+ if (alarm == null) {
|
|
|
354
|
+ alarm = createAlarm(meterNo, "设备离线", "MONITORING_DEVICE_OFFLINE", "大表设备离线,无法远程抄表");
|
|
|
355
|
+ } else {
|
|
|
356
|
+ alarm.put("additionalIssues", alarm.getOrDefault("additionalIssues", new ArrayList<>()));
|
|
|
357
|
+ ((List<String>) alarm.get("additionalIssues")).add("设备离线");
|
|
|
358
|
+ }
|
|
|
359
|
+ }
|
|
|
360
|
+
|
|
|
361
|
+ // 3. 零流量预警
|
|
|
362
|
+ if (consumption.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
363
|
+ if (alarm == null) {
|
|
|
364
|
+ alarm = createAlarm(meterNo, "零流量预警", "MONITORING_ZERO_FLOW", "大表月用量为零,建议检查表计状态");
|
|
|
365
|
+ } else {
|
|
|
366
|
+ alarm.put("additionalIssues", alarm.getOrDefault("additionalIssues", new ArrayList<>()));
|
|
|
367
|
+ ((List<String>) alarm.get("additionalIssues")).add("零流量");
|
|
|
368
|
+ }
|
|
|
369
|
+ }
|
|
|
370
|
+
|
|
|
371
|
+ return alarm;
|
|
|
372
|
+ }
|
|
|
373
|
+
|
|
|
374
|
+ /**
|
|
|
375
|
+ * 创建预警记录
|
|
|
376
|
+ */
|
|
|
377
|
+ private Map<String, Object> createAlarm(String meterNo, String title, String type, String description) {
|
|
|
378
|
+ Map<String, Object> alarm = new HashMap<>();
|
|
|
379
|
+ alarm.put("meterNo", meterNo);
|
|
|
380
|
+ alarm.put("title", title);
|
|
|
381
|
+ alarm.put("type", type);
|
|
|
382
|
+ alarm.put("description", description);
|
|
|
383
|
+ alarm.put("severity", "HIGH");
|
|
|
384
|
+ alarm.put("createdAt", LocalDateTime.now());
|
|
|
385
|
+ alarm.put("status", "PENDING");
|
|
|
386
|
+ return alarm;
|
|
|
387
|
+ }
|
|
|
388
|
+}
|