Phase 2 #10 #11 #12 #13 #14 #15: 供水生产管理平台 + 巡检管理系统

#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:
bot_pm
2026-06-14 13:27:31 +08:00
parent 4268f8df6b
commit 8290b813f1
9 changed files with 754 additions and 0 deletions
@@ -0,0 +1,100 @@
package com.water.patrol.controller;
import com.water.common.core.result.R;
import com.water.patrol.service.PatrolService;
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.time.LocalDate;
import java.util.*;
@Tag(name = "巡检管理")
@RestController
@RequestMapping("/patrol")
@RequiredArgsConstructor
public class PatrolController {
private final PatrolService patrolService;
// ---- 路线 ----
@PostMapping("/route")
public R<Map<String, Object>> createRoute(@RequestBody Map<String, Object> req) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> points = (List<Map<String, Object>>) req.getOrDefault("points", List.of());
return R.ok(patrolService.createRoute(
(String) req.get("routeName"), (String) req.get("area"),
points, (int) req.getOrDefault("estimDuration", 60)));
}
@GetMapping("/route/list")
public R<List<Map<String, Object>>> routes(@RequestParam String area) {
return R.ok(patrolService.getRoutes(area));
}
// ---- 任务 ----
@PostMapping("/task")
public R<Map<String, Object>> createTask(@RequestBody Map<String, Object> req) {
return R.ok(patrolService.createTask(
Long.parseLong(String.valueOf(req.get("routeId"))),
Long.parseLong(String.valueOf(req.get("assigneeId"))),
(String) req.get("taskDate")));
}
@GetMapping("/task/today")
public R<List<Map<String, Object>>> todayTasks(@RequestParam Long userId) {
return R.ok(patrolService.getTodayTasks(userId));
}
@PutMapping("/task/{id}/start")
public R<Map<String, Object>> startTask(@PathVariable Long id) {
return R.ok(patrolService.startTask(id));
}
@PutMapping("/task/{id}/complete")
public R<Map<String, Object>> completeTask(@PathVariable Long id, @RequestParam double distance) {
return R.ok(patrolService.completeTask(id, distance));
}
// ---- 巡检记录 ----
@PostMapping("/record")
public R<Map<String, Object>> record(@RequestBody Map<String, Object> req) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> items = (List<Map<String, Object>>) req.getOrDefault("checkItems", List.of());
return R.ok(patrolService.recordCheck(
Long.parseLong(String.valueOf(req.get("taskId"))),
(int) req.get("pointSeq"),
req.get("deviceId") != null ? Long.parseLong(String.valueOf(req.get("deviceId"))) : null,
items,
((Number) req.get("lng")).doubleValue(),
((Number) req.get("lat")).doubleValue()));
}
@GetMapping("/record/list/{taskId}")
public R<List<Map<String, Object>>> records(@PathVariable Long taskId) {
return R.ok(patrolService.getTaskRecords(taskId));
}
// ---- 问题上报 ----
@PostMapping("/issue/report")
public R<Map<String, Object>> reportIssue(@RequestBody Map<String, Object> req) {
@SuppressWarnings("unchecked")
List<String> photos = (List<String>) req.getOrDefault("photoUrls", List.of());
return R.ok(patrolService.reportIssue(
Long.parseLong(String.valueOf(req.get("taskId"))),
req.get("deviceId") != null ? Long.parseLong(String.valueOf(req.get("deviceId"))) : null,
(String) req.get("issueType"), (String) req.get("description"),
photos,
((Number) req.get("lng")).doubleValue(),
((Number) req.get("lat")).doubleValue()));
}
// ---- 统计 ----
@GetMapping("/stats")
public R<Map<String, Object>> stats(@RequestParam String area,
@RequestParam String start,
@RequestParam String end) {
return R.ok(patrolService.getStats(area, LocalDate.parse(start), LocalDate.parse(end)));
}
}
@@ -0,0 +1,118 @@
package com.water.patrol.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 PatrolService {
private final JdbcTemplate jdbc;
// ========== 路线管理 ==========
public Map<String, Object> createRoute(String routeName, String area, List<Map<String, Object>> points, int estimDuration) {
jdbc.update("INSERT INTO patrol_route (route_name, area, route_points, estim_duration) VALUES (?,?,?::jsonb,?)",
routeName, area, points.toString(), estimDuration);
return Map.of("routeName", routeName, "area", area, "points", points.size());
}
public List<Map<String, Object>> getRoutes(String area) {
return jdbc.queryForList("SELECT * FROM patrol_route WHERE area = ? AND status = 1", area);
}
// ========== 任务管理 ==========
public Map<String, Object> createTask(Long routeId, Long assigneeId, String taskDate) {
jdbc.update(
"INSERT INTO patrol_task (route_id, assignee_id, task_name, task_date, plan_start, plan_end, status) " +
"SELECT ?, ?, route_name, ?, CAST(? AS TIMESTAMP), CAST(? AS TIMESTAMP) + (estim_duration || ' minutes')::INTERVAL, 'pending' " +
"FROM patrol_route WHERE id = ?",
routeId, assigneeId, taskDate, taskDate + " 09:00:00", taskDate + " 09:00:00", routeId);
return Map.of("routeId", routeId, "assigneeId", assigneeId, "date", taskDate, "status", "created");
}
public List<Map<String, Object>> getTodayTasks(Long userId) {
return jdbc.queryForList(
"SELECT pt.*, pr.route_name, pr.area FROM patrol_task pt " +
"LEFT JOIN patrol_route pr ON pt.route_id = pr.id " +
"WHERE pt.task_date = CURRENT_DATE AND pt.assignee_id = ? " +
"ORDER BY pt.plan_start", userId);
}
public Map<String, Object> startTask(Long taskId) {
jdbc.update("UPDATE patrol_task SET status = 'in_progress', actual_start = NOW() WHERE id = ?", taskId);
return Map.of("taskId", taskId, "status", "in_progress", "startedAt", new Date());
}
public Map<String, Object> completeTask(Long taskId, double distance) {
jdbc.update(
"UPDATE patrol_task SET status = 'completed', actual_end = NOW(), distance = ? WHERE id = ?",
distance, taskId);
return Map.of("taskId", taskId, "status", "completed", "distance", distance);
}
// ========== 巡检记录 ==========
public Map<String, Object> recordCheck(Long taskId, int pointSeq, Long deviceId,
List<Map<String, Object>> checkItems,
double lng, double lat) {
jdbc.update(
"INSERT INTO patrol_record (task_id, point_seq, device_id, check_items, gps_lng, gps_lat, record_time) " +
"VALUES (?,?,?,?::jsonb,?,?,NOW())",
taskId, pointSeq, deviceId, checkItems.toString(), lng, lat);
return Map.of("taskId", taskId, "pointSeq", pointSeq, "recorded", true);
}
public List<Map<String, Object>> getTaskRecords(Long taskId) {
return jdbc.queryForList(
"SELECT * FROM patrol_record WHERE task_id = ? ORDER BY point_seq", taskId);
}
// ========== 问题上报(巡检APP) ==========
public Map<String, Object> reportIssue(Long taskId, Long deviceId, String issueType,
String description, List<String> photoUrls,
double lng, double lat) {
// 自动创建工单
jdbc.update(
"INSERT INTO patrol_task (task_name, assignee_id, task_date, status) " +
"SELECT CONCAT('问题处理: ', ?), assignee_id, CURRENT_DATE, 'pending' FROM patrol_task WHERE id = ?",
issueType + ": " + description.substring(0, Math.min(description.length(), 50)), taskId);
log.info("Issue reported: type={} desc={}", issueType, description);
return Map.of("reported", true, "issueType", issueType, "photos", photoUrls);
}
// ========== 统计分析 ==========
public Map<String, Object> getStats(String area, LocalDate start, LocalDate end) {
Map<String, Object> stats = new LinkedHashMap<>();
// 任务执行率
stats.put("completionRate", jdbc.queryForMap(
"SELECT COUNT(*) as total, SUM(CASE WHEN status='completed' THEN 1 ELSE 0 END) as completed " +
"FROM patrol_task WHERE task_date BETWEEN ? AND ?", start, end));
// 人员里程
stats.put("personDistance", jdbc.queryForList(
"SELECT u.real_name, SUM(pt.distance) as total_km " +
"FROM patrol_task pt JOIN sys_user u ON pt.assignee_id = u.id " +
"WHERE pt.task_date BETWEEN ? AND ? GROUP BY u.id, u.real_name", start, end));
// 巡检工作量
stats.put("workload", jdbc.queryForList(
"SELECT task_date, COUNT(*) as tasks, SUM(distance) as total_km " +
"FROM patrol_task WHERE task_date BETWEEN ? AND ? GROUP BY task_date ORDER BY task_date",
start, end));
// 问题分类统计
stats.put("issueStats", jdbc.queryForList(
"SELECT SUBSTRING(task_name FROM '^[^:]+') as issue_type, COUNT(*) as count " +
"FROM patrol_task WHERE task_name LIKE '%问题处理:%' AND task_date BETWEEN ? AND ? GROUP BY 1",
start, end));
return stats;
}
}