Lin Qilong 7 horas atrás
pai
commit
fa0adfff85
44 arquivos alterados com 2698 adições e 414 exclusões
  1. 18 2
      gw-admin/src/main/java/com/goldenwater/web/controller/hzz/EventClearController.java
  2. 26 0
      gw-admin/src/main/java/com/goldenwater/web/controller/hzz/RiverSectionController.java
  3. 29 2
      gw-admin/src/main/java/com/goldenwater/web/controller/hzz/ShorelineController.java
  4. 58 3
      gw-admin/src/main/java/com/goldenwater/web/controller/hzz/SupervisionController.java
  5. 2 2
      gw-admin/src/main/resources/application.yml
  6. 137 19
      gw-hzz/src/main/java/com/goldenwater/hzz/domain/EventDTO.java
  7. 15 0
      gw-hzz/src/main/java/com/goldenwater/hzz/domain/RiverSectionDTO.java
  8. 27 1
      gw-hzz/src/main/java/com/goldenwater/hzz/domain/SupervisionInfoDTO.java
  9. 4 1
      gw-hzz/src/main/java/com/goldenwater/hzz/mapper/EventClearMapper.java
  10. 9 0
      gw-hzz/src/main/java/com/goldenwater/hzz/mapper/RiverSectionMapper.java
  11. 3 0
      gw-hzz/src/main/java/com/goldenwater/hzz/mapper/ShorelineMapper.java
  12. 39 5
      gw-hzz/src/main/java/com/goldenwater/hzz/mapper/SupervisionMapper.java
  13. 4 1
      gw-hzz/src/main/java/com/goldenwater/hzz/service/EventClearService.java
  14. 21 0
      gw-hzz/src/main/java/com/goldenwater/hzz/service/RiverSectionService.java
  15. 4 2
      gw-hzz/src/main/java/com/goldenwater/hzz/service/RuleService.java
  16. 3 0
      gw-hzz/src/main/java/com/goldenwater/hzz/service/ShorelineService.java
  17. 109 11
      gw-hzz/src/main/java/com/goldenwater/hzz/service/SupervisionService.java
  18. 60 13
      gw-hzz/src/main/resources/mapper/hzz/EventClearMapper.xml
  19. 2 2
      gw-hzz/src/main/resources/mapper/hzz/RiverProjectMapper.xml
  20. 32 0
      gw-hzz/src/main/resources/mapper/hzz/RiverSectionMapper.xml
  21. 18 0
      gw-hzz/src/main/resources/mapper/hzz/ShorelineMapper.xml
  22. 170 15
      gw-hzz/src/main/resources/mapper/hzz/SupervisionMapper.xml
  23. 1 1
      gw-ui/.env.development
  24. 1 1
      gw-ui/.env.production
  25. 1 1
      gw-ui/.env.staging
  26. 12 0
      gw-ui/src/api/hzz/eventclear.js
  27. 29 22
      gw-ui/src/api/hzz/rule.js
  28. 12 0
      gw-ui/src/api/hzz/shoreline.js
  29. 22 0
      gw-ui/src/api/hzz/supervision.js
  30. 2 1
      gw-ui/src/api/hzz/workplan.js
  31. 1 1
      gw-ui/src/frontLayout/systemHeader.vue
  32. 5 3
      gw-ui/src/frontLayout/tabViewContainerWithRouter.vue
  33. 2 2
      gw-ui/src/router/index.js
  34. 1 1
      gw-ui/src/utils/request.js
  35. 2 0
      gw-ui/src/views/hlgl/assess/index.vue
  36. 10 2
      gw-ui/src/views/hlgl/bankline/index.vue
  37. 408 105
      gw-ui/src/views/hlgl/eventclear/index.vue
  38. 273 51
      gw-ui/src/views/hlgl/mcaf/index.vue
  39. 3 3
      gw-ui/src/views/hlgl/riverproject/index.vue
  40. 287 60
      gw-ui/src/views/hlgl/shoreline/index.vue
  41. 792 75
      gw-ui/src/views/hlgl/supervision/index.vue
  42. 1 0
      gw-ui/src/views/hlgl/syaxgl/index.vue
  43. 41 4
      gw-ui/src/views/hlgl/wps/index.vue
  44. 2 2
      sql/gw_dm.sql

+ 18 - 2
gw-admin/src/main/java/com/goldenwater/web/controller/hzz/EventClearController.java

@@ -1,6 +1,7 @@
 package com.goldenwater.web.controller.hzz;
 
 import com.goldenwater.common.core.controller.BaseController;
+import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.page.TableDataInfo;
 import com.goldenwater.hzz.domain.EventDTO;
 import com.goldenwater.hzz.service.EventClearService;
@@ -16,12 +17,27 @@ public class EventClearController extends BaseController {
     private EventClearService service;
 
     @GetMapping("/list")
-    public TableDataInfo list(@RequestParam(required = false) String adCode, @RequestParam(required = false) String evType, @RequestParam(required = false) String keyWord, @RequestParam(required = false) String objectType, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) {
-        return getDataTable(service.findListByAdCode(adCode, evType, keyWord, objectType, pageNum, pageSize));
+    public TableDataInfo list(@RequestParam(required = false) String adCode, @RequestParam(required = false) String evType, @RequestParam(required = false) String keyWord, @RequestParam(required = false) String objectType, @RequestParam(required = false) String status, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) {
+        return getDataTable(service.findListByAdCode(adCode, evType, keyWord, objectType, status, pageNum, pageSize));
     }
 
     @PostMapping("/search")
     public TableDataInfo search(@RequestBody EventDTO params, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) {
         return getDataTable(service.findList(params, pageNum, pageSize));
     }
+
+    @PostMapping("/save")
+    public AjaxResult save(@RequestBody EventDTO params) {
+        return toAjax(service.insertEvent(params));
+    }
+
+    @PostMapping("/update")
+    public AjaxResult update(@RequestBody EventDTO params) {
+        return toAjax(service.updateEvent(params));
+    }
+
+    @PostMapping("/delete/{guid}")
+    public AjaxResult delete(@PathVariable String guid) {
+        return toAjax(service.deleteEvent(guid));
+    }
 }

+ 26 - 0
gw-admin/src/main/java/com/goldenwater/web/controller/hzz/RiverSectionController.java

@@ -0,0 +1,26 @@
+package com.goldenwater.web.controller.hzz;
+
+import com.goldenwater.common.core.controller.BaseController;
+import com.goldenwater.common.core.domain.AjaxResult;
+import com.goldenwater.hzz.domain.RiverSectionDTO;
+import com.goldenwater.hzz.service.RiverSectionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/hzz/riversection")
+public class RiverSectionController extends BaseController {
+    @Autowired
+    private RiverSectionService service;
+
+    @GetMapping("/list")
+    public AjaxResult list(@RequestParam String objType, @RequestParam(required = false) String name) {
+        List<RiverSectionDTO> data = service.listByType(objType, name);
+        return success(data);
+    }
+}

+ 29 - 2
gw-admin/src/main/java/com/goldenwater/web/controller/hzz/ShorelineController.java

@@ -1,6 +1,8 @@
 package com.goldenwater.web.controller.hzz;
+
 import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
+import com.goldenwater.hzz.domain.ShorelineDTO;
 import com.goldenwater.hzz.service.ShorelineService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -8,6 +10,31 @@ import org.springframework.web.bind.annotation.*;
 @RestController
 @RequestMapping("/hzz/shoreline")
 public class ShorelineController extends BaseController {
-    @Autowired private ShorelineService service;
-    @GetMapping("/stats") public AjaxResult stats() { return success(service.getWaterLine()); }
+    @Autowired
+    private ShorelineService service;
+
+    @GetMapping("/list")
+    public AjaxResult list() {
+        return success(service.getWaterLine());
+    }
+
+    @GetMapping("/stats")
+    public AjaxResult stats() {
+        return success(service.getWaterLine());
+    }
+
+    @PostMapping("/save")
+    public AjaxResult save(@RequestBody ShorelineDTO params) {
+        return toAjax(service.insertLine(params));
+    }
+
+    @PostMapping("/update")
+    public AjaxResult update(@RequestBody ShorelineDTO params) {
+        return toAjax(service.updateLine(params));
+    }
+
+    @PostMapping("/delete")
+    public AjaxResult delete(@RequestBody ShorelineDTO params) {
+        return toAjax(service.deleteLine(params));
+    }
 }

+ 58 - 3
gw-admin/src/main/java/com/goldenwater/web/controller/hzz/SupervisionController.java

@@ -3,32 +3,87 @@ package com.goldenwater.web.controller.hzz;
 import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.page.TableDataInfo;
+import com.goldenwater.hzz.domain.SupervisionInfoDTO;
 import com.goldenwater.hzz.service.SupervisionService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 河湖管理督察(督导检查)
+ */
 @RestController
 @RequestMapping("/hzz/supervision")
 public class SupervisionController extends BaseController {
     @Autowired
     private SupervisionService service;
 
+    /** 督察任务列表(含审核状态与附件/分工/结果数量) */
     @GetMapping("/list")
-    public TableDataInfo list(@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) {
-        return getDataTable(service.getSupervisionList(pageNum, pageSize));
+    public TableDataInfo list(SupervisionInfoDTO query,
+                              @RequestParam(defaultValue = "1") int pageNum,
+                              @RequestParam(defaultValue = "10") int pageSize) {
+        return getDataTable(service.getSupervisionList(query, pageNum, pageSize));
     }
 
+    /** 督察详情:任务信息 + 附件 + 分工 + 结果 */
     @GetMapping("/detail/{guid}")
     public AjaxResult detail(@PathVariable String guid) {
         AjaxResult r = success();
+        r.put("info", service.getSupervisionByGuid(guid));
         r.put("attachments", service.getAttachmentByGuid(guid));
         r.put("divisions", service.getDivisionByGuid(guid));
         r.put("results", service.getResultByGuid(guid));
         return r;
     }
 
+    /** 审核督察结果:audit=1 通过、0 不通过 */
     @PostMapping("/audit")
-    public AjaxResult audit(@RequestParam String guid, @RequestParam String audit, @RequestParam(required = false) String auditInfo) {
+    public AjaxResult audit(@RequestParam String guid,
+                            @RequestParam String audit,
+                            @RequestParam(required = false) String auditInfo) {
         return toAjax(service.audit(guid, audit, auditInfo));
     }
+
+    /** 新增督察任务 */
+    @PostMapping("/save")
+    public AjaxResult save(@RequestBody SupervisionInfoDTO dto) {
+        dto.setCrCuserId(getUsername());
+        return toAjax(service.saveAssess(dto));
+    }
+
+    /** 修改督察任务 */
+    @PutMapping("/update")
+    public AjaxResult update(@RequestBody SupervisionInfoDTO dto) {
+        return toAjax(service.updateAssess(dto));
+    }
+
+    /** 删除督察任务(级联子表) */
+    @DeleteMapping("/delete/{guid}")
+    public AjaxResult delete(@PathVariable String guid) {
+        return toAjax(service.deleteAssess(guid));
+    }
+
+    /** 覆盖保存附件列表 */
+    @PostMapping("/attachment/save")
+    public AjaxResult saveAttachment(@RequestParam String guid,
+                                     @RequestBody List<Map<String, Object>> list) {
+        return toAjax(service.saveAttachments(guid, list));
+    }
+
+    /** 覆盖保存分工列表 */
+    @PostMapping("/division/save")
+    public AjaxResult saveDivision(@RequestParam String guid,
+                                   @RequestBody List<Map<String, Object>> list) {
+        return toAjax(service.saveDivisions(guid, list));
+    }
+
+    /** 覆盖保存结果列表 */
+    @PostMapping("/result/save")
+    public AjaxResult saveResult(@RequestParam String guid,
+                                 @RequestBody List<Map<String, Object>> list) {
+        return toAjax(service.saveResults(guid, list));
+    }
 }

+ 2 - 2
gw-admin/src/main/resources/application.yml

@@ -1,7 +1,7 @@
 # 开发环境配置
 server:
   # 服务器的HTTP端口,默认为8080
-  port: 8080
+  port: 8088
   servlet:
     # 应用的访问路径
     context-path: /
@@ -46,7 +46,7 @@ token:
   # 令牌密钥
   secret: abcdefghijklmnopqrstuvwxyz
   # 令牌有效期(默认30分钟)
-  expireTime: 30
+  expireTime: 1440
 
 # MyBatis配置
 mybatis:

+ 137 - 19
gw-hzz/src/main/java/com/goldenwater/hzz/domain/EventDTO.java

@@ -1,38 +1,156 @@
 package com.goldenwater.hzz.domain;
 
+import lombok.Data;
+
 import java.io.Serializable;
 
-/** ATT_EV_BASE 清四乱事件 */
+/**
+ * ATT_EV_BASE 清四乱事件
+ */
+@Data
 public class EventDTO implements Serializable {
     private String guid;
     private String evCode;
     private String adCode;
     private String adName;
-    private String objectType;
-    private String objectId;
-    private String objectName;
+    private String objType;
+    private String objCode;
+    private String objName;
     private String evType;
     private String eventDesc;
     private String eventAddress;
     private String status;
+    private String keyWord;
     private String dealDesc;
     private String findTs;
     private String doneDate;
     private String userName;
 
-    public String getGuid() { return guid; } public void setGuid(String v) { guid = v; }
-    public String getEvCode() { return evCode; } public void setEvCode(String v) { evCode = v; }
-    public String getAdCode() { return adCode; } public void setAdCode(String v) { adCode = v; }
-    public String getAdName() { return adName; } public void setAdName(String v) { adName = v; }
-    public String getObjectType() { return objectType; } public void setObjectType(String v) { objectType = v; }
-    public String getObjectId() { return objectId; } public void setObjectId(String v) { objectId = v; }
-    public String getObjectName() { return objectName; } public void setObjectName(String v) { objectName = v; }
-    public String getEvType() { return evType; } public void setEvType(String v) { evType = v; }
-    public String getEventDesc() { return eventDesc; } public void setEventDesc(String v) { eventDesc = v; }
-    public String getEventAddress() { return eventAddress; } public void setEventAddress(String v) { eventAddress = v; }
-    public String getStatus() { return status; } public void setStatus(String v) { status = v; }
-    public String getDealDesc() { return dealDesc; } public void setDealDesc(String v) { dealDesc = v; }
-    public String getFindTs() { return findTs; } public void setFindTs(String v) { findTs = v; }
-    public String getDoneDate() { return doneDate; } public void setDoneDate(String v) { doneDate = v; }
-    public String getUserName() { return userName; } public void setUserName(String v) { userName = v; }
+    public String getGuid() {
+        return guid;
+    }
+
+    public void setGuid(String v) {
+        guid = v;
+    }
+
+    public String getEvCode() {
+        return evCode;
+    }
+
+    public void setEvCode(String v) {
+        evCode = v;
+    }
+
+    public String getAdCode() {
+        return adCode;
+    }
+
+    public void setAdCode(String v) {
+        adCode = v;
+    }
+
+    public String getAdName() {
+        return adName;
+    }
+
+    public void setAdName(String v) {
+        adName = v;
+    }
+
+    public String getObjType() {
+        return objType;
+    }
+
+    public void setObjType(String v) {
+        objType = v;
+    }
+
+    public String getObjCode() {
+        return objCode;
+    }
+
+    public void setObjCode(String v) {
+        objCode = v;
+    }
+
+    public String getObjName() {
+        return objName;
+    }
+
+    public void setObjName(String v) {
+        objName = v;
+    }
+
+    public String getEvType() {
+        return evType;
+    }
+
+    public void setEvType(String v) {
+        evType = v;
+    }
+
+    public String getEventDesc() {
+        return eventDesc;
+    }
+
+    public void setEventDesc(String v) {
+        eventDesc = v;
+    }
+
+    public String getEventAddress() {
+        return eventAddress;
+    }
+
+    public void setEventAddress(String v) {
+        eventAddress = v;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String v) {
+        status = v;
+    }
+
+    public String getKeyWord() {
+        return keyWord;
+    }
+
+    public void setKeyWord(String v) {
+        keyWord = v;
+    }
+
+    public String getDealDesc() {
+        return dealDesc;
+    }
+
+    public void setDealDesc(String v) {
+        dealDesc = v;
+    }
+
+    public String getFindTs() {
+        return findTs;
+    }
+
+    public void setFindTs(String v) {
+        findTs = v;
+    }
+
+    public String getDoneDate() {
+        return doneDate;
+    }
+
+    public void setDoneDate(String v) {
+        doneDate = v;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String v) {
+        userName = v;
+    }
 }

+ 15 - 0
gw-hzz/src/main/java/com/goldenwater/hzz/domain/RiverSectionDTO.java

@@ -0,0 +1,15 @@
+package com.goldenwater.hzz.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 河段(按所在河湖分表)
+ */
+@Data
+public class RiverSectionDTO implements Serializable {
+    private String code;
+    private String name;
+    private String objType;
+}

+ 27 - 1
gw-hzz/src/main/java/com/goldenwater/hzz/domain/SupervisionInfoDTO.java

@@ -6,11 +6,23 @@ import lombok.NoArgsConstructor;
 import java.io.Serializable;
 
 /**
- * GW_SUPERVISION_INFO 督导信息
+ * 河湖管理督察(督导检查)信息
+ *
+ * <p>涉及的表:</p>
+ * <ul>
+ *     <li>主表 ATT_COUNCILOR_ASSESS:督察任务基本信息,字段以 CR_ 开头,主键 CR_ID</li>
+ *     <li>审核扩展表 GW_SUPERVISION_INFO:GUID = 主表 CR_ID,STATUS 审核结果、AUDIT_INFO 审核意见</li>
+ *     <li>子表 GW_SUPERVISION_ATTACHMENT / GW_SUPERVISION_DIVISION / GW_SUPERVISION_RESULT:
+ *         外键 SUPERVISION_GUID = 主表 CR_ID,分别记录附件、任务分工、督察结果</li>
+ * </ul>
  */
 @NoArgsConstructor
 @Data
 public class SupervisionInfoDTO implements Serializable {
+    /** 主键,取自 ATT_COUNCILOR_ASSESS.CR_ID,同时是各子表的 SUPERVISION_GUID */
+    private String guid;
+
+    /** ATT_COUNCILOR_ASSESS 主表字段 */
     private String crId;
     private String crCode;
     private String crName;
@@ -18,8 +30,22 @@ public class SupervisionInfoDTO implements Serializable {
     private String crStDate;
     private String crEtDate;
     private String crContent;
+    /** 业务状态:5 进行中、6 未提交、7 未审批、8 已退回、9 已通过 */
     private String crState;
     private String crCuserId;
     private String crCdate;
     private String crUdate;
+
+    /** GW_SUPERVISION_INFO 审核扩展字段:1 通过、0 不通过 */
+    private String auditStatus;
+    /** GW_SUPERVISION_INFO.AUDIT_INFO 审核意见 */
+    private String auditInfo;
+
+    /** 关联子表统计 */
+    private Integer attachmentCount;
+    private Integer divisionCount;
+    private Integer resultCount;
+
+    /** 查询条件(非表字段) */
+    private String keyWord;
 }

+ 4 - 1
gw-hzz/src/main/java/com/goldenwater/hzz/mapper/EventClearMapper.java

@@ -6,5 +6,8 @@ import java.util.List;
 
 public interface EventClearMapper {
     List<EventDTO> findList(EventDTO params);
-    List<EventDTO> findListByAdCode(@Param("adCode") String ad, @Param("evType") String et, @Param("keyWord") String kw, @Param("objectType") String ot);
+    List<EventDTO> findListByAdCode(@Param("adCode") String ad, @Param("evType") String et, @Param("keyWord") String kw, @Param("objectType") String ot, @Param("status") String status);
+    int insertEvent(EventDTO params);
+    int updateEvent(EventDTO params);
+    int deleteEvent(@Param("guid") String guid);
 }

+ 9 - 0
gw-hzz/src/main/java/com/goldenwater/hzz/mapper/RiverSectionMapper.java

@@ -0,0 +1,9 @@
+package com.goldenwater.hzz.mapper;
+
+import com.goldenwater.hzz.domain.RiverSectionDTO;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+public interface RiverSectionMapper {
+    List<RiverSectionDTO> listByType(@Param("objType") String objType, @Param("name") String name);
+}

+ 3 - 0
gw-hzz/src/main/java/com/goldenwater/hzz/mapper/ShorelineMapper.java

@@ -4,4 +4,7 @@ import java.util.List;
 
 public interface ShorelineMapper {
     List<ShorelineDTO> getWaterLine();
+    int insertLine(ShorelineDTO p);
+    int updateLine(ShorelineDTO p);
+    int deleteLine(ShorelineDTO p);
 }

+ 39 - 5
gw-hzz/src/main/java/com/goldenwater/hzz/mapper/SupervisionMapper.java

@@ -4,15 +4,49 @@ import com.goldenwater.hzz.domain.SupervisionInfoDTO;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
+import java.util.Map;
 
+/**
+ * 河湖管理督察(督导检查)
+ * 主表 ATT_COUNCILOR_ASSESS,审核扩展表 GW_SUPERVISION_INFO,
+ * 子表 GW_SUPERVISION_ATTACHMENT / GW_SUPERVISION_DIVISION / GW_SUPERVISION_RESULT
+ */
 public interface SupervisionMapper {
-    List<SupervisionInfoDTO> getSupervisionList();
+    List<SupervisionInfoDTO> getSupervisionList(SupervisionInfoDTO query);
 
-    List<SupervisionInfoDTO> getAttachmentByGuid(@Param("guid") String g);
+    SupervisionInfoDTO getSupervisionByGuid(@Param("guid") String guid);
 
-    List<SupervisionInfoDTO> getDivisionByGuid(@Param("guid") String g);
+    List<Map<String, Object>> getAttachmentByGuid(@Param("guid") String guid);
 
-    List<SupervisionInfoDTO> getResultByGuid(@Param("guid") String g);
+    List<Map<String, Object>> getDivisionByGuid(@Param("guid") String guid);
 
-    int audit(@Param("guid") String g, @Param("audit") String a, @Param("auditInfo") String ai);
+    List<Map<String, Object>> getResultByGuid(@Param("guid") String guid);
+
+    int audit(@Param("guid") String guid, @Param("audit") String audit, @Param("auditInfo") String auditInfo);
+
+    int updateAssessState(@Param("guid") String guid, @Param("crState") String crState);
+
+    // ===== 主表增删改 =====
+    int insertAssess(SupervisionInfoDTO dto);
+
+    int updateAssess(SupervisionInfoDTO dto);
+
+    int deleteAssess(@Param("guid") String guid);
+
+    int deleteInfoByGuid(@Param("guid") String guid);
+
+    // ===== 附件子表 =====
+    int deleteAttachmentByGuid(@Param("guid") String guid);
+
+    int insertAttachment(Map<String, Object> attach);
+
+    // ===== 分工子表 =====
+    int deleteDivisionByGuid(@Param("guid") String guid);
+
+    int insertDivision(Map<String, Object> division);
+
+    // ===== 结果子表 =====
+    int deleteResultByGuid(@Param("guid") String guid);
+
+    int insertResult(Map<String, Object> result);
 }

+ 4 - 1
gw-hzz/src/main/java/com/goldenwater/hzz/service/EventClearService.java

@@ -10,5 +10,8 @@ import java.util.List;
 public class EventClearService {
     @Autowired private EventClearMapper mapper;
     public List<EventDTO> findList(EventDTO p, int pn, int ps) { PageHelper.startPage(pn,ps); return mapper.findList(p); }
-    public List<EventDTO> findListByAdCode(String ad, String et, String kw, String ot, int pn, int ps) { PageHelper.startPage(pn,ps); return mapper.findListByAdCode(ad,et,kw,ot); }
+    public List<EventDTO> findListByAdCode(String ad, String et, String kw, String ot, String status, int pn, int ps) { PageHelper.startPage(pn,ps); return mapper.findListByAdCode(ad,et,kw,ot,status); }
+    public int insertEvent(EventDTO p) { return mapper.insertEvent(p); }
+    public int updateEvent(EventDTO p) { return mapper.updateEvent(p); }
+    public int deleteEvent(String guid) { return mapper.deleteEvent(guid); }
 }

+ 21 - 0
gw-hzz/src/main/java/com/goldenwater/hzz/service/RiverSectionService.java

@@ -0,0 +1,21 @@
+package com.goldenwater.hzz.service;
+
+import com.goldenwater.hzz.domain.RiverSectionDTO;
+import com.goldenwater.hzz.mapper.RiverSectionMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class RiverSectionService {
+    @Autowired private RiverSectionMapper mapper;
+    public List<RiverSectionDTO> listByType(String objType, String name) {
+        List<RiverSectionDTO> data = mapper.listByType(objType, name);
+        // 未传名称时默认只返回前十条,便于下拉快速展示
+        if (name == null || name.trim().isEmpty()) {
+            return data.stream().limit(10).collect(Collectors.toList());
+        }
+        return data;
+    }
+}

+ 4 - 2
gw-hzz/src/main/java/com/goldenwater/hzz/service/RuleService.java

@@ -1,6 +1,7 @@
 package com.goldenwater.hzz.service;
 
 import com.github.pagehelper.PageHelper;
+import com.goldenwater.common.utils.StringUtils;
 import com.goldenwater.hzz.domain.ArticleDTO;
 import com.goldenwater.hzz.domain.FileWsnDTO;
 import com.goldenwater.hzz.domain.RuleExecDTO;
@@ -26,7 +27,7 @@ public class RuleService {
     }
 
     public int insertWsn(FileWsnDTO dto) {
-        if (dto.getGuid() == null) dto.setGuid(UUID.randomUUID().toString().replace("-", ""));
+        if (StringUtils.isBlank(dto.getGuid())) dto.setGuid(UUID.randomUUID().toString().replace("-", ""));
         return mapper.insertWsn(dto);
     }
 
@@ -44,7 +45,8 @@ public class RuleService {
     }
 
     public int addArticle(ArticleDTO dto) {
-        if (dto.getGuid() == null) dto.setGuid(UUID.randomUUID().toString().replace("-", ""));
+        if (StringUtils.isBlank(dto.getGuid()))
+            dto.setGuid(UUID.randomUUID().toString().replace("-", ""));
         return mapper.addArticle(dto);
     }
 

+ 3 - 0
gw-hzz/src/main/java/com/goldenwater/hzz/service/ShorelineService.java

@@ -9,4 +9,7 @@ import java.util.List;
 public class ShorelineService {
     @Autowired private ShorelineMapper mapper;
     public List<ShorelineDTO> getWaterLine() { return mapper.getWaterLine(); }
+    public int insertLine(ShorelineDTO p) { return mapper.insertLine(p); }
+    public int updateLine(ShorelineDTO p) { return mapper.updateLine(p); }
+    public int deleteLine(ShorelineDTO p) { return mapper.deleteLine(p); }
 }

+ 109 - 11
gw-hzz/src/main/java/com/goldenwater/hzz/service/SupervisionService.java

@@ -5,32 +5,130 @@ import com.goldenwater.hzz.domain.SupervisionInfoDTO;
 import com.goldenwater.hzz.mapper.SupervisionMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
+/**
+ * 河湖管理督察(督导检查)业务:督察任务查询、附件/分工/结果查看、督察结果审核、任务维护
+ */
 @Service
 public class SupervisionService {
+    /** 审核通过后主表业务状态 */
+    private static final String STATE_PASSED = "9";
+    /** 审核不通过后主表业务状态(已退回) */
+    private static final String STATE_RETURNED = "8";
+    /** 新建任务默认业务状态:6 未提交 */
+    private static final String STATE_DEFAULT = "6";
+
     @Autowired
     private SupervisionMapper mapper;
 
-    public List<SupervisionInfoDTO> getSupervisionList(int p, int s) {
-        PageHelper.startPage(p, s);
-        return mapper.getSupervisionList();
+    public List<SupervisionInfoDTO> getSupervisionList(SupervisionInfoDTO query, int pageNum, int pageSize) {
+        PageHelper.startPage(pageNum, pageSize);
+        return mapper.getSupervisionList(query);
+    }
+
+    public SupervisionInfoDTO getSupervisionByGuid(String guid) {
+        return mapper.getSupervisionByGuid(guid);
+    }
+
+    public List<Map<String, Object>> getAttachmentByGuid(String guid) {
+        return mapper.getAttachmentByGuid(guid);
+    }
+
+    public List<Map<String, Object>> getDivisionByGuid(String guid) {
+        return mapper.getDivisionByGuid(guid);
+    }
+
+    public List<Map<String, Object>> getResultByGuid(String guid) {
+        return mapper.getResultByGuid(guid);
+    }
+
+    /**
+     * 审核:写入 GW_SUPERVISION_INFO 审核结果/意见,并回写主表 CR_STATE
+     *
+     * @param audit 1 通过、0 不通过
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public int audit(String guid, String audit, String auditInfo) {
+        int rows = mapper.audit(guid, audit, auditInfo);
+        mapper.updateAssessState(guid, "1".equals(audit) ? STATE_PASSED : STATE_RETURNED);
+        return rows;
+    }
+
+    /** 新增督察任务(编号为空时自动生成) */
+    @Transactional(rollbackFor = Exception.class)
+    public int saveAssess(SupervisionInfoDTO dto) {
+        if (dto.getCrCode() == null || dto.getCrCode().trim().isEmpty()) {
+            dto.setCrCode(genCrCode());
+        }
+        if (dto.getCrState() == null || dto.getCrState().trim().isEmpty()) {
+            dto.setCrState(STATE_DEFAULT);
+        }
+        return mapper.insertAssess(dto);
+    }
+
+    /** 修改督察任务 */
+    @Transactional(rollbackFor = Exception.class)
+    public int updateAssess(SupervisionInfoDTO dto) {
+        return mapper.updateAssess(dto);
+    }
+
+    /** 删除督察任务,并级联删除审核扩展表与三张子表 */
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteAssess(String guid) {
+        mapper.deleteResultByGuid(guid);
+        mapper.deleteDivisionByGuid(guid);
+        mapper.deleteAttachmentByGuid(guid);
+        mapper.deleteInfoByGuid(guid);
+        return mapper.deleteAssess(guid);
     }
 
-    public List<SupervisionInfoDTO> getAttachmentByGuid(String g) {
-        return mapper.getAttachmentByGuid(g);
+    /** 覆盖保存附件列表 */
+    @Transactional(rollbackFor = Exception.class)
+    public int saveAttachments(String guid, List<Map<String, Object>> list) {
+        mapper.deleteAttachmentByGuid(guid);
+        if (list != null) {
+            for (Map<String, Object> m : list) {
+                m.put("supervisionGuid", guid);
+                mapper.insertAttachment(m);
+            }
+        }
+        return list == null ? 0 : list.size();
     }
 
-    public List<SupervisionInfoDTO> getDivisionByGuid(String g) {
-        return mapper.getDivisionByGuid(g);
+    /** 覆盖保存分工列表 */
+    @Transactional(rollbackFor = Exception.class)
+    public int saveDivisions(String guid, List<Map<String, Object>> list) {
+        mapper.deleteDivisionByGuid(guid);
+        if (list != null) {
+            for (Map<String, Object> m : list) {
+                m.put("supervisionGuid", guid);
+                mapper.insertDivision(m);
+            }
+        }
+        return list == null ? 0 : list.size();
     }
 
-    public List<SupervisionInfoDTO> getResultByGuid(String g) {
-        return mapper.getResultByGuid(g);
+    /** 覆盖保存结果列表 */
+    @Transactional(rollbackFor = Exception.class)
+    public int saveResults(String guid, List<Map<String, Object>> list) {
+        mapper.deleteResultByGuid(guid);
+        if (list != null) {
+            for (Map<String, Object> m : list) {
+                m.put("supervisionGuid", guid);
+                mapper.insertResult(m);
+            }
+        }
+        return list == null ? 0 : list.size();
     }
 
-    public int audit(String g, String a, String ai) {
-        return mapper.audit(g, a, ai);
+    /** 生成督察编号:DC + 时间戳 */
+    private String genCrCode() {
+        return "DC" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
     }
 }

+ 60 - 13
gw-hzz/src/main/resources/mapper/hzz/EventClearMapper.xml

@@ -1,14 +1,14 @@
 <?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.goldenwater.hzz.mapper.EventClearMapper">
-    <select id="findList" resultType="com.goldenwater.hzz.domain.EventDTO" parameterType="java.util.Map">
-        SELECT EV.GUID AS "guid", EV.EV_CODE AS "evCode", EV.AD_CODE AS "adCode", AD.AD_NAME AS "adName",
-               EV.OBJ_TYPE AS "objectType", EV.OBJ_CODE AS "objectId",
-               CASE WHEN EV.OBJ_TYPE='REA' THEN REA.REA_NAME WHEN EV.OBJ_TYPE='LKS' THEN LKS.LKS_NAME ELSE RER.RER_NAME END AS "objectName",
+    <select id="findList" resultType="com.goldenwater.hzz.domain.EventDTO" parameterType="com.goldenwater.hzz.domain.EventDTO">
+        SELECT EV.GUID AS "guid", EV.EV_CODE AS "evCode", EV.AD_CODE AS "adCode", COALESCE(AD.AD_NAME, EV.AD_CODE) AS "adName",
+               EV.OBJ_TYPE AS "objType", EV.OBJ_CODE AS "objCode",
+               COALESCE(CASE WHEN EV.OBJ_TYPE='REA' THEN REA.REA_NAME WHEN EV.OBJ_TYPE='LKS' THEN LKS.LKS_NAME ELSE RER.RER_NAME END, EV.OBJ_CODE) AS "objName",
                EV.EV_TYPE AS "evType", EV.EV_DESC AS "eventDesc", EV.LOC AS "eventAddress",
                EV.STATUS AS "status", EV.DEAL_DESC AS "dealDesc",
-               TO_CHAR(EV.FIND_TS,'YYYY-MM-DD HH24:MI:SS') AS "findTs",
-               TO_CHAR(EV.DONE_DATE,'YYYY-MM-DD HH24:MI:SS') AS "doneDate",
+               TO_CHAR(EV.FIND_TS,'YYYY-MM-DD') AS "findTs",
+               TO_CHAR(EV.DONE_DATE,'YYYY-MM-DD') AS "doneDate",
                EV.REPO_NAME AS "userName"
         FROM ATT_EV_BASE EV
         LEFT JOIN ATT_REA_BASE REA ON EV.OBJ_CODE=REA.REA_CODE AND EV.OBJ_TYPE='REA'
@@ -16,19 +16,21 @@
         LEFT JOIN ATT_RER_BASE RER ON EV.OBJ_CODE=RER.RER_CODE AND EV.OBJ_TYPE='RER'
         LEFT JOIN ATT_AD_BASE AD ON EV.AD_CODE=AD.AD_CODE
         WHERE EV.TO_DATE IS NULL AND REA.EXPR_DATE IS NULL AND LKS.EXPR_DATE IS NULL AND RER.EXPR_DATE IS NULL AND AD.EXPR_DATE IS NULL AND EV.SOURCE_TYPE='3'
-        <if test="ad_code != null and ad_code != ''">AND EV.AD_CODE=#{ad_code}</if>
-        <if test="ev_type != null and ev_type != ''">AND EV.EV_TYPE=#{ev_type}</if>
-        <if test="key_word != null and key_word != ''">AND (REA.REA_NAME LIKE '%'||#{key_word}||'%' OR AD.AD_NAME LIKE '%'||#{key_word}||'%' OR EV.EV_DESC LIKE '%'||#{key_word}||'%')</if>
+        <if test="adCode != null and adCode != ''">AND EV.AD_CODE=#{adCode}</if>
+        <if test="evType != null and evType != ''">AND EV.EV_TYPE=#{evType}</if>
+        <if test="objType != null and objType != ''">AND EV.OBJ_TYPE=#{objType}</if>
+        <if test="status != null and status != ''">AND EV.STATUS=#{status}</if>
+        <if test="keyWord != null and keyWord != ''">AND (REA.REA_NAME LIKE '%'||#{keyWord}||'%' OR AD.AD_NAME LIKE '%'||#{keyWord}||'%' OR EV.EV_DESC LIKE '%'||#{keyWord}||'%')</if>
         ORDER BY EV.FIND_TS DESC
     </select>
     <select id="findListByAdCode" resultType="com.goldenwater.hzz.domain.EventDTO">
-        SELECT EV.GUID, EV.EV_CODE, EV.AD_CODE, AD.AD_NAME,
+        SELECT EV.GUID, EV.EV_CODE, EV.AD_CODE, COALESCE(AD.AD_NAME, EV.AD_CODE) AS "adName",
                EV.OBJ_TYPE, EV.OBJ_CODE,
-               CASE WHEN EV.OBJ_TYPE='REA' THEN REA.REA_NAME WHEN EV.OBJ_TYPE='LKS' THEN LKS.LKS_NAME ELSE RER.RER_NAME END AS "objectName",
+               COALESCE(CASE WHEN EV.OBJ_TYPE='REA' THEN REA.REA_NAME WHEN EV.OBJ_TYPE='LKS' THEN LKS.LKS_NAME ELSE RER.RER_NAME END, EV.OBJ_CODE) AS "objName",
                EV.EV_TYPE, EV.EV_DESC AS "eventDesc", EV.LOC AS "eventAddress",
                EV.STATUS AS "status", EV.DEAL_DESC AS "dealDesc",
-               TO_CHAR(EV.FIND_TS,'YYYY-MM-DD HH24:MI:SS') AS "findTs",
-               TO_CHAR(EV.DONE_DATE,'YYYY-MM-DD HH24:MI:SS') AS "doneDate",
+               TO_CHAR(EV.FIND_TS,'YYYY-MM-DD') AS "findTs",
+               TO_CHAR(EV.DONE_DATE,'YYYY-MM-DD') AS "doneDate",
                EV.REPO_NAME AS "userName"
         FROM ATT_EV_BASE EV
         LEFT JOIN ATT_REA_BASE REA ON EV.OBJ_CODE=REA.REA_CODE AND EV.OBJ_TYPE='REA'
@@ -38,7 +40,52 @@
         WHERE EV.TO_DATE IS NULL AND REA.EXPR_DATE IS NULL AND LKS.EXPR_DATE IS NULL AND RER.EXPR_DATE IS NULL AND AD.EXPR_DATE IS NULL AND EV.SOURCE_TYPE='3'
         <if test="adCode != null and adCode != ''">AND EV.AD_CODE=#{adCode}</if>
         <if test="evType != null and evType != ''">AND EV.EV_TYPE=#{evType}</if>
+        <if test="objectType != null and objectType != ''">AND EV.OBJ_TYPE=#{objectType}</if>
+        <if test="status != null and status != ''">AND EV.STATUS=#{status}</if>
         <if test="keyWord != null and keyWord != ''">AND (REA.REA_NAME LIKE '%'||#{keyWord}||'%' OR AD.AD_NAME LIKE '%'||#{keyWord}||'%' OR EV.EV_DESC LIKE '%'||#{keyWord}||'%')</if>
         ORDER BY EV.FIND_TS DESC
     </select>
+    <insert id="insertEvent" parameterType="com.goldenwater.hzz.domain.EventDTO">
+        INSERT INTO ATT_EV_BASE(GUID, EV_CODE, AD_CODE, OBJ_TYPE, OBJ_CODE, EV_TYPE, EV_DESC, LOC, STATUS, DEAL_DESC, FIND_TS, DONE_DATE, REPO_NAME, SOURCE_TYPE, TO_DATE)
+        VALUES(
+            SYS_GUID(),
+            'EV'||TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS'),
+            #{adCode},
+            #{objType},
+            #{objCode},
+            #{evType},
+            #{eventDesc},
+            #{eventAddress},
+            #{status},
+            #{dealDesc},
+            TO_DATE(#{findTs},'YYYY-MM-DD'),
+            <choose>
+                <when test="doneDate != null and doneDate != ''">TO_DATE(#{doneDate},'YYYY-MM-DD')</when>
+                <otherwise>NULL</otherwise>
+            </choose>,
+            #{userName},
+            '3',
+            NULL
+        )
+    </insert>
+    <update id="updateEvent" parameterType="com.goldenwater.hzz.domain.EventDTO">
+        UPDATE ATT_EV_BASE
+        SET AD_CODE = #{adCode},
+            OBJ_TYPE = #{objType},
+            OBJ_CODE = #{objCode},
+            EV_TYPE = #{evType},
+            EV_DESC = #{eventDesc},
+            LOC = #{eventAddress},
+            STATUS = #{status},
+            DEAL_DESC = #{dealDesc},
+            FIND_TS = TO_DATE(#{findTs},'YYYY-MM-DD'),
+            DONE_DATE = <choose>
+                <when test="doneDate != null and doneDate != ''">TO_DATE(#{doneDate},'YYYY-MM-DD')</when>
+                <otherwise>NULL</otherwise>
+            </choose>
+        WHERE GUID = #{guid}
+    </update>
+    <delete id="deleteEvent" parameterType="java.lang.String">
+        DELETE FROM ATT_EV_BASE WHERE GUID = #{guid}
+    </delete>
 </mapper>

+ 2 - 2
gw-hzz/src/main/resources/mapper/hzz/RiverProjectMapper.xml

@@ -18,10 +18,10 @@
     <select id="getShxmById" resultType="com.goldenwater.hzz.domain.RiverProjectDTO">SELECT * FROM GW_RIVER_PROJECT WHERE GUID=#{guid}</select>
     <insert id="saveShxm" parameterType="java.util.Map">
         INSERT INTO GW_RIVER_PROJECT(GUID,S_LINKMAN,S_UP_OLD,S_POST,S_PI,S_PN,S_X_BD,S_PS,S_PGOA_NAME,S_Y_BD,S_FAX,S_R_MAN,S_DS,S_DU,N_ID,S_R_DATE,S_DEPT,S_P_BUILD_STAGE,S_PHONE,S_LOCATION,S_UP,S_TYPE,S_PGOA_DATE,S_CODE,S_DESIGN_NAME,S_GC_NAME,S_LIMIT_DATE,S_PBT,S_PLAN_DATE,S_GC_LOCATION,S_PROJECT_NAME,S_URL)
-        VALUES(#{guid},#{sLinkman},#{sUpOld},#{sPost},#{sPi},#{sPn},#{sXBd},#{sPs},#{sPGOAName},#{sYBd},#{sFax},#{sRMan},#{sDs},#{sDu},#{nId},TO_DATE(#{sRDate},'YYYY-MM-DD'),#{sDept},#{sPBuildStage},#{sPhone},#{sLocation},#{sUp},#{sType},TO_DATE(#{sPGOADate},'YYYY-MM-DD'),#{sCode},#{sDesignName},#{sGcName},TO_DATE(#{sLimitDate},'YYYY-MM-DD'),#{sPBT},TO_DATE(#{sPlanDate},'YYYY-MM-DD'),#{sGcLocation},#{sProjectName},#{sUrl})
+        VALUES(#{guid},#{sLinkman},#{sUpOld},#{sPost},#{sPi},#{sPn},#{sXBd},#{sPs},#{sPGOAName},#{sYBd},#{sFax},#{sRMan},#{sDs},#{sDu},#{nId},TO_DATE(SUBSTR(#{sRDate},1,10),'YYYY-MM-DD'),#{sDept},#{sPBuildStage},#{sPhone},#{sLocation},#{sUp},#{sType},TO_DATE(SUBSTR(#{sPgoaDate},1,10),'YYYY-MM-DD'),#{sCode},#{sDesignName},#{sGcName},TO_DATE(SUBSTR(#{sLimitDate},1,10),'YYYY-MM-DD'),#{sPBT},TO_DATE(SUBSTR(#{sPlanDate},1,10),'YYYY-MM-DD'),#{sGcLocation},#{sProjectName},#{sUrl})
     </insert>
     <update id="editShxm" parameterType="java.util.Map">
-        UPDATE GW_RIVER_PROJECT SET S_LINKMAN=#{sLinkman},S_PROJECT_NAME=#{sProjectName},S_DEPT=#{sDept},S_LOCATION=#{sLocation},S_TYPE=#{sType},S_P_BUILD_STAGE=#{sPBuildStage},S_PHONE=#{sPhone},S_PGOA_DATE=TO_DATE(#{sPGOADate},'YYYY-MM-DD'),S_URL=#{sUrl} WHERE GUID=#{guid}
+        UPDATE GW_RIVER_PROJECT SET S_LINKMAN=#{sLinkman},S_PROJECT_NAME=#{sProjectName},S_DEPT=#{sDept},S_LOCATION=#{sLocation},S_TYPE=#{sType},S_P_BUILD_STAGE=#{sPBuildStage},S_PHONE=#{sPhone},S_PGOA_DATE=TO_DATE(SUBSTR(#{sPgoaDate},1,10),'YYYY-MM-DD'),S_URL=#{sUrl} WHERE GUID=#{guid}
     </update>
     <delete id="deleteShxm">DELETE FROM GW_RIVER_PROJECT WHERE GUID=#{guid}</delete>
     <select id="getFilesById" resultType="com.goldenwater.hzz.domain.RiverProjectDTO">SELECT GUID AS "guid",PRO_ID AS "proId",URL AS "url" FROM GW_RIVER_PROJECT_FILE WHERE PRO_ID=#{guid}</select>

+ 32 - 0
gw-hzz/src/main/resources/mapper/hzz/RiverSectionMapper.xml

@@ -0,0 +1,32 @@
+<?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.goldenwater.hzz.mapper.RiverSectionMapper">
+    <select id="listByType" resultType="com.goldenwater.hzz.domain.RiverSectionDTO">
+        <choose>
+            <when test="objType == 'REA'">
+                SELECT REA_CODE AS "code", REA_NAME AS "name", 'REA' AS "objType"
+                FROM ATT_REA_BASE
+                <where>
+                    <if test="name != null and name != ''">REA_NAME LIKE '%'||#{name}||'%'</if>
+                </where>
+            </when>
+            <when test="objType == 'LKS'">
+                SELECT LKS_CODE AS "code", LKS_NAME AS "name", 'LKS' AS "objType"
+                FROM ATT_LKS_BASE
+                <where>
+                    <if test="name != null and name != ''">LKS_NAME LIKE '%'||#{name}||'%'</if>
+                </where>
+            </when>
+            <when test="objType == 'RER'">
+                SELECT RER_CODE AS "code", RER_NAME AS "name", 'RER' AS "objType"
+                FROM ATT_RER_BASE
+                <where>
+                    <if test="name != null and name != ''">RER_NAME LIKE '%'||#{name}||'%'</if>
+                </where>
+            </when>
+            <otherwise>
+                SELECT '1' AS "code", '1' AS "name", 'NONE' AS "objType" FROM DUAL WHERE 1 = 0
+            </otherwise>
+        </choose>
+    </select>
+</mapper>

+ 18 - 0
gw-hzz/src/main/resources/mapper/hzz/ShorelineMapper.xml

@@ -3,5 +3,23 @@
 <mapper namespace="com.goldenwater.hzz.mapper.ShorelineMapper">
     <select id="getWaterLine" resultType="com.goldenwater.hzz.domain.ShorelineDTO">
         SELECT TYPE AS "type", BELONG AS "belong", LINELENG AS "lineLeng", LINEGN AS "lineGn", COUNT AS "count" FROM HZZ_LINELENG
+        ORDER BY TYPE, BELONG
     </select>
+
+    <insert id="insertLine" parameterType="com.goldenwater.hzz.domain.ShorelineDTO">
+        INSERT INTO HZZ_LINELENG(TYPE, BELONG, LINELENG, LINEGN, COUNT)
+        VALUES(#{type}, #{belong}, #{lineLeng}, #{lineGn}, #{count})
+    </insert>
+
+    <update id="updateLine" parameterType="com.goldenwater.hzz.domain.ShorelineDTO">
+        UPDATE HZZ_LINELENG
+        SET LINELENG = #{lineLeng},
+            LINEGN = #{lineGn},
+            COUNT = #{count}
+        WHERE TYPE = #{type} AND BELONG = #{belong}
+    </update>
+
+    <delete id="deleteLine" parameterType="com.goldenwater.hzz.domain.ShorelineDTO">
+        DELETE FROM HZZ_LINELENG WHERE TYPE = #{type} AND BELONG = #{belong}
+    </delete>
 </mapper>

+ 170 - 15
gw-hzz/src/main/resources/mapper/hzz/SupervisionMapper.xml

@@ -1,19 +1,174 @@
 <?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.goldenwater.hzz.mapper.SupervisionMapper">
-    <select id="getSupervisionList" resultType="com.goldenwater.hzz.domain.SupervisionInfoDTO">SELECT *
-                                                                                               FROM ATT_COUNCILOR_ASSESS</select>
-    <select id="getAttachmentByGuid" resultType="com.goldenwater.hzz.domain.SupervisionInfoDTO">SELECT *
-                                                                                                FROM GW_SUPERVISION_ATTACHMENT
-                                                                                                WHERE SUPERVISION_GUID = #{guid}</select>
-    <select id="getDivisionByGuid" resultType="com.goldenwater.hzz.domain.SupervisionInfoDTO">SELECT *
-                                                                                              FROM GW_SUPERVISION_DIVISION
-                                                                                              WHERE SUPERVISION_GUID = #{guid}</select>
-    <select id="getResultByGuid" resultType="com.goldenwater.hzz.domain.SupervisionInfoDTO">SELECT *
-                                                                                            FROM GW_SUPERVISION_RESULT
-                                                                                            WHERE SUPERVISION_GUID = #{guid}</select>
-    <update id="audit">UPDATE GW_SUPERVISION_INFO
-                       SET STATUS=#{audit},
-                           AUDIT_INFO=#{auditInfo}
-                       WHERE GUID = #{guid}</update>
+
+    <!--
+      河湖管理督察(督导检查)
+        主表     ATT_COUNCILOR_ASSESS      督察任务,主键 CR_ID,字段以 CR_ 开头
+        审核扩展 GW_SUPERVISION_INFO       GUID = 主表 CR_ID,STATUS 审核结果、AUDIT_INFO 审核意见
+        子表     GW_SUPERVISION_ATTACHMENT 附件   SUPERVISION_GUID = 主表 CR_ID
+                 GW_SUPERVISION_DIVISION   分工   SUPERVISION_GUID = 主表 CR_ID
+                 GW_SUPERVISION_RESULT     结果   SUPERVISION_GUID = 主表 CR_ID
+    -->
+
+    <!-- 督察任务列表:主表 + 审核扩展表 + 三张子表数量统计 -->
+    <select id="getSupervisionList" resultType="com.goldenwater.hzz.domain.SupervisionInfoDTO">
+        SELECT A.*,
+               A.CR_ID          AS "guid",
+               S.STATUS         AS "auditStatus",
+               S.AUDIT_INFO     AS "auditInfo",
+               (SELECT COUNT(1) FROM GW_SUPERVISION_ATTACHMENT F WHERE F.SUPERVISION_GUID = A.CR_ID) AS "attachmentCount",
+               (SELECT COUNT(1) FROM GW_SUPERVISION_DIVISION D WHERE D.SUPERVISION_GUID = A.CR_ID)   AS "divisionCount",
+               (SELECT COUNT(1) FROM GW_SUPERVISION_RESULT R WHERE R.SUPERVISION_GUID = A.CR_ID)     AS "resultCount"
+        FROM ATT_COUNCILOR_ASSESS A
+                 LEFT JOIN GW_SUPERVISION_INFO S ON S.GUID = A.CR_ID
+        <where>
+            <if test="crCode != null and crCode != ''">AND A.CR_CODE LIKE '%'||#{crCode}||'%'</if>
+            <if test="crName != null and crName != ''">AND A.CR_NAME LIKE '%'||#{crName}||'%'</if>
+            <if test="crType != null and crType != ''">AND A.CR_TYPE = #{crType}</if>
+            <if test="crState != null and crState != ''">AND A.CR_STATE = #{crState}</if>
+            <if test="keyWord != null and keyWord != ''">
+                AND (A.CR_CODE LIKE '%'||#{keyWord}||'%' OR A.CR_NAME LIKE '%'||#{keyWord}||'%' OR A.CR_CONTENT LIKE '%'||#{keyWord}||'%')
+            </if>
+        </where>
+        ORDER BY A.CR_CDATE DESC NULLS LAST
+    </select>
+
+    <!-- 督察任务详情(含审核信息) -->
+    <select id="getSupervisionByGuid" resultType="com.goldenwater.hzz.domain.SupervisionInfoDTO">
+        SELECT A.*,
+               A.CR_ID      AS "guid",
+               S.STATUS     AS "auditStatus",
+               S.AUDIT_INFO AS "auditInfo"
+        FROM ATT_COUNCILOR_ASSESS A
+                 LEFT JOIN GW_SUPERVISION_INFO S ON S.GUID = A.CR_ID
+        WHERE A.CR_ID = #{guid}
+    </select>
+
+    <!-- 附件:子表关联主表,带出督察编号/名称 -->
+    <select id="getAttachmentByGuid" resultType="java.util.LinkedHashMap">
+        SELECT F.*
+        FROM GW_SUPERVISION_ATTACHMENT F
+                 LEFT JOIN ATT_COUNCILOR_ASSESS A ON A.CR_ID = F.SUPERVISION_GUID
+        WHERE F.SUPERVISION_GUID = #{guid}
+    </select>
+
+    <!-- 分工 -->
+    <select id="getDivisionByGuid" resultType="java.util.LinkedHashMap">
+        SELECT D.*
+        FROM GW_SUPERVISION_DIVISION D
+                 LEFT JOIN ATT_COUNCILOR_ASSESS A ON A.CR_ID = D.SUPERVISION_GUID
+        WHERE D.SUPERVISION_GUID = #{guid}
+    </select>
+
+    <!-- 结果 -->
+    <select id="getResultByGuid" resultType="java.util.LinkedHashMap">
+        SELECT R.*
+        FROM GW_SUPERVISION_RESULT R
+                 LEFT JOIN ATT_COUNCILOR_ASSESS A ON A.CR_ID = R.SUPERVISION_GUID
+        WHERE R.SUPERVISION_GUID = #{guid}
+    </select>
+
+    <!-- 审核:写入审核扩展表,无记录时插入(GUID 与主表 CR_ID 一一对应) -->
+    <update id="audit">
+        MERGE INTO GW_SUPERVISION_INFO T
+        USING (SELECT #{guid} AS GUID FROM DUAL) S
+        ON (T.GUID = S.GUID)
+        WHEN MATCHED THEN
+            UPDATE SET T.STATUS = #{audit}, T.AUDIT_INFO = #{auditInfo}
+        WHEN NOT MATCHED THEN
+            INSERT (GUID, STATUS, AUDIT_INFO) VALUES (S.GUID, #{audit}, #{auditInfo})
+    </update>
+
+    <!-- 审核后回写主表业务状态:9 已通过 / 8 已退回 -->
+    <update id="updateAssessState">
+        UPDATE ATT_COUNCILOR_ASSESS
+        SET CR_STATE = #{crState}
+        WHERE CR_ID = #{guid}
+    </update>
+
+    <!-- 新增督察任务 -->
+    <insert id="insertAssess" parameterType="com.goldenwater.hzz.domain.SupervisionInfoDTO">
+        INSERT INTO ATT_COUNCILOR_ASSESS
+            (CR_ID, CR_CODE, CR_NAME, CR_TYPE, CR_ST_DATE, CR_ET_DATE, CR_CONTENT, CR_STATE, CR_CUSER_ID, CR_CDATE, CR_UDATE)
+        VALUES
+            (SYS_GUID(),
+             #{crCode},
+             #{crName},
+             #{crType},
+             <choose>
+                 <when test="crStDate != null and crStDate != ''">TO_DATE(#{crStDate},'YYYY-MM-DD')</when>
+                 <otherwise>NULL</otherwise>
+             </choose>,
+             <choose>
+                 <when test="crEtDate != null and crEtDate != ''">TO_DATE(#{crEtDate},'YYYY-MM-DD')</when>
+                 <otherwise>NULL</otherwise>
+             </choose>,
+             #{crContent},
+             #{crState},
+             #{crCuserId},
+             SYSDATE,
+             SYSDATE)
+    </insert>
+
+    <!-- 修改督察任务 -->
+    <update id="updateAssess" parameterType="com.goldenwater.hzz.domain.SupervisionInfoDTO">
+        UPDATE ATT_COUNCILOR_ASSESS
+        SET CR_CODE   = #{crCode},
+            CR_NAME   = #{crName},
+            CR_TYPE   = #{crType},
+            CR_ST_DATE = <choose>
+                            <when test="crStDate != null and crStDate != ''">TO_DATE(#{crStDate},'YYYY-MM-DD')</when>
+                            <otherwise>NULL</otherwise>
+                         </choose>,
+            CR_ET_DATE = <choose>
+                            <when test="crEtDate != null and crEtDate != ''">TO_DATE(#{crEtDate},'YYYY-MM-DD')</when>
+                            <otherwise>NULL</otherwise>
+                         </choose>,
+            CR_CONTENT = #{crContent},
+            CR_STATE   = #{crState},
+            CR_UDATE   = SYSDATE
+        WHERE CR_ID = #{guid}
+    </update>
+
+    <!-- 删除督察任务(主表,子表由 Service 级联删除) -->
+    <delete id="deleteAssess">
+        DELETE FROM ATT_COUNCILOR_ASSESS WHERE CR_ID = #{guid}
+    </delete>
+    <delete id="deleteInfoByGuid">
+        DELETE FROM GW_SUPERVISION_INFO WHERE GUID = #{guid}
+    </delete>
+
+    <!-- 附件子表:先删后插(覆盖保存) -->
+    <delete id="deleteAttachmentByGuid">
+        DELETE FROM GW_SUPERVISION_ATTACHMENT WHERE SUPERVISION_GUID = #{guid}
+    </delete>
+    <insert id="insertAttachment" parameterType="java.util.Map">
+        INSERT INTO GW_SUPERVISION_ATTACHMENT
+            (GUID, SUPERVISION_GUID, FILE_NAME, FILE_PATH, FILE_TYPE, FILE_SIZE, REMARK, CREATE_TIME)
+        VALUES
+            (SYS_GUID(), #{supervisionGuid}, #{fileName}, #{filePath}, #{fileType}, #{fileSize}, #{remark}, SYSDATE)
+    </insert>
+
+    <!-- 分工子表:先删后插(覆盖保存) -->
+    <delete id="deleteDivisionByGuid">
+        DELETE FROM GW_SUPERVISION_DIVISION WHERE SUPERVISION_GUID = #{guid}
+    </delete>
+    <insert id="insertDivision" parameterType="java.util.Map">
+        INSERT INTO GW_SUPERVISION_DIVISION
+            (GUID, SUPERVISION_GUID, DEPT_NAME, PERSON_NAME, TASK_DESC, REMARK, CREATE_TIME)
+        VALUES
+            (SYS_GUID(), #{supervisionGuid}, #{deptName}, #{personName}, #{taskDesc}, #{remark}, SYSDATE)
+    </insert>
+
+    <!-- 结果子表:先删后插(覆盖保存) -->
+    <delete id="deleteResultByGuid">
+        DELETE FROM GW_SUPERVISION_RESULT WHERE SUPERVISION_GUID = #{guid}
+    </delete>
+    <insert id="insertResult" parameterType="java.util.Map">
+        INSERT INTO GW_SUPERVISION_RESULT
+            (GUID, SUPERVISION_GUID, FIND_DESC, RESULT_DESC, STATUS, REMARK, CREATE_TIME)
+        VALUES
+            (SYS_GUID(), #{supervisionGuid}, #{findDesc}, #{resultDesc}, #{status}, #{remark}, SYSDATE)
+    </insert>
 </mapper>

+ 1 - 1
gw-ui/.env.development

@@ -11,4 +11,4 @@ VITE_APP_BASE_TITLE = '/hhgl'
 VITE_SERVICE_BASE_TITLE = '/gw-api'
 
 # 后端接口基础路径
-VITE_SERVER_URL = 'http://127.0.0.1:8080/'
+VITE_SERVER_URL = 'http://127.0.0.1:8088/'

+ 1 - 1
gw-ui/.env.production

@@ -6,7 +6,7 @@ VITE_APP_ENV = 'production'
 #vue启动端口
 VITE_APP_PORT = 25022
 # 前端基础路径
-VITE_APP_BASE_TITLE = '/gw'
+VITE_APP_BASE_TITLE = '/hhgl'
 # 太湖流域河湖管理系统/生产环境
 VITE_SERVICE_BASE_TITLE = '/gw-api'
 

+ 1 - 1
gw-ui/.env.staging

@@ -7,7 +7,7 @@ VITE_APP_ENV = 'staging'
 #vue启动端口
 VITE_APP_PORT = 25022
 # 前端基础路径
-VITE_APP_BASE_TITLE = '/gw'
+VITE_APP_BASE_TITLE = '/hhgl'
 
 # 太湖流域河湖管理系统/生产环境
 VITE_SERVICE_BASE_TITLE = '/gw-api'

+ 12 - 0
gw-ui/src/api/hzz/eventclear.js

@@ -6,3 +6,15 @@ export function listEventClear(query) {
 export function searchEventClear(data, pageNum, pageSize) {
   return request({ url: '/hzz/eventclear/search', method: 'post', params: { pageNum, pageSize }, data })
 }
+export function saveEventClear(data) {
+  return request({ url: '/hzz/eventclear/save', method: 'post', data })
+}
+export function updateEventClear(data) {
+  return request({ url: '/hzz/eventclear/update', method: 'post', data })
+}
+export function removeEventClear(guid) {
+  return request({ url: `/hzz/eventclear/delete/${guid}`, method: 'post' })
+}
+export function listRiverSection(objType, name) {
+  return request({ url: '/hzz/riversection/list', method: 'get', params: { objType, name }, timeout: 6 * 1000 * 5 })
+}

+ 29 - 22
gw-ui/src/api/hzz/rule.js

@@ -2,52 +2,59 @@ import request from '@/utils/request'
 
 // 将大写字段转换为小写驼峰格式
 function convertToCamelCase(data) {
-  if (!data || !Array.isArray(data)) return data
-  return data.map(item => {
-    const converted = {}
-    for (const key in item) {
-      if (item.hasOwnProperty(key)) {
-        // 将大写下划线格式转换为小写驼峰格式
-        const camelKey = key.toLowerCase().replace(/_([a-z])/g, (match, letter) => letter.toUpperCase())
-        converted[camelKey] = item[key]
-      }
-    }
-    return converted
-  })
+    if (!data || !Array.isArray(data)) return data
+    return data.map(item => {
+        const converted = {}
+        for (const key in item) {
+            if (item.hasOwnProperty(key)) {
+                // 将大写下划线格式转换为小写驼峰格式
+                const camelKey = key.toLowerCase().replace(/_([a-z])/g, (match, letter) => letter.toUpperCase())
+                converted[camelKey] = item[key]
+            }
+        }
+        return converted
+    })
 }
 
 // ==================== 制度规则 ====================
 export function listRule(adCode, ruleType) {
-  return request({ url: '/hzz/rule/list', method: 'get', params: { adCode, ruleType } })
+    return request({url: '/hzz/rule/list', method: 'get', params: {adCode, ruleType}, timeout: 60 * 1000 * 5})
 }
 
 // ==================== 制度文件 ====================
 export function listFile(query) {
-  return request({ url: '/hzz/rule/file/list', method: 'get', params: query })
+    return request({url: '/hzz/rule/file/list', method: 'get', params: query})
 }
+
 export function addFile(data) {
-  return request({ url: '/hzz/rule/file', method: 'post', data })
+    return request({url: '/hzz/rule/file', method: 'post', data})
 }
+
 export function updateFile(data) {
-  return request({ url: '/hzz/rule/file', method: 'put', data })
+    return request({url: '/hzz/rule/file', method: 'put', data})
 }
+
 export function delFile(guid) {
-  return request({ url: '/hzz/rule/file/' + guid, method: 'delete' })
+    return request({url: '/hzz/rule/file/' + guid, method: 'delete'})
 }
 
 // ==================== 工作动态 ====================
 export function listArticle(query) {
-  return request({ url: '/hzz/rule/article/list', method: 'get', params: query })
+    return request({url: '/hzz/rule/article/list', method: 'get', params: query})
 }
+
 export function getArticleTop5(type) {
-  return request({ url: '/hzz/rule/article/top5', method: 'get', params: { type } })
+    return request({url: '/hzz/rule/article/top5', method: 'get', params: {type}})
 }
+
 export function addArticle(data) {
-  return request({ url: '/hzz/rule/article', method: 'post', data })
+    return request({url: '/hzz/rule/article', method: 'post', data})
 }
+
 export function updateArticle(data) {
-  return request({ url: '/hzz/rule/article', method: 'put', data })
+    return request({url: '/hzz/rule/article', method: 'put', data})
 }
+
 export function delArticle(guid) {
-  return request({ url: '/hzz/rule/article/' + guid, method: 'delete' })
+    return request({url: '/hzz/rule/article/' + guid, method: 'delete'})
 }

+ 12 - 0
gw-ui/src/api/hzz/shoreline.js

@@ -3,3 +3,15 @@ import request from '@/utils/request'
 export function getShorelineStats() {
   return request({ url: '/hzz/shoreline/stats', method: 'get' })
 }
+export function listShoreline() {
+  return request({ url: '/hzz/shoreline/list', method: 'get' })
+}
+export function saveShoreline(data) {
+  return request({ url: '/hzz/shoreline/save', method: 'post', data })
+}
+export function updateShoreline(data) {
+  return request({ url: '/hzz/shoreline/update', method: 'post', data })
+}
+export function removeShoreline(data) {
+  return request({ url: '/hzz/shoreline/delete', method: 'post', data })
+}

+ 22 - 0
gw-ui/src/api/hzz/supervision.js

@@ -9,3 +9,25 @@ export function getSupervisionDetail(guid) {
 export function auditSupervision(guid, audit, auditInfo) {
   return request({ url: '/hzz/supervision/audit', method: 'post', params: { guid, audit, auditInfo } })
 }
+
+// 新增 / 修改 / 删除督察任务
+export function addSupervision(data) {
+  return request({ url: '/hzz/supervision/save', method: 'post', data })
+}
+export function updateSupervision(data) {
+  return request({ url: '/hzz/supervision/update', method: 'put', data })
+}
+export function delSupervision(guid) {
+  return request({ url: '/hzz/supervision/delete/' + guid, method: 'delete' })
+}
+
+// 覆盖保存 附件 / 分工 / 结果
+export function saveAttachments(guid, list) {
+  return request({ url: '/hzz/supervision/attachment/save', method: 'post', params: { guid }, data: list })
+}
+export function saveDivisions(guid, list) {
+  return request({ url: '/hzz/supervision/division/save', method: 'post', params: { guid }, data: list })
+}
+export function saveResults(guid, list) {
+  return request({ url: '/hzz/supervision/result/save', method: 'post', params: { guid }, data: list })
+}

+ 2 - 1
gw-ui/src/api/hzz/workplan.js

@@ -5,6 +5,7 @@ export function listWorkPlan(adCode) {
   return request({
     url: '/hzz/workplan/list',
     method: 'get',
-    params: { adCode }
+    params: { adCode },
+    timeout: 60 * 1000 * 5
   })
 }

+ 1 - 1
gw-ui/src/frontLayout/systemHeader.vue

@@ -22,7 +22,7 @@
             <router-link to="/user/profile">
               <el-dropdown-item>个人中心</el-dropdown-item>
             </router-link>
-            <router-link to="/hlgl/bankline">
+            <router-link to="/hzz/bankline">
               <el-dropdown-item>后台管理</el-dropdown-item>
             </router-link>
             <el-dropdown-item divided command="logout">

+ 5 - 3
gw-ui/src/frontLayout/tabViewContainerWithRouter.vue

@@ -1,9 +1,11 @@
 <template>
   <div id="tabViewContainer">
     <div id="viewsItemBar">
-      <transition name="fade-transform" mode="out-in">
-        <router-view :key="key" />
-      </transition>
+      <router-view v-slot="{ Component }">
+        <transition name="fade-transform" mode="out-in">
+          <component :is="Component" :key="key" />
+        </transition>
+      </router-view>
     </div>
   </div>
 </template>

+ 2 - 2
gw-ui/src/router/index.js

@@ -70,9 +70,9 @@ export const constantRoutes = [
     },
     // ==================== 一张图(FrontLayout) ====================
     {
-        path: '/onemap', component: FrontLayout, name: 'HzzOnemap',
+        path: '/onemap', component: FrontLayout,
         meta: {title: '一张图', icon: 'map'}, permissions: ['hzz:onemap:list'],
-        children: [{path: '', component: () => import('@/views/hlgl/onemap/index')}]
+        children: [{path: '', name: 'HzzOnemap', component: () => import('@/views/hlgl/onemap/index')}]
     },
     // ==================== 旧页面迁移(FrontLayout) ====================
     {

+ 1 - 1
gw-ui/src/utils/request.js

@@ -89,7 +89,7 @@ service.interceptors.response.use(res => {
         ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
           isRelogin.show = false
           useUserStore().logOut().then(() => {
-            location.href = "/gw/index";
+            location.href = "/hhgl/onemap";
           })
       }).catch(() => {
         isRelogin.show = false

+ 2 - 0
gw-ui/src/views/hlgl/assess/index.vue

@@ -192,6 +192,7 @@ const initCharts = () => {
           },
         ],
       });
+      c0.resize();
       window.addEventListener("resize", () => c0.resize());
     }
     if (provinceBar.value) {
@@ -234,6 +235,7 @@ const initCharts = () => {
           },
         ],
       });
+      c.resize();
       window.addEventListener("resize", () => c.resize());
     }
   });

+ 10 - 2
gw-ui/src/views/hlgl/bankline/index.vue

@@ -70,7 +70,7 @@
             <el-table-column label="日期" prop="startDate" width="120" />
             <el-table-column label="操作" width="180" fixed="right">
               <template #default="scope">
-                <el-link v-if="scope.row.url" :href="scope.row.url" target="_blank" type="primary">下载</el-link>
+                <el-button link type="info" size="small" @click="downloadAttachment(scope.row)">下载</el-button>
                 <el-button link type="primary" size="small" @click="handleEditFile(scope.row)">编辑</el-button>
                 <el-button link type="danger" size="small" @click="handleDeleteFile(scope.row)">删除</el-button>
               </template>
@@ -212,7 +212,7 @@ import FileUpload from '@/components/FileUpload'
 const loading = ref(false)
 const activeTab = ref('workplan')
 
-// ========== 左侧树 ========== 
+// ========== 左侧树 ==========
 const treeRef = ref(null)
 const treeFilter = ref('')
 const treeData = ref([])
@@ -280,6 +280,14 @@ const handleDelete = (row) => {
   })
 }
 
+const downloadAttachment = (row) => {
+  if (row.url) {
+    window.open(import.meta.env.VITE_SERVICE_BASE_TITLE + row.url, "_blank");
+  } else {
+    ElMessage.warning("该附件没有可下载的文件路径");
+  }
+};
+
 // ========== 制度文件 ==========
 const fileLoading = ref(false)
 const fileList = ref([])

+ 408 - 105
gw-ui/src/views/hlgl/eventclear/index.vue

@@ -5,64 +5,78 @@
       <el-form :model="q" :inline="true" size="default" class="search-form">
         <el-form-item label="所在河湖">
           <el-select
-            v-model="q.objectType"
-            placeholder="全部"
-            clearable
-            style="width: 130px"
-            @change="getList"
+              v-model="q.objectType"
+              placeholder="全部"
+              clearable
+              style="width: 130px"
+              @change="getList"
           >
-            <el-option label="太湖" value="0" /><el-option
-              label="望虞河"
-              value="1"
-            /><el-option label="太浦河" value="2" />
+            <el-option label="太湖" value="LKS"/>
+            <el-option
+                label="望虞河"
+                value="REA"
+            />
+            <el-option label="太浦河" value="RER"/>
           </el-select>
         </el-form-item>
         <el-form-item label="处理状态">
           <el-select
-            v-model="q.status"
-            placeholder="全部"
-            clearable
-            style="width: 110px"
-            @change="getList"
+              v-model="q.status"
+              placeholder="全部"
+              clearable
+              style="width: 110px"
+              @change="getList"
           >
-            <el-option label="待处理" value="0" /><el-option
-              label="处理中"
-              value="1"
-            /><el-option label="完成" value="2" /><el-option
-              label="完结"
-              value="3"
+            <el-option label="待处理" value="0"/>
+            <el-option
+                label="处理中"
+                value="1"
+            />
+            <el-option label="完成" value="2"/>
+            <el-option
+                label="完结"
+                value="3"
             />
           </el-select>
         </el-form-item>
         <el-form-item label="事件类型">
           <el-select
-            v-model="q.evType"
-            placeholder="全部"
-            clearable
-            style="width: 110px"
-            @change="getList"
+              v-model="q.evType"
+              placeholder="全部"
+              clearable
+              style="width: 110px"
+              @change="getList"
           >
-            <el-option label="乱占" value="1" /><el-option
-              label="乱采"
-              value="2"
-            /><el-option label="乱堆" value="3" /><el-option
-              label="乱建"
-              value="4"
-            /><el-option label="其他" value="5" />
+            <el-option label="乱占" value="1"/>
+            <el-option
+                label="乱采"
+                value="2"
+            />
+            <el-option label="乱堆" value="3"/>
+            <el-option
+                label="乱建"
+                value="4"
+            />
+            <el-option label="其他" value="5"/>
           </el-select>
         </el-form-item>
         <el-form-item label="关键词">
           <el-input
-            v-model="q.keyWord"
-            placeholder="河段名/描述"
-            clearable
-            style="width: 160px"
-            @keyup.enter="getList"
+              v-model="q.keyWord"
+              placeholder="河段名/描述"
+              clearable
+              style="width: 160px"
+              @keyup.enter="getList"
           />
         </el-form-item>
         <el-form-item>
+          <el-button type="success" icon="Plus" @click="openAdd"
+          >新增
+          </el-button
+          >
           <el-button type="primary" icon="Search" @click="getList"
-            >搜索</el-button
+          >搜索
+          </el-button
           >
           <el-button icon="Refresh" @click="resetQ">重置</el-button>
         </el-form-item>
@@ -72,28 +86,40 @@
     <!-- 表格区域 -->
     <div class="table-wrapper">
       <el-table
-        :data="list"
-        border
-        stripe
-        size="default"
-        v-loading="loading"
-        :header-cell-style="headerCellStyle"
-        class="data-table"
-        @row-click="showDetail"
+          :data="list"
+          border
+          stripe
+          size="default"
+          v-loading="loading"
+          :header-cell-style="headerCellStyle"
+          class="data-table"
+          @row-click="showDetail"
       >
-        <el-table-column type="index" label="序号" width="55" align="center" />
+        <el-table-column type="index" label="序号" width="55" align="center"/>
+        <el-table-column label="所在河湖" width="90" align="center">
+          <template #default="{ row }">
+            <el-tag
+                v-if="row.objType"
+                :type="objTypeTag(row.objType)"
+                size="small"
+                effect="plain"
+            >
+              {{ objTypeMap[row.objType] || row.objType || "-" }}
+            </el-tag>
+          </template>
+        </el-table-column>
         <el-table-column
-          prop="objectName"
-          label="河段名称"
-          show-overflow-tooltip
-          width="140"
-          align="center"
+            prop="objName"
+            label="河段名称"
+            show-overflow-tooltip
+            width="140"
+            align="center"
         />
         <el-table-column
-          prop="adName"
-          label="所属地区"
-          width="100"
-          align="center"
+            prop="adName"
+            label="所属地区"
+            width="100"
+            align="center"
         />
         <el-table-column label="事件类型" width="90" align="center">
           <template #default="{ row }">
@@ -103,11 +129,11 @@
           </template>
         </el-table-column>
         <el-table-column
-          prop="eventDesc"
-          label="问题描述"
-          show-overflow-tooltip
-          min-width="200"
-          align="center"
+            prop="eventDesc"
+            label="问题描述"
+            show-overflow-tooltip
+            min-width="180"
+            align="center"
         />
         <el-table-column label="状态" width="90" align="center">
           <template #default="{ row }">
@@ -117,43 +143,43 @@
           </template>
         </el-table-column>
         <el-table-column
-          prop="dealDesc"
-          label="整改情况"
-          show-overflow-tooltip
-          width="160"
-          align="center"
+            prop="dealDesc"
+            label="整改情况"
+            show-overflow-tooltip
+            width="160"
+            align="center"
         />
         <el-table-column
-          prop="findTs"
-          label="发现时间"
-          width="120"
-          align="center"
+            prop="findTs"
+            label="发现时间"
+            width="150"
+            align="center"
         />
         <el-table-column
-          prop="userName"
-          label="上报人"
-          width="100"
-          align="center"
+            prop="userName"
+            label="上报人"
+            width="100"
+            align="center"
         />
       </el-table>
       <div class="pagination-wrap" v-show="total > 0">
         <pagination
-          :total="total"
-          v-model:page="pageNum"
-          v-model:limit="pageSize"
-          @pagination="getList"
+            :total="total"
+            v-model:page="pageNum"
+            v-model:limit="pageSize"
+            @pagination="getList"
         />
       </div>
     </div>
 
     <!-- 详情弹窗 -->
     <el-dialog
-      v-model="dlg"
-      :title="cur?.objectName || '事件详情'"
-      width="950px"
-      top="3vh"
-      :close-on-click-modal="false"
-      class="detail-dialog"
+        v-model="dlg"
+        :title="cur?.objName || '事件详情'"
+        width="950px"
+        top="3vh"
+        :close-on-click-modal="false"
+        class="detail-dialog"
     >
       <div class="detail-grid" v-if="cur">
         <!-- 左侧信息 -->
@@ -162,7 +188,7 @@
           <div class="info-grid">
             <div class="info-item">
               <span class="info-label">河段名称</span
-              ><span class="info-value">{{ cur.objectName }}</span>
+              ><span class="info-value">{{ cur.objName }}</span>
             </div>
             <div class="info-item">
               <span class="info-label">问题描述</span
@@ -184,12 +210,20 @@
               <span class="info-label">所属省份</span
               ><span class="info-value">{{ cur.adName }}</span>
             </div>
+            <div class="info-item">
+              <span class="info-label">所在河湖</span>
+              <span class="info-value">
+                <el-tag :type="objTypeTag(cur.objType)" size="small">{{
+                    objTypeMap[cur.objType] || cur.objType || "-"
+                  }}</el-tag>
+              </span>
+            </div>
             <div class="info-item">
               <span class="info-label">事件类型</span
               ><span class="info-value">
                 <el-tag :type="evTypeTag(cur.evType)" size="small">{{
-                  evTypeMap[cur.evType]
-                }}</el-tag>
+                    evTypeMap[cur.evType]
+                  }}</el-tag>
               </span>
             </div>
             <div class="info-item">
@@ -214,12 +248,12 @@
           <div class="section-title" style="margin-top: 16px">现场图片</div>
           <div v-if="cur.images?.length" class="image-carousel">
             <el-carousel
-              height="240px"
-              indicator-position="outside"
-              arrow="always"
+                height="240px"
+                indicator-position="outside"
+                arrow="always"
             >
               <el-carousel-item v-for="(img, i) in cur.images" :key="i">
-                <img :src="img" class="carousel-img" @click="previewImg(img)" />
+                <img :src="img" class="carousel-img" @click="previewImg(img)"/>
               </el-carousel-item>
             </el-carousel>
           </div>
@@ -238,37 +272,201 @@
               <div class="check-state">{{ c.cState }}</div>
               <div v-if="c.files?.length" class="check-files">
                 <img
-                  v-for="(f, j) in c.files"
-                  :key="j"
-                  :src="f"
-                  class="check-img"
-                  @click="previewImg(f)"
+                    v-for="(f, j) in c.files"
+                    :key="j"
+                    :src="f"
+                    class="check-img"
+                    @click="previewImg(f)"
                 />
               </div>
             </div>
           </div>
-          <el-empty v-else description="暂无检查记录" :image-size="60" />
+          <el-empty v-else description="暂无检查记录" :image-size="60"/>
         </div>
       </div>
     </el-dialog>
+
+    <!-- 新增弹窗 -->
+    <el-dialog
+        v-model="addDlg"
+        title="新增清四乱事件"
+        width="640px"
+        top="5vh"
+        :close-on-click-modal="false"
+        @closed="resetForm"
+    >
+      <el-form
+          ref="formRef"
+          :model="form"
+          :rules="rules"
+          label-width="90px"
+          size="default"
+      >
+        <el-row :gutter="16">
+          <el-col :span="12">
+            <el-form-item label="所在河湖" prop="objType">
+              <el-select v-model="form.objType" style="width: 100%" @change="onObjTypeChange">
+                <el-option label="太湖" value="LKS"/>
+                <el-option label="望虞河" value="REA"/>
+                <el-option label="太浦河" value="RER"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="河段名称" prop="objCode">
+              <el-select v-model="form.objCode" style="width: 100%" placeholder="请先选择所在河湖,输入关键词搜索" :disabled="!form.objType"
+                         filterable remote reserve-keyword clearable
+                         :remote-method="remoteSections">
+                <el-option v-for="o in sectionOptions" :key="o.code" :label="o.name" :value="o.code"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="所属地区" prop="adCode">
+              <el-tree-select
+                v-model="form.adCode"
+                :props="{ value: 'adCode', label: 'adName', children: 'children' }"
+                value-key="adCode"
+                node-key="adCode"
+                lazy
+                :load="loadAdNode"
+                check-strictly
+                clearable
+                style="width: 100%"
+                placeholder="选择所属地区"
+                @change="onAdChange"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="上报人" prop="userName">
+              <el-input v-model="form.userName" placeholder="上报人"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="事件类型" prop="evType">
+              <el-select v-model="form.evType" style="width: 100%">
+                <el-option label="乱占" value="1"/>
+                <el-option label="乱采" value="2"/>
+                <el-option label="乱堆" value="3"/>
+                <el-option label="乱建" value="4"/>
+                <el-option label="其他" value="5"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="form.status" style="width: 100%">
+                <el-option label="待处理" value="0"/>
+                <el-option label="处理中" value="1"/>
+                <el-option label="完成" value="2"/>
+                <el-option label="完结" value="3"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="发现时间" prop="findTs">
+              <el-date-picker
+                  v-model="form.findTs"
+                  type="date"
+                  value-format="YYYY-MM-DD"
+                  style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="完成日期">
+              <el-date-picker
+                  v-model="form.doneDate"
+                  type="date"
+                  value-format="YYYY-MM-DD"
+                  style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="位置" prop="eventAddress">
+              <el-input v-model="form.eventAddress" placeholder="事件位置"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="问题描述" prop="eventDesc">
+              <el-input
+                  v-model="form.eventDesc"
+                  type="textarea"
+                  :rows="3"
+                  placeholder="请输入问题描述"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="整改情况">
+              <el-input
+                  v-model="form.dealDesc"
+                  type="textarea"
+                  :rows="2"
+                  placeholder="请输入整改情况"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <el-button @click="addDlg = false">取消</el-button>
+        <el-button type="primary" :loading="saving" @click="submitAdd"
+        >保存
+        </el-button
+        >
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, onMounted } from "vue";
-import { listEventClear } from "@/api/hzz/eventclear";
+import {onMounted, reactive, ref} from "vue";
+import {ElMessage} from "element-plus";
+import {listEventClear, saveEventClear, listRiverSection} from "@/api/hzz/eventclear";
+import {getChildren} from "@/api/hzz/adtree";
 
 const loading = ref(false);
 const list = ref([]);
 const total = ref(0);
 const pageNum = ref(1);
 const pageSize = ref(10);
-const q = ref({ objectType: "", status: "", evType: "", keyWord: "" });
+const q = ref({objectType: "", status: "", evType: "", keyWord: ""});
 const dlg = ref(false);
 const cur = ref(null);
 
-const evTypeMap = { 1: "乱占", 2: "乱采", 3: "乱堆", 4: "乱建", 5: "其他" };
-const statusMap = { 0: "待处理", 1: "处理中", 2: "完成", 3: "完结" };
+const addDlg = ref(false);
+const saving = ref(false);
+const formRef = ref(null);
+const form = reactive({
+  objType: "",
+  objCode: "",
+  adCode: "",
+  adName: "",
+  userName: "",
+  evType: "1",
+  status: "0",
+  findTs: "",
+  doneDate: "",
+  eventAddress: "",
+  eventDesc: "",
+  dealDesc: "",
+});
+const rules = {
+  objType: [{required: true, message: "请选择所在河湖", trigger: "change"}],
+  objCode: [{required: true, message: "请选择河段名称", trigger: "change"}],
+  adCode: [{required: true, message: "请输入所属地区", trigger: "blur"}],
+  evType: [{required: true, message: "请选择事件类型", trigger: "change"}],
+  status: [{required: true, message: "请选择状态", trigger: "change"}],
+  findTs: [{required: true, message: "请选择发现时间", trigger: "change"}],
+  eventDesc: [{required: true, message: "请输入问题描述", trigger: "blur"}],
+};
+
+const evTypeMap = {1: "乱占", 2: "乱采", 3: "乱堆", 4: "乱建", 5: "其他"};
+const statusMap = {0: "待处理", 1: "处理中", 2: "完成", 3: "完结"};
+const objTypeMap = {REA: "望虞河", LKS: "太湖", RER: "太浦河"};
 
 const headerCellStyle = {
   background: "#f5f7fa",
@@ -290,10 +488,55 @@ const evTypeTag = (type) => {
 };
 
 const statusTag = (status) => {
-  const map = { 0: "info", 1: "warning", 2: "primary", 3: "success" };
+  const map = {0: "info", 1: "warning", 2: "primary", 3: "success"};
   return map[status] || "info";
 };
 
+const objTypeTag = (type) => {
+  const map = {REA: "success", LKS: "primary", RER: "warning"};
+  return map[type] || "info";
+};
+
+const adNameMap = reactive({});
+const loadAdNode = async (node, resolve) => {
+  const code = node.level === 0 ? "000000000000" : node.data.adCode;
+  try {
+    const res = await getChildren(code);
+    const children = (res.data || []).map((i) => {
+      adNameMap[i.adCode] = i.adName;
+      return {...i, leaf: String(i.adGrad) >= "5"};
+    });
+    resolve(children);
+  } catch {
+    resolve([]);
+  }
+};
+const onAdChange = (val) => {
+  form.adCode = val;
+  form.adName = adNameMap[val] || "";
+};
+
+const sectionOptions = ref([]);
+const loadSections = async (name) => {
+  if (!form.objType) {
+    sectionOptions.value = [];
+    return;
+  }
+  try {
+    const res = await listRiverSection(form.objType, name);
+    sectionOptions.value = res.data || [];
+  } catch {
+    sectionOptions.value = [];
+  }
+};
+const remoteSections = (query) => {
+  loadSections(query);
+};
+const onObjTypeChange = () => {
+  form.objCode = "";
+  sectionOptions.value = [];
+};
+
 const getList = async () => {
   loading.value = true;
   try {
@@ -310,12 +553,41 @@ const getList = async () => {
 };
 
 const resetQ = () => {
-  q.value = { objectType: "", status: "", evType: "", keyWord: "" };
+  q.value = {objectType: "", status: "", evType: "", keyWord: ""};
   getList();
 };
 
+const openAdd = () => {
+  const d = new Date();
+  const pad = (n) => String(n).padStart(2, "0");
+  form.findTs = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
+  addDlg.value = true;
+};
+
+const resetForm = () => {
+  Object.keys(form).forEach((k) => (form[k] = ""));
+  form.evType = "1";
+  form.status = "0";
+  formRef.value?.clearValidate();
+};
+
+const submitAdd = async () => {
+  await formRef.value.validate();
+  saving.value = true;
+  try {
+    await saveEventClear({...form});
+    ElMessage.success("保存成功");
+    addDlg.value = false;
+    getList();
+  } catch (e) {
+    ElMessage.error("保存失败");
+  } finally {
+    saving.value = false;
+  }
+};
+
 const showDetail = (row) => {
-  cur.value = { ...row, images: row.images || [], checks: row.checks || [] };
+  cur.value = {...row, images: row.images || [], checks: row.checks || []};
   dlg.value = true;
 };
 
@@ -345,18 +617,22 @@ onMounted(() => getList());
   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
   flex-shrink: 0;
 }
+
 .search-form {
   display: flex;
   align-items: center;
   flex-wrap: wrap;
 }
+
 .search-form :deep(.el-form-item) {
   margin-bottom: 0;
   margin-right: 10px;
 }
+
 .search-form :deep(.el-input__wrapper) {
   border-radius: 6px;
 }
+
 .search-form :deep(.el-button) {
   border-radius: 6px;
 }
@@ -372,18 +648,22 @@ onMounted(() => getList());
   flex-direction: column;
   overflow: hidden;
 }
+
 .data-table {
   flex: 1;
   border-radius: 6px;
   overflow: hidden;
   cursor: pointer;
 }
+
 .data-table :deep(.el-table__body-wrapper) .el-table__row:hover {
   background-color: #f0f7ff !important;
 }
+
 .data-table :deep(.el-tooltip__popper) {
   max-width: 200px !important;
 }
+
 .pagination-wrap {
   padding-top: 12px;
   flex-shrink: 0;
@@ -394,27 +674,33 @@ onMounted(() => getList());
   border-radius: 12px;
   overflow: hidden;
 }
+
 .detail-dialog :deep(.el-dialog__header) {
   background: linear-gradient(135deg, #667eea, #764ba2);
   padding: 16px 24px;
   margin: 0;
   text-align: center;
 }
+
 .detail-dialog :deep(.el-dialog__title) {
   color: #fff;
   font-size: 16px;
   font-weight: 600;
 }
+
 .detail-dialog :deep(.el-dialog__headerbtn) {
   top: 16px;
 }
+
 .detail-dialog :deep(.el-dialog__close) {
   color: #fff;
   font-size: 18px;
 }
+
 .detail-dialog :deep(.el-dialog__close:hover) {
   color: #f0f0f0;
 }
+
 .detail-dialog :deep(.el-dialog__body) {
   padding: 20px 24px;
   max-height: 70vh;
@@ -426,16 +712,19 @@ onMounted(() => getList());
   display: flex;
   gap: 24px;
 }
+
 .detail-left {
   flex: 6;
   min-width: 0;
 }
+
 .detail-right {
   flex: 4;
   min-width: 0;
   border-left: 1px solid #eee;
   padding-left: 20px;
 }
+
 .section-title {
   font-size: 14px;
   font-weight: 600;
@@ -451,6 +740,7 @@ onMounted(() => getList());
   grid-template-columns: 1fr 1fr;
   gap: 8px 16px;
 }
+
 .info-item {
   display: flex;
   gap: 8px;
@@ -458,12 +748,14 @@ onMounted(() => getList());
   background: #fafbfc;
   border-radius: 6px;
 }
+
 .info-label {
   font-size: 12px;
   color: #999;
   flex-shrink: 0;
   min-width: 56px;
 }
+
 .info-value {
   font-size: 13px;
   color: #333;
@@ -475,6 +767,7 @@ onMounted(() => getList());
   border-radius: 8px;
   overflow: hidden;
 }
+
 .carousel-img {
   width: 100%;
   height: 100%;
@@ -489,6 +782,7 @@ onMounted(() => getList());
   flex-direction: column;
   gap: 10px;
 }
+
 .check-card {
   background: #fafbfc;
   border-radius: 8px;
@@ -496,35 +790,42 @@ onMounted(() => getList());
   border: 1px solid #f0f0f0;
   transition: all 0.2s;
 }
+
 .check-card:hover {
   border-color: #d6e4ff;
   background: #f5f9ff;
 }
+
 .check-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
   margin-bottom: 6px;
 }
+
 .check-person {
   font-size: 14px;
   font-weight: 600;
   color: #333;
 }
+
 .check-date {
   font-size: 12px;
   color: #999;
 }
+
 .check-state {
   font-size: 13px;
   color: #666;
   margin-bottom: 8px;
 }
+
 .check-files {
   display: flex;
   gap: 6px;
   flex-wrap: wrap;
 }
+
 .check-img {
   width: 80px;
   height: 60px;
@@ -533,9 +834,11 @@ onMounted(() => getList());
   cursor: pointer;
   transition: transform 0.2s;
 }
+
 .check-img:hover {
   transform: scale(1.05);
 }
+
 .empty-block {
   text-align: center;
   color: #bbb;

+ 273 - 51
gw-ui/src/views/hlgl/mcaf/index.vue

@@ -1,31 +1,62 @@
 <template>
   <div class="mcaf-page">
-    <el-card shadow="never">
+    <el-card style="height: 100%;" :body-style="{height: '100%'}" shadow="never">
       <template #header>一湖两河清四乱 — 数据管理</template>
       <el-form :model="q" :inline="true" size="small">
         <el-form-item label="所在河湖">
           <el-select v-model="q.objectType" placeholder="全部" clearable style="width:130px" @change="getList">
-            <el-option label="太湖" value="0"/><el-option label="望虞河" value="1"/><el-option label="太浦河" value="2"/><el-option label="其他" value="3"/>
+            <el-option label="太湖" value="LKS"/>
+            <el-option label="望虞河" value="REA"/>
+            <el-option label="太浦河" value="RER"/>
+            <el-option label="其他" value="3"/>
           </el-select>
         </el-form-item>
         <el-form-item label="状态">
           <el-select v-model="q.status" placeholder="全部" clearable style="width:110px" @change="getList">
-            <el-option label="待处理" value="0"/><el-option label="处理中" value="1"/><el-option label="完成" value="2"/><el-option label="完结" value="3"/>
+            <el-option label="待处理" value="0"/>
+            <el-option label="处理中" value="1"/>
+            <el-option label="完成" value="2"/>
+            <el-option label="完结" value="3"/>
           </el-select>
         </el-form-item>
-        <el-form-item label="关键词"><el-input v-model="q.keyWord" placeholder="搜索" clearable style="width:160px" @keyup.enter="getList"/></el-form-item>
-        <el-form-item><el-button type="primary" icon="Search" @click="getList">搜索</el-button></el-form-item>
-        <el-form-item><el-button type="success" icon="Plus" @click="addRow">新增</el-button></el-form-item>
+        <el-form-item label="关键词">
+          <el-input v-model="q.keyWord" placeholder="搜索" clearable style="width:160px" @keyup.enter="getList"/>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="getList">搜索</el-button>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="success" icon="Plus" @click="addRow">新增</el-button>
+        </el-form-item>
       </el-form>
 
-      <el-table :data="list" border size="small" v-loading="loading" @row-click="editRow">
-        <el-table-column type="index" label="xu" width="50" />
-        <el-table-column prop="objectName" label="河段名称" show-overflow-tooltip width="140" />
-        <el-table-column prop="adName" label="所属地区" width="100" />
-        <el-table-column prop="evType" label="事件类型" width="80" />
-        <el-table-column prop="eventDesc" label="问题描述" show-overflow-tooltip min-width="200" />
-        <el-table-column prop="status" label="状态" width="80" />
-        <el-table-column prop="findTs" label="发现时间" width="120" />
+      <el-table :data="list" border size="small" v-loading="loading" @row-click="editRow" height="calc(100% - 100px)">
+        <el-table-column type="index" align="center" label="序号" width="50"/>
+        <el-table-column label="所在河湖" width="90" align="center">
+          <template #default="{row}">
+            <el-tag :type="objTypeTag(row.objType)" size="small" effect="plain">
+              {{ objTypeMap[row.objType] || row.objType || '-' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="objName" label="河段名称" show-overflow-tooltip width="140"/>
+        <el-table-column prop="adName" label="所属地区" width="100"/>
+        <el-table-column label="事件类型" width="90" align="center">
+          <template #default="{row}">
+            <el-tag :type="evTypeTag(row.evType)" size="small" effect="plain">
+              {{ evTypeMap[row.evType] || row.evType || '-' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="eventDesc" label="问题描述" show-overflow-tooltip min-width="200"/>
+        <el-table-column label="状态" width="90" align="center">
+          <template #default="{row}">
+            <el-tag :type="statusTag(row.status)" size="small" effect="plain">
+              {{ statusMap[row.status] || row.status || '-' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="findTs" label="发现时间" width="120"/>
         <el-table-column label="操作" width="140" fixed="right">
           <template #default="{row}">
             <el-button link type="primary" size="small" @click.stop="editRow(row)">编辑</el-button>
@@ -33,25 +64,90 @@
           </template>
         </el-table-column>
       </el-table>
-      <pagination v-show="total>0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" @pagination="getList"/>
+      <pagination v-show="total>0" :total="total" v-model:page="pageNum" v-model:limit="pageSize"
+                  @pagination="getList"/>
     </el-card>
 
     <!-- 编辑弹窗 -->
     <el-dialog v-model="editDlg" :title="isNew?'新增事件':'编辑事件'" width="700px" top="5vh" @closed="resetForm">
       <el-form ref="fRef" :model="form" :rules="rules" label-width="100px" size="small">
         <el-row :gutter="16">
-          <el-col :span="12"><el-form-item label="河段名称" prop="objectName"><el-input v-model="form.objectName"/></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="所属地区" prop="adName"><el-input v-model="form.adName"/></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="事件类型" prop="evType">
-            <el-select v-model="form.evType" style="width:100%"><el-option label="乱占" value="1"/><el-option label="乱采" value="2"/><el-option label="乱堆" value="3"/><el-option label="乱建" value="4"/><el-option label="其他" value="5"/></el-select>
-          </el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="状态" prop="status">
-            <el-select v-model="form.status" style="width:100%"><el-option label="待处理" value="0"/><el-option label="处理中" value="1"/><el-option label="完成" value="2"/><el-option label="完结" value="3"/></el-select>
-          </el-form-item></el-col>
-          <el-col :span="24"><el-form-item label="问题描述" prop="eventDesc"><el-input v-model="form.eventDesc" type="textarea" :rows="3"/></el-form-item></el-col>
-          <el-col :span="24"><el-form-item label="整改情况" prop="dealDesc"><el-input v-model="form.dealDesc" type="textarea" :rows="2"/></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="发现时间"><el-date-picker v-model="form.findTs" type="date" value-format="YYYY-MM-DD" style="width:100%"/></el-form-item></el-col>
-          <el-col :span="12"><el-form-item label="完成时间"><el-date-picker v-model="form.doneDate" type="date" value-format="YYYY-MM-DD" style="width:100%"/></el-form-item></el-col>
+          <el-col :span="12">
+            <el-form-item label="所在河湖" prop="objType">
+              <el-select v-model="form.objType" style="width:100%" @change="onObjTypeChange">
+                <el-option label="太湖" value="LKS"/>
+                <el-option label="望虞河" value="REA"/>
+                <el-option label="太浦河" value="RER"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="河段名称" prop="objCode">
+              <el-select v-model="form.objCode" style="width:100%" placeholder="请先选择所在河湖,输入关键词搜索" :disabled="!form.objType"
+                         filterable remote reserve-keyword clearable
+                         :remote-method="remoteSections">
+                <el-option v-for="o in sectionOptions" :key="o.code" :label="o.name" :value="o.code"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="所属地区" prop="adCode">
+              <el-tree-select
+                v-model="form.adCode"
+                :props="{ value: 'adCode', label: 'adName', children: 'children' }"
+                value-key="adCode"
+                node-key="adCode"
+                lazy
+                :load="loadAdNode"
+                check-strictly
+                clearable
+                style="width: 100%"
+                placeholder="选择所属地区"
+                @change="onAdChange"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="事件类型" prop="evType">
+              <el-select v-model="form.evType" style="width:100%">
+                <el-option label="乱占" value="1"/>
+                <el-option label="乱采" value="2"/>
+                <el-option label="乱堆" value="3"/>
+                <el-option label="乱建" value="4"/>
+                <el-option label="其他" value="5"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="form.status" style="width:100%">
+                <el-option label="待处理" value="0"/>
+                <el-option label="处理中" value="1"/>
+                <el-option label="完成" value="2"/>
+                <el-option label="完结" value="3"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="问题描述" prop="eventDesc">
+              <el-input v-model="form.eventDesc" type="textarea" :rows="3"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="整改情况" prop="dealDesc">
+              <el-input v-model="form.dealDesc" type="textarea" :rows="2"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="发现时间">
+              <el-date-picker v-model="form.findTs" type="date" value-format="YYYY-MM-DD" style="width:100%"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="完成时间">
+              <el-date-picker v-model="form.doneDate" type="date" value-format="YYYY-MM-DD" style="width:100%"/>
+            </el-form-item>
+          </el-col>
         </el-row>
       </el-form>
       <template #footer>
@@ -63,35 +159,161 @@
 </template>
 
 <script setup>
-import {ref,reactive,onMounted} from 'vue'
-import {listEventClear, searchEventClear} from '@/api/hzz/eventclear'
-import {ElMessage,ElMessageBox} from 'element-plus'
+import {onMounted, reactive, ref} from 'vue'
+import {listEventClear, saveEventClear, updateEventClear, removeEventClear, listRiverSection} from '@/api/hzz/eventclear'
+import {getChildren} from '@/api/hzz/adtree'
+import {ElMessage, ElMessageBox} from 'element-plus'
+
+const objTypeMap = { REA: '望虞河', LKS: '太湖', RER: '太浦河' }
+const objTypeTag = (type) => {
+  const map = { REA: 'success', LKS: 'primary', RER: 'warning' }
+  return map[type] || 'info'
+}
+const adNameMap = reactive({})
+const loadAdNode = async (node, resolve) => {
+  const code = node.level === 0 ? '000000000000' : node.data.adCode
+  try {
+    const res = await getChildren(code)
+    const children = (res.data || []).map((i) => {
+      adNameMap[i.adCode] = i.adName
+      return {...i, leaf: String(i.adGrad) >= '5'}
+    })
+    resolve(children)
+  } catch {
+    resolve([])
+  }
+}
+const onAdChange = (val) => {
+  form.adCode = val
+  form.adName = adNameMap[val] || ''
+}
+const sectionOptions = ref([])
+const loadSections = async (name) => {
+  if (!form.objType) {
+    sectionOptions.value = []
+    return
+  }
+  try {
+    const res = await listRiverSection(form.objType, name)
+    sectionOptions.value = res.data || []
+  } catch {
+    sectionOptions.value = []
+  }
+}
+const remoteSections = (query) => {
+  loadSections(query)
+}
+const onObjTypeChange = () => {
+  form.objCode = ''
+  sectionOptions.value = []
+}
+const evTypeMap = { 1: '乱占', 2: '乱采', 3: '乱堆', 4: '乱建', 5: '其他' }
+const statusMap = { 0: '待处理', 1: '处理中', 2: '完成', 3: '完结' }
+const evTypeTag = (type) => {
+  const map = { 1: 'danger', 2: 'warning', 3: 'warning', 4: 'danger', 5: 'info' }
+  return map[type] || 'info'
+}
+const statusTag = (status) => {
+  const map = { 0: 'info', 1: 'warning', 2: 'primary', 3: 'success' }
+  return map[status] || 'info'
+}
 
-const loading=ref(false),list=ref([]),total=ref(0),pageNum=ref(1),pageSize=ref(10)
-const q=ref({objectType:'',status:'',keyWord:''})
-const editDlg=ref(false),isNew=ref(false),fRef=ref(null)
-const form=reactive({objectName:'',adName:'',evType:'1',status:'0',eventDesc:'',dealDesc:'',findTs:'',doneDate:''})
-const rules={objectName:[{required:true,message:'必填'}],eventDesc:[{required:true,message:'必填'}]}
+const loading = ref(false), list = ref([]), total = ref(0), pageNum = ref(1), pageSize = ref(10)
+const q = ref({objectType: '', status: '', keyWord: ''})
+const editDlg = ref(false), isNew = ref(false), fRef = ref(null)
+const form = reactive({
+  guid: '',
+  objType: '',
+  objCode: '',
+  adCode: '',
+  adName: '',
+  evType: '1',
+  status: '0',
+  eventDesc: '',
+  dealDesc: '',
+  findTs: '',
+  doneDate: ''
+})
+const rules = {
+  objType: [{required: true, message: '请选择所在河湖', trigger: 'change'}],
+  adCode: [{required: true, message: '请选择所属地区', trigger: 'change'}],
+  objCode: [{required: true, message: '请选择河段名称', trigger: 'change'}],
+  eventDesc: [{required: true, message: '必填'}],
+  findTs: [{required: true, message: '请选择发现时间', trigger: 'change'}]
+}
 
-const getList=async()=>{
-  loading.value=true
-  try{const r=await listEventClear({...q.value,pageNum:pageNum.value,pageSize:pageSize.value});list.value=r.rows||[];total.value=r.total||0}
-  finally{loading.value=false}
-}
-const resetForm=()=>{Object.keys(form).forEach(k=>form[k]='');form.evType='1';form.status='0'}
-const addRow=()=>{isNew.value=true;resetForm();editDlg.value=true}
-const editRow=(row)=>{isNew.value=false;Object.assign(form,row);editDlg.value=true}
-const delRow=async(row)=>{
-  await ElMessageBox.confirm('确认删除?','提示',{type:'warning'})
-  try{await searchEventClear({guid:row.guid},1,10);ElMessage.success('已删除');getList()}catch{ElMessage.error('删除失败')}
-}
-const submitForm=async()=>{
+const getList = async () => {
+  loading.value = true
+  try {
+    const r = await listEventClear({...q.value, pageNum: pageNum.value, pageSize: pageSize.value});
+    list.value = r.rows || [];
+    total.value = r.total || 0
+  } finally {
+    loading.value = false
+  }
+}
+const resetForm = () => {
+  Object.keys(form).forEach(k => form[k] = '');
+  form.evType = '1';
+  form.status = '0'
+}
+const addRow = () => {
+  isNew.value = true;
+  resetForm();
+  editDlg.value = true
+}
+const editRow = (row) => {
+  isNew.value = false;
+  Object.assign(form, row);
+  sectionOptions.value = form.objCode
+    ? [{ code: form.objCode, name: form.objName || form.objCode }]
+    : [];
+  editDlg.value = true
+}
+const delRow = async (row) => {
+  await ElMessageBox.confirm('确认删除?', '提示', {type: 'warning'})
+  try {
+    await removeEventClear(row.guid);
+    ElMessage.success('已删除');
+    getList()
+  } catch {
+    ElMessage.error('删除失败')
+  }
+}
+const submitForm = async () => {
   await fRef.value?.validate()
-  try{await searchEventClear({...form},1,10);ElMessage.success(isNew.value?'新增成功':'保存成功');editDlg.value=false;getList()}catch{ElMessage.error('操作失败')}
+  const payload = {
+    objType: form.objType,
+    objCode: form.objCode,
+    adCode: form.adCode,
+    evType: form.evType,
+    status: form.status,
+    eventDesc: form.eventDesc,
+    dealDesc: form.dealDesc,
+    findTs: form.findTs,
+    doneDate: form.doneDate
+  }
+  try {
+    if (isNew.value) {
+      await saveEventClear(payload);
+      ElMessage.success('新增成功');
+    } else {
+      await updateEventClear({ ...payload, guid: form.guid });
+      ElMessage.success('保存成功');
+    }
+    editDlg.value = false;
+    getList()
+  } catch {
+    ElMessage.error('操作失败')
+  }
 }
-onMounted(()=>getList())
+onMounted(() => getList())
 </script>
 
 <style scoped>
-.mcaf-page{padding:16px 20px;height:calc(100vh - 84px);overflow-y:auto;background:#f0f2f5}
+.mcaf-page {
+  padding: 16px 20px;
+  height: calc(100vh - 62px);
+  background: #f0f2f5
+}
 </style>

+ 3 - 3
gw-ui/src/views/hlgl/riverproject/index.vue

@@ -341,7 +341,7 @@ const handleDelete = async (row) => {
         cancelButtonText: "取消",
       },
     );
-    await delProject(row.GUID);
+    await delProject(row.guid);
     ElMessage.success("删除成功");
     getList();
   } catch {
@@ -360,7 +360,7 @@ const submitForm = async () => {
 
   submitLoading.value = true;
   try {
-    if (form.GUID) {
+    if (form.guid) {
       await updateProject(form);
       ElMessage.success("修改成功");
     } else {
@@ -370,7 +370,7 @@ const submitForm = async () => {
     dialogVisible.value = false;
     getList();
   } catch {
-    ElMessage.error(form.GUID ? "修改失败" : "新增失败");
+    ElMessage.error(form.guid ? "修改失败" : "新增失败");
   } finally {
     submitLoading.value = false;
   }

+ 287 - 60
gw-ui/src/views/hlgl/shoreline/index.vue

@@ -1,73 +1,300 @@
 <template>
-  <div class="app-container">
-    <el-row :gutter="20">
-      <!-- 表格 -->
-      <el-col :span="24">
-        <el-card shadow="hover">
-          <template #header>
-            <span>岸线功能区统计</span>
+  <div class="shoreline-page">
+    <!-- 搜索区域 -->
+    <div class="search-wrapper">
+      <el-form :model="q" :inline="true" size="default" class="search-form">
+        <el-form-item label="河(湖)名称">
+          <el-select
+              v-model="q.type"
+              placeholder="全部"
+              clearable
+              style="width: 140px"
+              @change="getList"
+          >
+            <el-option v-for="t in typeOptions" :key="t.value" :label="t.label" :value="t.value"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="功能区">
+          <el-select
+              v-model="q.belong"
+              placeholder="全部"
+              clearable
+              style="width: 140px"
+              @change="getList"
+          >
+            <el-option v-for="b in belongOptions" :key="b.value" :label="b.label" :value="b.value"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="success" icon="Plus" @click="openAdd">新增</el-button>
+          <el-button type="primary" icon="Search" @click="getList">搜索</el-button>
+          <el-button icon="Refresh" @click="resetQ">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <!-- 表格区域 -->
+    <div class="table-wrapper">
+      <el-table
+          :data="list"
+          border
+          stripe
+          size="default"
+          v-loading="loading"
+          :header-cell-style="headerCellStyle"
+          class="data-table"
+      >
+        <el-table-column type="index" label="序号" width="60" align="center"/>
+        <el-table-column prop="belong" label="河(湖)名称" width="130" align="center">
+          <template #default="{ row }">
+            <el-tag size="small" effect="plain" :type="typeTag[row.belong] || 'info'">
+              {{ typeMap[row.belong] || row.belong || "-" }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="type" label="功能区" width="130" align="center">
+          <template #default="{ row }">
+            <el-tag size="small" effect="plain">{{ belongMap[row.type] || row.type || "-" }}</el-tag>
           </template>
-          <el-table v-loading="loading" :data="tableData" border stripe>
-            <el-table-column prop="TYPE" label="类别" width="120" />
-            <el-table-column prop="BELONG" label="所属" width="150" />
-            <el-table-column prop="LINELENG" label="岸线长度(km)" width="140" />
-            <el-table-column prop="LINEGN" label="功能区长度(km)" width="140" />
-            <el-table-column prop="COUNT" label="功能区数量" width="120" />
-          </el-table>
-        </el-card>
-      </el-col>
-
-      <!-- 图表 -->
-      <el-col :span="24" style="margin-top:20px">
-        <el-card shadow="hover">
-          <template #header>
-            <span>岸线长度分布图</span>
+        </el-table-column>
+        <el-table-column prop="lineLeng" label="岸线长度(km)" align="center">
+          <template #default="{ row }">{{ row.lineLeng || "-" }}</template>
+        </el-table-column>
+        <el-table-column prop="lineGn" label="功能区长度(km)" align="center">
+          <template #default="{ row }">{{ row.lineGn || "-" }}</template>
+        </el-table-column>
+        <el-table-column prop="count" label="功能区数量" align="center">
+          <template #default="{ row }">{{ row.count || "-" }}</template>
+        </el-table-column>
+        <el-table-column label="操作" width="160" align="center" fixed="right">
+          <template #default="{ row }">
+            <el-button type="primary" link icon="Edit" @click="openEdit(row)">编辑</el-button>
+            <el-button type="danger" link icon="Delete" @click="handleDelete(row)">删除</el-button>
           </template>
-          <div ref="chartRef" style="width:100%;height:400px" />
-        </el-card>
-      </el-col>
-    </el-row>
+        </el-table-column>
+      </el-table>
+      <el-empty v-if="!loading && list.length === 0" description="暂无数据"/>
+    </div>
+
+    <!-- 新增/编辑弹窗 -->
+    <el-dialog
+        v-model="dlg"
+        :title="isEdit ? '编辑岸线数据' : '新增岸线数据'"
+        width="520px"
+        top="8vh"
+        :close-on-click-modal="false"
+        @closed="resetForm"
+    >
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px" size="default">
+        <el-form-item label="河(湖)名称" prop="type">
+          <el-select
+              v-model="form.belong"
+              style="width: 100%"
+              :disabled="isEdit"
+              placeholder="请选择河(湖)名称"
+          >
+            <el-option v-for="t in typeOptions " :key="t.value" :label="t.label" :value="t.value"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="功能区" prop="belong">
+          <el-select
+              v-model="form.type"
+              style="width: 100%"
+              :disabled="isEdit"
+              placeholder="请选择功能区"
+          >
+            <el-option v-for="b in belongOptions" :key="b.value" :label="b.label" :value="b.value"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="岸线长度(km)" prop="lineLeng">
+          <el-input v-model="form.lineLeng" placeholder="请输入岸线长度"/>
+        </el-form-item>
+        <el-form-item label="功能区长度(km)" prop="lineGn">
+          <el-input v-model="form.lineGn" placeholder="请输入功能区长度"/>
+        </el-form-item>
+        <el-form-item label="功能区数量" prop="count">
+          <el-input v-model="form.count" placeholder="请输入功能区数量"/>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dlg = false">取消</el-button>
+        <el-button type="primary" :loading="saving" @click="submit">保存</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, onMounted, nextTick } from 'vue'
-import { getShorelineStats } from '@/api/hzz/shoreline'
-import * as echarts from 'echarts'
+import {onMounted, reactive, ref} from "vue";
+import {ElMessage, ElMessageBox} from "element-plus";
+import {listShoreline, removeShoreline, saveShoreline, updateShoreline} from "@/api/hzz/shoreline";
+
+const typeMap = {th: "太湖", wyh: "望虞河", tph: "太浦河"};
+const belongMap = {1: "保护区", 2: "保留区", 3: "控制利用区"};
+const typeOptions = ref(Object.keys(typeMap).map((t) => ({label: typeMap[t], value: t})));
+const belongOptions = ref(Object.keys(belongMap).map((b) => ({label: belongMap[b], value: b})));
+const typeTag = {th: "primary", tph: "success", wyh: "warning"};
 
-const loading = ref(false)
-const tableData = ref([])
-const chartRef = ref(null)
+const loading = ref(false);
+const list = ref([]);
+const q = ref({type: "", belong: ""});
 
-onMounted(async () => {
-  loading.value = true
+const dlg = ref(false);
+const isEdit = ref(false);
+const saving = ref(false);
+const formRef = ref(null);
+const form = reactive({
+  type: "",
+  belong: "",
+  lineLeng: "",
+  lineGn: "",
+  count: "",
+});
+
+const rules = {
+  type: [{required: true, message: "请选择河(湖)名称", trigger: "change"}],
+  belong: [{required: true, message: "请选择功能区", trigger: "change"}],
+  lineLeng: [{required: true, message: "请输入岸线长度", trigger: "blur"}],
+  lineGn: [{required: true, message: "请输入功能区长度", trigger: "blur"}],
+  count: [{required: true, message: "请输入功能区数量", trigger: "blur"}],
+};
+
+const headerCellStyle = {
+  background: "#f5f7fa",
+  color: "#333",
+  fontWeight: "600",
+  fontSize: "14px",
+  textAlign: "center",
+};
+
+const getList = async () => {
+  loading.value = true;
   try {
-    const res = await getShorelineStats()
-    tableData.value = res.data || []
-    await nextTick()
-    initChart()
+    const r = await listShoreline();
+    let data = r.data || [];
+    if (q.value.type) data = data.filter((i) => i.type === q.value.type);
+    if (q.value.belong) data = data.filter((i) => i.belong === q.value.belong);
+    list.value = data;
   } finally {
-    loading.value = false
+    loading.value = false;
   }
-})
-
-const initChart = () => {
-  if (!chartRef.value || !tableData.value.length) return
-  const chart = echarts.init(chartRef.value)
-  const categories = tableData.value.map(r => r.BELONG || r.TYPE)
-  const lineLeng = tableData.value.map(r => Number(r.LINELENG) || 0)
-  const funcLeng = tableData.value.map(r => Number(r.LINEGN) || 0)
-
-  chart.setOption({
-    tooltip: { trigger: 'axis' },
-    legend: { data: ['岸线长度(km)', '功能区长度(km)'] },
-    xAxis: { type: 'category', data: categories, axisLabel: { rotate: 30 } },
-    yAxis: { type: 'value', name: 'km' },
-    series: [
-      { name: '岸线长度(km)', type: 'bar', data: lineLeng, itemStyle: { color: '#409EFF' } },
-      { name: '功能区长度(km)', type: 'bar', data: funcLeng, itemStyle: { color: '#67C23A' } }
-    ]
-  })
-  window.addEventListener('resize', () => chart.resize())
-}
+};
+
+const resetQ = () => {
+  q.value = {type: "", belong: ""};
+  getList();
+};
+
+const openAdd = () => {
+  isEdit.value = false;
+  dlg.value = true;
+};
+
+const openEdit = (row) => {
+  isEdit.value = true;
+  Object.assign(form, {
+    type: row.type,
+    belong: row.belong,
+    lineLeng: row.lineLeng,
+    lineGn: row.lineGn,
+    count: row.count,
+  });
+  dlg.value = true;
+};
+
+const resetForm = () => {
+  Object.keys(form).forEach((k) => (form[k] = ""));
+  formRef.value?.clearValidate();
+};
+
+const submit = async () => {
+  await formRef.value.validate();
+  saving.value = true;
+  try {
+    if (isEdit.value) {
+      await updateShoreline({...form});
+      ElMessage.success("修改成功");
+    } else {
+      await saveShoreline({...form});
+      ElMessage.success("新增成功");
+    }
+    dlg.value = false;
+    getList();
+  } catch (e) {
+    ElMessage.error(isEdit.value ? "修改失败" : "新增失败");
+  } finally {
+    saving.value = false;
+  }
+};
+
+const handleDelete = (row) => {
+  ElMessageBox.confirm(
+      `确认删除「${row.type} - ${row.belong}」的岸线数据吗?`,
+      "提示",
+      {type: "warning"}
+  )
+      .then(async () => {
+        await removeShoreline({type: row.type, belong: row.belong});
+        ElMessage.success("删除成功");
+        getList();
+      })
+      .catch(() => {
+      });
+};
+
+onMounted(() => getList());
 </script>
+
+<style scoped>
+.shoreline-page {
+  height: 100%;
+  background: #f0f2f5;
+  display: flex;
+  flex-direction: column;
+  padding: 16px;
+  gap: 12px;
+  overflow: hidden;
+}
+
+/* 搜索区域 */
+.search-wrapper {
+  background: #fff;
+  padding: 16px 20px;
+  border-radius: 10px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
+  flex-shrink: 0;
+}
+
+.search-form {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.search-form :deep(.el-form-item) {
+  margin-bottom: 0;
+  margin-right: 10px;
+}
+
+.search-form :deep(.el-button) {
+  border-radius: 6px;
+}
+
+/* 表格区域 */
+.table-wrapper {
+  flex: 1;
+  background: #fff;
+  border-radius: 10px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
+  padding: 16px;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+}
+
+.data-table {
+  flex: 1;
+  border-radius: 6px;
+  overflow: hidden;
+}
+</style>

Diferenças do arquivo suprimidas por serem muito extensas
+ 792 - 75
gw-ui/src/views/hlgl/supervision/index.vue


+ 1 - 0
gw-ui/src/views/hlgl/syaxgl/index.vue

@@ -460,5 +460,6 @@ onMounted(async () => {
 .chart-box {
   flex: 1;
   min-height: 0;
+  height: 100%;
 }
 </style>

+ 41 - 4
gw-ui/src/views/hlgl/wps/index.vue

@@ -141,7 +141,22 @@
           <el-row :gutter="20">
             <el-col :span="24">
               <el-form-item label="关联项目" prop="smId">
-                <el-input v-model="form.smId" placeholder="请输入关联项目ID" />
+                <el-select
+                  v-model="form.smId"
+                  placeholder="请选择关联项目"
+                  filterable
+                  clearable
+                  style="width: 100%"
+                  :loading="projectLoading"
+                  @change="handleProjectChange"
+                >
+                  <el-option
+                    v-for="item in riverProjectOptions"
+                    :key="item.guid"
+                    :label="item.sProjectName"
+                    :value="item.guid"
+                  />
+                </el-select>
               </el-form-item>
             </el-col>
             <el-col :span="24">
@@ -209,6 +224,7 @@
 <script setup>
 import { ref, reactive, onMounted } from "vue";
 import { listWps, addWps, updateWps, delWps } from "@/api/hzz/wps";
+import { getAllProject } from "@/api/hzz/riverproject";
 import { ElMessage, ElMessageBox } from "element-plus";
 
 const showSearch = ref(true);
@@ -220,6 +236,24 @@ const pageSize = ref(10);
 const wpsList = ref([]);
 const queryParams = ref({ projectName: "", startDate: "", endDate: "" });
 
+const riverProjectOptions = ref([]);
+const projectLoading = ref(false);
+
+const getRiverProjectOptions = async () => {
+  projectLoading.value = true;
+  try {
+    const res = await getAllProject();
+    riverProjectOptions.value = res.data || [];
+  } finally {
+    projectLoading.value = false;
+  }
+};
+
+const handleProjectChange = (guid) => {
+  const selected = riverProjectOptions.value.find((item) => item.guid === guid);
+  form.sProjectName = selected ? selected.sProjectName : "";
+};
+
 const dialogVisible = ref(false);
 const dialogTitle = ref("");
 const formRef = ref(null);
@@ -281,7 +315,7 @@ const handleDelete = async (row) => {
         cancelButtonText: "取消",
       },
     );
-    await delWps(row.GUID);
+    await delWps(row.guid);
     ElMessage.success("删除成功");
     getList();
   } catch {
@@ -301,7 +335,7 @@ const submitForm = async () => {
 
   submitLoading.value = true;
   try {
-    if (form.GUID) {
+    if (form.guid) {
       await updateWps(form);
       ElMessage.success("修改成功");
     } else {
@@ -317,7 +351,10 @@ const submitForm = async () => {
   }
 };
 
-onMounted(() => getList());
+onMounted(() => {
+  getList();
+  getRiverProjectOptions();
+});
 </script>
 
 <style scoped>

+ 2 - 2
sql/gw_dm.sql

@@ -40,8 +40,8 @@ insert into sys_dept values(109,  102, '0,100,102',  '财务部门',   2, '若
 -- ----------------------------
 DROP TABLE IF EXISTS sys_user;
 create table sys_user (
-  user_id           BIGINT      not null IDENTITY(1,1)   ,
-  dept_id           BIGINT      default null              ,
+  user_id           VARCHAR2(32)      not null   ,
+  dept_id           VARCHAR2(32)      default null              ,
   user_name         VARCHAR2(30)     not null                  ,
   nick_name         VARCHAR2(30)     not null                  ,
   user_type         VARCHAR2(2)      default '00'              ,

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff