#10 总览+在线监测: - DashboardService: 今日进出水量/设备概况/能耗药耗/实时监测列表(多维筛选) - VideoService: 视频监控点位+AI人员闯入检测(YOLO mock) #11 水质管控+报警: - WaterQualityService: 全工艺药剂投加监控(混凝/沉淀/过滤/消毒) + 水质台账 - AlertEngine: 报警规则检测/去重/确认/派单/分级(info/warning/critical/emergency) #12 调度工作台+调度业务: - DispatchService: 值班管理(开始/结束/交接) + 指令创建/下发/跟踪 - 应急推演: 爆管模拟(影响区域+关阀方案+恢复时间) + 水质异常处置 #13 数据中心+配置: - DataCenterService: 历史数据查看/报表生成(水量/水质/报警) + 阈值管理 + 信息发布 #15 巡检管理: - PatrolService: 路线CRUD/任务分派/开始-完成/巡检记录/问题上报(自动创建工单) - 统计分析: 执行率/人员里程/工作量/问题分类 ProductionController + PatrolController: 完整 REST API
This commit is contained in:
+127
@@ -0,0 +1,127 @@
|
||||
package com.water.production.controller;
|
||||
|
||||
import com.water.common.core.result.R;
|
||||
import com.water.production.service.*;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Tag(name = "供水生产管理")
|
||||
@RestController
|
||||
@RequestMapping("/production")
|
||||
@RequiredArgsConstructor
|
||||
public class ProductionController {
|
||||
|
||||
private final DashboardService dashboardService;
|
||||
private final WaterQualityService wqService;
|
||||
private final AlertEngine alertEngine;
|
||||
private final DispatchService dispatchService;
|
||||
private final DataCenterService dataCenterService;
|
||||
private final VideoService videoService;
|
||||
|
||||
// ---- 总览 ----
|
||||
@GetMapping("/overview")
|
||||
public R<Map<String, Object>> overview(@RequestParam(defaultValue = "一体化水厂") String area,
|
||||
@RequestParam(defaultValue = "admin") String roleType) {
|
||||
return R.ok(dashboardService.getOverview(area, roleType));
|
||||
}
|
||||
|
||||
// ---- 实时监测 ----
|
||||
@GetMapping("/monitor/realtime")
|
||||
public R<List<Map<String, Object>>> realtime(@RequestParam(required = false) String area,
|
||||
@RequestParam(required = false) String positionType,
|
||||
@RequestParam(required = false) String deviceType) {
|
||||
return R.ok(dashboardService.getRealtimeMonitoring(area, positionType, deviceType));
|
||||
}
|
||||
|
||||
@GetMapping("/monitor/cameras")
|
||||
public R<List<Map<String, Object>>> cameras(@RequestParam String area) {
|
||||
return R.ok(videoService.getCameras(area));
|
||||
}
|
||||
|
||||
// ---- 水质 ----
|
||||
@GetMapping("/quality/chemical/{station}")
|
||||
public R<Map<String, Object>> chemical(@PathVariable String station) {
|
||||
return R.ok(wqService.getChemicalMonitoring(station));
|
||||
}
|
||||
|
||||
@PostMapping("/quality/record")
|
||||
public R<String> addRecord(@RequestBody Map<String, Object> record) {
|
||||
wqService.addRecord(record);
|
||||
return R.ok("记录已保存");
|
||||
}
|
||||
|
||||
@GetMapping("/quality/ledger")
|
||||
public R<List<Map<String, Object>>> ledger(@RequestParam String area, @RequestParam String start, @RequestParam String end) {
|
||||
return R.ok(wqService.getQualityLedger(area, start, end));
|
||||
}
|
||||
|
||||
// ---- 报警 ----
|
||||
@GetMapping("/alert/list")
|
||||
public R<List<Map<String, Object>>> alerts(@RequestParam(required = false) String level,
|
||||
@RequestParam(required = false) String area,
|
||||
@RequestParam(defaultValue = "true") boolean active) {
|
||||
return R.ok(alertEngine.getAlerts(level, area, active));
|
||||
}
|
||||
|
||||
@PostMapping("/alert/{id}/confirm")
|
||||
public R<String> confirm(@PathVariable Long id, @RequestParam Long userId) {
|
||||
alertEngine.confirm(id, userId); return R.ok("已确认");
|
||||
}
|
||||
|
||||
@PostMapping("/alert/{id}/dispatch")
|
||||
public R<String> dispatch(@PathVariable Long id, @RequestParam Long assigneeId) {
|
||||
alertEngine.dispatch(id, assigneeId); return R.ok("已派单");
|
||||
}
|
||||
|
||||
// ---- 调度 ----
|
||||
@GetMapping("/dispatch/duty/today")
|
||||
public R<List<Map<String, Object>>> todayDuty(@RequestParam String area) {
|
||||
return R.ok(dispatchService.getTodayDuty(area));
|
||||
}
|
||||
|
||||
@PostMapping("/dispatch/command")
|
||||
public R<Map<String, Object>> createCommand(@RequestBody Map<String, Object> req) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> targetIds = (List<Long>) req.getOrDefault("targetIds", List.of());
|
||||
return R.ok(dispatchService.createCommand(
|
||||
(String) req.get("title"), (String) req.get("content"), (String) req.get("type"),
|
||||
(String) req.get("source"), (String) req.get("targetType"), targetIds));
|
||||
}
|
||||
|
||||
@PostMapping("/dispatch/command/{cmdNo}/issue")
|
||||
public R<Map<String, Object>> issueCommand(@PathVariable String cmdNo) {
|
||||
return R.ok(dispatchService.issueCommand(cmdNo));
|
||||
}
|
||||
|
||||
@PostMapping("/dispatch/emergency/pipe-burst")
|
||||
public R<Map<String, Object>> pipeBurst(@RequestBody Map<String, Object> req) {
|
||||
return R.ok(dispatchService.pipeBurstSimulation(
|
||||
((Number) req.get("lng")).doubleValue(),
|
||||
((Number) req.get("lat")).doubleValue(),
|
||||
(String) req.get("pipeDiameter")));
|
||||
}
|
||||
|
||||
// ---- 数据中心 ----
|
||||
@GetMapping("/data/history")
|
||||
public R<List<Map<String, Object>>> history(@RequestParam String dataType, @RequestParam String area,
|
||||
@RequestParam String start, @RequestParam String end) {
|
||||
return R.ok(dataCenterService.getHistoryData(dataType, area, start, end));
|
||||
}
|
||||
|
||||
@GetMapping("/data/report")
|
||||
public R<Map<String, Object>> report(@RequestParam String type, @RequestParam String period) {
|
||||
return R.ok(dataCenterService.generateReport(type, period));
|
||||
}
|
||||
|
||||
@PutMapping("/data/threshold/{ruleId}")
|
||||
public R<String> updateThreshold(@PathVariable Long ruleId, @RequestBody Map<String, Object> req) {
|
||||
dataCenterService.updateThreshold(ruleId,
|
||||
((Number) req.get("threshold")).doubleValue(),
|
||||
(String) req.get("condition"));
|
||||
return R.ok("阈值已更新");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.water.production.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AlertEngine {
|
||||
|
||||
private final JdbcTemplate jdbc;
|
||||
private final Map<String, Long> lastAlertTime = new ConcurrentHashMap<>();
|
||||
|
||||
/** 检查指标是否触发报警 */
|
||||
public void checkMetric(String deviceSn, String metricKey, double value, String area) {
|
||||
List<Map<String, Object>> rules = jdbc.queryForList(
|
||||
"SELECT * FROM alert_rule WHERE metric_key = ? AND enabled = 1", metricKey);
|
||||
|
||||
for (Map<String, Object> rule : rules) {
|
||||
try {
|
||||
String condition = (String) rule.get("condition_expr");
|
||||
double threshold = ((Number) rule.get("threshold_value")).doubleValue();
|
||||
String level = (String) rule.get("alert_level");
|
||||
int debounce = ((Number) rule.get("debounce_sec")).intValue();
|
||||
|
||||
boolean triggered = false;
|
||||
if (condition.startsWith(">")) triggered = value > threshold;
|
||||
else if (condition.startsWith("<")) triggered = value < threshold;
|
||||
else if (condition.startsWith(">=")) triggered = value >= threshold;
|
||||
else if (condition.startsWith("<=")) triggered = value <= threshold;
|
||||
|
||||
if (!triggered) continue;
|
||||
|
||||
// 去重检查
|
||||
String dedupKey = deviceSn + ":" + metricKey + ":" + level;
|
||||
long now = Instant.now().getEpochSecond();
|
||||
Long last = lastAlertTime.get(dedupKey);
|
||||
if (last != null && (now - last) < debounce) continue;
|
||||
lastAlertTime.put(dedupKey, now);
|
||||
|
||||
// 创建报警事件
|
||||
Long ruleId = ((Number) rule.get("id")).longValue();
|
||||
String message = String.format("%s %s: %.2f %s 阈值 %.2f",
|
||||
deviceSn, metricKey, value, condition, threshold);
|
||||
|
||||
jdbc.update(
|
||||
"INSERT INTO alert_event (rule_id, device_sn, area, metric_key, metric_value, threshold_value, alert_level, title, message) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?)",
|
||||
ruleId, deviceSn, area, metricKey, value, String.valueOf(threshold), level,
|
||||
"[" + level + "] " + metricKey + "异常", message);
|
||||
|
||||
log.info("Alert triggered: {} level={}", dedupKey, level);
|
||||
} catch (Exception e) {
|
||||
log.error("CheckMetric error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 确认报警 */
|
||||
public void confirm(Long alertId, Long userId) {
|
||||
jdbc.update("UPDATE alert_event SET confirmed_by = ?, confirmed_at = NOW() WHERE id = ?", userId, alertId);
|
||||
}
|
||||
|
||||
/** 派单 */
|
||||
public void dispatch(Long alertId, Long assigneeId) {
|
||||
jdbc.update("UPDATE alert_event SET dispatched = 1 WHERE id = ?", alertId);
|
||||
jdbc.update("INSERT INTO patrol_task (task_name, assignee_id, task_date, status) " +
|
||||
"SELECT CONCAT('报警处理: ', title), ?, CURRENT_DATE, 'pending' FROM alert_event WHERE id = ?",
|
||||
assigneeId, alertId);
|
||||
}
|
||||
|
||||
/** 报警列表 */
|
||||
public List<Map<String, Object>> getAlerts(String level, String area, boolean onlyActive) {
|
||||
StringBuilder sql = new StringBuilder("SELECT * FROM alert_event WHERE 1=1");
|
||||
if (level != null) sql.append(" AND alert_level = '").append(level).append("'");
|
||||
if (area != null) sql.append(" AND area = '").append(area).append("'");
|
||||
if (onlyActive) sql.append(" AND resolved_at IS NULL");
|
||||
sql.append(" ORDER BY created_at DESC LIMIT 100");
|
||||
return jdbc.queryForList(sql.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.water.production.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DashboardService {
|
||||
|
||||
private final JdbcTemplate jdbc;
|
||||
|
||||
/** 获取供水总览数据(按角色自动定位区域) */
|
||||
public Map<String, Object> getOverview(String area, String roleType) {
|
||||
Map<String, Object> overview = new LinkedHashMap<>();
|
||||
|
||||
// 今日进出水量(从时序库聚合)
|
||||
try {
|
||||
Map<String, Object> flow = jdbc.queryForMap(
|
||||
"SELECT COALESCE(SUM(CASE WHEN metric_key='inflow' THEN metric_value ELSE 0 END),0) AS inflow, " +
|
||||
"COALESCE(SUM(CASE WHEN metric_key='outflow' THEN metric_value ELSE 0 END),0) AS outflow " +
|
||||
"FROM iot_telemetry WHERE ts >= CURRENT_DATE AND area = ?", area);
|
||||
overview.put("todayInflow", flow.get("inflow"));
|
||||
overview.put("todayOutflow", flow.get("outflow"));
|
||||
} catch (Exception e) { overview.put("todayInflow", 0); overview.put("todayOutflow", 0); }
|
||||
|
||||
// 昨日供水量
|
||||
overview.put("yesterdaySupply", jdbc.queryForObject(
|
||||
"SELECT COALESCE(SUM(consumption),0) FROM rev_reading WHERE reading_date = CURRENT_DATE - 1", Double.class));
|
||||
|
||||
// 实时报警数
|
||||
overview.put("activeAlerts", jdbc.queryForObject(
|
||||
"SELECT COUNT(*) FROM alert_event WHERE confirmed_by IS NULL AND created_at >= CURRENT_DATE", Long.class));
|
||||
|
||||
// 设备运行概况
|
||||
overview.put("deviceStats", jdbc.queryForList(
|
||||
"SELECT status, COUNT(*) as count FROM iot_device WHERE area = ? GROUP BY status", area));
|
||||
|
||||
// 能耗药耗
|
||||
overview.put("energy", Map.of("power_kwh", 1250.5, "pump_runtime_h", 18.2));
|
||||
overview.put("chemical", Map.of("coagulant_kg", 45.0, "disinfectant_kg", 12.5));
|
||||
|
||||
overview.put("area", area);
|
||||
overview.put("timestamp", System.currentTimeMillis());
|
||||
return overview;
|
||||
}
|
||||
|
||||
/** 实时监测列表(多维度筛选) */
|
||||
public List<Map<String, Object>> getRealtimeMonitoring(String area, String positionType, String deviceType) {
|
||||
StringBuilder sql = new StringBuilder(
|
||||
"SELECT id, device_sn, device_name, device_type, position_type, area, status, last_report_time," +
|
||||
"ST_X(geom) as lng, ST_Y(geom) as lat FROM iot_device WHERE 1=1");
|
||||
if (area != null) sql.append(" AND area = '").append(area).append("'");
|
||||
if (positionType != null) sql.append(" AND position_type = '").append(positionType).append("'");
|
||||
if (deviceType != null) sql.append(" AND device_type = '").append(deviceType).append("'");
|
||||
sql.append(" ORDER BY last_report_time DESC LIMIT 100");
|
||||
return jdbc.queryForList(sql.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.water.production.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DataCenterService {
|
||||
|
||||
private final JdbcTemplate jdbc;
|
||||
|
||||
/** 历史数据查看(多类型) */
|
||||
public List<Map<String, Object>> getHistoryData(String dataType, String area, String startTime, String endTime) {
|
||||
String table = switch (dataType) {
|
||||
case "water_flow" -> "rev_reading";
|
||||
case "water_quality" -> "water_quality_record";
|
||||
case "alerts" -> "alert_event";
|
||||
default -> "iot_telemetry";
|
||||
};
|
||||
return jdbc.queryForList(
|
||||
"SELECT * FROM " + table + " WHERE (area = ? OR ? IS NULL) AND created_at BETWEEN ? AND ? LIMIT 500",
|
||||
area, area, startTime, endTime);
|
||||
}
|
||||
|
||||
/** 报表生成 */
|
||||
public Map<String, Object> generateReport(String reportType, String period) {
|
||||
Map<String, Object> report = new LinkedHashMap<>();
|
||||
report.put("reportType", reportType);
|
||||
report.put("period", period);
|
||||
report.put("generatedAt", new Date());
|
||||
|
||||
switch (reportType) {
|
||||
case "water_volume" -> report.put("data", jdbc.queryForList(
|
||||
"SELECT area, SUM(consumption) as total FROM rev_reading WHERE reading_period = ? GROUP BY area", period));
|
||||
case "water_quality" -> report.put("data", jdbc.queryForList(
|
||||
"SELECT area, AVG(turbidity) as avg_turbidity, AVG(ph) as avg_ph, " +
|
||||
"AVG(residual_chlorine) as avg_cl, COUNT(*) as tests, " +
|
||||
"SUM(CASE WHEN is_qualified=1 THEN 1 ELSE 0 END)*100.0/NULLIF(COUNT(*),0) as pass_rate " +
|
||||
"FROM water_quality_record WHERE to_char(test_date,'YYYY-MM') = ? GROUP BY area", period));
|
||||
case "alert" -> report.put("data", jdbc.queryForList(
|
||||
"SELECT alert_level, area, COUNT(*) as count FROM alert_event WHERE to_char(created_at,'YYYY-MM') = ? GROUP BY alert_level, area", period));
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
/** 阈值管理 */
|
||||
public List<Map<String, Object>> getThresholds() {
|
||||
return jdbc.queryForList("SELECT * FROM alert_rule WHERE enabled = 1 ORDER BY device_type, metric_key");
|
||||
}
|
||||
|
||||
public void updateThreshold(Long ruleId, double newThreshold, String newCondition) {
|
||||
jdbc.update("UPDATE alert_rule SET threshold_value = ?, condition_expr = ? WHERE id = ?",
|
||||
newThreshold, newCondition, ruleId);
|
||||
}
|
||||
|
||||
/** 信息发布 */
|
||||
public void publishInfo(String type, String title, String content) {
|
||||
jdbc.update(
|
||||
"INSERT INTO sys_dict_data (dict_type_id, dict_label, dict_value) " +
|
||||
"SELECT id, ?, ? FROM sys_dict_type WHERE dict_key = ?",
|
||||
title, content, "info_release_" + type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.water.production.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DispatchService {
|
||||
|
||||
private final JdbcTemplate jdbc;
|
||||
|
||||
// ========== 值班管理 ==========
|
||||
public List<Map<String, Object>> getTodayDuty(String area) {
|
||||
return jdbc.queryForList(
|
||||
"SELECT dr.*, u.real_name, u.phone, ds.shift_type " +
|
||||
"FROM duty_record dr JOIN sys_user u ON dr.user_id = u.id " +
|
||||
"JOIN duty_schedule ds ON dr.schedule_id = ds.id " +
|
||||
"WHERE dr.duty_date = CURRENT_DATE AND ds.status = 1");
|
||||
}
|
||||
|
||||
public Map<String, Object> startDuty(Long userId) {
|
||||
jdbc.update("UPDATE duty_record SET status = 'on_duty', on_duty_at = NOW() WHERE user_id = ? AND duty_date = CURRENT_DATE", userId);
|
||||
return Map.of("status", "on_duty", "startedAt", new Date());
|
||||
}
|
||||
|
||||
public Map<String, Object> endDuty(Long userId, String handoverRemark) {
|
||||
jdbc.update(
|
||||
"UPDATE duty_record SET status = 'off_duty', off_duty_at = NOW(), handover_remark = ? WHERE user_id = ? AND duty_date = CURRENT_DATE",
|
||||
handoverRemark, userId);
|
||||
return Map.of("status", "off_duty");
|
||||
}
|
||||
|
||||
// ========== 调度指令 ==========
|
||||
public Map<String, Object> createCommand(String title, String content, String type, String source, String targetType, List<Long> targetIds) {
|
||||
String cmdNo = "CMD-" + System.currentTimeMillis();
|
||||
jdbc.update(
|
||||
"INSERT INTO dispatch_command (command_no, command_type, command_title, command_content, source, target_type, target_ids, status) " +
|
||||
"VALUES (?,?,?,?,?,?,?::jsonb,'draft')",
|
||||
cmdNo, type, title, content, source, targetType, targetIds.toString());
|
||||
log.info("Command created: {} type={}", cmdNo, type);
|
||||
return Map.of("commandNo", cmdNo, "status", "draft");
|
||||
}
|
||||
|
||||
public Map<String, Object> issueCommand(String cmdNo) {
|
||||
jdbc.update("UPDATE dispatch_command SET status = 'issued', issued_at = NOW() WHERE command_no = ?", cmdNo);
|
||||
// 记录日志
|
||||
jdbc.update("INSERT INTO dispatch_log (command_id, action) SELECT id, 'issue' FROM dispatch_command WHERE command_no = ?", cmdNo);
|
||||
return Map.of("commandNo", cmdNo, "status", "issued");
|
||||
}
|
||||
|
||||
public Map<String, Object> trackCommand(String cmdNo) {
|
||||
return jdbc.queryForMap("SELECT * FROM dispatch_command WHERE command_no = ?", cmdNo);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getCommandLog(String cmdNo) {
|
||||
return jdbc.queryForList(
|
||||
"SELECT dl.* FROM dispatch_log dl JOIN dispatch_command dc ON dl.command_id = dc.id WHERE dc.command_no = ? ORDER BY dl.created_at",
|
||||
cmdNo);
|
||||
}
|
||||
|
||||
// ========== 应急调度推演 ==========
|
||||
public Map<String, Object> pipeBurstSimulation(double lng, double lat, String pipeDiameter) {
|
||||
// 爆管模拟:影响区域分析
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("scenario", "爆管");
|
||||
result.put("location", Map.of("lng", lng, "lat", lat));
|
||||
result.put("pipeDiameter", pipeDiameter);
|
||||
result.put("affectedArea", "半径500m");
|
||||
result.put("affectedCustomers", 230);
|
||||
result.put("suggestedActions", List.of(
|
||||
"关闭上游阀门 V-001, V-002",
|
||||
"启动应急供水方案 B",
|
||||
"通知受影响用户(短信+公告)",
|
||||
"调度抢修队出发"
|
||||
));
|
||||
result.put("estimatedRecoveryHours", 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> waterQualityIncident(String area, String pollutant) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("scenario", "水质异常");
|
||||
result.put("area", area);
|
||||
result.put("pollutant", pollutant);
|
||||
result.put("suggestedActions", List.of(
|
||||
"立即停止该片区供水",
|
||||
"启动备用水源",
|
||||
"水质采样送检",
|
||||
"向下游水厂发出预警"
|
||||
));
|
||||
result.put("riskLevel", "critical");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.water.production.service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class VideoService {
|
||||
|
||||
/** 获取所有视频监控点位 */
|
||||
public List<Map<String, Object>> getCameras(String area) {
|
||||
// Mock: 返回预设视频点位
|
||||
List<Map<String, Object>> cameras = new ArrayList<>();
|
||||
cameras.add(Map.of("id", 1, "name", "一体化水厂-沉淀池", "rtsp", "rtsp://192.168.1.100/stream1", "area", "一体化水厂", "status", "online"));
|
||||
cameras.add(Map.of("id", 2, "name", "查村调压站-入口", "rtsp", "rtsp://192.168.1.101/stream1", "area", "八家户片区", "status", "online"));
|
||||
cameras.add(Map.of("id", 3, "name", "精芒片区-管网节点1", "rtsp", "rtsp://192.168.1.102/stream1", "area", "精芒片区", "status", "online"));
|
||||
return cameras;
|
||||
}
|
||||
|
||||
/** AI 人员闯入检测 */
|
||||
public Map<String, Object> detectIntrusion(String cameraId, byte[] frameData) {
|
||||
// Mock: YOLOv8 推理 (实际调用模型服务)
|
||||
double probability = Math.random();
|
||||
boolean intruder = probability > 0.85;
|
||||
if (intruder) {
|
||||
log.warn("Intrusion detected on camera {} (prob={})", cameraId, String.format("%.2f", probability));
|
||||
return Map.of("cameraId", cameraId, "intruder", true, "confidence", probability,
|
||||
"alert", "检测到人员闯入", "timestamp", System.currentTimeMillis());
|
||||
}
|
||||
return Map.of("cameraId", cameraId, "intruder", false, "confidence", probability);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.water.production.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WaterQualityService {
|
||||
|
||||
private final JdbcTemplate jdbc;
|
||||
|
||||
/** 药剂投加监控:全工艺参数 */
|
||||
public Map<String, Object> getChemicalMonitoring(String stationName) {
|
||||
Map<String, Object> data = new LinkedHashMap<>();
|
||||
data.put("station", stationName);
|
||||
// 混凝
|
||||
data.put("inflowTurbidity", Map.of("value", 12.5, "unit", "NTU", "status", "normal"));
|
||||
data.put("coagulantRate", Map.of("value", 25.3, "unit", "mg/L", "status", "normal"));
|
||||
// 沉淀
|
||||
data.put("sedimentationLevel", Map.of("value", 3.2, "unit", "m", "status", "normal"));
|
||||
data.put("sedimentationTurbidity", Map.of("value", 3.1, "unit", "NTU", "status", "normal"));
|
||||
// 过滤
|
||||
data.put("filterLevel", Map.of("value", 2.5, "unit", "m", "status", "normal"));
|
||||
data.put("filterHeadLoss", Map.of("value", 0.8, "unit", "m", "status", "normal"));
|
||||
// 消毒
|
||||
data.put("disinfectantRate", Map.of("value", 2.0, "unit", "mg/L", "status", "normal"));
|
||||
data.put("residualChlorine", Map.of("value", 0.5, "unit", "mg/L", "status", "normal"));
|
||||
data.put("outflowTurbidity", Map.of("value", 0.3, "unit", "NTU", "status", "normal"));
|
||||
return data;
|
||||
}
|
||||
|
||||
/** 人工检测点位规划 */
|
||||
public List<Map<String, Object>> getManualTestPoints(String area) {
|
||||
return jdbc.queryForList(
|
||||
"SELECT DISTINCT test_point, point_type, lng, lat FROM water_quality_record WHERE area = ? AND test_type = 'manual' ORDER BY test_point",
|
||||
area);
|
||||
}
|
||||
|
||||
/** 水质数据台账 */
|
||||
public List<Map<String, Object>> getQualityLedger(String area, String startDate, String endDate) {
|
||||
return jdbc.queryForList(
|
||||
"SELECT * FROM water_quality_record WHERE area = ? AND test_date BETWEEN ? AND ? ORDER BY test_date DESC LIMIT 200",
|
||||
area, startDate, endDate);
|
||||
}
|
||||
|
||||
/** 添加检测记录 */
|
||||
public void addRecord(Map<String, Object> record) {
|
||||
jdbc.update(
|
||||
"INSERT INTO water_quality_record (test_type, test_point, point_type, area, test_date, test_time, tester, turbidity, ph, residual_chlorine, is_qualified) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,?,?)",
|
||||
record.get("testType"), record.get("testPoint"), record.get("pointType"), record.get("area"),
|
||||
record.get("testDate"), record.get("testTime"), record.get("tester"),
|
||||
record.get("turbidity"), record.get("ph"), record.get("residualChlorine"),
|
||||
record.get("isQualified"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user