3 Commits f4a7c43cbb ... 6126144416

Auteur SHA1 Bericht Datum
  林仔 6126144416 Merge remote-tracking branch 'origin/master' 1 week geleden
  林仔 be6720db03 feat(warning): 添加预警管理系统功能 1 week geleden
  林仔 53ec2c938a feat(equipment): 添加设备状态管理和测试功能 2 weken geleden

+ 60 - 22
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/base/EquipmentBaseController.java

@@ -11,15 +11,14 @@ import com.zksy.common.core.domain.AjaxResult;
 import com.zksy.common.enums.BusinessType;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
+import java.util.Map;
 
-/**
- * 设备基础信息
- */
 @Slf4j
 @RestController
 @RequestMapping("/EquipmentBase")
@@ -34,22 +33,21 @@ public class EquipmentBaseController {
     @Anonymous
     public AjaxResult getById(@PathVariable String id) {
         EquipmentBase equipmentBase = service.getById(id);
-        if(equipmentBase==null){
+        if (equipmentBase == null) {
             return AjaxResult.error("该设备信息不存在");
         }
         return AjaxResult.success(equipmentBase);
     }
 
-    //TODO 待优化
     @Anonymous
     @GetMapping("/findByPage")
     @ApiOperation(value = "设备基础信息分页")
     public Page findByPage(long pageNum, long pageSize,
-                           @RequestParam(required = false)String equipmentCode,
-                           @RequestParam(required = false)String equipmentName,
-                           @RequestParam(required = false)String equipmentModel,
-                           @RequestParam(required = false)String manufacturer) throws Exception {
-        return service.findByPage(pageNum, pageSize, equipmentCode,equipmentName,equipmentModel,manufacturer);
+                           @RequestParam(required = false) String equipmentCode,
+                           @RequestParam(required = false) String equipmentName,
+                           @RequestParam(required = false) String equipmentModel,
+                           @RequestParam(required = false) String manufacturer) throws Exception {
+        return service.findByPage(pageNum, pageSize, equipmentCode, equipmentName, equipmentModel, manufacturer);
     }
 
     @Anonymous
@@ -64,22 +62,20 @@ public class EquipmentBaseController {
     @Log(title = "新增设备基础信息", businessType = BusinessType.INSERT)
     public AjaxResult save(@RequestBody EquipmentBase entity) {
         boolean saved = service.saveWithCheck(entity);
-        return saved ? AjaxResult.success("新增成功",saved)
-                : AjaxResult.error("新增失败",saved);
+        return saved ? AjaxResult.success("新增成功", saved)
+                : AjaxResult.error("新增失败", saved);
     }
 
     @PostMapping("/saveBatch")
     @ApiOperation(value = "设备基础信息批量新增")
     @Log(title = "批量新增设备基础信息", businessType = BusinessType.INSERT)
     public AjaxResult saveBatch(@RequestBody List<EquipmentBase> entityList) {
-        // 基础校验:列表不能为空
         if (CollectionUtils.isEmpty(entityList)) {
             return AjaxResult.error("批量新增失败:设备列表不能为空");
         }
-
         boolean saved = service.saveBatchWithCheck(entityList);
-        return saved ? AjaxResult.success("新增成功",saved)
-                : AjaxResult.error("新增失败",saved);
+        return saved ? AjaxResult.success("新增成功", saved)
+                : AjaxResult.error("新增失败", saved);
     }
 
     @PutMapping("/updateById")
@@ -87,8 +83,8 @@ public class EquipmentBaseController {
     @Log(title = "修改设备基础信息", businessType = BusinessType.UPDATE)
     public AjaxResult updateById(@RequestBody EquipmentBase entity) {
         boolean updated = service.updateWithCheck(entity);
-        return updated ? AjaxResult.success("修改成功",updated)
-                : AjaxResult.error("修改失败",updated);
+        return updated ? AjaxResult.success("修改成功", updated)
+                : AjaxResult.error("修改失败", updated);
     }
 
     @DeleteMapping("/deleteById")
@@ -96,8 +92,8 @@ public class EquipmentBaseController {
     @Log(title = "删除设备基础信息", businessType = BusinessType.DELETE)
     public AjaxResult deleteById(String id) {
         boolean deleted = service.removeWithCheck(id);
-        return deleted ? AjaxResult.success("删除成功",deleted)
-                : AjaxResult.error("删除失败",deleted);
+        return deleted ? AjaxResult.success("删除成功", deleted)
+                : AjaxResult.error("删除失败", deleted);
     }
 
     @DeleteMapping("/deleteBatchById")
@@ -105,7 +101,49 @@ public class EquipmentBaseController {
     @Log(title = "设备基础信息批量删除", businessType = BusinessType.DELETE)
     public AjaxResult deleteBatchById(@RequestParam List<String> ids) {
         boolean deleted = service.removeBatchWithCheck(ids);
-        return deleted ? AjaxResult.success("删除成功",deleted)
-                : AjaxResult.error("删除失败",deleted);
+        return deleted ? AjaxResult.success("删除成功", deleted)
+                : AjaxResult.error("删除失败", deleted);
+    }
+
+    @PutMapping("/updateStatus")
+    @ApiOperation(value = "设备状态维护(启用/禁用/维修等)")
+    @Log(title = "设备状态维护", businessType = BusinessType.UPDATE)
+    @Anonymous
+    public AjaxResult updateEquipmentStatus(
+            @ApiParam("设备ID") @RequestParam String equipmentId,
+            @ApiParam("状态值") @RequestParam Integer currentStatus) {
+        boolean updated = service.updateEquipmentStatus(equipmentId, currentStatus);
+        return updated ? AjaxResult.success("状态更新成功")
+                : AjaxResult.error("状态更新失败");
+    }
+
+    @PostMapping("/test")
+    @ApiOperation(value = "设备测试验证")
+    @Log(title = "设备测试验证", businessType = BusinessType.OTHER)
+    @Anonymous
+    public AjaxResult testEquipment(
+            @ApiParam("设备ID") @RequestParam String equipmentId,
+            @ApiParam("测试类型") @RequestParam(required = false) String testType,
+            @ApiParam("测试详情") @RequestParam(required = false) String testDetail,
+            @ApiParam("测试人") @RequestParam(required = false) String testUser) {
+        boolean tested = service.testEquipment(equipmentId, testType, testDetail, testUser);
+        return tested ? AjaxResult.success("测试成功")
+                : AjaxResult.error("测试失败");
+    }
+
+    @GetMapping("/detail/{equipmentId}")
+    @ApiOperation(value = "设备详情(含关联信息)")
+    @Anonymous
+    public AjaxResult getEquipmentDetail(@PathVariable String equipmentId) {
+        Map<String, Object> detail = service.getEquipmentDetail(equipmentId);
+        return AjaxResult.success(detail);
+    }
+
+    @GetMapping("/byPoint/{pointId}")
+    @ApiOperation(value = "根据监测点查询设备")
+    @Anonymous
+    public AjaxResult getEquipmentByPoint(@PathVariable String pointId) {
+        List<EquipmentBase> list = service.getEquipmentByPoint(pointId);
+        return AjaxResult.success(list);
     }
 }

+ 364 - 0
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/warning/EarlyWarningController.java

@@ -0,0 +1,364 @@
+package com.zksy.web.controller.warning;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zksy.base.warning.domain.EarlyWarning;
+import com.zksy.base.warning.domain.WarningArchive;
+import com.zksy.base.warning.domain.WarningDisposal;
+import com.zksy.base.warning.domain.WarningSaveDTO;
+import com.zksy.base.warning.service.EarlyWarningService;
+import com.zksy.common.annotation.Anonymous;
+import com.zksy.common.annotation.Log;
+import com.zksy.common.core.domain.AjaxResult;
+import com.zksy.common.enums.BusinessType;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping("/warning")
+@Api(tags = "预警管理")
+public class EarlyWarningController {
+
+    @Autowired
+    private EarlyWarningService earlyWarningService;
+
+    @GetMapping("/list")
+    @ApiOperation("分页查询预警列表")
+    @Anonymous
+    public AjaxResult getWarningList(
+            @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum,
+            @ApiParam("每页数量") @RequestParam(defaultValue = "10") Integer pageSize,
+            @ApiParam("预警名称") @RequestParam(required = false) String warningName,
+            @ApiParam("预警类型") @RequestParam(required = false) String warningType,
+            @ApiParam("预警级别") @RequestParam(required = false) String warningLevel,
+            @ApiParam("状态") @RequestParam(required = false) String status) {
+        Page<?> page = new Page<>(pageNum, pageSize);
+        IPage<Map<String, Object>> result = earlyWarningService.getWarningList(page, warningName, warningType, warningLevel, status);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/todo/list")
+    @ApiOperation("待办预警列表")
+    @Anonymous
+    public AjaxResult getTodoList(
+            @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum,
+            @ApiParam("每页数量") @RequestParam(defaultValue = "10") Integer pageSize,
+            @ApiParam("用户ID") @RequestParam String userId,
+            @ApiParam("待办类型") @RequestParam(required = false) String todoType,
+            @ApiParam("预警名称") @RequestParam(required = false) String warningName) {
+        Page<?> page = new Page<>(pageNum, pageSize);
+        IPage<Map<String, Object>> result = earlyWarningService.getTodoList(page, userId, todoType, warningName);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/detail/{warningId}")
+    @ApiOperation("预警详情")
+    @Anonymous
+    public AjaxResult getWarningDetail(@PathVariable String warningId) {
+        Map<String, Object> detail = earlyWarningService.getWarningDetail(warningId);
+        if (detail == null) {
+            return AjaxResult.error("预警信息不存在");
+        }
+        return AjaxResult.success(detail);
+    }
+
+    @PostMapping("/save")
+    @ApiOperation("保存预警信息")
+    @Log(title = "保存预警信息", businessType = BusinessType.INSERT)
+    public AjaxResult saveWarning(WarningSaveDTO entity) {
+        boolean result = earlyWarningService.saveWarning(entity.getWarning(), entity.getAlarmIds(), entity.getFiles());
+        return result ? AjaxResult.success("保存成功", entity.getWarning().getWarningId()) : AjaxResult.error("保存失败");
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("修改预警信息")
+    @Log(title = "修改预警信息", businessType = BusinessType.UPDATE)
+    public AjaxResult updateWarning(EarlyWarning warning, List<MultipartFile> files) {
+        boolean result = earlyWarningService.updateWarning(warning, files);
+        return result ? AjaxResult.success("修改成功") : AjaxResult.error("修改失败");
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation("删除预警信息")
+    @Log(title = "删除预警信息", businessType = BusinessType.DELETE)
+    public AjaxResult deleteWarning(@RequestParam String warningId) {
+        boolean result = earlyWarningService.deleteWarning(warningId);
+        return result ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
+    }
+
+    @DeleteMapping("/delete/batch")
+    @ApiOperation("批量删除预警信息")
+    @Log(title = "批量删除预警信息", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatchWarning(@RequestParam List<String> warningIds) {
+        boolean result = earlyWarningService.deleteBatchWarning(warningIds);
+        return result ? AjaxResult.success("批量删除成功") : AjaxResult.error("批量删除失败");
+    }
+
+    @PostMapping("/publish/{warningId}")
+    @ApiOperation("发布预警")
+    @Log(title = "发布预警", businessType = BusinessType.UPDATE)
+    public AjaxResult publishWarning(
+            @PathVariable String warningId,
+            @ApiParam("处置人") @RequestParam(required = false, defaultValue = "system") String disposalUser) {
+        boolean result = earlyWarningService.publishWarning(warningId, disposalUser);
+        return result ? AjaxResult.success("发布成功") : AjaxResult.error("发布失败");
+    }
+
+    @PostMapping("/upgrade")
+    @ApiOperation("预警升级")
+    @Log(title = "预警升级", businessType = BusinessType.UPDATE)
+    public AjaxResult upgradeWarning(
+            @ApiParam("预警ID") @RequestParam String warningId,
+            @ApiParam("新预警级别") @RequestParam String newLevel,
+            @ApiParam("处置人") @RequestParam(required = false, defaultValue = "system") String disposalUser,
+            @ApiParam("处置说明") @RequestParam String disposalContent) {
+        boolean result = earlyWarningService.upgradeWarning(warningId, newLevel, disposalUser, disposalContent);
+        return result ? AjaxResult.success("升级成功") : AjaxResult.error("升级失败");
+    }
+
+    @PostMapping("/resolve")
+    @ApiOperation("解除预警")
+    @Log(title = "解除预警", businessType = BusinessType.UPDATE)
+    public AjaxResult resolveWarning(
+            @ApiParam("预警ID") @RequestParam String warningId,
+            @ApiParam("处置人") @RequestParam(required = false, defaultValue = "system") String disposalUser,
+            @ApiParam("处置说明") @RequestParam String disposalContent) {
+        boolean result = earlyWarningService.resolveWarning(warningId, disposalUser, disposalContent);
+        return result ? AjaxResult.success("解除成功") : AjaxResult.error("解除失败");
+    }
+
+    @PostMapping("/return")
+    @ApiOperation("退回重办")
+    @Log(title = "退回重办", businessType = BusinessType.UPDATE)
+    public AjaxResult returnWarning(
+            @ApiParam("预警ID") @RequestParam String warningId,
+            @ApiParam("处置人") @RequestParam(required = false, defaultValue = "system") String disposalUser,
+            @ApiParam("退回说明") @RequestParam String disposalContent) {
+        boolean result = earlyWarningService.returnWarning(warningId, disposalUser, disposalContent);
+        return result ? AjaxResult.success("退回成功") : AjaxResult.error("退回失败");
+    }
+
+    @PostMapping("/supervision")
+    @ApiOperation("预警督办")
+    @Log(title = "预警督办", businessType = BusinessType.OTHER)
+    public AjaxResult supervisionWarning(
+            @ApiParam("预警ID") @RequestParam String warningId,
+            @ApiParam("督办人员") @RequestParam String supervisionUser,
+            @ApiParam("督办意见") @RequestParam String supervisionContent,
+            @ApiParam("通知方式") @RequestParam String notificationType,
+            @ApiParam("通知内容") @RequestParam(required = false) String notificationContent,
+            @ApiParam("附件地址") @RequestParam(required = false) String attachmentUrl) {
+        boolean result = earlyWarningService.supervisionWarning(warningId, supervisionUser, supervisionContent, notificationType, notificationContent, attachmentUrl);
+        return result ? AjaxResult.success("督办成功") : AjaxResult.error("督办失败");
+    }
+
+    @PostMapping("/instruction")
+    @ApiOperation("领导批示")
+    @Log(title = "领导批示", businessType = BusinessType.OTHER)
+    public AjaxResult addLeaderInstruction(
+            @ApiParam("预警ID") @RequestParam String warningId,
+            @ApiParam("领导姓名") @RequestParam String leaderName,
+            @ApiParam("批示内容") @RequestParam String instructionContent,
+            @ApiParam("短信接收人") @RequestParam(required = false) String smsReceivers) {
+        boolean result = earlyWarningService.addLeaderInstruction(warningId, leaderName, instructionContent, smsReceivers);
+        return result ? AjaxResult.success("批示成功") : AjaxResult.error("批示失败");
+    }
+
+    @PostMapping("/link/alarms")
+    @ApiOperation("关联报警信息")
+    public AjaxResult linkAlarms(
+            @ApiParam("预警ID") @RequestParam String warningId,
+            @ApiParam("报警ID列表") @RequestParam List<String> alarmIds) {
+        boolean result = earlyWarningService.linkAlarms(warningId, alarmIds);
+        return result ? AjaxResult.success("关联成功") : AjaxResult.error("关联失败");
+    }
+
+    @GetMapping("/link/alarms/{warningId}")
+    @ApiOperation("获取关联的报警列表")
+    public AjaxResult getLinkedAlarms(@PathVariable String warningId) {
+        List<Map<String, Object>> result = earlyWarningService.getLinkedAlarms(warningId);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/disposal/{warningId}")
+    @ApiOperation("获取处置记录列表")
+    public AjaxResult getDisposalList(@PathVariable String warningId) {
+        List<Map<String, Object>> result = earlyWarningService.getDisposalList(warningId);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/statistics")
+    @ApiOperation("获取统计数据")
+    @Anonymous
+    public AjaxResult getStatistics() {
+        Map<String, Object> result = earlyWarningService.getStatistics();
+        return AjaxResult.success(result);
+    }
+
+    /*@GetMapping("/config/types")
+    @ApiOperation("获取预警类型配置")
+    public AjaxResult getTypeConfigList() {
+        List<Map<String, Object>> result = earlyWarningService.getTypeConfigList();
+        return AjaxResult.success(result);
+    }*/
+
+    @GetMapping("/search")
+    @ApiOperation("综合搜索预警信息")
+    @Anonymous
+    public AjaxResult searchWarnings(
+            @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum,
+            @ApiParam("每页数量") @RequestParam(defaultValue = "10") Integer pageSize,
+            @ApiParam("预警名称") @RequestParam(required = false) String warningName,
+            @ApiParam("预警编号") @RequestParam(required = false) String warningNo,
+            @ApiParam("预警类型") @RequestParam(required = false) String warningType,
+            @ApiParam("预警级别") @RequestParam(required = false) String warningLevel,
+            @ApiParam("状态") @RequestParam(required = false) String status,
+            @ApiParam("预警位置") @RequestParam(required = false) String location,
+            @ApiParam("发布人") @RequestParam(required = false) String publisher,
+            @ApiParam("权属单位") @RequestParam(required = false) String ownershipUnit,
+            @ApiParam("开始时间") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
+            @ApiParam("结束时间") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
+        Page<?> page = new Page<>(pageNum, pageSize);
+        IPage<Map<String, Object>> result = earlyWarningService.searchWarnings(page, warningName, warningNo, warningType, warningLevel, status, location, publisher, ownershipUnit, startTime, endTime);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/detail/full/{warningId}")
+    @ApiOperation("获取预警完整详情(含GIS定位和电子存档)")
+    @Anonymous
+    public AjaxResult getWarningFullDetail(@PathVariable String warningId) {
+        Map<String, Object> detail = earlyWarningService.getWarningFullDetail(warningId);
+        if (detail == null) {
+            return AjaxResult.error("预警信息不存在");
+        }
+        return AjaxResult.success(detail);
+    }
+
+    @GetMapping("/processing/list")
+    @ApiOperation("获取处置过程跟踪 - 进行中的预警")
+    @Anonymous
+    public AjaxResult getProcessingWarnings(
+            @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum,
+            @ApiParam("每页数量") @RequestParam(defaultValue = "10") Integer pageSize,
+            @ApiParam("预警类型") @RequestParam(required = false) String warningType,
+            @ApiParam("预警级别") @RequestParam(required = false) String warningLevel) {
+        Page<?> page = new Page<>(pageNum, pageSize);
+        IPage<Map<String, Object>> result = earlyWarningService.getProcessingWarnings(page, warningType, warningLevel);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/completed/list")
+    @ApiOperation("获取处置过程跟踪 - 已完成的预警")
+    @Anonymous
+    public AjaxResult getCompletedWarnings(
+            @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum,
+            @ApiParam("每页数量") @RequestParam(defaultValue = "10") Integer pageSize,
+            @ApiParam("预警类型") @RequestParam(required = false) String warningType,
+            @ApiParam("预警级别") @RequestParam(required = false) String warningLevel,
+            @ApiParam("开始时间") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
+            @ApiParam("结束时间") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
+        Page<?> page = new Page<>(pageNum, pageSize);
+        IPage<Map<String, Object>> result = earlyWarningService.getCompletedWarnings(page, warningType, warningLevel, startTime, endTime);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/disposal/history/{warningId}")
+    @ApiOperation("获取预警处置历史记录")
+    @Anonymous
+    public AjaxResult getDisposalHistory(@PathVariable String warningId) {
+        List<Map<String, Object>> result = earlyWarningService.getDisposalHistory(warningId);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/attachments/{warningId}")
+    @ApiOperation("获取预警附件列表")
+    @Anonymous
+    public AjaxResult getAttachments(@PathVariable String warningId) {
+        List<Map<String, Object>> result = earlyWarningService.getAttachments(warningId);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/dashboard/statistics")
+    @ApiOperation("获取仪表盘统计数据")
+    @Anonymous
+    public AjaxResult getDashboardStatistics() {
+        Map<String, Object> result = earlyWarningService.getDashboardStatistics();
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/archive/{warningId}")
+    @ApiOperation("获取预警归档信息")
+    @Anonymous
+    public AjaxResult getArchive(@PathVariable String warningId) {
+        WarningArchive archive = earlyWarningService.getArchiveByWarningId(warningId);
+        if (archive == null) {
+            return AjaxResult.error("归档信息不存在");
+        }
+        return AjaxResult.success(archive);
+    }
+
+    @GetMapping("/archive/list")
+    @ApiOperation("获取归档列表")
+    @Anonymous
+    public AjaxResult getArchiveList(
+            @ApiParam("页码") @RequestParam(defaultValue = "1") Integer pageNum,
+            @ApiParam("每页数量") @RequestParam(defaultValue = "10") Integer pageSize,
+            @ApiParam("预警名称") @RequestParam(required = false) String warningName,
+            @ApiParam("预警类型") @RequestParam(required = false) String warningType,
+            @ApiParam("预警级别") @RequestParam(required = false) String warningLevel,
+            @ApiParam("开始时间") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
+            @ApiParam("结束时间") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
+        Page<WarningArchive> page = new Page<>(pageNum, pageSize);
+        IPage<WarningArchive> result = earlyWarningService.getArchiveList(page, warningName, warningType, warningLevel, startTime, endTime);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/process/{warningId}")
+    @ApiOperation("获取预警处置过程记录(完整流程)")
+    @Anonymous
+    public AjaxResult getDisposalProcess(@PathVariable String warningId) {
+        List<WarningDisposal> result = earlyWarningService.getDisposalProcess(warningId);
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/diagram/{warningId}")
+    @ApiOperation("获取预警流程可视化数据(路线图)")
+    @Anonymous
+    public AjaxResult getProcessDiagram(@PathVariable String warningId) {
+        Map<String, Object> result = earlyWarningService.getProcessDiagram(warningId);
+        if (result != null && result.containsKey("error")) {
+            return AjaxResult.error(result.get("error").toString());
+        }
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/disposal/detail/{disposalId}")
+    @ApiOperation("获取预警处置详情")
+    @Anonymous
+    public AjaxResult getDisposalDetail(@PathVariable String disposalId) {
+        Map<String, Object> result = earlyWarningService.getDisposalDetail(disposalId);
+        if (result == null) {
+            return AjaxResult.error("处置记录不存在");
+        }
+        return AjaxResult.success(result);
+    }
+
+    @GetMapping("/process/statistics/{warningId}")
+    @ApiOperation("获取预警流程统计信息")
+    @Anonymous
+    public AjaxResult getProcessStatistics(@PathVariable String warningId) {
+        Map<String, Object> result = earlyWarningService.getProcessStatistics(warningId);
+        return AjaxResult.success(result);
+    }
+}

+ 35 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/alarm/domain/WarningThreshold.java

@@ -73,6 +73,41 @@ public class WarningThreshold implements Serializable {
     @ApiModelProperty(value = "备注")
     private String remark;
 
+    /**
+     * 关联设备ID
+     */
+    @TableField(value = "equipment_id")
+    @ApiModelProperty(value = "关联设备ID")
+    private String equipmentId;
+
+    /**
+     * 关联监测点ID
+     */
+    @TableField(value = "point_id")
+    @ApiModelProperty(value = "关联监测点ID")
+    private String pointId;
+
+    /**
+     * 监测类型
+     */
+    @TableField(value = "monitor_type")
+    @ApiModelProperty(value = "监测类型(水位、流量、压力、温度等)")
+    private String monitorType;
+
+    /**
+     * 预警级别
+     */
+    @TableField(value = "warning_level")
+    @ApiModelProperty(value = "预警级别(1-蓝色 2-黄色 3-橙色 4-红色)")
+    private String warningLevel;
+
+    /**
+     * 比较运算符
+     */
+    @TableField(value = "operator")
+    @ApiModelProperty(value = "比较运算符(>、<、>=、<=、=、!=)")
+    private String operator;
+
     /**
      * 创建时间
      */

+ 10 - 28
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/EquipmentBaseService.java

@@ -9,49 +9,31 @@ import com.zksy.manhole.dto.out.EquipmentBaseOutDTO;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Map;
 
-@Service
 public interface EquipmentBaseService extends IService<EquipmentBase> {
 
     Page<EquipmentBase> findByPage(long pageNum, long pageSize,
-                                   String equipmentCode,String equipmentName,
-                                   String equipmentModel,String manufacturer);
+                                   String equipmentCode, String equipmentName,
+                                   String equipmentModel, String manufacturer);
 
-    /**
-     * 新增仪器信息
-     * @param entity
-     * @return
-     */
     boolean saveWithCheck(EquipmentBase entity);
 
-    /**
-     * 新增仪器信息
-     * @param entityList
-     * @return
-     */
     boolean saveBatchWithCheck(List<EquipmentBase> entityList);
 
-    /**
-     * 修改仪器信息
-     * @param entity
-     * @return
-     */
     boolean updateWithCheck(EquipmentBase entity);
 
-    /**
-     * 删除设备基础信息
-     * @param id
-     * @return
-     */
     boolean removeWithCheck(String id);
 
-    /**
-     * 设备基础信息批量删除
-     * @param ids
-     * @return
-     */
     boolean removeBatchWithCheck(List<String> ids);
 
+    boolean updateEquipmentStatus(String equipmentId, Integer currentStatus);
+
+    boolean testEquipment(String equipmentId, String testType, String testDetail, String testUser);
+
+    Map<String, Object> getEquipmentDetail(String equipmentId);
+
+    List<EquipmentBase> getEquipmentByPoint(String pointId);
 //    EquipmentBase getByIdTest(String id);
 
     /**

+ 161 - 54
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/impl/EquipmentBaseServiceImpl.java

@@ -7,6 +7,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zksy.base.domain.*;
+import com.zksy.base.mapper.*;
+import com.zksy.base.alarm.domain.WarningThreshold;
+import com.zksy.base.alarm.mapper.WarningThresholdMapper;
 import com.zksy.base.domain.EquipmentBase;
 import com.zksy.base.domain.EquipmentMaintain;
 import com.zksy.base.domain.EquipmentStatus;
@@ -30,6 +34,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
+import java.util.*;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -48,16 +54,22 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
     @Autowired
     private EquipmentStatusMapper equipmentStatusMapper;
 
-//    @Autowired
-//    private EquipmentBaseMapper equipmentBaseMapper;
+    @Autowired
+    private EquipmentPointRelMapper equipmentPointRelMapper;
+
+    @Autowired
+    private EquipmentTestMapper equipmentTestMapper;
+
+    @Autowired
+    private WarningThresholdMapper warningThresholdMapper;
 
     @Autowired
     private ManholeDataMapper manholeDataMapper;
 
     @Override
     public Page<EquipmentBase> findByPage(long pageNum, long pageSize,
-                                          String equipmentCode,String equipmentName,
-                                          String equipmentModel,String manufacturer) {
+                                          String equipmentCode, String equipmentName,
+                                          String equipmentModel, String manufacturer) {
         Page<EquipmentBase> page = new Page<>(pageNum, pageSize);
         LambdaQueryWrapper<EquipmentBase> queryWrapper = new LambdaQueryWrapper<>();
         if (equipmentCode != null && !equipmentCode.isEmpty()) {
@@ -72,22 +84,17 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
         if (manufacturer != null && !manufacturer.isEmpty()) {
             queryWrapper.like(EquipmentBase::getManufacturer, manufacturer);
         }
+        queryWrapper.orderByDesc(EquipmentBase::getCreateTime);
         return this.page(page, queryWrapper);
     }
 
-    /**
-     * 新增仪器信息
-     * @param entity
-     * @return
-     */
     @Override
     public boolean saveWithCheck(EquipmentBase entity) {
         String equipmentTypeId = entity.getEquipmentTypeId();
         EquipmentType equipmentType = equipmentTypeMapper.selectById(equipmentTypeId);
-        if(equipmentType==null){
+        if (equipmentType == null) {
             throw new ServiceException("设备类型不存在,请检查equipment_type_id:");
         }
-        //校验设备编码是否已存在
         LambdaQueryWrapper<EquipmentBase> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(EquipmentBase::getEquipmentCode, entity.getEquipmentCode());
         long count = this.count(queryWrapper);
@@ -97,15 +104,8 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
         return this.save(entity);
     }
 
-    /**
-     * 批量新增
-     * @param entityList
-     * @return
-     */
     @Override
     public boolean saveBatchWithCheck(List<EquipmentBase> entityList) {
-
-        //是否有重复编码
         Set<String> codeSet = new HashSet<>();
         for (EquipmentBase entity : entityList) {
             String code = entity.getEquipmentCode();
@@ -115,93 +115,81 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
             codeSet.add(code);
         }
 
-        //校验
         for (EquipmentBase entity : entityList) {
-            //校验设备类型是否存在
             if (equipmentTypeMapper.selectById(entity.getEquipmentTypeId()) == null) {
                 throw new ServiceException("设备类型不存在:" + entity.getEquipmentTypeId());
             }
-            //校验设备编码是否已存在
             LambdaQueryWrapper<EquipmentBase> wrapper = new LambdaQueryWrapper<>();
             wrapper.eq(EquipmentBase::getEquipmentCode, entity.getEquipmentCode());
             if (this.count(wrapper) > 0) {
                 throw new ServiceException("设备编码已存在:" + entity.getEquipmentCode());
             }
         }
-        //保存
         return this.saveBatch(entityList);
     }
 
-    /**
-     * 修改仪器信息
-     * @param entity
-     * @return
-     */
     @Override
     @Transactional
     public boolean updateWithCheck(EquipmentBase entity) {
-        //设备是否存在
         String equipmentId = entity.getEquipmentId();
         if (this.getById(equipmentId) == null) {
             throw new ServiceException("设备不存在,无法修改:" + equipmentId);
         }
 
-        //修改设备类型ID,需要校验新类型是否存在
         String newTypeId = entity.getEquipmentTypeId();
         if (newTypeId != null && equipmentTypeMapper.selectById(newTypeId) == null) {
             throw new ServiceException("设备类型不存在:" + newTypeId);
         }
 
-        //修改设备编码,需要校验新编码是否已被使用
         String newCode = entity.getEquipmentCode();
         if (newCode != null) {
             LambdaQueryWrapper<EquipmentBase> wrapper = new LambdaQueryWrapper<>();
             wrapper.eq(EquipmentBase::getEquipmentCode, newCode)
-                    .ne(EquipmentBase::getEquipmentId, equipmentId); // 排除自身
+                    .ne(EquipmentBase::getEquipmentId, equipmentId);
             if (this.count(wrapper) > 0) {
                 throw new ServiceException("设备编码已被使用:" + newCode);
             }
         }
-        //修改
         return this.updateById(entity);
     }
 
-    /**
-     * 删除设备基础信息
-     * @param equipmentId
-     * @return
-     */
     @Override
     @Transactional
     public boolean removeWithCheck(String equipmentId) {
-        //校验设备是否存在
         EquipmentBase equipment = this.getById(equipmentId);
         if (equipment == null) {
             throw new ServiceException("设备不存在:" + equipmentId);
         }
 
-        //删除关联的维护记录
         LambdaQueryWrapper<EquipmentMaintain> maintainWrapper = new LambdaQueryWrapper<>();
         maintainWrapper.eq(EquipmentMaintain::getEquipmentId, equipmentId);
         equipmentMaintainMapper.delete(maintainWrapper);
         log.info("已删除设备[{}]的维护记录", equipmentId);
 
-        //删除关联的状态记录
         LambdaQueryWrapper<EquipmentStatus> statusWrapper = new LambdaQueryWrapper<>();
         statusWrapper.eq(EquipmentStatus::getEquipmentId, equipmentId);
         equipmentStatusMapper.delete(statusWrapper);
         log.info("已删除设备[{}]的状态记录", equipmentId);
 
-        //删除设备
-        boolean deleted = this.baseMapper.deleteById(equipmentId) > 0;
-        return deleted;
+        LambdaQueryWrapper<EquipmentPointRel> relWrapper = new LambdaQueryWrapper<>();
+        relWrapper.eq(EquipmentPointRel::getEquipmentId, equipmentId);
+        equipmentPointRelMapper.delete(relWrapper);
+        log.info("已删除设备[{}]的监测点关联", equipmentId);
+
+        // 现在 WarningThreshold 有了 equipmentId 字段,直接匹配
+        LambdaQueryWrapper<WarningThreshold> thresholdWrapper = new LambdaQueryWrapper<>();
+        thresholdWrapper.eq(WarningThreshold::getEquipmentId, equipmentId);
+        warningThresholdMapper.delete(thresholdWrapper);
+        log.info("已删除设备[{}]的预警阈值配置", equipmentId);
+
+        LambdaQueryWrapper<EquipmentTest> testWrapper = new LambdaQueryWrapper<>();
+        testWrapper.eq(EquipmentTest::getEquipmentId, equipmentId);
+        equipmentTestMapper.delete(testWrapper);
+        log.info("已删除设备[{}]的测试记录", equipmentId);
+
+        return this.baseMapper.deleteById(equipmentId) > 0;
     }
 
-    /**
-     * 设备基础信息批量删除
-     * @param equipmentIds
-     * @return
-     */
     @Override
     @Transactional
     public boolean removeBatchWithCheck(List<String> equipmentIds) {
@@ -209,16 +197,14 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
             throw new ServiceException("批量删除失败:设备ID列表不能为空");
         }
 
-        //校验设备是否存在
         List<EquipmentBase> existEquipments = this.listByIds(equipmentIds);
         if (existEquipments.isEmpty()) {
             throw new ServiceException("批量删除失败:所有设备ID均不存在");
         }
-        // 提取存在的设备ID
         List<String> existIds = existEquipments.stream()
                 .map(EquipmentBase::getEquipmentId)
                 .collect(Collectors.toList());
-        //无效ID
+
         List<String> invalidIds = equipmentIds.stream()
                 .filter(id -> !existIds.contains(id))
                 .collect(Collectors.toList());
@@ -226,18 +212,32 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
             log.warn("批量删除中存在无效设备ID:{}", invalidIds);
         }
 
-        //批量删除关联的维护记录
         LambdaQueryWrapper<EquipmentMaintain> maintainWrapper = new LambdaQueryWrapper<>();
         maintainWrapper.in(EquipmentMaintain::getEquipmentId, existIds);
         equipmentMaintainMapper.delete(maintainWrapper);
         log.info("已批量删除{}条设备的维护记录", existIds.size());
 
-        //批量删除关联的状态记录
         LambdaQueryWrapper<EquipmentStatus> statusWrapper = new LambdaQueryWrapper<>();
         statusWrapper.in(EquipmentStatus::getEquipmentId, existIds);
         equipmentStatusMapper.delete(statusWrapper);
         log.info("已批量删除{}条设备的状态记录", existIds.size());
-        //删除
+
+        LambdaQueryWrapper<EquipmentPointRel> relWrapper = new LambdaQueryWrapper<>();
+        relWrapper.in(EquipmentPointRel::getEquipmentId, existIds);
+        equipmentPointRelMapper.delete(relWrapper);
+        log.info("已批量删除{}条设备的监测点关联", existIds.size());
+
+        // 现在 WarningThreshold 有了 equipmentId 字段,直接匹配
+        LambdaQueryWrapper<WarningThreshold> thresholdWrapper = new LambdaQueryWrapper<>();
+        thresholdWrapper.in(WarningThreshold::getEquipmentId, existIds);
+        warningThresholdMapper.delete(thresholdWrapper);
+        log.info("已批量删除{}条设备的预警阈值配置", existIds.size());
+
+        LambdaQueryWrapper<EquipmentTest> testWrapper = new LambdaQueryWrapper<>();
+        testWrapper.in(EquipmentTest::getEquipmentId, existIds);
+        equipmentTestMapper.delete(testWrapper);
+        log.info("已批量删除{}条设备的测试记录", existIds.size());
+
         return this.removeByIds(existIds);
     }
 
@@ -393,4 +393,111 @@ public class EquipmentBaseServiceImpl extends ServiceImpl<EquipmentBaseMapper, E
         return outDTOList;
     }
 
+    @Override
+    @Transactional
+    public boolean updateEquipmentStatus(String equipmentId, Integer currentStatus) {
+        EquipmentBase equipment = this.getById(equipmentId);
+        if (equipment == null) {
+            throw new ServiceException("设备不存在:" + equipmentId);
+        }
+
+        LambdaQueryWrapper<EquipmentStatus> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(EquipmentStatus::getEquipmentId, equipmentId);
+        EquipmentStatus status = equipmentStatusMapper.selectOne(wrapper);
+
+        if (status == null) {
+            status = new EquipmentStatus();
+            status.setEquipmentId(equipmentId);
+            status.setCurrentStatus(currentStatus);
+            status.setAlarmStatus(0);
+            status.setOnlineStatus(1);
+            status.setStatusUpdateTime(LocalDateTime.now());
+            return equipmentStatusMapper.insert(status) > 0;
+        } else {
+            status.setCurrentStatus(currentStatus);
+            status.setStatusUpdateTime(LocalDateTime.now());
+            return equipmentStatusMapper.updateById(status) > 0;
+        }
+    }
+
+    @Override
+    @Transactional
+    public boolean testEquipment(String equipmentId, String testType, String testDetail, String testUser) {
+        EquipmentBase equipment = this.getById(equipmentId);
+        if (equipment == null) {
+            throw new ServiceException("设备不存在:" + equipmentId);
+        }
+
+        EquipmentTest test = new EquipmentTest();
+        test.setEquipmentId(equipmentId);
+        test.setTestType(testType);
+        test.setTestResult("SUCCESS");
+        test.setTestDetail(testDetail);
+        test.setTestTime(LocalDateTime.now());
+        test.setTestUser(testUser);
+        return equipmentTestMapper.insert(test) > 0;
+    }
+
+    @Override
+    public Map<String, Object> getEquipmentDetail(String equipmentId) {
+        EquipmentBase equipment = this.getById(equipmentId);
+        if (equipment == null) {
+            throw new ServiceException("设备不存在:" + equipmentId);
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("equipmentInfo", equipment);
+
+        if (equipment.getEquipmentTypeId() != null) {
+            EquipmentType type = equipmentTypeMapper.selectById(equipment.getEquipmentTypeId());
+            result.put("typeInfo", type);
+        }
+
+        LambdaQueryWrapper<EquipmentStatus> statusWrapper = new LambdaQueryWrapper<>();
+        statusWrapper.eq(EquipmentStatus::getEquipmentId, equipmentId);
+        EquipmentStatus status = equipmentStatusMapper.selectOne(statusWrapper);
+        result.put("statusInfo", status);
+
+        LambdaQueryWrapper<EquipmentMaintain> maintainWrapper = new LambdaQueryWrapper<>();
+        maintainWrapper.eq(EquipmentMaintain::getEquipmentId, equipmentId);
+        maintainWrapper.orderByDesc(EquipmentMaintain::getMaintainDate);
+        List<EquipmentMaintain> maintainList = equipmentMaintainMapper.selectList(maintainWrapper);
+        result.put("maintainList", maintainList);
+
+        LambdaQueryWrapper<EquipmentPointRel> relWrapper = new LambdaQueryWrapper<>();
+        relWrapper.eq(EquipmentPointRel::getEquipmentId, equipmentId);
+        List<EquipmentPointRel> relList = equipmentPointRelMapper.selectList(relWrapper);
+        result.put("pointRelList", relList);
+
+        // 现在 WarningThreshold 有了 equipmentId 字段,直接匹配
+        LambdaQueryWrapper<WarningThreshold> thresholdWrapper = new LambdaQueryWrapper<>();
+        thresholdWrapper.eq(WarningThreshold::getEquipmentId, equipmentId);
+        List<WarningThreshold> thresholdList = warningThresholdMapper.selectList(thresholdWrapper);
+        result.put("thresholdList", thresholdList);
+
+        LambdaQueryWrapper<EquipmentTest> testWrapper = new LambdaQueryWrapper<>();
+        testWrapper.eq(EquipmentTest::getEquipmentId, equipmentId);
+        testWrapper.orderByDesc(EquipmentTest::getTestTime);
+        List<EquipmentTest> testList = equipmentTestMapper.selectList(testWrapper);
+        result.put("testList", testList);
+
+        return result;
+    }
+
+    @Override
+    public List<EquipmentBase> getEquipmentByPoint(String pointId) {
+        LambdaQueryWrapper<EquipmentPointRel> relWrapper = new LambdaQueryWrapper<>();
+        relWrapper.eq(EquipmentPointRel::getPointId, pointId);
+        List<EquipmentPointRel> relList = equipmentPointRelMapper.selectList(relWrapper);
+
+        if (relList.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        List<String> equipmentIds = relList.stream()
+                .map(EquipmentPointRel::getEquipmentId)
+                .collect(Collectors.toList());
+
+        return this.listByIds(equipmentIds);
+    }
 }

+ 110 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/warning/domain/EarlyWarning.java

@@ -0,0 +1,110 @@
+package com.zksy.base.warning.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@TableName("early_warning")
+@Api(value = "预警信息")
+@Data
+public class EarlyWarning implements Serializable {
+
+    @TableId(value = "warning_id", type = IdType.ASSIGN_UUID)
+    @ApiModelProperty("预警ID")
+    private String warningId;
+
+    @TableField("warning_no")
+    @ApiModelProperty("预警编号")
+    private String warningNo;
+
+    @TableField("warning_name")
+    @ApiModelProperty("预警名称")
+    private String warningName;
+
+    @TableField("warning_type")
+    @ApiModelProperty("预警类型")
+    private String warningType;
+
+    @TableField("warning_level")
+    @ApiModelProperty("预警级别")
+    private String warningLevel;
+
+    @TableField("warning_special")
+    @ApiModelProperty("预警专项")
+    private String warningSpecial;
+
+    @TableField("location")
+    @ApiModelProperty("预警位置")
+    private String location;
+
+    @TableField("longitude")
+    @ApiModelProperty("经度")
+    private BigDecimal longitude;
+
+    @TableField("latitude")
+    @ApiModelProperty("纬度")
+    private BigDecimal latitude;
+
+    @TableField("ownership_unit")
+    @ApiModelProperty("权属单位")
+    private String ownershipUnit;
+
+    @TableField("publisher")
+    @ApiModelProperty("发布人")
+    private String publisher;
+
+    @TableField("publish_time")
+    @ApiModelProperty("发布时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime publishTime;
+
+    @TableField("handler")
+    @ApiModelProperty("处置人")
+    private String handler;
+
+    @TableField("status")
+    @ApiModelProperty("状态")
+    private String status;
+
+    @TableField("warning_content")
+    @ApiModelProperty("预警内容描述")
+    private String warningContent;
+
+    @TableField("process_instance_id")
+    @ApiModelProperty("工作流实例ID")
+    private String processInstanceId;
+
+    @TableField("create_by")
+    @ApiModelProperty("创建人")
+    private String createBy;
+
+    @TableField("create_time")
+    @ApiModelProperty("创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime createTime;
+
+    @TableField("update_by")
+    @ApiModelProperty("更新人")
+    private String updateBy;
+
+    @TableField("update_time")
+    @ApiModelProperty("更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime updateTime;
+
+    @TableField("remark")
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @TableField(exist = false)
+    private static final long serialVersionUID = 1L;
+}

+ 30 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/warning/mapper/EarlyWarningMapper.java

@@ -0,0 +1,30 @@
+package com.zksy.base.warning.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zksy.base.warning.domain.EarlyWarning;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface EarlyWarningMapper extends BaseMapper<EarlyWarning> {
+
+    IPage<Map<String, Object>> selectWarningList(Page<?> page, @Param("warningName") String warningName, @Param("warningType") String warningType, @Param("warningLevel") String warningLevel, @Param("status") String status);
+
+    IPage<Map<String, Object>> searchWarnings(Page<?> page, @Param("warningName") String warningName, @Param("warningNo") String warningNo, @Param("warningType") String warningType, @Param("warningLevel") String warningLevel, @Param("status") String status, @Param("location") String location, @Param("publisher") String publisher, @Param("ownershipUnit") String ownershipUnit, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
+
+    IPage<Map<String, Object>> selectTodoList(Page<?> page, @Param("userId") String userId, @Param("todoType") String todoType, @Param("warningName") String warningName);
+
+    IPage<Map<String, Object>> selectProcessingWarnings(Page<?> page, @Param("warningType") String warningType, @Param("warningLevel") String warningLevel);
+
+    IPage<Map<String, Object>> selectCompletedWarnings(Page<?> page, @Param("warningType") String warningType, @Param("warningLevel") String warningLevel, @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
+
+    Map<String, Object> selectWarningDetail(@Param("warningId") String warningId);
+
+    List<Map<String, Object>> selectStatistics();
+}

+ 78 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/warning/service/EarlyWarningService.java

@@ -0,0 +1,78 @@
+package com.zksy.base.warning.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zksy.base.warning.domain.EarlyWarning;
+import com.zksy.base.warning.domain.WarningArchive;
+import com.zksy.base.warning.domain.WarningDisposal;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+public interface EarlyWarningService extends IService<EarlyWarning> {
+
+    IPage<Map<String, Object>> getWarningList(Page<?> page, String warningName, String warningType, String warningLevel, String status);
+
+    IPage<Map<String, Object>> searchWarnings(Page<?> page, String warningName, String warningNo, String warningType, String warningLevel, String status, String location, String publisher, String ownershipUnit, LocalDateTime startTime, LocalDateTime endTime);
+
+    IPage<Map<String, Object>> getTodoList(Page<?> page, String userId, String todoType, String warningName);
+
+    Map<String, Object> getWarningDetail(String warningId);
+
+    Map<String, Object> getWarningFullDetail(String warningId);
+
+    boolean saveWarning(EarlyWarning warning, List<String> alarmIds, List<MultipartFile> files);
+
+    boolean updateWarning(EarlyWarning warning, List<MultipartFile> files);
+
+    boolean deleteWarning(String warningId);
+
+    boolean deleteBatchWarning(List<String> warningIds);
+
+    boolean publishWarning(String warningId, String disposalUser);
+
+    boolean upgradeWarning(String warningId, String newLevel, String disposalUser, String disposalContent);
+
+    boolean resolveWarning(String warningId, String disposalUser, String disposalContent);
+
+    boolean returnWarning(String warningId, String disposalUser, String disposalContent);
+
+    boolean supervisionWarning(String warningId, String supervisionUser, String supervisionContent, String notificationType, String notificationContent, String attachmentUrl);
+
+    boolean addLeaderInstruction(String warningId, String leaderName, String instructionContent, String smsReceivers);
+
+    boolean linkAlarms(String warningId, List<String> alarmIds);
+
+    List<Map<String, Object>> getLinkedAlarms(String warningId);
+
+    List<Map<String, Object>> getDisposalList(String warningId);
+
+    List<Map<String, Object>> getDisposalHistory(String warningId);
+
+    IPage<Map<String, Object>> getProcessingWarnings(Page<?> page, String warningType, String warningLevel);
+
+    IPage<Map<String, Object>> getCompletedWarnings(Page<?> page, String warningType, String warningLevel, LocalDateTime startTime, LocalDateTime endTime);
+
+    List<Map<String, Object>> getAttachments(String warningId);
+
+    Map<String, Object> getStatistics();
+
+    Map<String, Object> getDashboardStatistics();
+
+    List<Map<String, Object>> getTypeConfigList();
+
+    WarningArchive getArchiveByWarningId(String warningId);
+
+    IPage<WarningArchive> getArchiveList(Page<WarningArchive> page, String warningName, String warningType, String warningLevel, LocalDateTime startTime, LocalDateTime endTime);
+
+    List<WarningDisposal> getDisposalProcess(String warningId);
+
+    Map<String, Object> getProcessDiagram(String warningId);
+
+    Map<String, Object> getDisposalDetail(String disposalId);
+
+    Map<String, Object> getProcessStatistics(String warningId);
+}

+ 768 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/warning/service/impl/EarlyWarningServiceImpl.java

@@ -0,0 +1,768 @@
+package com.zksy.base.warning.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zksy.base.warning.domain.*;
+import com.zksy.base.warning.mapper.*;
+import com.zksy.base.warning.service.EarlyWarningService;
+import com.zksy.common.config.ZksyConfig;
+import com.zksy.common.core.domain.entity.SysDictData;
+import com.zksy.common.utils.DictUtils;
+import com.zksy.common.utils.file.FileUploadUtils;
+import com.zksy.common.utils.file.FileUtils;
+import com.zksy.service.MinioFileStorageService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+@Service
+public class EarlyWarningServiceImpl extends ServiceImpl<EarlyWarningMapper, EarlyWarning>
+        implements EarlyWarningService {
+
+    @Autowired
+    private EarlyWarningMapper earlyWarningMapper;
+    @Autowired
+    private AlarmWarningRelMapper alarmWarningRelMapper;
+    @Autowired
+    private WarningAttachmentMapper warningAttachmentMapper;
+    @Autowired
+    private WarningDisposalMapper warningDisposalMapper;
+    @Autowired
+    private WarningTodoMapper warningTodoMapper;
+
+    @Autowired
+    private WarningArchiveMapper warningArchiveMapper;
+    @Autowired
+    private MinioFileStorageService minioFileStorageService;
+
+    @Override
+    public IPage<Map<String, Object>> getWarningList(Page<?> page, String warningName, String warningType, String warningLevel, String status) {
+        return earlyWarningMapper.selectWarningList(page, warningName, warningType, warningLevel, status);
+    }
+
+    @Override
+    public IPage<Map<String, Object>> searchWarnings(Page<?> page, String warningName, String warningNo, String warningType, String warningLevel, String status, String location, String publisher, String ownershipUnit, LocalDateTime startTime, LocalDateTime endTime) {
+        return earlyWarningMapper.searchWarnings(page, warningName, warningNo, warningType, warningLevel, status, location, publisher, ownershipUnit, startTime, endTime);
+    }
+
+    @Override
+    public IPage<Map<String, Object>> getTodoList(Page<?> page, String userId, String todoType, String warningName) {
+        return earlyWarningMapper.selectTodoList(page, userId, todoType, warningName);
+    }
+
+    @Override
+    public Map<String, Object> getWarningDetail(String warningId) {
+        Map<String, Object> detail = earlyWarningMapper.selectWarningDetail(warningId);
+        if (detail != null) {
+            detail.put("attachmentList", getAttachmentList(warningId));
+            detail.put("disposalList", getDisposalList(warningId));
+            detail.put("alarmList", getLinkedAlarms(warningId));
+        }
+        return detail;
+    }
+
+    @Override
+    public Map<String, Object> getWarningFullDetail(String warningId) {
+        Map<String, Object> result = new HashMap<>();
+        Map<String, Object> basicInfo = earlyWarningMapper.selectWarningDetail(warningId);
+        if (basicInfo == null) {
+            return null;
+        }
+
+        result.put("basicInfo", basicInfo);
+        result.put("gisLocation", getGisLocation(basicInfo));
+        result.put("disposalHistory", getDisposalHistory(warningId));
+        result.put("attachmentList", getAttachmentList(warningId));
+        result.put("alarmList", getLinkedAlarms(warningId));
+        result.put("electronicArchive", generateElectronicArchive(basicInfo));
+
+        return result;
+    }
+
+    private Map<String, Object> getGisLocation(Map<String, Object> warningInfo) {
+        Map<String, Object> gis = new HashMap<>();
+        gis.put("longitude", warningInfo.get("longitude"));
+        gis.put("latitude", warningInfo.get("latitude"));
+        gis.put("location", warningInfo.get("location"));
+        return gis;
+    }
+
+    private Map<String, Object> generateElectronicArchive(Map<String, Object> warningInfo) {
+        String warningId = (String) warningInfo.get("warningId");
+        
+        // 先查询是否已存在归档记录
+        LambdaQueryWrapper<WarningArchive> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(WarningArchive::getWarningId, warningId);
+        WarningArchive existingArchive = warningArchiveMapper.selectOne(wrapper);
+        
+        if (existingArchive != null) {
+            // 如果已存在,直接返回
+            Map<String, Object> archive = new HashMap<>();
+            archive.put("archiveId", existingArchive.getArchiveId());
+            archive.put("archiveNo", existingArchive.getArchiveNo());
+            archive.put("createTime", existingArchive.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            archive.put("archiveContent", existingArchive.getArchiveContent());
+            archive.put("archiveStatus", existingArchive.getArchiveStatus());
+            return archive;
+        }
+        
+        // 如果不存在,创建新归档
+        WarningArchive archive = new WarningArchive();
+        archive.setWarningId(warningId);
+        archive.setArchiveNo("EA_" + warningInfo.get("warningNo"));
+        archive.setWarningNo((String) warningInfo.get("warningNo"));
+        archive.setWarningName((String) warningInfo.get("warningName"));
+        archive.setWarningType((String) warningInfo.get("warningType"));
+        archive.setWarningLevel((String) warningInfo.get("warningLevel"));
+        archive.setLocation((String) warningInfo.get("location"));
+        archive.setLongitude(warningInfo.get("longitude") != null ? ((Number) warningInfo.get("longitude")).doubleValue() : null);
+        archive.setLatitude(warningInfo.get("latitude") != null ? ((Number) warningInfo.get("latitude")).doubleValue() : null);
+        archive.setOwnershipUnit((String) warningInfo.get("ownershipUnit"));
+        archive.setPublisher((String) warningInfo.get("publisher"));
+        archive.setPublishTime(warningInfo.get("publishTime") instanceof LocalDateTime ? (LocalDateTime) warningInfo.get("publishTime") : null);
+        archive.setHandler((String) warningInfo.get("handler"));
+        archive.setWarningContent((String) warningInfo.get("warningContent"));
+        archive.setArchiveContent((String) warningInfo.get("warningContent"));
+        archive.setArchiveStatus("已归档");
+        archive.setCreateTime(LocalDateTime.now());
+        
+        warningArchiveMapper.insert(archive);
+        
+        Map<String, Object> result = new HashMap<>();
+        result.put("archiveId", archive.getArchiveId());
+        result.put("archiveNo", archive.getArchiveNo());
+        result.put("createTime", archive.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        result.put("archiveContent", archive.getArchiveContent());
+        result.put("archiveStatus", archive.getArchiveStatus());
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveWarning(EarlyWarning warning, List<String> alarmIds, List<MultipartFile> files) {
+        String warningNo = "WJ" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
+        warning.setWarningNo(warningNo);
+        warning.setStatus("DRAFT");
+        warning.setCreateTime(LocalDateTime.now());
+        warning.setUpdateTime(LocalDateTime.now());
+
+        boolean result = save(warning);
+        if (result) {
+            if (alarmIds != null && !alarmIds.isEmpty()) {
+                linkAlarms(warning.getWarningId(), alarmIds);
+            }
+            if (files != null && !files.isEmpty()) {
+                saveAttachments(warning.getWarningId(), files);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 保存附件
+     */
+    private void saveAttachments(String warningId, List<MultipartFile> files) {
+        try {
+            for (MultipartFile file : files) {
+                String path = minioFileStorageService.uploadFile(file, "warning");
+                // 上传文件
+                String fileName = path.substring(path.lastIndexOf("/") + 1);
+                // 保存附件信息
+                WarningAttachment attachment = new WarningAttachment();
+                attachment.setWarningId(warningId);
+                attachment.setAttachmentName(fileName);
+                attachment.setAttachmentUrl(path);
+                attachment.setAttachmentType(file.getContentType());
+                attachment.setAttachmentSize(file.getSize());
+                attachment.setCreateTime(LocalDateTime.now());
+                warningAttachmentMapper.insert(attachment);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("附件保存失败", e);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateWarning(EarlyWarning warning, List<MultipartFile> files) {
+        warning.setUpdateTime(LocalDateTime.now());
+        boolean result = updateById(warning);
+        if (result && files != null && !files.isEmpty()) {
+            saveAttachments(warning.getWarningId(), files);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteWarning(String warningId) {
+        // 先查询附件列表,删除物理文件
+        List<WarningAttachment> attachments = warningAttachmentMapper.selectList(
+                new LambdaQueryWrapper<WarningAttachment>()
+                        .eq(WarningAttachment::getWarningId, warningId)
+        );
+        for (WarningAttachment attachment : attachments) {
+            String attachmentUrl = attachment.getAttachmentUrl();
+            if (attachmentUrl != null && !attachmentUrl.isEmpty()) {
+                // 删除minio文件
+                minioFileStorageService.deleteFile(attachmentUrl);
+            }
+        }
+
+        // 删除关联数据
+        LambdaQueryWrapper<AlarmWarningRel> relWrapper = new LambdaQueryWrapper<>();
+        relWrapper.eq(AlarmWarningRel::getWarningId, warningId);
+        alarmWarningRelMapper.delete(relWrapper);
+
+        LambdaQueryWrapper<WarningAttachment> attachmentWrapper = new LambdaQueryWrapper<>();
+        attachmentWrapper.eq(WarningAttachment::getWarningId, warningId);
+        warningAttachmentMapper.delete(attachmentWrapper);
+
+        LambdaQueryWrapper<WarningDisposal> disposalWrapper = new LambdaQueryWrapper<>();
+        disposalWrapper.eq(WarningDisposal::getWarningId, warningId);
+        warningDisposalMapper.delete(disposalWrapper);
+
+        LambdaQueryWrapper<WarningTodo> todoWrapper = new LambdaQueryWrapper<>();
+        todoWrapper.eq(WarningTodo::getWarningId, warningId);
+        warningTodoMapper.delete(todoWrapper);
+
+        LambdaQueryWrapper<WarningArchive> archiveWrapper = new LambdaQueryWrapper<>();
+        archiveWrapper.eq(WarningArchive::getWarningId, warningId);
+        warningArchiveMapper.delete(archiveWrapper);
+
+        // 删除主表记录
+        return removeById(warningId);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteBatchWarning(List<String> warningIds) {
+        for (String warningId : warningIds) {
+            deleteWarning(warningId);
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean publishWarning(String warningId, String disposalUser) {
+        EarlyWarning warning = getById(warningId);
+        if (warning == null) return false;
+
+        warning.setStatus("PENDING");
+        warning.setPublishTime(LocalDateTime.now());
+        warning.setUpdateTime(LocalDateTime.now());
+
+        boolean result = updateById(warning);
+
+        if (result) {
+            addDisposalRecord(warningId, "RELEASE", null, null, disposalUser, "系统发布预警信息");
+            createTodo(warningId, warning.getHandler(), "待办预警", "TODO");
+        }
+
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean upgradeWarning(String warningId, String newLevel, String disposalUser, String disposalContent) {
+        EarlyWarning warning = getById(warningId);
+        if (warning == null) return false;
+
+        String oldLevel = warning.getWarningLevel();
+        warning.setWarningLevel(newLevel);
+        warning.setUpdateTime(LocalDateTime.now());
+
+        boolean result = updateById(warning);
+        if (result) {
+            addDisposalRecord(warningId, "UPGRADE", oldLevel, newLevel, disposalUser, disposalContent);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean resolveWarning(String warningId, String disposalUser, String disposalContent) {
+        EarlyWarning warning = getById(warningId);
+        if (warning == null) return false;
+
+        warning.setStatus("CLOSED");
+        warning.setUpdateTime(LocalDateTime.now());
+
+        boolean result = updateById(warning);
+        if (result) {
+            addDisposalRecord(warningId, "RESOLVE", null, null, disposalUser, disposalContent);
+            completeTodo(warningId);
+            
+            // 解除预警时自动创建归档
+            Map<String, Object> warningDetail = earlyWarningMapper.selectWarningDetail(warningId);
+            if (warningDetail != null) {
+                generateElectronicArchive(warningDetail);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean returnWarning(String warningId, String disposalUser, String disposalContent) {
+        EarlyWarning warning = getById(warningId);
+        if (warning == null) return false;
+
+        warning.setStatus("PENDING");
+        warning.setUpdateTime(LocalDateTime.now());
+
+        boolean result = updateById(warning);
+        if (result) {
+            addDisposalRecord(warningId, "RETURN", null, null, disposalUser, disposalContent);
+        }
+        return result;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean supervisionWarning(String warningId, String supervisionUser, String supervisionContent, String notificationType, String notificationContent, String attachmentUrl) {
+        WarningDisposal disposal = new WarningDisposal();
+        disposal.setWarningId(warningId);
+        disposal.setDisposalType("SUPERVISION");
+        disposal.setDisposalUser(supervisionUser);
+        disposal.setDisposalContent(supervisionContent);
+        disposal.setSupervisionUser(supervisionUser);
+        disposal.setSupervisionContent(supervisionContent);
+        disposal.setNotificationType(notificationType);
+        disposal.setCreateTime(LocalDateTime.now());
+
+        return warningDisposalMapper.insert(disposal) > 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean addLeaderInstruction(String warningId, String leaderName, String instructionContent, String smsReceivers) {
+        WarningDisposal disposal = new WarningDisposal();
+        disposal.setWarningId(warningId);
+        disposal.setDisposalType("INSTRUCTION");
+        disposal.setDisposalUser(leaderName);
+        disposal.setDisposalContent(instructionContent);
+        disposal.setCreateTime(LocalDateTime.now());
+
+        return warningDisposalMapper.insert(disposal) > 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean linkAlarms(String warningId, List<String> alarmIds) {
+        LambdaQueryWrapper<AlarmWarningRel> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(AlarmWarningRel::getWarningId, warningId);
+        alarmWarningRelMapper.delete(wrapper);
+
+        if (alarmIds != null && !alarmIds.isEmpty()) {
+            for (String alarmId : alarmIds) {
+                AlarmWarningRel rel = new AlarmWarningRel();
+                rel.setWarningId(warningId);
+                rel.setAlarmId(alarmId);
+                rel.setCreateTime(LocalDateTime.now());
+                alarmWarningRelMapper.insert(rel);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public List<Map<String, Object>> getLinkedAlarms(String warningId) {
+        return alarmWarningRelMapper.selectAlarmListByWarningId(warningId);
+    }
+
+    @Override
+    public List<Map<String, Object>> getDisposalList(String warningId) {
+        return warningDisposalMapper.selectDisposalList(warningId);
+    }
+
+    @Override
+    public List<Map<String, Object>> getDisposalHistory(String warningId) {
+        return warningDisposalMapper.selectDisposalList(warningId);
+    }
+
+    @Override
+    public IPage<Map<String, Object>> getProcessingWarnings(Page<?> page, String warningType, String warningLevel) {
+        return earlyWarningMapper.selectProcessingWarnings(page, warningType, warningLevel);
+    }
+
+    @Override
+    public IPage<Map<String, Object>> getCompletedWarnings(Page<?> page, String warningType, String warningLevel, LocalDateTime startTime, LocalDateTime endTime) {
+        return earlyWarningMapper.selectCompletedWarnings(page, warningType, warningLevel, startTime, endTime);
+    }
+
+    @Override
+    public List<Map<String, Object>> getAttachments(String warningId) {
+        return getAttachmentList(warningId);
+    }
+
+    @Override
+    public Map<String, Object> getStatistics() {
+        List<Map<String, Object>> statsList = earlyWarningMapper.selectStatistics();
+        if (statsList != null && !statsList.isEmpty()) {
+            return statsList.get(0);
+        }
+        return new HashMap<>();
+    }
+
+    @Override
+    public Map<String, Object> getDashboardStatistics() {
+        Map<String, Object> result = new HashMap<>();
+        
+        Map<String, Object> basicStats = getStatistics();
+        result.put("basicStats", basicStats);
+        
+        List<Map<String, Object>> typeStats = getWarningTypeStatistics();
+        result.put("typeStats", typeStats);
+        
+        List<Map<String, Object>> levelStats = getWarningLevelStatistics();
+        result.put("levelStats", levelStats);
+        
+        List<Map<String, Object>> trendStats = getWarningTrendStatistics();
+        result.put("trendStats", trendStats);
+        
+        return result;
+    }
+
+    private List<Map<String, Object>> getWarningTypeStatistics() {
+        List<SysDictData> types = DictUtils.getDictCache("warning_type");
+        List<Map<String, Object>> result = new ArrayList<>();
+        if (types != null) {
+            for (SysDictData type : types) {
+                LambdaQueryWrapper<EarlyWarning> wrapper = new LambdaQueryWrapper<>();
+                wrapper.eq(EarlyWarning::getWarningType, type.getDictValue());
+                long count = count(wrapper);
+                
+                Map<String, Object> item = new HashMap<>();
+                item.put("typeCode", type.getDictValue());
+                item.put("typeName", type.getDictLabel());
+                item.put("count", count);
+                result.add(item);
+            }
+        }
+        return result;
+    }
+
+    private List<Map<String, Object>> getWarningLevelStatistics() {
+        List<Map<String, Object>> result = new ArrayList<>();
+        // 预警级别:1-4
+        for (int i = 1; i <= 4; i++) {
+            String levelCode = String.valueOf(i);
+            LambdaQueryWrapper<EarlyWarning> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(EarlyWarning::getWarningLevel, levelCode);
+            long count = count(wrapper);
+            
+            Map<String, Object> item = new HashMap<>();
+            item.put("levelCode", levelCode);
+            item.put("count", count);
+            result.add(item);
+        }
+        return result;
+    }
+
+    private List<Map<String, Object>> getWarningTrendStatistics() {
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (int i = 6; i >= 0; i--) {
+            LocalDateTime date = LocalDateTime.now().minusDays(i);
+            LocalDateTime startOfDay = date.toLocalDate().atStartOfDay();
+            LocalDateTime endOfDay = date.toLocalDate().atTime(23, 59, 59);
+            
+            LambdaQueryWrapper<EarlyWarning> wrapper = new LambdaQueryWrapper<>();
+            wrapper.ge(EarlyWarning::getCreateTime, startOfDay);
+            wrapper.le(EarlyWarning::getCreateTime, endOfDay);
+            long count = count(wrapper);
+            
+            Map<String, Object> item = new HashMap<>();
+            item.put("date", date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            item.put("count", count);
+            result.add(item);
+        }
+        return result;
+    }
+
+    @Override
+    public List<Map<String, Object>> getTypeConfigList() {
+        List<SysDictData> list = DictUtils.getDictCache("warning_type");
+        List<Map<String, Object>> result = new ArrayList<>();
+        if (list != null) {
+            for (SysDictData config : list) {
+                Map<String, Object> map = new HashMap<>();
+                map.put("dictCode", config.getDictCode());
+                map.put("typeCode", config.getDictValue());
+                map.put("typeName", config.getDictLabel());
+                result.add(map);
+            }
+        }
+        return result;
+    }
+
+    private void addDisposalRecord(String warningId, String disposalType, String oldLevel, String newLevel, String disposalUser, String content) {
+        WarningDisposal disposal = new WarningDisposal();
+        disposal.setWarningId(warningId);
+        disposal.setDisposalType(disposalType);
+        disposal.setOldLevel(oldLevel);
+        disposal.setNewLevel(newLevel);
+        disposal.setDisposalUser(disposalUser);
+        disposal.setDisposalContent(content);
+        disposal.setCreateTime(LocalDateTime.now());
+        warningDisposalMapper.insert(disposal);
+    }
+
+    private List<Map<String, Object>> getAttachmentList(String warningId) {
+        List<WarningAttachment> list = warningAttachmentMapper.selectList(
+                new LambdaQueryWrapper<WarningAttachment>()
+                        .eq(WarningAttachment::getWarningId, warningId)
+                        .orderByDesc(WarningAttachment::getCreateTime)
+        );
+
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (WarningAttachment attachment : list) {
+            Map<String, Object> map = new HashMap<>();
+            map.put("attachmentId", attachment.getAttachmentId());
+            map.put("attachmentName", attachment.getAttachmentName());
+            map.put("attachmentUrl", attachment.getAttachmentUrl());
+            map.put("attachmentType", attachment.getAttachmentType());
+            map.put("attachmentSize", attachment.getAttachmentSize());
+            map.put("createTime", attachment.getCreateTime());
+            result.add(map);
+        }
+        return result;
+    }
+
+    private void createTodo(String warningId, String userId, String taskName, String todoType) {
+        WarningTodo todo = new WarningTodo();
+        todo.setWarningId(warningId);
+        todo.setUserId(userId);
+        todo.setUserName(userId);
+        todo.setTodoType(todoType);
+        todo.setReadStatus("UNREAD");
+        todo.setTaskName(taskName);
+        todo.setCreateTime(LocalDateTime.now());
+        warningTodoMapper.insert(todo);
+    }
+
+    private void completeTodo(String warningId) {
+        LambdaQueryWrapper<WarningTodo> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(WarningTodo::getWarningId, warningId)
+                .eq(WarningTodo::getTodoType, "TODO");
+        List<WarningTodo> todos = warningTodoMapper.selectList(wrapper);
+
+        for (WarningTodo todo : todos) {
+            todo.setTodoType("DONE");
+            todo.setReadStatus("READ");
+            todo.setCompleteTime(LocalDateTime.now());
+            warningTodoMapper.updateById(todo);
+        }
+    }
+
+    @Override
+    public WarningArchive getArchiveByWarningId(String warningId) {
+        LambdaQueryWrapper<WarningArchive> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(WarningArchive::getWarningId, warningId);
+        return warningArchiveMapper.selectOne(wrapper);
+    }
+
+    @Override
+    public IPage<WarningArchive> getArchiveList(Page<WarningArchive> page, String warningName, String warningType, String warningLevel, LocalDateTime startTime, LocalDateTime endTime) {
+        LambdaQueryWrapper<WarningArchive> wrapper = new LambdaQueryWrapper<>();
+        
+        if (warningName != null && !warningName.isEmpty()) {
+            wrapper.like(WarningArchive::getWarningName, warningName);
+        }
+        if (warningType != null && !warningType.isEmpty()) {
+            wrapper.eq(WarningArchive::getWarningType, warningType);
+        }
+        if (warningLevel != null && !warningLevel.isEmpty()) {
+            wrapper.eq(WarningArchive::getWarningLevel, warningLevel);
+        }
+        if (startTime != null) {
+            wrapper.ge(WarningArchive::getCreateTime, startTime);
+        }
+        if (endTime != null) {
+            wrapper.le(WarningArchive::getCreateTime, endTime);
+        }
+        
+        wrapper.orderByDesc(WarningArchive::getCreateTime);
+        return warningArchiveMapper.selectPage(page, wrapper);
+    }
+
+    private static final Map<String, String> DISPOSAL_TYPE_MAP = new HashMap<>();
+    static {
+        DISPOSAL_TYPE_MAP.put("RELEASE", "发布预警");
+        DISPOSAL_TYPE_MAP.put("UPGRADE", "升级预警");
+        DISPOSAL_TYPE_MAP.put("RESOLVE", "解除预警");
+        DISPOSAL_TYPE_MAP.put("RETURN", "退回重办");
+        DISPOSAL_TYPE_MAP.put("SUPERVISION", "预警督办");
+        DISPOSAL_TYPE_MAP.put("INSTRUCTION", "领导批示");
+    }
+
+    @Override
+    public List<WarningDisposal> getDisposalProcess(String warningId) {
+        LambdaQueryWrapper<WarningDisposal> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(WarningDisposal::getWarningId, warningId);
+        wrapper.orderByAsc(WarningDisposal::getCreateTime);
+        return warningDisposalMapper.selectList(wrapper);
+    }
+
+    @Override
+    public Map<String, Object> getProcessDiagram(String warningId) {
+        Map<String, Object> result = new HashMap<>();
+        List<Map<String, Object>> nodes = new ArrayList<>();
+        List<Map<String, Object>> edges = new ArrayList<>();
+
+        EarlyWarning warning = earlyWarningMapper.selectById(warningId);
+        if (warning == null) {
+            result.put("error", "预警不存在");
+            return result;
+        }
+
+        List<WarningDisposal> disposals = getDisposalProcess(warningId);
+
+        Map<String, Object> startNode = new HashMap<>();
+        startNode.put("id", "start");
+        startNode.put("name", "预警创建");
+        startNode.put("type", "startEvent");
+        startNode.put("x", 50);
+        startNode.put("y", 150);
+        startNode.put("status", "completed");
+        nodes.add(startNode);
+
+        int x = 180;
+        String lastNodeId = "start";
+
+        for (int i = 0; i < disposals.size(); i++) {
+            WarningDisposal disposal = disposals.get(i);
+            String nodeId = "task_" + i;
+            String typeName = DISPOSAL_TYPE_MAP.getOrDefault(disposal.getDisposalType(), "处置");
+
+            Map<String, Object> taskNode = new HashMap<>();
+            taskNode.put("id", nodeId);
+            taskNode.put("name", typeName);
+            taskNode.put("type", "userTask");
+            taskNode.put("x", x);
+            taskNode.put("y", 150);
+            taskNode.put("status", "completed");
+            taskNode.put("disposalUser", disposal.getDisposalUser());
+            taskNode.put("disposalTime", disposal.getCreateTime() != null ? 
+                    disposal.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
+            taskNode.put("disposalId", disposal.getDisposalId());
+            nodes.add(taskNode);
+
+            Map<String, Object> edge = new HashMap<>();
+            edge.put("source", lastNodeId);
+            edge.put("target", nodeId);
+            edge.put("label", "");
+            edge.put("status", "completed");
+            edges.add(edge);
+
+            lastNodeId = nodeId;
+            x += 180;
+        }
+
+        String status = warning.getStatus();
+        String currentStatus = "waiting";
+        if ("CLOSED".equals(status) || "HANDLED".equals(status)) {
+            currentStatus = "completed";
+        } else if ("PROCESSING".equals(status) || "PENDING".equals(status) || "RELEASED".equals(status)) {
+            currentStatus = "active";
+        }
+
+        Map<String, Object> endNode = new HashMap<>();
+        endNode.put("id", "end");
+        endNode.put("name", "处置完成");
+        endNode.put("type", "endEvent");
+        endNode.put("x", x);
+        endNode.put("y", 150);
+        endNode.put("status", currentStatus);
+        nodes.add(endNode);
+
+        if (!disposals.isEmpty()) {
+            Map<String, Object> lastEdge = new HashMap<>();
+            lastEdge.put("source", lastNodeId);
+            lastEdge.put("target", "end");
+            lastEdge.put("label", "");
+            lastEdge.put("status", currentStatus);
+            edges.add(lastEdge);
+        }
+
+        result.put("nodes", nodes);
+        result.put("edges", edges);
+        result.put("warningId", warningId);
+        result.put("warningName", warning.getWarningName());
+        result.put("warningNo", warning.getWarningNo());
+        result.put("status", warning.getStatus());
+        result.put("totalTasks", disposals.size());
+        result.put("processDefinitionName", "预警处置流程");
+
+        return result;
+    }
+
+    @Override
+    public Map<String, Object> getDisposalDetail(String disposalId) {
+        WarningDisposal disposal = warningDisposalMapper.selectById(disposalId);
+        if (disposal == null) {
+            return null;
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("disposalId", disposal.getDisposalId());
+        result.put("warningId", disposal.getWarningId());
+        result.put("disposalType", disposal.getDisposalType());
+        result.put("disposalTypeName", DISPOSAL_TYPE_MAP.getOrDefault(disposal.getDisposalType(), "未知"));
+        result.put("oldLevel", disposal.getOldLevel());
+        result.put("newLevel", disposal.getNewLevel());
+        result.put("disposalUser", disposal.getDisposalUser());
+        result.put("disposalContent", disposal.getDisposalContent());
+        result.put("supervisionUser", disposal.getSupervisionUser());
+        result.put("supervisionContent", disposal.getSupervisionContent());
+        result.put("notificationType", disposal.getNotificationType());
+        result.put("createTime", disposal.getCreateTime() != null ? 
+                disposal.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
+
+        return result;
+    }
+
+    @Override
+    public Map<String, Object> getProcessStatistics(String warningId) {
+        Map<String, Object> result = new HashMap<>();
+
+        List<WarningDisposal> disposals = getDisposalProcess(warningId);
+        EarlyWarning warning = earlyWarningMapper.selectById(warningId);
+
+        result.put("warningId", warningId);
+        result.put("warningName", warning != null ? warning.getWarningName() : null);
+        result.put("totalDisposals", disposals.size());
+
+        Map<String, Integer> typeCount = new HashMap<>();
+        for (WarningDisposal disposal : disposals) {
+            String type = disposal.getDisposalType();
+            typeCount.put(type, typeCount.getOrDefault(type, 0) + 1);
+        }
+        result.put("typeDistribution", typeCount);
+
+        Set<String> handlers = new HashSet<>();
+        for (WarningDisposal disposal : disposals) {
+            if (disposal.getDisposalUser() != null) {
+                handlers.add(disposal.getDisposalUser());
+            }
+        }
+        result.put("handlerCount", handlers.size());
+
+        if (!disposals.isEmpty()) {
+            result.put("firstDisposalTime", disposals.get(0).getCreateTime() != null ? 
+                    disposals.get(0).getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
+            result.put("lastDisposalTime", disposals.get(disposals.size() - 1).getCreateTime() != null ? 
+                    disposals.get(disposals.size() - 1).getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null);
+        }
+
+        return result;
+    }
+}

+ 146 - 0
pipe-network-service/zksy-system/src/main/resources/mapper/warning/EarlyWarningMapper.xml

@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zksy.base.warning.mapper.EarlyWarningMapper">
+
+    <select id="selectWarningList" resultType="java.util.Map">
+        SELECT w.*
+        FROM early_warning w
+        <where>
+            <if test="warningName != null and warningName != ''">
+                AND w.warning_name LIKE CONCAT('%', #{warningName}, '%')
+            </if>
+            <if test="warningType != null and warningType != ''">
+                AND w.warning_type = #{warningType}
+            </if>
+            <if test="warningLevel != null and warningLevel != ''">
+                AND w.warning_level = #{warningLevel}
+            </if>
+            <if test="status != null and status != ''">
+                AND w.status = #{status}
+            </if>
+        </where>
+        ORDER BY w.create_time DESC
+    </select>
+
+    <select id="searchWarnings" resultType="java.util.Map">
+        SELECT w.*
+        FROM early_warning w
+        <where>
+            <if test="warningName != null and warningName != ''">
+                AND w.warning_name LIKE CONCAT('%', #{warningName}, '%')
+            </if>
+            <if test="warningNo != null and warningNo != ''">
+                AND w.warning_no LIKE CONCAT('%', #{warningNo}, '%')
+            </if>
+            <if test="warningType != null and warningType != ''">
+                AND w.warning_type = #{warningType}
+            </if>
+            <if test="warningLevel != null and warningLevel != ''">
+                AND w.warning_level = #{warningLevel}
+            </if>
+            <if test="status != null and status != ''">
+                AND w.status = #{status}
+            </if>
+            <if test="location != null and location != ''">
+                AND w.location LIKE CONCAT('%', #{location}, '%')
+            </if>
+            <if test="publisher != null and publisher != ''">
+                AND w.publisher LIKE CONCAT('%', #{publisher}, '%')
+            </if>
+            <if test="ownershipUnit != null and ownershipUnit != ''">
+                AND w.ownership_unit LIKE CONCAT('%', #{ownershipUnit}, '%')
+            </if>
+            <if test="startTime != null">
+                AND w.create_time >= #{startTime}
+            </if>
+            <if test="endTime != null">
+                AND w.create_time &lt;= #{endTime}
+            </if>
+        </where>
+        ORDER BY w.create_time DESC
+    </select>
+
+    <select id="selectTodoList" resultType="java.util.Map">
+        SELECT
+            t.*,
+            w.warning_name,
+            w.warning_type,
+            w.warning_level,
+            w.handler,
+            w.publisher,
+            w.location,
+            w.ownership_unit,
+            w.publish_time
+        FROM warning_todo t
+        LEFT JOIN early_warning w ON t.warning_id = w.warning_id
+        <where>
+            t.user_id = #{userId}
+            <if test="todoType != null and todoType != ''">
+                AND t.todo_type = #{todoType}
+            </if>
+            <if test="warningName != null and warningName != ''">
+                AND w.warning_name LIKE CONCAT('%', #{warningName}, '%')
+            </if>
+        </where>
+        ORDER BY t.create_time DESC
+    </select>
+
+    <select id="selectProcessingWarnings" resultType="java.util.Map">
+        SELECT w.*
+        FROM early_warning w
+        <where>
+            AND w.status IN ('PENDING', 'PROCESSING', 'RELEASED')
+            <if test="warningType != null and warningType != ''">
+                AND w.warning_type = #{warningType}
+            </if>
+            <if test="warningLevel != null and warningLevel != ''">
+                AND w.warning_level = #{warningLevel}
+            </if>
+        </where>
+        ORDER BY w.publish_time DESC
+    </select>
+
+    <select id="selectCompletedWarnings" resultType="java.util.Map">
+        SELECT w.*
+        FROM early_warning w
+        <where>
+            AND w.status IN ('HANDLED', 'CLOSED')
+            <if test="warningType != null and warningType != ''">
+                AND w.warning_type = #{warningType}
+            </if>
+            <if test="warningLevel != null and warningLevel != ''">
+                AND w.warning_level = #{warningLevel}
+            </if>
+            <if test="startTime != null">
+                AND w.update_time >= #{startTime}
+            </if>
+            <if test="endTime != null">
+                AND w.update_time &lt;= #{endTime}
+            </if>
+        </where>
+        ORDER BY w.update_time DESC
+    </select>
+
+    <select id="selectWarningDetail" resultType="java.util.Map">
+        SELECT w.*
+        FROM early_warning w
+        WHERE w.warning_id = #{warningId}
+    </select>
+
+    <select id="selectStatistics" resultType="java.util.Map">
+        SELECT
+            COUNT(*) AS total,
+            SUM(CASE WHEN status = 'DRAFT' THEN 1 ELSE 0 END) AS draftCount,
+            SUM(CASE WHEN status = 'PENDING' THEN 1 ELSE 0 END) AS pendingCount,
+            SUM(CASE WHEN status = 'PROCESSING' THEN 1 ELSE 0 END) AS processingCount,
+            SUM(CASE WHEN status = 'RELEASED' THEN 1 ELSE 0 END) AS releasedCount,
+            SUM(CASE WHEN status = 'HANDLED' THEN 1 ELSE 0 END) AS handledCount,
+            SUM(CASE WHEN status = 'CLOSED' THEN 1 ELSE 0 END) AS closedCount,
+            SUM(CASE WHEN warning_level = '1' THEN 1 ELSE 0 END) AS level1Count,
+            SUM(CASE WHEN warning_level = '2' THEN 1 ELSE 0 END) AS level2Count,
+            SUM(CASE WHEN warning_level = '3' THEN 1 ELSE 0 END) AS level3Count,
+            SUM(CASE WHEN warning_level = '4' THEN 1 ELSE 0 END) AS level4Count
+        FROM early_warning
+    </select>
+
+</mapper>