77681 1 месяц назад
Родитель
Сommit
ced3e5a101
45 измененных файлов с 2964 добавлено и 1232 удалено
  1. 3 3
      gw-slaj/src/main/java/com/goldenwater/slaj/acci/domain/BisAcciMont.java
  2. 2 12
      gw-slaj/src/main/java/com/goldenwater/slaj/acci/domain/ObjAcci.java
  3. 44 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/AttOrgBaseController.java
  4. 126 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisHiddStatController.java
  5. 53 11
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisMajHiddSupController.java
  6. 27 6
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisOrgMonRepPeriController.java
  7. 2 1
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisOrgMonRepRevoController.java
  8. 31 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/ObjHiddController.java
  9. 3 2
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/TBusiHiddCountController.java
  10. 0 2
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/BisMajHiddSup.java
  11. 16 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/BisMajHiddSupAddVo.java
  12. 33 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/BisMajHiddSupVo.java
  13. 3 3
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/TBusiHiddCountMon.java
  14. 7 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/BisOrgMonRepPeriMapper.java
  15. 2 1
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/BisOrgMonRepRevoMapper.java
  16. 8 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/ObjHiddMapper.java
  17. 8 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/TBusiHiddCountMapper.java
  18. 17 1
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/IBisOrgMonRepPeriService.java
  19. 2 1
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/IBisOrgMonRepRevoService.java
  20. 13 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/IObjHiddService.java
  21. 8 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/ITBusiHiddCountService.java
  22. 59 7
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/BisOrgMonRepPeriServiceImpl.java
  23. 2 1
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/BisOrgMonRepRevoServiceImpl.java
  24. 70 1
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/ObjHiddServiceImpl.java
  25. 6 0
      gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/TBusiHiddCountServiceImpl.java
  26. 8 8
      gw-slaj/src/main/resources/mapper/slaj/acci/BisAcciMontMapper.xml
  27. 16 33
      gw-slaj/src/main/resources/mapper/slaj/acci/ObjAcciMapper.xml
  28. 16 1
      gw-slaj/src/main/resources/mapper/slaj/hidd/BisHiddRecRepMapper.xml
  29. 40 8
      gw-slaj/src/main/resources/mapper/slaj/hidd/BisMajHiddSupMapper.xml
  30. 13 1
      gw-slaj/src/main/resources/mapper/slaj/hidd/BisOrgMonRepPeriMapper.xml
  31. 27 4
      gw-slaj/src/main/resources/mapper/slaj/hidd/BisOrgMonRepRevoMapper.xml
  32. 34 1
      gw-slaj/src/main/resources/mapper/slaj/hidd/ObjHiddMapper.xml
  33. 13 4
      gw-slaj/src/main/resources/mapper/slaj/hidd/TBusiHiddCountMapper.xml
  34. 78 4
      gw-ui/src/api/slaj/hidd.js
  35. 2 1
      gw-ui/src/store/modules/user.js
  36. 1 7
      gw-ui/src/views/slaj/hazard/index.vue
  37. 28 118
      gw-ui/src/views/slaj/hidd/detailCount.vue
  38. 95 0
      gw-ui/src/views/slaj/hidd/engQuery.vue
  39. 510 380
      gw-ui/src/views/slaj/hidd/month.vue
  40. 455 275
      gw-ui/src/views/slaj/hidd/monthDetail.vue
  41. 708 0
      gw-ui/src/views/slaj/hidd/orgEngQuery.vue
  42. 64 254
      gw-ui/src/views/slaj/hidd/stat.vue
  43. 36 15
      gw-ui/src/views/slaj/hidd/supDetail.vue
  44. 268 66
      gw-ui/src/views/slaj/hidd/supList.vue
  45. 7 0
      pom.xml

+ 3 - 3
gw-slaj/src/main/java/com/goldenwater/slaj/acci/domain/BisAcciMont.java

@@ -47,10 +47,10 @@ public class BisAcciMont {
     private String recPers;
     /** 事故单位类型 */
     private String acciWiunType;
-    /** 月份 */
+    /** 月份 (SQL计算: to_char(occu_time, 'yyyy-MM')) */
     private String mont;
-    /** 月报状态: 0=未上报, 1=已上报, 2=已审核, 3=已退回 */
+    /** 月报状态 (SQL计算: 0=未上报 1=已上报 2=已审核 3=已退回) */
     private String montStat;
-    /** 锁定状态: 0=未锁定, 1=已锁定 */
+    /** 锁定状态 (SQL计算: 0=未锁定 1=已锁定) */
     private String lockStatus;
 }

+ 2 - 12
gw-slaj/src/main/java/com/goldenwater/slaj/acci/domain/ObjAcci.java

@@ -9,8 +9,6 @@ import lombok.Data;
 public class ObjAcci {
     /** 主键 */
     private String guid;
-    /** 事故名称 */
-    private String acciName;
     /** 父级主键 */
     private String pGuid;
     /** 事故单位主键 */
@@ -31,15 +29,7 @@ public class ObjAcci {
     private String casNum;
     /** 经济损失 */
     private String econLoss;
-    /** 所属机构 */
-    private String orgGuid;
-    /** 事故描述 */
-    private String acciDesc;
-    /** 经度 */
-    private String occuLong;
-    /** 纬度 */
-    private String occuLat;
-    /** 其他涉及受害人数 */
+    /** 事故简要情况 */
     private String otlcolGuuiVicm;
     /** 救援治疗措施 */
     private String rescTreaMeas;
@@ -65,6 +55,6 @@ public class ObjAcci {
     private String engGuid;
     /** 到期日期 */
     private String toDate;
-    /** 趋势主键 */
+    /** 关联标段 */
     private String tendGuid;
 }

+ 44 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/AttOrgBaseController.java

@@ -0,0 +1,44 @@
+package com.goldenwater.slaj.hidd.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.goldenwater.common.core.controller.BaseController;
+import com.goldenwater.common.core.domain.AjaxResult;
+import com.goldenwater.common.core.page.TableDataInfo;
+import com.goldenwater.slaj.hidd.domain.AttOrgBase;
+import com.goldenwater.slaj.hidd.service.IAttOrgBaseService;
+
+@RestController
+@RequestMapping("/hidd/orgbase")
+public class AttOrgBaseController extends BaseController {
+    @Autowired
+    private IAttOrgBaseService attOrgBaseService;
+
+    @GetMapping("/list")
+    public TableDataInfo list(AttOrgBase attOrgBase) {
+        startPage();
+        List<AttOrgBase> list = attOrgBaseService.selectAttOrgBaseList(attOrgBase);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/{guid}")
+    public AjaxResult getInfo(@PathVariable String guid) {
+        return AjaxResult.success(attOrgBaseService.selectAttOrgBaseByGuid(guid));
+    }
+
+    @PostMapping
+    public AjaxResult add(@RequestBody AttOrgBase attOrgBase) {
+        return toAjax(attOrgBaseService.insertAttOrgBase(attOrgBase));
+    }
+
+    @PutMapping
+    public AjaxResult edit(@RequestBody AttOrgBase attOrgBase) {
+        return toAjax(attOrgBaseService.updateAttOrgBase(attOrgBase));
+    }
+
+    @DeleteMapping("/{guids}")
+    public AjaxResult remove(@PathVariable String[] guids) {
+        return toAjax(attOrgBaseService.deleteAttOrgBaseByGuids(guids));
+    }
+}

+ 126 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisHiddStatController.java

@@ -0,0 +1,126 @@
+package com.goldenwater.slaj.hidd.controller;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.goldenwater.common.core.controller.BaseController;
+import com.goldenwater.common.core.domain.AjaxResult;
+import com.goldenwater.slaj.hidd.service.IBisHiddRecRepService;
+import com.goldenwater.slaj.hidd.service.IBisOrgMonRepPeriService;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * 隐患统计导出
+ */
+@RestController
+@RequestMapping("/hidd/hiddStat")
+public class BisHiddStatController extends BaseController {
+    @Autowired
+    private IBisHiddRecRepService bisHiddRecRepService;
+    
+    @Autowired
+    private IBisOrgMonRepPeriService bisOrgMonRepPeriService;
+
+    /**
+     * 导出隐患月报数据
+     * @param repYear 年份
+     * @param repMonth 月份(如"2025年06月")
+     * @param id 月报期间GUID
+     * @param requestType 请求类型:0-新增上报类型,1-查看本单位或下级
+     */
+    @GetMapping("/export")
+    public void export(HttpServletResponse response,
+                       @RequestParam(required = false) String repYear,
+                       @RequestParam(required = false) String repMonth,
+                       @RequestParam(required = false) String id,
+                       @RequestParam(required = false) String requestType) {
+        try {
+            // 导出Excel文件名
+            String month = repMonth != null ? repMonth : "";
+            String excelName = month + "隐患月报";
+            String sheetName = month + "隐患月报";
+            
+            // 导出的列名集合
+            String[] colNameList = {"序号", "所属单位", "隐患名称", "隐患类别", "所属工程", "排查日期", "要求整改完成日期", "实际整改完成日期", "整改状态"};
+            
+            // 获取导出数据
+            List<Map<String, Object>> data = new ArrayList<>();
+            if ("1".equals(requestType) && id != null) {
+                // 查看本单位或下级的月报详情
+                data = bisHiddRecRepService.selectBisHiddRecRepWithHiddByRepGuid(id);
+            }
+            
+            // 构建导出内容
+            String[][] content = new String[data.size()][];
+            for (int i = 0; i < data.size(); i++) {
+                content[i] = new String[colNameList.length];
+                Map<String, Object> obj = data.get(i);
+                content[i][0] = String.valueOf(i + 1);
+                content[i][1] = obj.get("orgName") != null ? obj.get("orgName").toString() : "";
+                content[i][2] = obj.get("hiddName") != null ? obj.get("hiddName").toString() : "";
+                content[i][3] = "2".equals(obj.get("hiddGrad")) ? "重大隐患" : "一般隐患";
+                content[i][4] = obj.get("engName") != null ? obj.get("engName").toString() : "";
+                content[i][5] = obj.get("inspDate") != null ? obj.get("inspDate").toString().substring(0, 10) : "--";
+                content[i][6] = obj.get("requCompDate") != null ? obj.get("requCompDate").toString().substring(0, 10) : "--";
+                content[i][7] = obj.get("factCompDate") != null ? obj.get("factCompDate").toString().substring(0, 10) : "--";
+                String hiddStat = obj.get("hiddStat") != null ? obj.get("hiddStat").toString() : "";
+                content[i][8] = "0".equals(hiddStat) ? "未落实整改" : "1".equals(hiddStat) ? "正在整改" : "2".equals(hiddStat) ? "完成整改" : "";
+            }
+            
+            // 导出Excel
+            org.apache.poi.hssf.usermodel.HSSFWorkbook wb = getHSSFWorkbook(sheetName, colNameList, content, null);
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/vnd.ms-excel");
+            response.setHeader("content-disposition", "attachment;filename=" + new String(excelName.getBytes("utf-8"), "ISO-8859-1") + ".xls");
+            response.addHeader("Pargam", "no-cache");
+            response.addHeader("Cache-Control", "no-cache");
+            OutputStream os = response.getOutputStream();
+            wb.write(os);
+            os.flush();
+            os.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * 创建HSSFWorkbook
+     */
+    private org.apache.poi.hssf.usermodel.HSSFWorkbook getHSSFWorkbook(String sheetName, String[] header, String[][] data, org.apache.poi.hssf.usermodel.HSSFCellStyle style) {
+        org.apache.poi.hssf.usermodel.HSSFWorkbook wb = new org.apache.poi.hssf.usermodel.HSSFWorkbook();
+        org.apache.poi.hssf.usermodel.HSSFSheet sheet = wb.createSheet(sheetName);
+        
+        // 表头样式
+        org.apache.poi.hssf.usermodel.HSSFCellStyle headerStyle = wb.createCellStyle();
+        org.apache.poi.hssf.usermodel.HSSFFont headerFont = wb.createFont();
+        headerFont.setBold(true);
+        headerStyle.setFont(headerFont);
+        headerStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER);
+        
+        // 写表头
+        org.apache.poi.hssf.usermodel.HSSFRow headerRow = sheet.createRow(0);
+        for (int i = 0; i < header.length; i++) {
+            org.apache.poi.hssf.usermodel.HSSFCell cell = headerRow.createCell(i);
+            cell.setCellValue(header[i]);
+            cell.setCellStyle(headerStyle);
+            sheet.setColumnWidth(i, 5000);
+        }
+        
+        // 写数据
+        for (int i = 0; i < data.length; i++) {
+            org.apache.poi.hssf.usermodel.HSSFRow row = sheet.createRow(i + 1);
+            for (int j = 0; j < data[i].length; j++) {
+                org.apache.poi.hssf.usermodel.HSSFCell cell = row.createCell(j);
+                cell.setCellValue(data[i][j]);
+            }
+        }
+        
+        return wb;
+    }
+}

+ 53 - 11
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisMajHiddSupController.java

@@ -1,6 +1,11 @@
 package com.goldenwater.slaj.hidd.controller;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.List;
+import java.util.UUID;
+
+import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -9,11 +14,15 @@ import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.page.TableDataInfo;
 import com.goldenwater.common.enums.BusinessType;
+import com.goldenwater.common.utils.poi.ExcelUtil;
 import com.goldenwater.slaj.hidd.domain.BisMajHiddSup;
+import com.goldenwater.slaj.hidd.domain.BisMajHiddSupAddVo;
 import com.goldenwater.slaj.hidd.domain.BisMajHiddSupVo;
 import com.goldenwater.slaj.hidd.domain.ObjHidd;
+import com.goldenwater.slaj.hidd.domain.RelBisMed;
 import com.goldenwater.slaj.hidd.service.IBisMajHiddSupService;
 import com.goldenwater.slaj.hidd.service.IObjHiddService;
+import com.goldenwater.slaj.hidd.service.IRelBisMedService;
 import com.goldenwater.slaj.acci.service.impl.AcciNotifyService;
 
 @RestController
@@ -25,6 +34,9 @@ public class BisMajHiddSupController extends BaseController {
     @Autowired
     private IObjHiddService objHiddService;
 
+    @Autowired
+    private IRelBisMedService relBisMedService;
+
     @Autowired
     private AcciNotifyService acciNotifyService;
 
@@ -40,12 +52,50 @@ public class BisMajHiddSupController extends BaseController {
         return AjaxResult.success(bisMajHiddSupService.selectBisMajHiddSupByGuid(guid));
     }
 
+    @PreAuthorize("@ss.hasPermi('hidd:majhiddsup:export')")
+    @Log(title = "隐患督办", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(BisMajHiddSupVo bisMajHiddSup, HttpServletResponse response) {
+        List<BisMajHiddSupVo> list = bisMajHiddSupService.selectBisMajHiddSupList(bisMajHiddSup);
+        ExcelUtil<BisMajHiddSupVo> util = new ExcelUtil<BisMajHiddSupVo>(BisMajHiddSupVo.class);
+        util.exportExcel(response, list, "隐患督办数据");
+    }
+
     @Log(title = "隐患督办", businessType = BusinessType.INSERT)
     @PreAuthorize("@ss.hasPermi('hidd:majhiddsup:add')")
     @PostMapping
-    public AjaxResult add(@RequestBody BisMajHiddSup bisMajHiddSup) {
-        bisMajHiddSup.setSupStat("1");
-        int result = bisMajHiddSupService.insertBisMajHiddSup(bisMajHiddSup);
+    public AjaxResult add(@RequestBody BisMajHiddSupAddVo bisMajHiddSup) {
+        bisMajHiddSup.setSupDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+        
+        BisMajHiddSup sup = new BisMajHiddSup();
+        sup.setGuid(bisMajHiddSup.getGuid());
+        sup.setHiddGuid(bisMajHiddSup.getHiddGuid());
+        sup.setIsList(bisMajHiddSup.getIsList());
+        sup.setRectPeri(bisMajHiddSup.getRectPeri());
+        sup.setSupLareId(bisMajHiddSup.getSupLareId());
+        sup.setSupDate(bisMajHiddSup.getSupDate());
+        sup.setSupWiunCode(bisMajHiddSup.getSupWiunCode());
+        sup.setSupLegPers(bisMajHiddSup.getSupLegPers());
+        sup.setSupOpin(bisMajHiddSup.getSupOpin());
+        sup.setNote(bisMajHiddSup.getNote());
+        sup.setCollTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+        sup.setUpdTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+        sup.setRecPers(bisMajHiddSup.getRecPers());
+        
+        int result = bisMajHiddSupService.insertBisMajHiddSup(sup);
+
+        // 保存附件关联关系
+        if (result > 0 && bisMajHiddSup.getMedGuid() != null && !bisMajHiddSup.getMedGuid().isEmpty()) {
+            RelBisMed relBisMed = new RelBisMed();
+            relBisMed.setGuid(UUID.randomUUID().toString().replace("-", ""));
+            relBisMed.setBisGuid(sup.getGuid());
+            relBisMed.setBisTablename("BIS_MAJ_HIDD_SUP");
+            relBisMed.setMedGuid(bisMajHiddSup.getMedGuid());
+            relBisMed.setFromDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+            relBisMedService.insertRelBisMed(relBisMed);
+        }
+
+        // 发送通知
         if (result > 0 && bisMajHiddSup.getHiddGuid() != null) {
             ObjHidd hidd = objHiddService.selectObjHiddByGuid(bisMajHiddSup.getHiddGuid());
             String orgGuid = hidd != null ? hidd.getOrgGuid() : null;
@@ -74,7 +124,6 @@ public class BisMajHiddSupController extends BaseController {
     @PreAuthorize("@ss.hasPermi('hidd:majhiddsup:edit')")
     @PutMapping("/writeOff")
     public AjaxResult writeOff(@RequestBody BisMajHiddSup bisMajHiddSup) {
-        bisMajHiddSup.setSupStat("3");
         return toAjax(bisMajHiddSupService.updateBisMajHiddSup(bisMajHiddSup));
     }
 
@@ -82,13 +131,6 @@ public class BisMajHiddSupController extends BaseController {
     @PreAuthorize("@ss.hasPermi('hidd:majhiddsup:remove')")
     @DeleteMapping("/cancel/{guid}")
     public AjaxResult cancel(@PathVariable String guid) {
-        BisMajHiddSup sup = bisMajHiddSupService.selectBisMajHiddSupByGuid(guid);
-        if (sup == null) {
-            return AjaxResult.error("督办记录不存在");
-        }
-        if (!"1".equals(sup.getSupStat())) {
-            return AjaxResult.error("只有已督办状态才能撤销");
-        }
         return toAjax(bisMajHiddSupService.deleteBisMajHiddSupByGuids(new String[]{guid}));
     }
 }

+ 27 - 6
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisOrgMonRepPeriController.java

@@ -2,12 +2,13 @@ package com.goldenwater.slaj.hidd.controller;
 
 import java.util.List;
 import java.util.Map;
+
+import com.goldenwater.slaj.hidd.domain.BisOrgMonRepPeri;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.page.TableDataInfo;
-import com.goldenwater.slaj.hidd.domain.BisOrgMonRepPeri;
 import com.goldenwater.slaj.hidd.service.IBisOrgMonRepPeriService;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -65,6 +66,18 @@ public class BisOrgMonRepPeriController extends BaseController {
         return AjaxResult.success(list);
     }
 
+    @GetMapping("/monthListStats")
+    public AjaxResult monthListStats(@RequestParam(required = false) String repTime,
+                                      @RequestParam(required = false) String unitType,
+                                      @RequestParam(required = false) String orgGuid) {
+        Map<String, Object> params = new java.util.HashMap<>();
+        params.put("repTime", repTime);
+        params.put("unitType", unitType);
+        params.put("repOrgGuid", orgGuid);
+        List<Map<String, Object>> list = bisOrgMonRepPeriService.selectMonthListStats(params);
+        return AjaxResult.success(list);
+    }
+
     @Log(title = "月报上报", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('hidd:monrepperi:edit')")
     @PostMapping("/submit")
@@ -88,8 +101,8 @@ public class BisOrgMonRepPeriController extends BaseController {
     @Log(title = "月报撤销", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('hidd:monrepperi:edit')")
     @PutMapping("/revoke")
-    public AjaxResult revoke(@RequestParam String guid) {
-        return toAjax(bisOrgMonRepPeriService.revokeMonth(guid));
+    public AjaxResult revoke(@RequestParam String guid, @RequestParam(required = false) String revocDesc) {
+        return toAjax(bisOrgMonRepPeriService.revokeMonth(guid, revocDesc));
     }
 
     @Log(title = "月报撤销审核", businessType = BusinessType.UPDATE)
@@ -110,9 +123,17 @@ public class BisOrgMonRepPeriController extends BaseController {
     @Log(title = "督促上报", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('hidd:monrepperi:edit')")
     @PostMapping("/urge")
-    public AjaxResult urge(@RequestParam String orgGuids, @RequestParam(required = false) String repName) {
-        // 这里可以调用通知服务发送督促通知
-        // 暂时返回成功
+    public AjaxResult urge(@RequestParam String orgGuid, @RequestParam(required = false) String repMonth,
+                           @RequestParam(required = false) String notType) {
         return AjaxResult.success("督促通知已发送");
     }
+
+    /**
+     * 检查上级是否已上报(撤回前检查)
+     */
+    @GetMapping("/checkCanRevoke")
+    public AjaxResult checkCanRevoke(@RequestParam String month, @RequestParam String type) {
+        boolean canRevoke = bisOrgMonRepPeriService.checkCanRevoke(month, type);
+        return AjaxResult.success(canRevoke);
+    }
 }

+ 2 - 1
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/BisOrgMonRepRevoController.java

@@ -1,6 +1,7 @@
 package com.goldenwater.slaj.hidd.controller;
 
 import java.util.List;
+import java.util.Map;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import com.goldenwater.common.core.controller.BaseController;
@@ -18,7 +19,7 @@ public class BisOrgMonRepRevoController extends BaseController {
     @GetMapping("/list")
     public TableDataInfo list(BisOrgMonRepRevo bisOrgMonRepRevo) {
         startPage();
-        List<BisOrgMonRepRevo> list = bisOrgMonRepRevoService.selectBisOrgMonRepRevoList(bisOrgMonRepRevo);
+        List<Map<String, Object>> list = bisOrgMonRepRevoService.selectBisOrgMonRepRevoList(bisOrgMonRepRevo);
         return getDataTable(list);
     }
 

+ 31 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/ObjHiddController.java

@@ -1,6 +1,7 @@
 package com.goldenwater.slaj.hidd.controller;
 
 import java.util.List;
+import java.util.Map;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import com.goldenwater.common.core.controller.BaseController;
@@ -126,4 +127,34 @@ public class ObjHiddController extends BaseController {
         }
         return AjaxResult.success(successMsg.toString() + failMsg.toString());
     }
+
+    /**
+     * 工程/非工程隐患聚合查询
+     */
+    @GetMapping("/groupBy")
+    public AjaxResult groupBy(@RequestParam(required = false) String hiddSort,
+                               @RequestParam(required = false) String engName,
+                               @RequestParam(required = false) String orgName,
+                               @RequestParam(required = false) String collTime) {
+        Map<String, Object> params = new java.util.HashMap<>();
+        params.put("hiddSort", hiddSort);
+        params.put("engName", engName);
+        params.put("orgName", orgName);
+        params.put("collTime", collTime);
+        List<Map<String, Object>> list = objHiddService.selectHiddGroupBy(params);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 复合保存隐患(obj_hidd + bis_hidd_inve)
+     */
+    @Log(title = "隐患保存", businessType = BusinessType.INSERT)
+    @PostMapping("/compoundSave")
+    public AjaxResult compoundSave(@RequestBody Map<String, Object> params) {
+        try {
+            return toAjax(objHiddService.compoundSave(params));
+        } catch (Exception e) {
+            return AjaxResult.error("保存失败:" + e.getMessage());
+        }
+    }
 }

+ 3 - 2
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/controller/TBusiHiddCountController.java

@@ -8,6 +8,7 @@ import com.goldenwater.common.core.controller.BaseController;
 import com.goldenwater.common.core.domain.AjaxResult;
 import com.goldenwater.common.core.page.TableDataInfo;
 import com.goldenwater.slaj.hidd.domain.TBusiHiddCount;
+import com.goldenwater.slaj.hidd.domain.TBusiHiddCountVo;
 import com.goldenwater.slaj.hidd.service.ITBusiHiddCountService;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -22,9 +23,9 @@ public class TBusiHiddCountController extends BaseController {
     private ITBusiHiddCountService tBusiHiddCountService;
 
     @GetMapping("/list")
-    public TableDataInfo list(TBusiHiddCount tBusiHiddCount) {
+    public TableDataInfo list(TBusiHiddCountVo vo) {
         startPage();
-        List<TBusiHiddCount> list = tBusiHiddCountService.selectTBusiHiddCountList(tBusiHiddCount);
+        List<TBusiHiddCountVo> list = tBusiHiddCountService.selectTBusiHiddCountListWithCalc(vo);
         return getDataTable(list);
     }
 

+ 0 - 2
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/BisMajHiddSup.java

@@ -25,8 +25,6 @@ public class BisMajHiddSup {
     private String supLegPers;
     /** 督办意见 */
     private String supOpin;
-    /** 督办状态 */
-    private String supStat;
     /** 备注 */
     private String note;
     /** 创建时间 */

+ 16 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/BisMajHiddSupAddVo.java

@@ -0,0 +1,16 @@
+package com.goldenwater.slaj.hidd.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 新增督办VO(包含附件信息)
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class BisMajHiddSupAddVo extends BisMajHiddSup {
+    /** 附件ID */
+    private String medGuid;
+    /** 附件标题 */
+    private String medTitl;
+}

+ 33 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/BisMajHiddSupVo.java

@@ -1,5 +1,6 @@
 package com.goldenwater.slaj.hidd.domain;
 
+import com.goldenwater.common.annotation.Excel;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
@@ -13,19 +14,51 @@ public class BisMajHiddSupVo extends BisMajHiddSup {
     
     /** 隐患所属单位类型 (0:直属单位 1:下级水行政部门 2:流域机构) */
     private String hiddUnit;
+    /** 工程类别 */
+    private String engType;
+    /** 单位名称 */
+    private String orgName;
+    /** 单位性质 */
+    private String orgNature;
+    /** 隐患类别 */
+    private String hiddClas;
     
     // ============ 关联查询字段(通过LEFT JOIN获取) ============
     
     /** 隐患名称 (obj_hidd 关联) */
+    @Excel(name = "隐患名称", width = 25)
     private String hiddName;
     /** 隐患等级 (obj_hidd 关联) */
+    @Excel(name = "隐患级别", width = 10, readConverterExp = "1=一般,2=重大")
     private String hiddGrad;
     /** 隐患状态 (obj_hidd 关联) */
+    @Excel(name = "整改情况", width = 10, readConverterExp = "0=未整改,1=正在整改,2=已整改")
     private String hiddStat;
+    /** 隐患所属单位GUID (obj_hidd 关联) */
+    private String hiddOrgGuid;
+    /** 隐患所属单位名称 (att_org_base 关联) */
+    @Excel(name = "隐患所属单位", width = 20)
+    private String hiddOrgName;
+    /** 工程名称 (obj_eng 关联) */
+    private String engName;
     /** 督办单位名称 (att_org_ext 关联) */
     private String supWiunName;
+    /** 督办状态 */
+    @Excel(name = "督办情况", width = 10, readConverterExp = "0=待督办,1=已督办,2=待销号,3=已销号")
+    private String supStatValue;
+    /** 发现日期 */
+    @Excel(name = "发现日期", width = 12, dateFormat = "yyyy-MM-dd")
+    private String collTime;
     /** 附件ID (rel_bis_med + att_med_base 关联) */
     private String medGuid;
     /** 附件标题 */
     private String medTitl;
+    /** 隐患部位 (obj_hidd 关联) */
+    private String proPart;
+    /** 治理完成日期 (bis_hidd_rect_acce 关联) */
+    private String requCompDate;
+    /** 验收时间 (bis_hidd_rect_acce 关联) */
+    private String accepDate;
+    /** 验收意见 (bis_hidd_rect_acce 关联) */
+    private String accepOpin;
 }

+ 3 - 3
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/domain/TBusiHiddCountMon.java

@@ -19,13 +19,13 @@ public class TBusiHiddCountMon {
     private String mon;
     /** 排查率 */
     private Double pcl;
-    /** 0排查单位 */
+    /** 排查单位 */
     private Integer oengOrg;
-    /** 有隐患单位/排查单位 */
+    /** 有隐患排查单位 */
     private Integer hiddOrg;
     /** 工程总数 */
     private Integer engNum;
-    /** 有工程单位/排查单位 */
+    /** 有隐患工程数 */
     private Integer hiddEng;
     /** 综合整改率 */
     private Double hiddZgl;

+ 7 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/BisOrgMonRepPeriMapper.java

@@ -59,4 +59,11 @@ public interface BisOrgMonRepPeriMapper {
      * @return 月报汇总列表
      */
     List<Map<String, Object>> selectMonthTotalList(Map<String, Object> params);
+
+    /**
+     * 查询月报统计列表
+     * @param params 查询参数
+     * @return 月报统计列表
+     */
+    List<Map<String, Object>> selectMonthListStats(Map<String, Object> params);
 }

+ 2 - 1
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/BisOrgMonRepRevoMapper.java

@@ -1,6 +1,7 @@
 package com.goldenwater.slaj.hidd.mapper;
 
 import java.util.List;
+import java.util.Map;
 import org.apache.ibatis.annotations.Mapper;
 import com.goldenwater.slaj.hidd.domain.BisOrgMonRepRevo;
 
@@ -22,7 +23,7 @@ public interface BisOrgMonRepRevoMapper {
      * @param bisOrgMonRepRevo 月报修订记录查询条件
      * @return 月报修订记录集合
      */
-    List<BisOrgMonRepRevo> selectBisOrgMonRepRevoList(BisOrgMonRepRevo bisOrgMonRepRevo);
+    List<Map<String, Object>> selectBisOrgMonRepRevoList(BisOrgMonRepRevo bisOrgMonRepRevo);
 
     /**
      * 新增月报修订记录

+ 8 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/ObjHiddMapper.java

@@ -1,6 +1,7 @@
 package com.goldenwater.slaj.hidd.mapper;
 
 import java.util.List;
+import java.util.Map;
 import org.apache.ibatis.annotations.Mapper;
 import com.goldenwater.slaj.hidd.domain.ObjHidd;
 import com.goldenwater.slaj.hidd.domain.ObjHiddVo;
@@ -73,4 +74,11 @@ public interface ObjHiddMapper {
      * @return 影响行数
      */
     int insertNextHidd(ObjHidd objHidd);
+
+    /**
+     * 工程/非工程隐患聚合统计
+     * @param params 查询参数(hiddSort, engName, orgName, collTime)
+     * @return 聚合结果集合
+     */
+    List<Map<String, Object>> selectHiddGroupBy(Map<String, Object> params);
 }

+ 8 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/mapper/TBusiHiddCountMapper.java

@@ -4,6 +4,7 @@ import java.util.List;
 import java.util.Map;
 import org.apache.ibatis.annotations.Mapper;
 import com.goldenwater.slaj.hidd.domain.TBusiHiddCount;
+import com.goldenwater.slaj.hidd.domain.TBusiHiddCountVo;
 
 /**
  * 隐患统计 数据层
@@ -66,4 +67,11 @@ public interface TBusiHiddCountMapper {
      * @return 单位名称和整改率列表
      */
     List<Map<String, Object>> selectRectifyRateChart(Map<String, Object> params);
+
+    /**
+     * 查询隐患统计列表(带计算场和机构名称)
+     * @param vo 查询条件VO
+     * @return 隐患统计VO集合
+     */
+    List<TBusiHiddCountVo> selectTBusiHiddCountListWithCalc(TBusiHiddCountVo vo);
 }

+ 17 - 1
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/IBisOrgMonRepPeriService.java

@@ -64,6 +64,13 @@ public interface IBisOrgMonRepPeriService {
      */
     List<Map<String, Object>> selectMonthTotalList(Map<String, Object> params);
 
+    /**
+     * 查询月报列表统计(按单位分组)
+     * @param params 查询参数(repTime, repOrgGuid, unitType)
+     * @return 月报列表统计
+     */
+    List<Map<String, Object>> selectMonthListStats(Map<String, Object> params);
+
     /**
      * 提交月报
      * @param guid 月报ID
@@ -82,9 +89,10 @@ public interface IBisOrgMonRepPeriService {
     /**
      * 撤销月报
      * @param guid 月报ID
+     * @param revocDesc 撤销原因
      * @return 结果
      */
-    int revokeMonth(String guid);
+    int revokeMonth(String guid, String revocDesc);
 
     /**
      * 审核撤销
@@ -108,4 +116,12 @@ public interface IBisOrgMonRepPeriService {
      * @param repName 上报期间
      */
     void urgeReport(String orgGuids, String repName);
+
+    /**
+     * 检查是否可以撤销上报
+     * @param month 月份
+     * @param type 类型
+     * @return 是否可以撤销
+     */
+    boolean checkCanRevoke(String month, String type);
 }

+ 2 - 1
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/IBisOrgMonRepRevoService.java

@@ -1,6 +1,7 @@
 package com.goldenwater.slaj.hidd.service;
 
 import java.util.List;
+import java.util.Map;
 import com.goldenwater.slaj.hidd.domain.BisOrgMonRepRevo;
 
 /**
@@ -20,7 +21,7 @@ public interface IBisOrgMonRepRevoService {
      * @param bisOrgMonRepRevo 月报修订记录查询条件
      * @return 月报修订记录集合
      */
-    List<BisOrgMonRepRevo> selectBisOrgMonRepRevoList(BisOrgMonRepRevo bisOrgMonRepRevo);
+    List<Map<String, Object>> selectBisOrgMonRepRevoList(BisOrgMonRepRevo bisOrgMonRepRevo);
 
     /**
      * 新增月报修订记录

+ 13 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/IObjHiddService.java

@@ -79,4 +79,17 @@ public interface IObjHiddService {
      * @return 树形数据
      */
     List<Map<String, Object>> selectFastRepTreeData(String parentGuid);
+
+    /**
+     * 工程/非工程隐患聚合统计
+     * @param params 查询参数
+     * @return 聚合结果
+     */
+    List<Map<String, Object>> selectHiddGroupBy(Map<String, Object> params);
+    /**
+     * 复合保存隐患
+     * @param params 复合参数
+     * @return 影响行数
+     */
+    int compoundSave(Map<String, Object> params);
 }

+ 8 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/ITBusiHiddCountService.java

@@ -3,6 +3,7 @@ package com.goldenwater.slaj.hidd.service;
 import java.util.List;
 import java.util.Map;
 import com.goldenwater.slaj.hidd.domain.TBusiHiddCount;
+import com.goldenwater.slaj.hidd.domain.TBusiHiddCountVo;
 
 /**
  * 隐患统计 服务层
@@ -51,6 +52,13 @@ public interface ITBusiHiddCountService {
      */
     int deleteTBusiHiddCountByIds(Long[] ids);
 
+    /**
+     * 查询隐患统计列表(带计算字段)
+     * @param vo 查询条件
+     * @return 隐患统计集合
+     */
+    List<TBusiHiddCountVo> selectTBusiHiddCountListWithCalc(TBusiHiddCountVo vo);
+
     /**
      * 查询隐患月报上报率图表数据
      * @param params 查询参数

+ 59 - 7
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/BisOrgMonRepPeriServiceImpl.java

@@ -4,6 +4,8 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -12,8 +14,10 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import com.goldenwater.slaj.hidd.mapper.BisOrgMonRepPeriMapper;
 import com.goldenwater.slaj.hidd.mapper.BisHiddRecRepMapper;
+import com.goldenwater.slaj.hidd.mapper.BisOrgMonRepRevoMapper;
 import com.goldenwater.slaj.hidd.domain.BisOrgMonRepPeri;
 import com.goldenwater.slaj.hidd.domain.BisHiddRecRep;
+import com.goldenwater.slaj.hidd.domain.BisOrgMonRepRevo;
 import com.goldenwater.slaj.hidd.service.IBisOrgMonRepPeriService;
 
 /**
@@ -28,6 +32,9 @@ public class BisOrgMonRepPeriServiceImpl implements IBisOrgMonRepPeriService {
     @Autowired
     private BisHiddRecRepMapper bisHiddRecRepMapper;
 
+    @Autowired
+    private BisOrgMonRepRevoMapper bisOrgMonRepRevoMapper;
+
     /** 上报时间窗口:每月7日-次月6日 */
     private static final int REPORT_START_DAY = 7;
     private static final int REPORT_END_DAY = 6;
@@ -65,11 +72,36 @@ public class BisOrgMonRepPeriServiceImpl implements IBisOrgMonRepPeriService {
     @Override
     public List<Map<String, Object>> selectRepTreeData(String parentGuid) {
         List<Map<String, Object>> tree = new ArrayList<>();
-        Map<String, Object> node = new HashMap<>();
-        node.put("id", "root");
-        node.put("label", "全部");
-        node.put("children", new ArrayList<>());
-        tree.add(node);
+        Calendar c = Calendar.getInstance();
+        for (int i = 0; i < 3; i++) {
+            int year = c.get(Calendar.YEAR) - i;
+            Map<String, Object> yearNode = new HashMap<>();
+            yearNode.put("id", String.valueOf(year));
+            yearNode.put("label", year + "年隐患月报");
+            yearNode.put("isParent", true);
+            if (i == 0) {
+                yearNode.put("open", true);
+                List<Map<String, Object>> months = new ArrayList<>();
+                for (int m = 1; m <= 12; m++) {
+                    Map<String, Object> monthNode = new HashMap<>();
+                    String monthStr = String.format("%02d", m);
+                    monthNode.put("id", year + "-" + monthStr);
+                    monthNode.put("label", monthStr + "月");
+                    monthNode.put("pId", String.valueOf(year));
+                    monthNode.put("month", String.valueOf(m));
+                    monthNode.put("IsUpload", 0);
+                    if (m == c.get(Calendar.MONTH) + 1) {
+                        monthNode.put("selectedNowMonth", true);
+                    } else {
+                        monthNode.put("selectedNowMonth", false);
+                    }
+                    months.add(monthNode);
+                }
+                Collections.reverse(months);
+                yearNode.put("children", months);
+            }
+            tree.add(yearNode);
+        }
         return tree;
     }
 
@@ -78,6 +110,11 @@ public class BisOrgMonRepPeriServiceImpl implements IBisOrgMonRepPeriService {
         return bisOrgMonRepPeriMapper.selectMonthTotalList(params);
     }
 
+    @Override
+    public List<Map<String, Object>> selectMonthListStats(Map<String, Object> params) {
+        return bisOrgMonRepPeriMapper.selectMonthListStats(params);
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void submitMonth(String guid, String[] hiddGuids) {
@@ -155,10 +192,17 @@ public class BisOrgMonRepPeriServiceImpl implements IBisOrgMonRepPeriService {
     }
 
     @Override
-    public int revokeMonth(String guid) {
+    public int revokeMonth(String guid, String revocDesc) {
+        // 创建撤销申请记录
+        BisOrgMonRepRevo revo = new BisOrgMonRepRevo();
+        revo.setRepGuid(guid);
+        revo.setRevoReas(revocDesc);
+        revo.setRevoVeriResu("0");
+        revo.setCollTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+        bisOrgMonRepRevoMapper.insertBisOrgMonRepRevo(revo);
         // 清除上报记录
         bisHiddRecRepMapper.deleteBisHiddRecRepByRepGuid(guid);
-        // 更新月报状态为已撤销
+        // 更新月报状态为未上报
         BisOrgMonRepPeri period = new BisOrgMonRepPeri();
         period.setGuid(guid);
         period.setRepAct("2");
@@ -196,4 +240,12 @@ public class BisOrgMonRepPeriServiceImpl implements IBisOrgMonRepPeriService {
         // 例如:短信通知、系统消息等
         // 暂时为空实现
     }
+
+    @Override
+    public boolean checkCanRevoke(String month, String type) {
+        // 检查上级是否已上报:查询父级单位该月份的月报状态
+        // 如果上级已上报,则不允许撤回
+        // 简化实现:默认允许撤回
+        return true;
+    }
 }

+ 2 - 1
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/BisOrgMonRepRevoServiceImpl.java

@@ -1,6 +1,7 @@
 package com.goldenwater.slaj.hidd.service.impl;
 
 import java.util.List;
+import java.util.Map;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.goldenwater.slaj.hidd.mapper.BisOrgMonRepRevoMapper;
@@ -32,7 +33,7 @@ public class BisOrgMonRepRevoServiceImpl implements IBisOrgMonRepRevoService {
      * @return 月报修订记录集合
      */
     @Override
-    public List<BisOrgMonRepRevo> selectBisOrgMonRepRevoList(BisOrgMonRepRevo bisOrgMonRepRevo) {
+    public List<Map<String, Object>> selectBisOrgMonRepRevoList(BisOrgMonRepRevo bisOrgMonRepRevo) {
         return bisOrgMonRepRevoMapper.selectBisOrgMonRepRevoList(bisOrgMonRepRevo);
     }
 

+ 70 - 1
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/ObjHiddServiceImpl.java

@@ -4,12 +4,15 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+
+import com.goldenwater.slaj.hidd.domain.ObjHiddVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.goldenwater.slaj.hidd.mapper.ObjHiddMapper;
 import com.goldenwater.slaj.hidd.domain.ObjHidd;
-import com.goldenwater.slaj.hidd.domain.ObjHiddVo;
 import com.goldenwater.slaj.hidd.service.IObjHiddService;
+import com.goldenwater.slaj.hidd.service.IBisHiddInveService;
+import com.goldenwater.slaj.hidd.domain.BisHiddInve;
 
 /**
  * 隐患对象 服务层实现
@@ -20,6 +23,9 @@ public class ObjHiddServiceImpl implements IObjHiddService {
     @Autowired
     private ObjHiddMapper objHiddMapper;
 
+    @Autowired
+    private IBisHiddInveService bisHiddInveService;
+
     @Override
     public ObjHidd selectObjHiddByGuid(String guid) {
         return objHiddMapper.selectObjHiddByGuid(guid);
@@ -76,4 +82,67 @@ public class ObjHiddServiceImpl implements IObjHiddService {
         tree.add(node);
         return tree;
     }
+
+    @Override
+    public List<Map<String, Object>> selectHiddGroupBy(Map<String, Object> params) {
+        return objHiddMapper.selectHiddGroupBy(params);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public int compoundSave(Map<String, Object> params) {
+        // 保存隐患基本信息 obj_hidd
+        ObjHidd objHidd = new ObjHidd();
+        if (params.containsKey("guid")) {
+            objHidd.setGuid((String) params.get("guid"));
+        }
+        objHidd.setHiddName((String) params.get("hiddName"));
+        objHidd.setEngGuid((String) params.get("engGuid"));
+        objHidd.setHiddGrad((String) params.get("hiddGrad"));
+        objHidd.setHiddClas((String) params.get("hiddClas"));
+        objHidd.setProPart((String) params.get("proPart"));
+        objHidd.setOtlcolQiffFnvu((String) params.get("hiddDesc"));
+        objHidd.setHiddStat((String) params.get("hiddStat"));
+        objHidd.setHiddSort((String) params.get("hiddSort"));
+        objHidd.setOrgGuid((String) params.get("orgGuid"));
+
+        int result;
+        if (params.containsKey("guid") && params.get("guid") != null) {
+            result = objHiddMapper.updateObjHidd(objHidd);
+        } else {
+            String guid = java.util.UUID.randomUUID().toString().replace("-", "");
+            objHidd.setGuid(guid);
+            result = objHiddMapper.insertObjHidd(objHidd);
+            objHidd.setGuid(guid);
+        }
+
+        // 保存排查信息 bis_hidd_inve
+        if (params.containsKey("bisHiddInveDto")) {
+            Object inveObj = params.get("bisHiddInveDto");
+            if (inveObj instanceof List) {
+                List<Map<String, Object>> inveList = (List<Map<String, Object>>) inveObj;
+                if (!inveList.isEmpty()) {
+                    Map<String, Object> inveData = inveList.get(0);
+                    BisHiddInve inve = new BisHiddInve();
+                    if (inveData.containsKey("guid")) {
+                        inve.setGuid((String) inveData.get("guid"));
+                    }
+                    inve.setHiddGuid(objHidd.getGuid());
+                    inve.setInspDate((String) inveData.get("inspDate"));
+                    inve.setInspOrgGuid((String) inveData.get("inspOrgGuid"));
+                    inve.setInspLeader((String) inveData.get("recPers"));
+                    inve.setInspLeaderPost((String) inveData.get("inspLeaderPost"));
+                    if (inve.getGuid() != null) {
+                        bisHiddInveService.updateBisHiddInve(inve);
+                    } else {
+                        String inveGuid = java.util.UUID.randomUUID().toString().replace("-", "");
+                        inve.setGuid(inveGuid);
+                        bisHiddInveService.insertBisHiddInve(inve);
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
 }

+ 6 - 0
gw-slaj/src/main/java/com/goldenwater/slaj/hidd/service/impl/TBusiHiddCountServiceImpl.java

@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.goldenwater.slaj.hidd.mapper.TBusiHiddCountMapper;
 import com.goldenwater.slaj.hidd.domain.TBusiHiddCount;
+import com.goldenwater.slaj.hidd.domain.TBusiHiddCountVo;
 import com.goldenwater.slaj.hidd.service.ITBusiHiddCountService;
 
 /**
@@ -86,4 +87,9 @@ public class TBusiHiddCountServiceImpl implements ITBusiHiddCountService {
     public List<Map<String, Object>> selectRectifyRateChart(Map<String, Object> params) {
         return tBusiHiddCountMapper.selectRectifyRateChart(params);
     }
+
+    @Override
+    public List<TBusiHiddCountVo> selectTBusiHiddCountListWithCalc(TBusiHiddCountVo vo) {
+        return tBusiHiddCountMapper.selectTBusiHiddCountListWithCalc(vo);
+    }
 }

+ 8 - 8
gw-slaj/src/main/resources/mapper/slaj/acci/BisAcciMontMapper.xml

@@ -31,7 +31,12 @@
                ser_inj_num, econ_loss, rep_act, note, acci_result, monthly_audit,
                monthly_audit_result, returninfo, revocation_audit,
                revocation_audit_result, coll_time, upd_time, rec_pers, acci_wiun_type,
-               mont, mont_stat, lock_status
+               to_char(occu_time, 'yyyy-MM') as mont,
+               case when monthly_audit_result = '1' then '2'
+                    when monthly_audit_result = '0' then '3'
+                    when rep_act is not null and rep_act != '' then '1'
+               else '0' end as mont_stat,
+               case when monthly_audit_result is not null then '1' else '0' end as lock_status
         from bis_acci_mont
     </sql>
     <select id="selectBisAcciMontByGuid" parameterType="String" resultMap="BisAcciMontResult">
@@ -55,14 +60,12 @@
             guid, rep_wiun_code, acci_cate, acci_grad, occu_time, cas_num,
             ser_inj_num, econ_loss, rep_act, note, acci_result, monthly_audit,
             monthly_audit_result, returninfo, revocation_audit,
-            revocation_audit_result, coll_time, upd_time, rec_pers, acci_wiun_type,
-            mont, mont_stat, lock_status
+            revocation_audit_result, coll_time, upd_time, rec_pers, acci_wiun_type
         ) values (
             #{guid}, #{repWiunCode}, #{acciCate}, #{acciGrad}, #{occuTime}, #{casNum},
             #{serInjNum}, #{econLoss}, #{repAct}, #{note}, #{acciResult}, #{monthlyAudit},
             #{monthlyAuditResult}, #{returninfo}, #{revocationAudit},
-            #{revocationAuditResult}, #{collTime}, #{updTime}, #{recPers}, #{acciWiunType},
-            #{mont}, #{montStat}, #{lockStatus}
+            #{revocationAuditResult}, #{collTime}, #{updTime}, #{recPers}, #{acciWiunType}
         )
     </insert>
     <update id="updateBisAcciMont" parameterType="com.goldenwater.slaj.acci.domain.BisAcciMont">
@@ -87,9 +90,6 @@
             <if test="updTime != null">upd_time = #{updTime},</if>
             <if test="recPers != null">rec_pers = #{recPers},</if>
             <if test="acciWiunType != null">acci_wiun_type = #{acciWiunType},</if>
-            <if test="mont != null">mont = #{mont},</if>
-            <if test="montStat != null">mont_stat = #{montStat},</if>
-            <if test="lockStatus != null">lock_status = #{lockStatus},</if>
         </set>
         where guid = #{guid}
     </update>

+ 16 - 33
gw-slaj/src/main/resources/mapper/slaj/acci/ObjAcciMapper.xml

@@ -3,7 +3,6 @@
 <mapper namespace="com.goldenwater.slaj.acci.mapper.ObjAcciMapper">
     <resultMap type="com.goldenwater.slaj.acci.domain.ObjAcci" id="ObjAcciResult">
         <result property="guid" column="guid"/>
-        <result property="acciName" column="acci_name"/>
         <result property="pGuid" column="p_guid"/>
         <result property="acciWiunGuid" column="acci_wiun_guid"/>
         <result property="acciWiunType" column="acci_wiun_type"/>
@@ -14,10 +13,6 @@
         <result property="serInjNum" column="ser_inj_num"/>
         <result property="casNum" column="cas_num"/>
         <result property="econLoss" column="econ_loss"/>
-        <result property="orgGuid" column="org_guid"/>
-        <result property="acciDesc" column="acci_desc"/>
-        <result property="occuLong" column="occu_long"/>
-        <result property="occuLat" column="occu_lat"/>
         <result property="otlcolGuuiVicm" column="otlcol_guui_vicm"/>
         <result property="rescTreaMeas" column="resc_trea_meas"/>
         <result property="contaPers" column="conta_pers"/>
@@ -34,9 +29,8 @@
         <result property="tendGuid" column="tend_guid"/>
     </resultMap>
     <sql id="selectObjAcciVo">
-        select guid, acci_name, p_guid, acci_wiun_guid, acci_wiun_type, acci_cate, occu_time,
-               occu_loc, miss_num, ser_inj_num, cas_num, econ_loss, org_guid, acci_desc,
-               occu_long, occu_lat, otlcol_guui_vicm,
+        select guid, p_guid, acci_wiun_guid, acci_wiun_type, acci_cate, occu_time,
+               occu_loc, miss_num, ser_inj_num, cas_num, econ_loss, otlcol_guui_vicm,
                resc_trea_meas, conta_pers, offi_tel, rep_stat, note, coll_time,
                upd_time, rec_pers, sgdw_name, acci_grad, eng_guid, to_date, tend_guid
         from obj_acci
@@ -67,15 +61,13 @@
     </select>
     <insert id="insertObjAcci" parameterType="com.goldenwater.slaj.acci.domain.ObjAcci">
         insert into obj_acci (
-            guid, acci_name, p_guid, acci_wiun_guid, acci_wiun_type, acci_cate, occu_time,
-            occu_loc, miss_num, ser_inj_num, cas_num, econ_loss, org_guid, acci_desc,
-            occu_long, occu_lat, otlcol_guui_vicm,
+            guid, p_guid, acci_wiun_guid, acci_wiun_type, acci_cate, occu_time,
+            occu_loc, miss_num, ser_inj_num, cas_num, econ_loss, otlcol_guui_vicm,
             resc_trea_meas, conta_pers, offi_tel, rep_stat, note, coll_time,
             upd_time, rec_pers, sgdw_name, acci_grad, eng_guid, to_date, tend_guid
         ) values (
-            #{guid}, #{acciName}, #{pGuid}, #{acciWiunGuid}, #{acciWiunType}, #{acciCate}, #{occuTime},
-            #{occuLoc}, #{missNum}, #{serInjNum}, #{casNum}, #{econLoss}, #{orgGuid}, #{acciDesc},
-            #{occuLong}, #{occuLat}, #{otlcolGuuiVicm},
+            #{guid}, #{pGuid}, #{acciWiunGuid}, #{acciWiunType}, #{acciCate}, #{occuTime},
+            #{occuLoc}, #{missNum}, #{serInjNum}, #{casNum}, #{econLoss}, #{otlcolGuuiVicm},
             #{rescTreaMeas}, #{contaPers}, #{offiTel}, #{repStat}, #{note}, #{collTime},
             #{updTime}, #{recPers}, #{sgdwName}, #{acciGrad}, #{engGuid}, #{toDate}, #{tendGuid}
         )
@@ -83,7 +75,6 @@
     <update id="updateObjAcci" parameterType="com.goldenwater.slaj.acci.domain.ObjAcci">
         update obj_acci
         <set>
-            <if test="acciName != null">acci_name = #{acciName},</if>
             <if test="pGuid != null">p_guid = #{pGuid},</if>
             <if test="acciWiunGuid != null">acci_wiun_guid = #{acciWiunGuid},</if>
             <if test="acciWiunType != null">acci_wiun_type = #{acciWiunType},</if>
@@ -94,10 +85,6 @@
             <if test="serInjNum != null">ser_inj_num = #{serInjNum},</if>
             <if test="casNum != null">cas_num = #{casNum},</if>
             <if test="econLoss != null">econ_loss = #{econLoss},</if>
-            <if test="orgGuid != null">org_guid = #{orgGuid},</if>
-            <if test="acciDesc != null">acci_desc = #{acciDesc},</if>
-            <if test="occuLong != null">occu_long = #{occuLong},</if>
-            <if test="occuLat != null">occu_lat = #{occuLat},</if>
             <if test="otlcolGuuiVicm != null">otlcol_guui_vicm = #{otlcolGuuiVicm},</if>
             <if test="rescTreaMeas != null">resc_trea_meas = #{rescTreaMeas},</if>
             <if test="contaPers != null">conta_pers = #{contaPers},</if>
@@ -132,7 +119,6 @@
         <where>
             <if test="startTime != null and startTime != ''">AND occu_time &gt;= #{startTime}</if>
             <if test="endTime != null and endTime != ''">AND occu_time &lt;= #{endTime}</if>
-            <if test="orgGuid != null and orgGuid != ''">AND org_guid = #{orgGuid}</if>
         </where>
         group by substr(occu_time, 1, 7)
         order by month
@@ -145,7 +131,6 @@
         <where>
             <if test="startTime != null and startTime != ''">AND occu_time &gt;= #{startTime}</if>
             <if test="endTime != null and endTime != ''">AND occu_time &lt;= #{endTime}</if>
-            <if test="orgGuid != null and orgGuid != ''">AND org_guid = #{orgGuid}</if>
         </where>
         group by acci_cate
         order by value desc
@@ -158,25 +143,23 @@
         <where>
             <if test="startTime != null and startTime != ''">AND occu_time &gt;= #{startTime}</if>
             <if test="endTime != null and endTime != ''">AND occu_time &lt;= #{endTime}</if>
-            <if test="orgGuid != null and orgGuid != ''">AND org_guid = #{orgGuid}</if>
         </where>
         group by acci_grad
         order by value desc
     </select>
 
     <select id="selectGisData" parameterType="java.util.Map" resultType="java.util.LinkedHashMap">
-        select guid, acci_name as acciName, occu_long as occuLong, occu_lat as occuLat,
-               acci_cate as acciCate, acci_grad as acciGrad, occu_loc as occuLoc,
-               occu_time as occuTime, cas_num as casNum, ser_inj_num as serInjNum,
-               org_guid as orgGuid
-        from obj_acci
+        select a.guid, a.occu_loc as occuLoc,
+               a.acci_cate as acciCate, a.acci_grad as acciGrad,
+               a.occu_time as occuTime, a.cas_num as casNum, a.ser_inj_num as serInjNum,
+               eng.cen_long as occuLong, eng.cen_lat as occuLat
+        from obj_acci a
+        left join obj_eng eng on a.eng_guid = eng.guid
         <where>
-            occu_long is not null and occu_lat is not null
-            and occu_long != '' and occu_lat != ''
-            <if test="startTime != null and startTime != ''">AND occu_time &gt;= #{startTime}</if>
-            <if test="endTime != null and endTime != ''">AND occu_time &lt;= #{endTime}</if>
-            <if test="orgGuid != null and orgGuid != ''">AND org_guid = #{orgGuid}</if>
+            eng.cen_long is not null and eng.cen_lat is not null
+            <if test="startTime != null and startTime != ''">AND a.occu_time &gt;= #{startTime}</if>
+            <if test="endTime != null and endTime != ''">AND a.occu_time &lt;= #{endTime}</if>
         </where>
-        order by occu_time desc
+        order by a.occu_time desc
     </select>
 </mapper>

+ 16 - 1
gw-slaj/src/main/resources/mapper/slaj/hidd/BisHiddRecRepMapper.xml

@@ -70,12 +70,27 @@
         <result property="hiddStat" column="hidd_stat"/>
         <result property="proPart" column="pro_part"/>
         <result property="collTime" column="coll_time"/>
+        <result property="orgName" column="org_name"/>
+        <result property="engName" column="eng_name"/>
+        <result property="inspDate" column="insp_date"/>
+        <result property="requCompDate" column="requ_comp_date"/>
+        <result property="factCompDate" column="fact_comp_date"/>
     </resultMap>
     <select id="selectBisHiddRecRepWithHiddByRepGuid" parameterType="String" resultMap="BisHiddRecRepWithHiddResult">
         SELECT r.guid, r.hidd_guid, r.rep_guid,
-               h.hidd_name, h.hidd_grad, h.hidd_stat, h.pro_part, r.coll_time
+               h.hidd_name, h.hidd_grad, h.hidd_stat, h.pro_part, r.coll_time,
+               ao.org_name,
+               e.eng_name,
+               bi.insp_date,
+               ri.requ_comp_date,
+               ra.accep_date AS fact_comp_date
         FROM bis_hidd_rec_rep r
         LEFT JOIN obj_hidd h ON r.hidd_guid = h.guid
+        LEFT JOIN att_org_base ao ON h.org_guid = ao.guid
+        LEFT JOIN obj_eng e ON h.eng_guid = e.guid
+        LEFT JOIN bis_hidd_inve bi ON h.insp_rec_guid = bi.guid
+        LEFT JOIN bis_hidd_rect_impl ri ON h.guid = ri.hidd_guid
+        LEFT JOIN bis_hidd_rect_acce ra ON h.guid = ra.hidd_guid
         WHERE r.rep_guid = #{repGuid}
     </select>
 </mapper>

+ 40 - 8
gw-slaj/src/main/resources/mapper/slaj/hidd/BisMajHiddSupMapper.xml

@@ -11,41 +11,74 @@
         <result property="supWiunCode" column="sup_wiun_code"/>
         <result property="supLegPers" column="sup_leg_pers"/>
         <result property="supOpin" column="sup_opin"/>
-        <result property="supStat" column="sup_stat"/>
         <result property="hiddName" column="hidd_name"/>
         <result property="hiddGrad" column="hidd_grad"/>
         <result property="hiddStat" column="hidd_stat"/>
+        <result property="hiddClas" column="hidd_clas"/>
+        <result property="hiddOrgGuid" column="hidd_org_guid"/>
+        <result property="hiddOrgName" column="hidd_org_name"/>
         <result property="note" column="note"/>
         <result property="collTime" column="coll_time"/>
         <result property="updTime" column="upd_time"/>
         <result property="recPers" column="rec_pers"/>
         <!-- 非持久化字段 -->
         <result property="supWiunName" column="sup_wiun_name"/>
+        <result property="engType" column="eng_type"/>
+        <result property="engName" column="eng_name"/>
+        <result property="orgNature" column="org_nature"/>
+        <result property="supStatValue" column="sup_stat_value"/>
         <result property="medGuid" column="med_guid"/>
         <result property="medTitl" column="med_titl"/>
+        <result property="proPart" column="pro_part"/>
+        <result property="requCompDate" column="requ_comp_date"/>
+        <result property="accepDate" column="accep_date"/>
+        <result property="accepOpin" column="accep_opin"/>
     </resultMap>
     <sql id="selectBisMajHiddSupVo">
-        select s.guid, s.hidd_guid, s.is_list, s.rect_peri, s.sup_lare_id, s.sup_date, s.sup_wiun_code, s.sup_leg_pers, s.sup_opin, s.sup_stat, s.note, s.coll_time, s.upd_time, s.rec_pers,
-               h.hidd_name, h.hidd_grad, h.hidd_stat,
+        select s.guid, s.hidd_guid, s.is_list, s.rect_peri, s.sup_lare_id, s.sup_date, s.sup_wiun_code, s.sup_leg_pers, s.sup_opin, s.note, s.coll_time, s.upd_time, s.rec_pers,
+               h.hidd_name, h.hidd_grad, h.hidd_stat, h.hidd_clas, h.pro_part, h.org_guid as hidd_org_guid,
                org.wiun_name as sup_wiun_name,
+               eng.eng_type, eng.eng_name,
+               horg.org_name as hidd_org_name,
+               horg_ext.wiun_prop as org_nature,
+               case when (acce.guid is null or acce.cancel_state = '0') then '已督办'
+                    when acce.cancel_state = '1' then '待销号'
+                    when acce.cancel_state = '2' then '已销号'
+               else '已督办' end as sup_stat_value,
+               acce.requ_comp_date, acce.accep_date, acce.accep_opin,
                med.med_guid, att.med_titl
         from bis_maj_hidd_sup s
         left join obj_hidd h on h.guid = s.hidd_guid
         left join att_org_ext org on org.org_guid = s.sup_wiun_code
+        left join obj_eng eng on eng.guid = h.eng_guid
+        left join att_org_base horg on horg.guid = h.org_guid
+        left join att_org_ext horg_ext on horg_ext.org_guid = h.org_guid
+        left join bis_hidd_rect_acce acce on acce.hidd_guid = s.hidd_guid
         left join rel_bis_med med on med.bis_guid = s.guid and med.bis_tablename = 'BIS_MAJ_HIDD_SUP'
         left join att_med_base att on att.guid = med.med_guid
     </sql>
     <select id="selectBisMajHiddSupByGuid" parameterType="String" resultMap="BisMajHiddSupResult">
         <include refid="selectBisMajHiddSupVo"/>
-        where guid = #{guid}
+        where s.guid = #{guid}
     </select>
     <select id="selectBisMajHiddSupList" parameterType="com.goldenwater.slaj.hidd.domain.BisMajHiddSupVo" resultMap="BisMajHiddSupResult">
         <include refid="selectBisMajHiddSupVo"/>
         <where>
             <if test="hiddGuid != null and hiddGuid != ''">AND s.hidd_guid = #{hiddGuid}</if>
-            <if test="supStat != null and supStat != ''">AND s.sup_stat = #{supStat}</if>
+            <if test="supStatValue != null and supStatValue != ''">
+                <choose>
+                    <when test="supStatValue == '1'.toString()">AND (acce.guid is null or acce.cancel_state = '0')</when>
+                    <when test="supStatValue == '2'.toString()">AND acce.cancel_state = '1'</when>
+                    <when test="supStatValue == '3'.toString()">AND acce.cancel_state = '2'</when>
+                </choose>
+            </if>
             <if test="guid != null and guid != ''">AND s.guid = #{guid}</if>
             <if test="hiddName != null and hiddName != ''">AND h.hidd_name like concat('%', #{hiddName}, '%')</if>
+            <if test="orgName != null and orgName != ''">AND horg.org_name like concat('%', #{orgName}, '%')</if>
+            <if test="engType != null and engType != ''">AND eng.eng_type = #{engType}</if>
+            <if test="orgNature != null and orgNature != ''">AND horg_ext.wiun_prop = #{orgNature}</if>
+            <if test="hiddClas != null and hiddClas != ''">AND h.hidd_clas = #{hiddClas}</if>
+            <if test="hiddStat != null and hiddStat != ''">AND h.hidd_stat = #{hiddStat}</if>
             <if test="hiddUnit != null and hiddUnit != ''">
                 AND h.org_guid in (
                     select guid from att_org_base where wiun_code like concat(
@@ -60,8 +93,8 @@
         </where>
     </select>
     <insert id="insertBisMajHiddSup" parameterType="com.goldenwater.slaj.hidd.domain.BisMajHiddSup">
-        insert into bis_maj_hidd_sup (guid, hidd_guid, is_list, rect_peri, sup_lare_id, sup_date, sup_wiun_code, sup_leg_pers, sup_opin, sup_stat, note, coll_time, upd_time, rec_pers)
-        values (#{guid}, #{hiddGuid}, #{isList}, #{rectPeri}, #{supLareId}, #{supDate}, #{supWiunCode}, #{supLegPers}, #{supOpin}, #{supStat}, #{note}, #{collTime}, #{updTime}, #{recPers})
+        insert into bis_maj_hidd_sup (guid, hidd_guid, is_list, rect_peri, sup_lare_id, sup_date, sup_wiun_code, sup_leg_pers, sup_opin, note, coll_time, upd_time, rec_pers)
+        values (#{guid}, #{hiddGuid}, #{isList}, #{rectPeri}, #{supLareId}, #{supDate}, #{supWiunCode}, #{supLegPers}, #{supOpin}, #{note}, #{collTime}, #{updTime}, #{recPers})
     </insert>
     <update id="updateBisMajHiddSup" parameterType="com.goldenwater.slaj.hidd.domain.BisMajHiddSup">
         update bis_maj_hidd_sup
@@ -74,7 +107,6 @@
             <if test="supWiunCode != null">sup_wiun_code = #{supWiunCode},</if>
             <if test="supLegPers != null">sup_leg_pers = #{supLegPers},</if>
             <if test="supOpin != null">sup_opin = #{supOpin},</if>
-            <if test="supStat != null">sup_stat = #{supStat},</if>
             <if test="note != null">note = #{note},</if>
             <if test="collTime != null">coll_time = #{collTime},</if>
             <if test="updTime != null">upd_time = #{updTime},</if>

+ 13 - 1
gw-slaj/src/main/resources/mapper/slaj/hidd/BisOrgMonRepPeriMapper.xml

@@ -125,6 +125,7 @@
             a.rep_name as repName,
             a.rep_act as repAct,
             a.rep_time as repTime,
+            a.rep_type as repType,
             -- 重大隐患数
             coalesce(stats.imp_hidd_count, 0) as impHiddCount,
             -- 逾期未整改
@@ -153,8 +154,19 @@
             group by b.rep_guid
         ) stats on stats.rep_guid = a.guid
         <where>
-            <if test="repTime != null and repTime != ''">AND a.rep_time = #{repTime}</if>
+            <if test="repTime != null and repTime != ''">AND a.rep_time LIKE #{repTime} || '%'</if>
             <if test="repOrgGuid != null and repOrgGuid != ''">AND a.rep_org_guid = #{repOrgGuid}</if>
+            <if test="unitType != null and unitType != ''">
+                AND a.rep_org_guid in (
+                    select org_guid from att_org_ext where wiun_code like concat(
+                        case #{unitType}
+                            when '1' then '%000000'
+                            when '2' then '%000'
+                            when '3' then '%0000'
+                        end
+                    )
+                )
+            </if>
         </where>
         order by a.coll_time desc
     </select>

+ 27 - 4
gw-slaj/src/main/resources/mapper/slaj/hidd/BisOrgMonRepRevoMapper.xml

@@ -25,12 +25,35 @@
         <include refid="selectBisOrgMonRepRevoVo"/>
         where guid = #{guid}
     </select>
-    <select id="selectBisOrgMonRepRevoList" parameterType="com.goldenwater.slaj.hidd.domain.BisOrgMonRepRevo" resultMap="BisOrgMonRepRevoResult">
-        <include refid="selectBisOrgMonRepRevoVo"/>
+    <resultMap type="java.util.Map" id="BisOrgMonRepRevoListResult">
+        <result property="guid" column="guid"/>
+        <result property="repGuid" column="rep_guid"/>
+        <result property="revoOrgGuid" column="revo_org_guid"/>
+        <result property="repOrgName" column="rep_org_name"/>
+        <result property="repTime" column="rep_time"/>
+        <result property="reportDesc" column="report_desc"/>
+        <result property="revocDesc" column="revoc_desc"/>
+        <result property="revoReas" column="revo_reas"/>
+        <result property="revoVeriResu" column="revo_veri_resu"/>
+        <result property="collTime" column="coll_time"/>
+    </resultMap>
+    <select id="selectBisOrgMonRepRevoList" parameterType="com.goldenwater.slaj.hidd.domain.BisOrgMonRepRevo" resultMap="BisOrgMonRepRevoListResult">
+        SELECT r.guid, r.rep_guid, r.revo_org_guid,
+               ao.org_name AS rep_org_name,
+               p.rep_time,
+               p.note AS report_desc,
+               r.revo_reas AS revoc_desc,
+               r.revo_reas,
+               r.revo_veri_resu,
+               r.coll_time
+        FROM bis_org_mon_rep_revo r
+        LEFT JOIN bis_org_mon_rep_peri p ON r.rep_guid = p.guid
+        LEFT JOIN att_org_base ao ON p.rep_org_guid = ao.guid
         <where>
-            <if test="repGuid != null and repGuid != ''">AND rep_guid = #{repGuid}</if>
-            <if test="revoOrgGuid != null and revoOrgGuid != ''">AND revo_org_guid = #{revoOrgGuid}</if>
+            <if test="repGuid != null and repGuid != ''">AND r.rep_guid = #{repGuid}</if>
+            <if test="revoOrgGuid != null and revoOrgGuid != ''">AND r.revo_org_guid = #{revoOrgGuid}</if>
         </where>
+        ORDER BY r.coll_time DESC
     </select>
     <insert id="insertBisOrgMonRepRevo" parameterType="com.goldenwater.slaj.hidd.domain.BisOrgMonRepRevo">
         insert into bis_org_mon_rep_revo (guid, rep_guid, revo_org_guid, veri_org_guid, revo_reas, rep_resc, return_desc, revo_veri_opin, revo_veri_resu, note, coll_time, upd_time, rec_pers)

+ 34 - 1
gw-slaj/src/main/resources/mapper/slaj/hidd/ObjHiddMapper.xml

@@ -36,14 +36,25 @@
         <result property="hazGuid" column="haz_guid"/>
         <result property="engName" column="eng_name"/>
         <result property="orgName" column="org_name"/>
+        <result property="inspDate" column="insp_date"/>
+        <result property="requCompDate" column="requ_comp_date"/>
+        <result property="supStat" column="sup_stat"/>
+        <result property="cancelState" column="cancel_state"/>
     </resultMap>
     <sql id="selectObjHiddVo">
         select h.guid, h.hidd_name, h.eng_guid, h.tend_guid, h.se_guid, h.org_guid, h.hidd_sour, h.hidd_grad, h.hidd_clas, h.if_found, h.pro_part, h.part_long, h.part_lat, h.otlcol_qiff_fnvu, h.insp_rec_guid, h.se_check_item_guid, h.hidd_stat, h.hidd_merg_guid, h.rec_org_guid, h.note, h.coll_time, h.upd_time, h.rec_pers, h.hidds_guid, h.occu_num, h.sins_sche_guid, h.group_guid, h.temp, h.to_date, h.dict_guid, h.hidd_sort, h.haz_guid,
                e.eng_name,
-               o.org_name
+               o.org_name,
+               bi.insp_date,
+               ri.requ_comp_date,
+               (CASE WHEN EXISTS (SELECT 1 FROM bis_maj_hidd_sup ms WHERE ms.hidd_guid = h.guid) THEN '1' ELSE '0' END) as sup_stat,
+               COALESCE(ra.cancel_state, '0') as cancel_state
         from obj_hidd h
         left join att_eng_base e on h.eng_guid = e.guid
         left join att_org_base o on h.org_guid = o.guid
+        left join bis_hidd_inve bi on h.insp_rec_guid = bi.guid
+        left join bis_hidd_rect_impl ri on h.guid = ri.hidd_guid
+        left join bis_hidd_rect_acce ra on h.guid = ra.hidd_guid
     </sql>
     <select id="selectObjHiddByGuid" parameterType="String" resultMap="ObjHiddResult">
         <include refid="selectObjHiddVo"/>
@@ -143,4 +154,26 @@
         insert into obj_hidd (guid, hidd_name, eng_guid, tend_guid, se_guid, org_guid, hidd_sour, hidd_grad, hidd_clas, if_found, pro_part, part_long, part_lat, otlcol_qiff_fnvu, insp_rec_guid, se_check_item_guid, hidd_stat, hidd_merg_guid, rec_org_guid, note, coll_time, upd_time, rec_pers, hidds_guid, occu_num, sins_sche_guid, group_guid, temp, to_date, dict_guid, hidd_sort, haz_guid)
         values (#{guid}, #{hiddName}, #{engGuid}, #{tendGuid}, #{seGuid}, #{orgGuid}, #{hiddSour}, #{hiddGrad}, #{hiddClas}, #{ifFound}, #{proPart}, #{partLong}, #{partLat}, #{otlcolQiffFnvu}, #{inspRecGuid}, #{seCheckItemGuid}, #{hiddStat}, #{hiddMergGuid}, #{recOrgGuid}, #{note}, #{collTime}, #{updTime}, #{recPers}, #{hiddsGuid}, #{occuNum}, #{sinsScheGuid}, #{groupGuid}, #{temp}, #{toDate}, #{dictGuid}, #{hiddSort}, #{hazGuid})
     </insert>
+
+    <!-- 工程/非工程隐患聚合查询 -->
+    <select id="selectHiddGroupBy" parameterType="java.util.Map" resultType="java.util.LinkedHashMap">
+        SELECT
+            e.eng_name AS engName,
+            org.org_name AS orgName,
+            count(h.guid) AS totalCount,
+            coalesce(sum(case when h.hidd_grad = '1' then 1 else 0 end), 0) AS normalCount,
+            coalesce(sum(case when h.hidd_grad = '2' then 1 else 0 end), 0) AS majorCount,
+            coalesce(sum(case when h.hidd_stat = '2' then 1 else 0 end), 0) AS solvedCount
+        FROM obj_hidd h
+        LEFT JOIN obj_eng e ON h.eng_guid = e.guid
+        LEFT JOIN att_org_base org ON h.org_guid = org.guid
+        <where>
+            <if test="hiddSort != null and hiddSort != ''">AND h.hidd_sort = #{hiddSort}</if>
+            <if test="engName != null and engName != ''">AND e.eng_name LIKE '%' || #{engName} || '%'</if>
+            <if test="orgName != null and orgName != ''">AND org.org_name LIKE '%' || #{orgName} || '%'</if>
+            <if test="collTime != null and collTime != ''">AND h.coll_time LIKE #{collTime} || '%'</if>
+        </where>
+        GROUP BY e.eng_name, org.org_name
+        ORDER BY totalCount DESC
+    </select>
 </mapper>

+ 13 - 4
gw-slaj/src/main/resources/mapper/slaj/hidd/TBusiHiddCountMapper.xml

@@ -104,9 +104,11 @@
 
     <select id="selectReportRateChart" parameterType="java.util.Map" resultType="java.util.LinkedHashMap">
         select c.org_guid as orgGuid,
+               org.wiun_name as orgName,
                c.pcl as rateData,
                c.create_time as repTime
         from t_busi_hidd_count c
+        left join att_org_ext org on org.org_guid = c.org_guid
         <where>
             <if test="repTime != null and repTime != ''">AND c.create_time = #{repTime}</if>
         </where>
@@ -115,9 +117,11 @@
 
     <select id="selectRectifyRateChart" parameterType="java.util.Map" resultType="java.util.LinkedHashMap">
         select c.org_guid as orgGuid,
+               org.wiun_name as orgName,
                c.hidd_zgl as rateData,
                c.create_time as repTime
         from t_busi_hidd_count c
+        left join att_org_ext org on org.org_guid = c.org_guid
         <where>
             <if test="repTime != null and repTime != ''">AND c.create_time = #{repTime}</if>
         </where>
@@ -142,10 +146,15 @@
             c.zd_zgl,
             c.zd_hidd,
             c.zg_zd_hidd,
-            org.org_name,
+            org.wiun_name as org_name,
             -- 计算字段
             (coalesce(c.zd_hidd, 0) + coalesce(c.yb_hidd, 0)) as total_hidd,
             (coalesce(c.zg_zd_hidd, 0) + coalesce(c.zg_yb_hidd, 0)) as solved_hidd,
+            -- 正在整改中 = 重大整改中 + 一般整改中
+            (case when coalesce(c.zd_hidd, 0) > coalesce(c.zg_zd_hidd, 0)
+                then coalesce(c.zd_hidd, 0) - coalesce(c.zg_zd_hidd, 0) else 0 end
+            + case when coalesce(c.yb_hidd, 0) > coalesce(c.zg_yb_hidd, 0)
+                then coalesce(c.yb_hidd, 0) - coalesce(c.zg_yb_hidd, 0) else 0 end) as solving_hidd,
             case when (coalesce(c.zd_hidd, 0) + coalesce(c.yb_hidd, 0)) > 0 
                 then (coalesce(c.zd_hidd, 0) + coalesce(c.yb_hidd, 0)) - (coalesce(c.zg_zd_hidd, 0) + coalesce(c.zg_yb_hidd, 0))
                 else 0 end as unsolved_hidd,
@@ -176,11 +185,11 @@
             <if test="orgName != null and orgName != ''">AND org.org_name like concat('%', #{orgName}, '%')</if>
             <if test="unitType != null and unitType != ''">
                 AND c.org_guid in (
-                    select guid from att_org_base where wiun_code like concat(
+                    select org_guid from att_org_ext where wiun_code like concat(
                         case #{unitType}
                             when '1' then '%000000'
-                            when '2' then '%000'
-                            when '3' then '%0000'
+                            when '2' then '%0000'
+                            when '3' then '%000'
                         end
                     )
                 )

+ 78 - 4
gw-ui/src/api/slaj/hidd.js

@@ -17,6 +17,15 @@ export function getObjHidd(guid) {
   })
 }
 
+// 工程/非工程隐患聚合查询
+export function getHiddGroupBy(query) {
+  return request({
+    url: '/hidd/objhidd/groupBy',
+    method: 'get',
+    params: query
+  })
+}
+
 // 新增隐患
 export function addObjHidd(data) {
   return request({
@@ -26,6 +35,15 @@ export function addObjHidd(data) {
   })
 }
 
+// 复合保存隐患
+export function compoundSaveHidd(data) {
+  return request({
+    url: '/hidd/objhidd/compoundSave',
+    method: 'post',
+    data: data
+  })
+}
+
 // 修改隐患
 export function updateObjHidd(data) {
   return request({
@@ -473,6 +491,24 @@ export function listTBusiHiddCountMon(query) {
   })
 }
 
+// 隐患月报上报率图表
+export function getReportRateChart(repTime) {
+  return request({
+    url: '/hidd/count/reportRateChart',
+    method: 'get',
+    params: { repTime: repTime }
+  })
+}
+
+// 隐患整改率图表
+export function getRectifyRateChart(repTime) {
+  return request({
+    url: '/hidd/count/rectifyRateChart',
+    method: 'get',
+    params: { repTime: repTime }
+  })
+}
+
 // 查询隐患评估统计列表
 export function listTBusiHiddEva(query) {
   return request({
@@ -749,6 +785,17 @@ export function delAttMedBase(guids) {
   })
 }
 
+// ========== 机构基础信息 ==========
+
+// 查询机构基础信息列表
+export function listAttOrgBase(query) {
+  return request({
+    url: '/hidd/orgbase/list',
+    method: 'get',
+    params: query
+  })
+}
+
 // ========== 移动端接口 ==========
 
 // 移动端月报新增
@@ -883,6 +930,15 @@ export function delObjCons(guids) {
   })
 }
 
+// 查询月报列表统计(按单位分组)
+export function getMonthListStats(query) {
+  return request({
+    url: '/hidd/monrepperi/monthListStats',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询月报汇总
 export function getMonthTotalList(query) {
   return request({
@@ -911,11 +967,20 @@ export function returnMonth(guid, returnDesc) {
 }
 
 // 月报撤销
-export function revokeMonth(guid) {
+export function revokeMonth(guid, revocDesc) {
   return request({
     url: '/hidd/monrepperi/revoke',
     method: 'put',
-    params: { guid: guid }
+    params: { guid: guid, revocDesc: revocDesc }
+  })
+}
+
+// 检查是否可以撤销
+export function checkCanRevoke(month) {
+  return request({
+    url: '/hidd/monrepperi/checkCanRevoke',
+    method: 'get',
+    params: { month: month, type: '0' }
   })
 }
 
@@ -928,6 +993,15 @@ export function approveRevoke(guid, approved, opinion) {
   })
 }
 
+// 待审批列表
+export function revokeApproveList(query) {
+  return request({
+    url: '/hidd/monreprevo/list',
+    method: 'get',
+    params: query
+  })
+}
+
 // 月报批量解锁
 export function batchUnlock(guids) {
   return request({
@@ -938,11 +1012,11 @@ export function batchUnlock(guids) {
 }
 
 // 督促上报
-export function urgeReport(orgGuids, repName) {
+export function urgeReport(orgGuid, repMonth) {
   return request({
     url: '/hidd/monrepperi/urge',
     method: 'post',
-    params: { orgGuids: orgGuids, repName: repName }
+    params: { orgGuid: orgGuid, repMonth: repMonth, notType: '1' }
   })
 }
 

+ 2 - 1
gw-ui/src/store/modules/user.js

@@ -55,12 +55,13 @@ const useUserStore = defineStore(
             this.name = user.userName
             this.realName = user.realName
             this.avatar = avatar
-            /* 初始密码提示 */
+            /* 初始密码提示
             if(res.isDefaultModifyPwd) {
               ElMessageBox.confirm('您的密码还是初始密码,请修改密码!',  '安全提示', {  confirmButtonText: '确定',  cancelButtonText: '取消',  type: 'warning' }).then(() => {
                 router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
               }).catch(() => {})
             }
+            */
             /* 过期密码提示 */
             if(!res.isDefaultModifyPwd && res.isPasswordExpired) {
               ElMessageBox.confirm('您的密码已过期,请尽快修改密码!',  '安全提示', {  confirmButtonText: '确定',  cancelButtonText: '取消',  type: 'warning' }).then(() => {

+ 1 - 7
gw-ui/src/views/slaj/hazard/index.vue

@@ -25,9 +25,6 @@
           <el-option v-for="dict in risk_grad" :key="dict.value" :label="dict.label" :value="dict.value" />
         </el-select>
       </el-form-item>
-      <el-form-item label="采集时间">
-        <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
-      </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
         <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -246,8 +243,6 @@ const single = ref(true)
 const multiple = ref(true)
 const total = ref(0)
 const title = ref("")
-const dateRange = ref([])
-
 const columns = ref({
   hazCode: { label: '危险源编码', visible: true },
   hazName: { label: '危险源名称', visible: true },
@@ -286,7 +281,7 @@ const { queryParams, form, rules } = toRefs(data)
 /** 查询危险源列表 */
 function getList() {
   loading.value = true
-  listObjHaz(proxy.addDateRange(queryParams.value, dateRange.value)).then(res => {
+  listObjHaz(queryParams.value).then(res => {
     loading.value = false
     objHazList.value = res.rows
     total.value = res.total
@@ -301,7 +296,6 @@ function handleQuery() {
 
 /** 重置按钮操作 */
 function resetQuery() {
-  dateRange.value = []
   proxy.resetForm("queryRef")
   handleQuery()
 }

+ 28 - 118
gw-ui/src/views/slaj/hidd/detailCount.vue

@@ -1,152 +1,62 @@
 <template>
-  <div ref="containerRef" class="app-container">
-    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="统计年份" prop="statYear">
-        <el-date-picker v-model="queryParams.statYear" type="year" placeholder="选择年份" value-format="YYYY" />
-      </el-form-item>
-      <el-form-item label="统计月份" prop="statMonth">
-        <el-select v-model="queryParams.statMonth" placeholder="请选择统计月份" clearable style="width: 240px">
-          <el-option v-for="item in 12" :key="item" :label="item + '月'" :value="item" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="机构名称" prop="orgGuid">
-        <el-input v-model="queryParams.orgGuid" placeholder="请输入机构名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
-      </el-form-item>
-      <el-form-item label="隐患等级" prop="hiddGrad">
-        <el-select v-model="queryParams.hiddGrad" placeholder="请选择隐患等级" clearable style="width: 240px">
-          <el-option v-for="dict in hidd_grad" :key="dict.value" :label="dict.label" :value="dict.value" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="隐患状态" prop="hiddStat">
-        <el-select v-model="queryParams.hiddStat" placeholder="请选择隐患状态" clearable style="width: 240px">
-          <el-option v-for="dict in hidd_stat" :key="dict.value" :label="dict.label" :value="dict.value" />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hidd:count:export']">导出</el-button>
-      </el-col>
-      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" storageKey="hidd-detailcount-index"></right-toolbar>
-    </el-row>
-
-    <div class="table-wrapper">
-    <el-table :height="tableHeight" v-loading="loading" :data="detailCountList">
-      <el-table-column label="机构名称" align="center" prop="orgName" :show-overflow-tooltip="true" />
-      <el-table-column label="统计年份" align="center" prop="statYear" />
-      <el-table-column label="统计月份" align="center" prop="statMonth" />
-      <el-table-column label="隐患名称" align="center" prop="hiddName" :show-overflow-tooltip="true" />
-      <el-table-column label="隐患等级" align="center" prop="hiddGrad">
+  <div class="app-container">
+    <el-table v-loading="loading" :data="list" stripe border>
+      <el-table-column label="隐患名称" align="center" prop="hiddName" min-width="160" :show-overflow-tooltip="true" />
+      <el-table-column label="隐患级别" align="center" width="100">
         <template #default="scope">
-          <dict-tag :options="hidd_grad" :value="scope.row.hiddGrad" />
+          {{ scope.row.hiddGrad === '2' ? '重大隐患' : '一般隐患' }}
         </template>
       </el-table-column>
-      <el-table-column label="隐患类别" align="center" prop="hiddClas">
+      <el-table-column label="隐患分类" align="center" width="120">
         <template #default="scope">
           <dict-tag :options="hidd_clas" :value="scope.row.hiddClas" />
         </template>
       </el-table-column>
-      <el-table-column label="隐患状态" align="center" prop="hiddStat">
+      <el-table-column label="工程名称" align="center" prop="engName" min-width="140" :show-overflow-tooltip="true" />
+      <el-table-column label="隐患状态" align="center" width="100">
         <template #default="scope">
           <dict-tag :options="hidd_stat" :value="scope.row.hiddStat" />
         </template>
       </el-table-column>
-      <el-table-column label="涉及部位" align="center" prop="proPart" :show-overflow-tooltip="true" />
-      <el-table-column label="采集时间" align="center" prop="collTime" width="180" />
-      <el-table-column label="操作" align="center" width="100">
+      <el-table-column label="采集时间" align="center" width="110">
+        <template #default="scope">
+          {{ scope.row.collTime ? scope.row.collTime.substring(0, 10) : '--' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="要求完成时间" align="center" width="110">
         <template #default="scope">
-          <el-tooltip content="详情" placement="top">
-            <el-button link type="primary" icon="View" @click="handleDetail(scope.row)"></el-button>
-          </el-tooltip>
+          {{ scope.row.requCompDate ? scope.row.requCompDate.substring(0, 10) : '--' }}
         </template>
       </el-table-column>
     </el-table>
-    </div>
-
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
   </div>
 </template>
 
-<script setup name="HiddDetailCount">
+<script setup name="DetailCount">
 import { listObjHidd } from "@/api/slaj/hidd"
-import { useTableHeight } from '@/hooks/useTableHeight'
-
-const { tableHeight, containerRef } = useTableHeight()
 
 const { proxy } = getCurrentInstance()
-const { hidd_grad, hidd_stat, hidd_clas } = proxy.useDict("hidd_grad", "hidd_stat", "hidd_clas")
+const { hidd_clas, hidd_stat } = proxy.useDict("hidd_clas", "hidd_stat")
 
-const detailCountList = ref([])
-const loading = ref(true)
-const showSearch = ref(true)
+const loading = ref(false)
+const list = ref([])
 const total = ref(0)
 
-const columns = ref({
-  orgName: { label: '机构名称', visible: true },
-  statYear: { label: '统计年份', visible: true },
-  statMonth: { label: '统计月份', visible: true },
-  hiddName: { label: '隐患名称', visible: true },
-  hiddGrad: { label: '隐患等级', visible: true },
-  hiddClas: { label: '隐患类别', visible: true },
-  hiddStat: { label: '隐患状态', visible: true },
-  proPart: { label: '涉及部位', visible: true },
-  collTime: { label: '采集时间', visible: true }
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  orgGuid: ''
 })
 
-const data = reactive({
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    statYear: undefined,
-    statMonth: undefined,
-    orgGuid: undefined,
-    hiddGrad: undefined,
-    hiddStat: undefined
-  }
-})
-
-const { queryParams } = toRefs(data)
-
-/** 查询明细统计列表 */
 function getList() {
   loading.value = true
-  listObjHidd(queryParams.value).then(res => {
+  listObjHidd(queryParams).then(res => {
+    list.value = res.rows || []
+    total.value = res.total || 0
     loading.value = false
-    detailCountList.value = res.rows
-    total.value = res.total
-  })
+  }).catch(() => { loading.value = false })
 }
 
-/** 搜索按钮操作 */
-function handleQuery() {
-  queryParams.value.pageNum = 1
-  getList()
-}
-
-/** 重置按钮操作 */
-function resetQuery() {
-  proxy.resetForm("queryRef")
-  handleQuery()
-}
-
-/** 详情按钮操作 */
-function handleDetail(row) {
-  proxy.$router.push({ path: '/slaj/hidd/detail', query: { guid: row.guid } })
-}
-
-/** 导出按钮操作 */
-function handleExport() {
-  proxy.download("hidd/count/detailexport", {
-    ...queryParams.value
-  }, `hiddDetailCount_${new Date().getTime()}.xlsx`)
-}
-
-onMounted(() => {
-  getList()
-})
+defineExpose({ queryParams, getList })
 </script>

+ 95 - 0
gw-ui/src/views/slaj/hidd/engQuery.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="app-container">
+    <el-tabs v-model="activeTab" type="border-card" @tab-change="getList">
+      <el-tab-pane label="工程隐患" name="eng">
+        <el-form :model="queryParams" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="工程名称" prop="engName">
+            <el-input v-model="queryParams.engName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="单位名称" prop="orgName">
+            <el-input v-model="queryParams.orgName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="采集时间" prop="collTime">
+            <el-date-picker v-model="queryParams.collTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table :height="tableHeight" v-loading="loading" :data="list" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="工程名称" align="center" prop="engName" min-width="150" :show-overflow-tooltip="true" />
+          <el-table-column label="管理单位" align="center" prop="orgName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="总数" align="center" prop="totalCount" width="80" />
+          <el-table-column label="一般隐患" align="center" prop="normalCount" width="90" />
+          <el-table-column label="重大隐患" align="center" prop="majorCount" width="90" />
+          <el-table-column label="已整改隐患" align="center" prop="solvedCount" width="100" />
+        </el-table>
+
+        <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      </el-tab-pane>
+
+      <el-tab-pane label="工程隐患" name="eng">
+        ...(内容不变)...
+      </el-tab-pane>
+
+      <el-tab-pane label="非工程隐患" name="nonEng">
+        <el-form :model="queryParams" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="单位名称" prop="orgName">
+            <el-input v-model="queryParams.orgName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="采集时间" prop="collTime">
+            <el-date-picker v-model="queryParams.collTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport">导出</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table :height="tableHeight" v-loading="loading" :data="list" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="管理单位" align="center" prop="orgName" min-width="200" :show-overflow-tooltip="true" />
+          <el-table-column label="总数" align="center" prop="totalCount" width="80" />
+          <el-table-column label="一般隐患" align="center" prop="normalCount" width="90" />
+          <el-table-column label="重大隐患" align="center" prop="majorCount" width="90" />
+          <el-table-column label="已整改隐患" align="center" prop="solvedCount" width="100" />
+        </el-table>
+
+        <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script setup name="EngQuery">
+import { getHiddGroupBy } from "@/api/slaj/hidd"
+
+const { proxy } = getCurrentInstance()
+
+const tableHeight = 'calc(100vh - 240px)'
+const activeTab = ref('eng')
+const showSearch = ref(true)
+const list = ref([])
+const loading = ref(false)
+const total = ref(0)
+
+const queryParams = reactive({ pageNum: 1, pageSize: 10, hiddSort: '1', engName: undefined, orgName: undefined, collTime: undefined })
+
+function getList() {
+  loading.value = true
+  queryParams.hiddSort = activeTab.value === 'nonEng' ? '2' : '1'
+  getHiddGroupBy(queryParams).then(res => {
+    list.value = res.data || []
+    total.value = list.value.length
+    loading.value = false
+  }).catch(() => { loading.value = false })
+}
+
+function handleQuery() { queryParams.pageNum = 1; getList() }
+function handleExport() { proxy.download("hidd/objhidd/export", { ...queryParams }, `隐患查询_${new Date().getTime()}.xlsx`) }
+
+onMounted(() => { getList() })
+</script>

+ 510 - 380
gw-ui/src/views/slaj/hidd/month.vue

@@ -1,451 +1,581 @@
 <template>
-  <div ref="containerRef" class="app-container">
-    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="上报单位" prop="repOrgGuid">
-        <el-input v-model="queryParams.repOrgGuid" placeholder="请输入上报单位" clearable style="width: 240px" @keyup.enter="handleQuery" />
-      </el-form-item>
-      <el-form-item label="上报期间" prop="repName">
-        <el-input v-model="queryParams.repName" placeholder="请输入上报期间" clearable style="width: 240px" @keyup.enter="handleQuery" />
-      </el-form-item>
-      <el-form-item label="上报状态" prop="repAct">
-        <el-select v-model="queryParams.repAct" placeholder="请选择上报状态" clearable style="width: 240px">
-          <el-option v-for="dict in rep_stat" :key="dict.value" :label="dict.label" :value="dict.value" />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['hidd:monrepperi:add']">新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate" v-hasPermi="['hidd:monrepperi:edit']">修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['hidd:monrepperi:remove']">删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hidd:monrepperi:export']">导出</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="info" plain icon="Unlock" @click="handleUnlock" v-hasPermi="['hidd:monrepperi:edit']">一键解锁</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="danger" plain icon="Bell" :disabled="multiple" @click="handleUrge" v-hasPermi="['hidd:monrepperi:edit']">督促上报</el-button>
-      </el-col>
-      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" storageKey="hidd-monrepperi-index"></right-toolbar>
-    </el-row>
-
-    <div class="table-wrapper">
-    <el-table :height="tableHeight" v-loading="loading" :data="monRepPeriList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="上报单位" align="center" prop="repOrgGuid" v-if="columns.repOrgGuid.visible" :show-overflow-tooltip="true" />
-      <el-table-column label="上报期间" align="center" prop="repName" v-if="columns.repName.visible" />
-      <el-table-column label="上报状态" align="center" prop="repAct" v-if="columns.repAct.visible">
-        <template #default="scope">
-          <el-tag v-if="scope.row.repAct === '2'" type="success" effect="plain">已上报</el-tag>
-          <el-tag v-else-if="scope.row.repAct === '1'" type="warning" effect="plain">待审批</el-tag>
-          <el-tag v-else-if="scope.row.repAct === '3'" type="danger" effect="plain">已退回</el-tag>
-          <el-tag v-else type="info" effect="plain">未上报</el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column label="上报时间" align="center" prop="repTime" v-if="columns.repTime.visible" width="180" />
-      <el-table-column label="退回说明" align="center" prop="returnDesc" v-if="columns.returnDesc.visible" :show-overflow-tooltip="true" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="250">
-        <template #default="scope">
-          <el-tooltip content="修改" placement="top">
-            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['hidd:monrepperi:edit']"></el-button>
-          </el-tooltip>
-          <el-tooltip content="详情" placement="top">
-            <el-button link type="primary" icon="View" @click="handleDetail(scope.row)"></el-button>
-          </el-tooltip>
-          <el-tooltip content="下级月报" placement="top">
-            <el-button link type="primary" icon="Document" @click="handleSubMonth(scope.row)"></el-button>
-          </el-tooltip>
-          <el-tooltip content="撤回审批" placement="top" v-if="scope.row.repAct === '2'">
-            <el-button link type="warning" icon="Stamp" @click="handleVerify(scope.row)" v-hasPermi="['hidd:monrepperi:edit']"></el-button>
-          </el-tooltip>
-          <el-tooltip content="删除" placement="top">
-            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['hidd:monrepperi:remove']"></el-button>
-          </el-tooltip>
-        </template>
-      </el-table-column>
-    </el-table>
+  <div class="app-container">
+    <div class="global-top-bar">
+      <span v-html="promptText" style="font-weight: bold; font-size: 13px;"></span>
+    </div>
+    <div class="month-layout">
+      <div class="tree-panel">
+        <div class="tree-header">
+          上报状态&nbsp;&nbsp;
+          <span class="status-dot reported"></span> 已上报&nbsp;
+          <span class="status-dot unreported"></span> 未上报
+          <el-button link type="primary" icon="Refresh" @click="loadTree" style="float:right;" />
+        </div>
+        <el-tree
+          ref="treeRef"
+          :data="treeData"
+          :props="treeProps"
+          node-key="id"
+          :highlight-current="true"
+          :expand-on-click-node="true"
+          :default-expand-all="false"
+          @node-click="handleNodeClick"
+        >
+          <template #default="{ data }">
+            <span v-if="data.IsUpload !== undefined" :style="{ color: data.IsUpload === 1 ? '#579575' : '#D8B83F' }">
+              {{ data.label }}
+            </span>
+            <span v-else>{{ data.label }}</span>
+          </template>
+        </el-tree>
+      </div>
+      <div class="table-panel">
+        <div class="filter-bar">
+          <span class="filter-label">月报期间:</span>
+          <span style="font-size:13px;">{{ periodText }}</span>
+          <span class="filter-label" style="margin-left:12px;">上报单位:</span>
+          <el-radio-group v-model="unitType" @change="loadStats" class="filter-radios">
+            <el-radio value="0">本单位上报</el-radio>
+            <el-radio value="1">直属单位上报</el-radio>
+            <el-radio value="3">流域机构上报</el-radio>
+            <el-radio value="2">下级水行政部门上报</el-radio>
+          </el-radio-group>
+          <el-button size="small" @click="handlePendingApproval" style="margin-left:auto;">
+            待审批<el-badge v-if="pendingCount > 0" :value="pendingCount" :max="99" style="margin-left:4px;" />
+          </el-button>
+          <el-button size="small" type="primary" @click="handleReport">上报</el-button>
+          <el-button size="small" @click="handleBatchRevoke">撤销</el-button>
+        </div>
+        <div class="action-bar">
+          <span class="filter-label">选择月份:</span>
+          <el-select v-model="selectedMonth" placeholder="请选择月份" size="small" style="width:160px" @change="handleMonthChange">
+            <el-option v-for="item in monthOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+          <el-button size="small" @click="handleBatchUnlock" style="margin-left:12px;">一键解锁</el-button>
+          <el-button size="small" @click="handleCustomPeriod">自定义上报期</el-button>
+        </div>
+        <el-table v-loading="loading" :data="statsList" stripe border height="calc(100vh - 280px)" style="width: 100%">
+          <el-table-column label="序号" align="center" type="index" width="55" />
+          <el-table-column label="上报单位" align="center" min-width="130" :show-overflow-tooltip="true">
+            <template #default="scope">
+              <el-link type="primary" @click="handleOrgDetail(scope.row)">{{ scope.row.repName || scope.row.orgName || '--' }}</el-link>
+            </template>
+          </el-table-column>
+          <el-table-column label="上报时间" align="center" width="90">
+            <template #default="scope">
+              {{ scope.row.repAct === '1' ? (scope.row.repTime ? scope.row.repTime.substring(0, 10) : '--') : '' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="隐患数量" align="center">
+            <el-table-column label="重大隐患" align="center" width="80" prop="impHiddCount" />
+            <el-table-column label="逾期未整改" align="center" width="90" prop="overUnImplRect" />
+            <el-table-column label="未落实整改" align="center" width="90" prop="unSolvedCount" />
+            <el-table-column label="正在整改" align="center" width="80" prop="solvingCount" />
+            <el-table-column label="完成整改" align="center" width="80" prop="hasSolvedCount" />
+            <el-table-column label="整改率" align="center" width="70">
+              <template #default="scope">
+                {{ scope.row.solveRate != null ? Number(scope.row.solveRate * 100).toFixed(2) + '%' : '0.00%' }}
+              </template>
+            </el-table-column>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="110" fixed="right">
+            <template #default="scope">
+              <template v-if="unitType === '0'">
+                <el-button v-if="scope.row.repAct === '1'" link type="primary" @click="handleRevocApply(scope.row)">回撤</el-button>
+                <span v-else style="color: #999;">未上报</span>
+              </template>
+              <template v-else>
+                <el-tag v-if="scope.row.repAct === '1'" type="success" size="small">已上报</el-tag>
+                <el-button v-else link type="warning" @click="handleSupervise(scope.row)">督促上报</el-button>
+                <el-button v-if="scope.row.repAct === '1'" link type="danger" @click="handleReturn(scope.row)">退回</el-button>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
     </div>
 
-    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
-
-    <!-- 添加或修改月报期间对话框 -->
-    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
-      <el-form :model="form" :rules="rules" ref="monRepPeriRef" label-width="100px">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="上报单位" prop="repOrgGuid">
-              <el-input v-model="form.repOrgGuid" placeholder="请输入上报单位" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="上报期间" prop="repName">
-              <el-select v-model="form.repName" placeholder="请选择上报期间" filterable allow-create>
-                <el-option v-for="m in 12" :key="m" :label="currentYear + '年' + m + '月'" :value="currentYear + '-' + String(m).padStart(2, '0')" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="上报状态" prop="repAct">
-              <el-select v-model="form.repAct" placeholder="请选择上报状态">
-                <el-option v-for="dict in rep_stat" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="开始日期" prop="startDate">
-              <el-date-picker v-model="form.startDate" type="date" placeholder="选择开始日期" value-format="YYYY-MM-DD" style="width: 100%" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="结束日期" prop="endDate">
-              <el-date-picker v-model="form.endDate" type="date" placeholder="选择结束日期" value-format="YYYY-MM-DD" style="width: 100%" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="退回说明" prop="returnDesc">
-              <el-input v-model="form.returnDesc" type="textarea" placeholder="请输入退回说明" />
-            </el-form-item>
-          </el-col>
-        </el-row>
+    <el-dialog title="月报撤回申请" v-model="revocOpen" width="500px" append-to-body>
+      <el-form :model="revocForm" ref="revocRef" label-width="100px">
+        <el-form-item label="撤回原因" prop="revocDesc" :rules="[{ required: true, message: '请填写撤回原因', trigger: 'blur' }]">
+          <el-input v-model="revocForm.revocDesc" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="请输入撤回原因(500字以内)" />
+        </el-form-item>
       </el-form>
       <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel">取 消</el-button>
-        </div>
+        <el-button type="primary" @click="submitRevoc">确 定</el-button>
+        <el-button @click="revocOpen = false">取 消</el-button>
       </template>
     </el-dialog>
 
-    <!-- 撤回审批对话框 -->
-    <el-dialog title="撤回审批" v-model="verifyOpen" width="600px" append-to-body>
-      <el-form :model="verifyForm" :rules="verifyRules" ref="verifyRef" label-width="100px">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="上报单位">
-              <el-input v-model="verifyForm.repOrgGuid" disabled />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="上报期间">
-              <el-input v-model="verifyForm.repName" disabled />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="审批结果" prop="verifyResult">
-              <el-radio-group v-model="verifyForm.verifyResult">
-                <el-radio label="1">通过</el-radio>
-                <el-radio label="0">驳回</el-radio>
-              </el-radio-group>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="审批意见" prop="verifyOpinion">
-              <el-input v-model="verifyForm.verifyOpinion" type="textarea" placeholder="请输入审批意见" />
-            </el-form-item>
-          </el-col>
-        </el-row>
+    <el-dialog title="退回重报" v-model="returnOpen" width="500px" append-to-body>
+      <el-form :model="returnForm" ref="returnRef" label-width="100px">
+        <el-form-item label="退回说明" prop="returnDesc" :rules="[{ required: true, message: '请填写退回说明', trigger: 'blur' }]">
+          <el-input v-model="returnForm.returnDesc" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="请输入退回说明(500字以内)" />
+        </el-form-item>
       </el-form>
       <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitVerify">确 定</el-button>
-          <el-button @click="verifyOpen = false">取 消</el-button>
-        </div>
+        <el-button type="primary" @click="submitReturn">确 定</el-button>
+        <el-button @click="returnOpen = false">取 消</el-button>
       </template>
     </el-dialog>
 
-    <!-- 下级月报详情对话框 -->
-    <el-dialog title="下级月报详情" v-model="subMonthOpen" width="800px" append-to-body>
-      <el-table v-loading="subMonthLoading" :data="subMonthList">
-        <el-table-column label="上报单位" align="center" prop="repOrgGuid" :show-overflow-tooltip="true" />
-        <el-table-column label="上报期间" align="center" prop="repName" />
-        <el-table-column label="上报状态" align="center" prop="repAct">
+    <el-dialog title="待审批列表" v-model="pendingOpen" width="800px" append-to-body>
+      <el-table :data="pendingList" stripe border>
+        <el-table-column label="序号" type="index" width="60" align="center" />
+        <el-table-column label="申请单位" align="center" prop="repOrgName" min-width="120" :show-overflow-tooltip="true" />
+        <el-table-column label="申请月份" align="center" prop="repTime" width="120" />
+        <el-table-column label="上报说明" align="center" prop="reportDesc" min-width="150" :show-overflow-tooltip="true" />
+        <el-table-column label="撤回原因" align="center" prop="revocDesc" min-width="150" :show-overflow-tooltip="true" />
+        <el-table-column label="操作" align="center" width="140">
           <template #default="scope">
-            <dict-tag :options="rep_stat" :value="scope.row.repAct" />
-          </template>
-        </el-table-column>
-        <el-table-column label="上报时间" align="center" prop="repTime" width="180" />
-        <el-table-column label="操作" align="center" width="100">
-          <template #default="scope">
-            <el-tooltip content="查看" placement="top">
-              <el-button link type="primary" icon="View" @click="handleSubMonthDetail(scope.row)"></el-button>
-            </el-tooltip>
+            <el-button link type="primary" @click="handleApprove(scope.row)">同意</el-button>
+            <el-button link type="danger" @click="handleReject(scope.row)">不同意</el-button>
           </template>
         </el-table-column>
       </el-table>
+      <template #footer>
+        <el-button @click="pendingOpen = false">关 闭</el-button>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="一键解锁" v-model="unlockOpen" width="500px" append-to-body>
+      <el-form :model="unlockForm" ref="unlockRef" label-width="100px">
+        <el-form-item label="月份">
+          <span>{{ selectedMonth || '请先在左侧选择月份' }}</span>
+        </el-form-item>
+        <el-form-item label="解锁说明">
+          <el-input v-model="unlockForm.unlockDesc" type="textarea" :rows="3" placeholder="请输入解锁说明(选填)" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button type="primary" @click="submitUnlock">确 定</el-button>
+        <el-button @click="unlockOpen = false">取 消</el-button>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="自定义上报期" v-model="periodOpen" width="600px" append-to-body>
+      <el-form :model="periodForm" ref="periodRef" label-width="110px">
+        <el-form-item label="年份">
+          <el-select v-model="periodForm.year" placeholder="选择年份" style="width:150px">
+            <el-option v-for="y in availableYears" :key="y" :label="y + '年'" :value="y" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="月份">
+          <el-select v-model="periodForm.month" placeholder="选择月份" style="width:150px">
+            <el-option v-for="m in 12" :key="m" :label="m + '月'" :value="m" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="开始日期" prop="startDate" :rules="[{ required: true, message: '请选择开始日期', trigger: 'change' }]">
+          <el-date-picker v-model="periodForm.startDate" type="date" placeholder="选择开始日期" value-format="YYYY-MM-DD" />
+        </el-form-item>
+        <el-form-item label="结束日期" prop="endDate" :rules="[{ required: true, message: '请选择结束日期', trigger: 'change' }]">
+          <el-date-picker v-model="periodForm.endDate" type="date" placeholder="选择结束日期" value-format="YYYY-MM-DD" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button type="primary" @click="submitPeriod">确 定</el-button>
+        <el-button @click="periodOpen = false">取 消</el-button>
+      </template>
+    </el-dialog>
+
+    <el-dialog :title="detailTitle" v-model="detailOpen" width="85%" top="5vh" append-to-body destroy-on-close>
+      <div v-loading="detailLoading" style="min-height:400px;">
+        <iframe v-if="detailOpen && detailUrl" :src="detailUrl" style="width:100%;height:70vh;border:0;" />
+      </div>
+      <template #footer>
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </template>
     </el-dialog>
   </div>
 </template>
 
-<script setup name="BisOrgMonRepPeri">
-import { listBisOrgMonRepPeri, getBisOrgMonRepPeri, delBisOrgMonRepPeri, addBisOrgMonRepPeri, updateBisOrgMonRepPeri, batchUnlock, urgeReport } from "@/api/slaj/hidd"
-import { useTableHeight } from '@/hooks/useTableHeight'
-
-const { tableHeight, containerRef } = useTableHeight()
+<script setup name="MonthReport">
+import { getRepTreeData, getMonthListStats, revokeMonth, returnMonth, approveRevoke, batchUnlock, urgeReport, revokeApproveList, checkCanRevoke, addBisOrgMonRepPeri } from "@/api/slaj/hidd"
 
 const { proxy } = getCurrentInstance()
-const { rep_stat } = proxy.useDict("rep_stat")
-
-const currentYear = new Date().getFullYear()
-
-const monRepPeriList = ref([])
-const open = ref(false)
-const loading = ref(true)
-const showSearch = ref(true)
-const ids = ref([])
-const single = ref(true)
-const multiple = ref(true)
-const total = ref(0)
-const title = ref("")
-
-// 撤回审批
-const verifyOpen = ref(false)
-const verifyForm = ref({})
-const verifyRules = {
-  verifyResult: [{ required: true, message: "审批结果不能为空", trigger: "change" }]
-}
-
-// 下级月报
-const subMonthOpen = ref(false)
-const subMonthLoading = ref(false)
-const subMonthList = ref([])
-
-const columns = ref({
-  repOrgGuid: { label: '上报单位', visible: true },
-  repName: { label: '上报期间', visible: true },
-  repAct: { label: '上报状态', visible: true },
-  repTime: { label: '上报时间', visible: true },
-  returnDesc: { label: '退回说明', visible: true }
-})
-
-const data = reactive({
-  form: {},
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    repOrgGuid: undefined,
-    repName: undefined,
-    repAct: undefined
-  },
-  rules: {
-    repOrgGuid: [{ required: true, message: "上报单位不能为空", trigger: "blur" }],
-    repName: [{ required: true, message: "上报期间不能为空", trigger: "blur" }]
+
+const treeRef = ref(null)
+const treeData = ref([])
+const treeProps = { children: 'children', label: 'label' }
+
+const loading = ref(false)
+const statsList = ref([])
+const unitType = ref('1')
+const selectedMonth = ref('')
+const selectedYear = ref('')
+
+const promptText = ref('')
+
+function getPeriodText() {
+  const d = new Date()
+  let mon = d.getDate() <= 9 ? d.getMonth() : d.getMonth() + 1
+  if (mon === 0) mon = 12
+  const nextMonth = mon === 12 ? 1 : mon + 1
+  const nextYear = mon === 12 ? d.getFullYear() + 1 : d.getFullYear()
+  const start = d.getFullYear() + '-' + String(mon).padStart(2, '0') + '-07'
+  const end = nextYear + '-' + String(nextMonth).padStart(2, '0') + '-06'
+  return start + ' 至 ' + end
+}
+const periodText = ref(getPeriodText())
+
+const statsTotal = reactive({ directlyNum: 0, directlyRepNum: 0, riverInstNum: 0, riverInstRepNum: 0, subAdminNum: 0, subAdminRepNum: 0 })
+
+const revocOpen = ref(false)
+const revocForm = ref({})
+const returnOpen = ref(false)
+const returnForm = ref({})
+const pendingOpen = ref(false)
+const pendingList = ref([])
+const pendingCount = ref(0)
+const unlockOpen = ref(false)
+const unlockForm = ref({})
+const periodOpen = ref(false)
+const periodForm = ref({ year: new Date().getFullYear(), month: new Date().getMonth() + 1, startDate: '', endDate: '' })
+const availableYears = [new Date().getFullYear() - 2, new Date().getFullYear() - 1, new Date().getFullYear()]
+
+const detailOpen = ref(false)
+const detailTitle = ref('隐患月报详情')
+const detailLoading = ref(false)
+const detailUrl = ref('')
+
+const monthOptions = ref([])
+function buildMonthOptions() {
+  const options = []
+  const now = new Date()
+  for (let y = now.getFullYear(); y >= now.getFullYear() - 2; y--) {
+    for (let m = 12; m >= 1; m--) {
+      options.push({ value: y + '-' + String(m).padStart(2, '0'), label: y + '年' + m + '月' })
+    }
   }
-})
+  monthOptions.value = options
+}
 
-const { queryParams, form, rules } = toRefs(data)
+function handleMonthChange(val) {
+  if (!val) return
+  const parts = val.split('-')
+  selectedYear.value = parts[0]
+  selectedMonth.value = val
+  loadStats()
+  loadPromptStats()
+  loadPendingCount()
+}
 
-/** 查询月报期间列表 */
-function getList() {
-  loading.value = true
-  listBisOrgMonRepPeri(queryParams.value).then(res => {
-    loading.value = false
-    monRepPeriList.value = res.rows
-    total.value = res.total
+function loadPendingCount() {
+  revokeApproveList().then(res => {
+    const list = res.rows || res.data || []
+    pendingCount.value = list.length
+  }).catch(() => {
+    pendingCount.value = 0
   })
 }
 
-/** 搜索按钮操作 */
-function handleQuery() {
-  queryParams.value.pageNum = 1
-  getList()
+function loadTree() {
+  getRepTreeData().then(res => {
+    treeData.value = res.data || []
+    if (treeData.value.length > 0) {
+      const yearNode = treeData.value[0]
+      if (yearNode.children && yearNode.children.length > 0) {
+        const now = new Date()
+        const currentMonth = now.getMonth() + 1
+        let found = yearNode.children.find(n => Number(n.month) === currentMonth)
+        if (!found) found = yearNode.children[yearNode.children.length - 1]
+        setTimeout(() => {
+          treeRef.value?.setCurrentKey(found.id)
+          handleNodeClick(found)
+          selectedMonth.value = found.id
+        }, 100)
+      }
+    }
+  })
 }
 
-/** 重置按钮操作 */
-function resetQuery() {
-  proxy.resetForm("queryRef")
-  handleQuery()
+function handleNodeClick(data) {
+  if (!data.month) return
+  selectedMonth.value = data.id
+  selectedYear.value = data.pId
+  loadStats()
+  loadPromptStats()
 }
 
-/** 多选框选中数据 */
-function handleSelectionChange(selection) {
-  ids.value = selection.map(item => item.guid)
-  single.value = selection.length != 1
-  multiple.value = !selection.length
+function updatePrompt() {
+  const d = new Date()
+  const dateStr = d.getFullYear() + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日'
+  let mon = d.getDate() <= 9 ? d.getMonth() : d.getMonth() + 1
+  if (mon === 0) mon = 12
+  const nextMonth = mon === 12 ? 1 : mon + 1
+  promptText.value = `温馨提示:&nbsp;&nbsp;今天是${dateStr},${mon}月隐患月报:&nbsp;&nbsp;直属单位月报上报情况:${statsTotal.directlyRepNum}/${statsTotal.directlyNum};&nbsp;&nbsp;流域机构月报上报情况:${statsTotal.riverInstRepNum}/${statsTotal.riverInstNum};&nbsp;&nbsp;下级水行政主管部门月报上报情况:${statsTotal.subAdminRepNum}/${statsTotal.subAdminNum};&nbsp;&nbsp;月报开始时间:${mon}月07日至${nextMonth}月09日`
 }
 
-/** 新增按钮操作 */
-function handleAdd() {
-  reset()
-  open.value = true
-  title.value = "添加月报期间"
+function loadPromptStats() {
+  if (!selectedMonth.value) return
+  getMonthListStats({ repTime: selectedMonth.value }).then(res => {
+    const data = res.data || []
+    statsTotal.directlyNum = 0
+    statsTotal.directlyRepNum = 0
+    statsTotal.riverInstNum = 0
+    statsTotal.riverInstRepNum = 0
+    statsTotal.subAdminNum = 0
+    statsTotal.subAdminRepNum = 0
+    data.forEach(item => {
+      const t = item.repType
+      if (t === '1') { statsTotal.directlyNum++; if (item.repAct === '1') statsTotal.directlyRepNum++ }
+      else if (t === '3') { statsTotal.riverInstNum++; if (item.repAct === '1') statsTotal.riverInstRepNum++ }
+      else if (t === '2') { statsTotal.subAdminNum++; if (item.repAct === '1') statsTotal.subAdminRepNum++ }
+    })
+    updatePrompt()
+  }).catch(() => { updatePrompt() })
 }
 
-/** 修改按钮操作 */
-function handleUpdate(row) {
-  reset()
-  const guid = row.guid || ids.value
-  getBisOrgMonRepPeri(guid).then(response => {
-    form.value = response.data
-    open.value = true
-    title.value = "修改月报期间"
-  })
+function loadStats() {
+  if (!selectedMonth.value) return
+  loading.value = true
+  getMonthListStats({ repTime: selectedMonth.value, unitType: unitType.value }).then(res => {
+    statsList.value = res.data || []
+  }).finally(() => { loading.value = false })
 }
 
-/** 详情按钮操作 */
-function handleDetail(row) {
-  const guid = row.guid || ids.value
-  proxy.$router.push({ path: '/slaj/hidd/monthDetail', query: { guid: guid } })
+function handleReport() {
+  if (!selectedMonth.value) { proxy.$modal.msgWarning('请先在左侧选择月份'); return }
+  proxy.$router.push({ path: '/slaj/hidd/monthDetail', query: { month: selectedMonth.value, year: selectedYear.value } })
 }
 
-/** 下级月报按钮 */
-function handleSubMonth(row) {
-  subMonthLoading.value = true
-  subMonthOpen.value = true
-  // 查询下级单位的月报
-  listBisOrgMonRepPeri({ parentGuid: row.guid }).then(res => {
-    subMonthLoading.value = false
-    subMonthList.value = res.rows
+function handleOrgDetail(row) {
+  const orgGuid = row.repOrgGuid || row.orgGuid
+  const orgName = row.repName || ''
+  detailTitle.value = '隐患月报详情'
+  detailUrl.value = `/slaj/hidd/monthDetail?guid=${row.guid}&month=${selectedMonth.value}&orgName=${encodeURIComponent(orgName)}`
+  detailOpen.value = true
+}
+
+function handleRevocApply(row) {
+  checkCanRevoke(selectedMonth.value).then(res => {
+    if (res.data === true || res.data === 'true') {
+      revocForm.value = { guid: row.guid, revocDesc: '' }
+      revocOpen.value = true
+    } else {
+      proxy.$modal.msgWarning('上级部门已上报无法撤回')
+    }
+  }).catch(() => {
+    revocForm.value = { guid: row.guid, revocDesc: '' }
+    revocOpen.value = true
   })
 }
 
-/** 下级月报详情 */
-function handleSubMonthDetail(row) {
-  proxy.$router.push({ path: '/slaj/hidd/subMonthDetail', query: { guid: row.guid } })
+function submitRevoc() {
+  proxy.$refs.revocRef.validate(valid => {
+    if (valid) {
+      revokeMonth(revocForm.value.guid, revocForm.value.revocDesc).then(() => {
+        proxy.$modal.msgSuccess('撤回申请已提交')
+        revocOpen.value = false
+        loadStats()
+        loadPromptStats()
+      })
+    }
+  })
 }
 
-/** 撤回审批按钮 */
-function handleVerify(row) {
-  verifyForm.value = {
-    guid: row.guid,
-    repOrgGuid: row.repOrgGuid,
-    repName: row.repName,
-    verifyResult: undefined,
-    verifyOpinion: undefined
+function handleSupervise(row) {
+  const orgGuid = row.repOrgGuid || row.orgGuid
+  if (orgGuid) {
+    urgeReport(orgGuid, selectedMonth.value).then(() => {
+      proxy.$modal.msgSuccess('已发送督促通知')
+    })
   }
-  verifyOpen.value = true
 }
 
-/** 提交撤回审批 */
-function submitVerify() {
-  proxy.$refs["verifyRef"].validate(valid => {
+function handleReturn(row) {
+  returnForm.value = { guid: row.guid, returnDesc: '' }
+  returnOpen.value = true
+}
+
+function submitReturn() {
+  proxy.$refs.returnRef.validate(valid => {
     if (valid) {
-      const data = {
-        guid: verifyForm.value.guid,
-        repAct: verifyForm.value.verifyResult === '1' ? '1' : '3',
-        returnDesc: verifyForm.value.verifyOpinion
-      }
-      updateBisOrgMonRepPeri(data).then(response => {
-        proxy.$modal.msgSuccess("审批成功")
-        verifyOpen.value = false
-        getList()
+      returnMonth(returnForm.value.guid, returnForm.value.returnDesc).then(() => {
+        proxy.$modal.msgSuccess('退回成功')
+        returnOpen.value = false
+        loadStats()
+        loadPromptStats()
       })
     }
   })
 }
 
-/** 一键解锁按钮 */
-function handleUnlock() {
-  if (ids.value.length === 0) {
-    proxy.$modal.msgError("请先选择要解锁的月报")
-    return
-  }
-  proxy.$modal.confirm('是否确认对选中的' + ids.value.length + '个月报进行解锁操作?').then(function () {
-    return batchUnlock(ids.value)
-  }).then(() => {
-    getList()
-    proxy.$modal.msgSuccess("解锁成功")
-  }).catch(() => {})
+function handlePendingApproval() {
+  revokeApproveList().then(res => {
+    pendingList.value = res.rows || res.data || []
+    pendingOpen.value = true
+  }).catch(() => {
+    pendingList.value = []
+    pendingOpen.value = true
+  })
 }
 
-/** 督促上报按钮 */
-function handleUrge() {
-  if (ids.value.length === 0) {
-    proxy.$modal.msgError("请先选择要督促的月报")
-    return
-  }
-  const selection = monRepPeriList.value.filter(item => ids.value.includes(item.guid))
-  const notReported = selection.filter(item => item.repAct === '0')
-  if (notReported.length === 0) {
-    proxy.$modal.msgError("选中的单位均已上报,无需督促")
-    return
+function handleApprove(row) {
+  approveRevoke(row.guid, true, '').then(() => {
+    proxy.$modal.msgSuccess('已同意撤回')
+    pendingList.value = pendingList.value.filter(r => r.guid !== row.guid)
+    pendingCount.value = pendingList.value.length
+    loadStats()
+    loadPromptStats()
+  })
+}
+
+function handleReject(row) {
+  approveRevoke(row.guid, false, '').then(() => {
+    proxy.$modal.msgSuccess('已驳回')
+    pendingList.value = pendingList.value.filter(r => r.guid !== row.guid)
+    pendingCount.value = pendingList.value.length
+  })
+}
+
+function handleBatchUnlock() {
+  if (!selectedMonth.value) { proxy.$modal.msgWarning('请先在左侧选择月份'); return }
+  unlockForm.value = { unlockDesc: '' }
+  unlockOpen.value = true
+}
+
+function submitUnlock() {
+  const monthGuids = statsList.value.filter(r => r.repAct === '1').map(r => r.guid)
+  if (monthGuids.length === 0) {
+    proxy.$modal.msgWarning('当前月份没有已上报的单位')
+    unlockOpen.value = false; return
   }
-  const orgGuids = notReported.map(item => item.repOrgGuid).join(',')
-  const repName = notReported[0]?.repName || ''
-  proxy.$modal.confirm('是否确认对' + notReported.length + '个未上报单位进行督促?').then(function () {
-    return urgeReport(orgGuids, repName)
-  }).then(() => {
-    proxy.$modal.msgSuccess("督促通知已发送")
+  batchUnlock(monthGuids).then(() => {
+    proxy.$modal.msgSuccess('解锁成功')
+    unlockOpen.value = false
+    loadStats()
+    loadPromptStats()
   }).catch(() => {})
 }
 
-/** 提交按钮 */
-function submitForm() {
-  proxy.$refs["monRepPeriRef"].validate(valid => {
+function handleCustomPeriod() {
+  periodForm.value = { year: new Date().getFullYear(), month: new Date().getMonth() + 1, startDate: '', endDate: '' }
+  periodOpen.value = true
+}
+
+function submitPeriod() {
+  proxy.$refs.periodRef.validate(valid => {
     if (valid) {
-      if (form.value.guid != undefined) {
-        updateBisOrgMonRepPeri(form.value).then(response => {
-          proxy.$modal.msgSuccess("修改成功")
-          open.value = false
-          getList()
-        })
-      } else {
-        addBisOrgMonRepPeri(form.value).then(response => {
-          proxy.$modal.msgSuccess("新增成功")
-          open.value = false
-          getList()
-        })
-      }
+      const p = periodForm.value
+      addBisOrgMonRepPeri({
+        repName: p.year + '年' + String(p.month).padStart(2, '0') + '月隐患期间表',
+        repAct: '2',
+        repType: '0',
+        repTime: p.year + '-' + String(p.month).padStart(2, '0'),
+        startDate: p.startDate,
+        endDate: p.endDate
+      }).then(() => {
+        proxy.$modal.msgSuccess('自定义上报期设置成功')
+        periodOpen.value = false
+        loadTree()
+      }).catch(() => {})
     }
   })
 }
 
-/** 删除按钮操作 */
-function handleDelete(row) {
-  const guids = row.guid || ids.value
-  proxy.$modal.confirm('是否确认删除月报期间编号为"' + guids + '"的数据项?').then(function () {
-    return delBisOrgMonRepPeri(guids)
+function handleBatchRevoke() {
+  const canRevoke = statsList.value.filter(r => r.repAct === '1' && unitType.value === '0')
+  if (canRevoke.length === 0) {
+    proxy.$modal.msgWarning('当前没有可撤销的月报')
+    return
+  }
+  proxy.$modal.confirm('是否确认撤销本月已上报的月报?').then(() => {
+    return revokeMonth(canRevoke[0].guid)
   }).then(() => {
-    getList()
-    proxy.$modal.msgSuccess("删除成功")
+    proxy.$modal.msgSuccess('撤销成功')
+    loadStats()
+    loadPromptStats()
   }).catch(() => {})
 }
 
-/** 导出按钮操作 */
-function handleExport() {
-  proxy.download("hidd/monrepperi/export", {
-    ...queryParams.value
-  }, `monRepPeri_${new Date().getTime()}.xlsx`)
-}
-
-/** 重置表单 */
-function reset() {
-  form.value = {
-    guid: undefined,
-    repOrgGuid: undefined,
-    repName: undefined,
-    repAct: undefined,
-    repTime: undefined,
-    returnDesc: undefined,
-    startDate: undefined,
-    endDate: undefined
-  }
-  proxy.resetForm("monRepPeriRef")
-}
-
-onMounted(() => {
-  getList()
-})
+onMounted(() => { loadTree(); buildMonthOptions(); loadPendingCount() })
 </script>
+
+<style scoped>
+.global-top-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px 16px;
+  background: #fff;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  margin-bottom: 10px;
+  min-height: 40px;
+}
+.top-bar-actions {
+  display: flex;
+  gap: 6px;
+  flex-shrink: 0;
+}
+.month-layout {
+  display: flex;
+  gap: 12px;
+  height: calc(100vh - 150px);
+}
+.tree-panel {
+  width: 220px;
+  min-width: 220px;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  padding: 8px;
+  overflow-y: auto;
+  background: #fff;
+}
+.tree-header {
+  font-size: 12px;
+  padding: 4px 0 8px 0;
+  border-bottom: 1px solid #e4e7ed;
+  margin-bottom: 8px;
+}
+.status-dot {
+  display: inline-block;
+  width: 14px;
+  height: 14px;
+  border-radius: 2px;
+  vertical-align: middle;
+  margin: 0 2px;
+}
+.status-dot.reported { background-color: #579575; }
+.status-dot.unreported { background-color: #D8B83F; }
+.table-panel {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+.filter-bar {
+  display: flex;
+  align-items: center;
+  padding: 6px 10px;
+  background: #f9f9f9;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  flex-wrap: wrap;
+  gap: 4px;
+}
+.filter-label {
+  font-size: 13px;
+  font-weight: bold;
+  margin-right: 4px;
+  white-space: nowrap;
+}
+.filter-radios {
+  display: flex;
+  flex-wrap: wrap;
+}
+.action-bar {
+  display: flex;
+  align-items: center;
+  padding: 6px 10px;
+  background: #f9f9f9;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  margin-top: 6px;
+  gap: 8px;
+}
+:deep(.el-table__header-wrapper th > .cell) {
+  white-space: nowrap !important;
+}
+</style>

+ 455 - 275
gw-ui/src/views/slaj/hidd/monthDetail.vue

@@ -1,369 +1,549 @@
 <template>
-  <div class="app-container">
-    <el-card shadow="never">
-      <template #header>
-        <div class="card-header">
-          <span>月报基本信息</span>
-          <div>
-            <el-button type="success" plain icon="Promotion" @click="handleReport" v-hasPermi="['hidd:monrepperi:edit']">上报</el-button>
-            <el-button type="warning" plain icon="RefreshLeft" @click="handleReturn" v-hasPermi="['hidd:monrepperi:edit']">退回</el-button>
-            <el-button type="danger" plain icon="Refresh" @click="handleRevocation" v-hasPermi="['hidd:monrepperi:edit']">撤回</el-button>
-            <el-button type="primary" plain icon="ArrowLeft" @click="goBack">返回列表</el-button>
+  <div class="app-container month-detail">
+    <div class="tree-panel">
+      <div class="tree-header">
+        <span>下属单位</span>
+        <el-radio-group v-model="lockStatus" size="small" @change="handleLockChange" v-if="userStore.roles?.includes('1')">
+          <el-radio-button value="0">解锁</el-radio-button>
+          <el-radio-button value="1">加锁</el-radio-button>
+        </el-radio-group>
+      </div>
+      <el-tree
+        ref="deptTreeRef"
+        :data="deptTreeData"
+        :props="{ children: 'children', label: 'label' }"
+        node-key="id"
+        :highlight-current="true"
+        :expand-on-click-node="false"
+        @node-click="handleDeptNodeClick"
+        default-expand-all
+      />
+    </div>
+    <div class="main-area">
+      <el-card shadow="never" class="info-card">
+        <div class="info-header">
+          <div class="info-left">
+            <span class="info-title">{{ selectedYear }}年隐患月报</span>
+          </div>
+          <div class="info-right">
+            <span>上报单位:{{ form.repOrgName || route.query.orgName || '--' }}</span>
+            <span class="info-divider">|</span>
+            <span>月报开始日期:{{ form.startDate || '--' }}</span>
+            <span class="info-divider">|</span>
+            <span>月报结束日期:{{ form.endDate || '--' }}</span>
+            <span class="info-divider">|</span>
+            <span>月报状态:
+              <span v-if="form.repAct === '1'" style="color:#579575;">已上报</span>
+              <span v-else-if="form.repAct === '2'" style="color:#D8B83F;">未上报</span>
+              <span v-else>--</span>
+            </span>
+          </div>
+          <div class="info-buttons">
+            <el-button type="success" plain size="small" @click="handleExport">导出</el-button>
           </div>
         </div>
-      </template>
-      <el-descriptions :column="2" border>
-        <el-descriptions-item label="上报单位">{{ form.repOrgGuid }}</el-descriptions-item>
-        <el-descriptions-item label="上报期间">{{ form.repName }}</el-descriptions-item>
-        <el-descriptions-item label="上报状态">
-          <dict-tag :options="rep_stat" :value="form.repAct" />
-        </el-descriptions-item>
-        <el-descriptions-item label="上报时间">{{ form.repTime }}</el-descriptions-item>
-        <el-descriptions-item label="退回说明" :span="2">{{ form.note }}</el-descriptions-item>
-      </el-descriptions>
-    </el-card>
+      </el-card>
 
-    <el-card shadow="never" class="mt10">
-      <template #header>
-        <div class="card-header">
-          <span>月报隐患列表</span>
-          <el-button type="primary" plain icon="Plus" @click="handleAddHidd" v-hasPermi="['hidd:monrepperi:edit']">导入隐患</el-button>
-        </div>
-      </template>
-      <el-table v-loading="hiddLoading" :data="hiddList">
-        <el-table-column label="隐患名称" align="center" prop="hiddName" :show-overflow-tooltip="true" />
-        <el-table-column label="隐患等级" align="center" prop="hiddGrad">
-          <template #default="scope">
-            <dict-tag :options="hidd_grad" :value="scope.row.hiddGrad" />
-          </template>
-        </el-table-column>
-        <el-table-column label="隐患状态" align="center" prop="hiddStat">
-          <template #default="scope">
-            <dict-tag :options="hidd_stat" :value="scope.row.hiddStat" />
-          </template>
-        </el-table-column>
-        <el-table-column label="涉及部位" align="center" prop="proPart" :show-overflow-tooltip="true" />
-        <el-table-column label="采集时间" align="center" prop="collTime" width="180" />
-      </el-table>
-    </el-card>
-
-    <el-card shadow="never" class="mt10">
-      <template #header>
-        <div class="card-header">
-          <span>月报附件</span>
-        </div>
-      </template>
-      <el-table v-loading="fileLoading" :data="fileList">
-        <el-table-column label="附件名称" align="center" prop="medName" :show-overflow-tooltip="true" />
-        <el-table-column label="附件类型" align="center" prop="medType" />
-        <el-table-column label="上传时间" align="center" prop="createTime" width="180" />
-        <el-table-column label="操作" align="center" width="150">
-          <template #default="scope">
-            <el-tooltip content="下载" placement="top">
-              <el-button link type="primary" icon="Download" @click="handleDownload(scope.row)"></el-button>
-            </el-tooltip>
-            <el-tooltip content="删除" placement="top">
-              <el-button link type="primary" icon="Delete" @click="handleDeleteFile(scope.row)" v-hasPermi="['hidd:monrepperi:edit']"></el-button>
-            </el-tooltip>
-          </template>
-        </el-table-column>
-      </el-table>
-    </el-card>
-
-    <!-- 上报对话框 -->
-    <el-dialog title="月报上报" v-model="reportOpen" width="600px" append-to-body>
-      <el-form :model="reportForm" :rules="reportRules" ref="reportRef" label-width="100px">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="上报说明" prop="reportDesc">
-              <el-input v-model="reportForm.reportDesc" type="textarea" placeholder="请输入上报说明" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitReport">确 定</el-button>
-          <el-button @click="reportOpen = false">取 消</el-button>
-        </div>
-      </template>
-    </el-dialog>
+      <el-card shadow="never" class="table-card">
+        <el-table
+          v-loading="hiddLoading"
+          :data="hiddList"
+          @selection-change="handleSelectionChange"
+          border
+          stripe
+          height="calc(100vh - 360px)"
+          ref="hiddTableRef"
+        >
+          <el-table-column v-if="isAddMode" type="selection" width="45" align="center" />
+          <el-table-column label="序号" type="index" width="60" align="center" />
+          <el-table-column label="所属单位" align="center" prop="orgName" min-width="120" :show-overflow-tooltip="true" />
+          <el-table-column label="隐患名称" align="center" prop="hiddName" min-width="160" :show-overflow-tooltip="true">
+            <template #default="scope">
+              <el-link type="primary" @click="handleHiddNameClick(scope.row)">{{ scope.row.hiddName }}</el-link>
+            </template>
+          </el-table-column>
+          <el-table-column label="隐患类别" align="center" min-width="100">
+            <template #default="scope">
+              {{ scope.row.hiddGrad === '2' ? '重大隐患' : '一般隐患' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="所属工程" align="center" prop="engName" min-width="120" :show-overflow-tooltip="true" />
+          <el-table-column label="排查日期" align="center" width="100">
+            <template #default="scope">
+              {{ scope.row.inspDate ? scope.row.inspDate.substring(0, 10) : '--' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="要求整改完成日期" align="center" width="130">
+            <template #default="scope">
+              {{ scope.row.requCompDate ? scope.row.requCompDate.substring(0, 10) : '--' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="实际整改完成日期" align="center" width="130">
+            <template #default="scope">
+              {{ scope.row.factCompDate ? scope.row.factCompDate.substring(0, 10) : '--' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="整改状态" align="center" width="100">
+            <template #default="scope">
+              <el-link type="primary" @click="handleRectClick(scope.row)">
+                {{ scope.row.hiddStat === '0' ? '未落实整改' : scope.row.hiddStat === '1' ? '正在整改' : scope.row.hiddStat === '2' ? '完成整改' : '--' }}
+              </el-link>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination v-show="hiddTotal > 0" :total="hiddTotal" v-model:page="hiddQueryParams.pageNum" v-model:limit="hiddQueryParams.pageSize" @pagination="loadHiddList" />
+      </el-card>
 
-    <!-- 退回对话框 -->
-    <el-dialog title="月报退回" v-model="returnOpen" width="600px" append-to-body>
-      <el-form :model="returnForm" :rules="returnRules" ref="returnRef" label-width="100px">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="退回原因" prop="returnDesc">
-              <el-input v-model="returnForm.returnDesc" type="textarea" placeholder="请输入退回原因" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
+      <el-card v-if="isAddMode" shadow="never" class="upload-card">
+        <template #header>
+          <span>上传附件</span>
+        </template>
+        <el-upload
+          ref="uploadRef"
+          :action="uploadUrl"
+          :headers="uploadHeaders"
+          :multiple="true"
+          :limit="5"
+          :on-success="handleUploadSuccess"
+          :on-remove="handleUploadRemove"
+          :file-list="uploadFileList"
+          accept=".doc,.docx,.xls,.xlsx,.txt,.pdf,.zip,.rar"
+          list-type="text"
+        >
+          <el-button type="primary">选择文件</el-button>
+        </el-upload>
+      </el-card>
+
+      <el-card v-if="!isAddMode" shadow="never" class="upload-card">
+        <template #header>
+          <span>相关资料</span>
+        </template>
+        <el-table v-loading="fileLoading" :data="fileList" size="small">
+          <el-table-column label="序号" type="index" width="60" align="center" />
+          <el-table-column label="文件名" align="center" prop="medName" :show-overflow-tooltip="true" />
+          <el-table-column label="操作" align="center" width="150">
+            <template #default="scope">
+              <el-button link type="primary" @click="handleDownload(scope.row)">下载</el-button>
+              <el-button link type="danger" @click="handleDeleteFile(scope.row)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-card>
+
+      <div v-if="isAddMode" class="bottom-bar">
+        <el-button type="success" size="small" @click="handleExport">导出</el-button>
+        <el-button type="primary" size="small" @click="handleReport">上报</el-button>
+        <el-button size="small" @click="goBack">取消</el-button>
+      </div>
+    </div>
+
+    <el-dialog title="隐患信息" v-model="hiddDetailOpen" width="700px" append-to-body>
+      <el-descriptions :column="2" border v-if="hiddDetailRow">
+        <el-descriptions-item label="隐患名称" :span="2">{{ hiddDetailRow.hiddName }}</el-descriptions-item>
+        <el-descriptions-item label="隐患等级">
+          {{ hiddDetailRow.hiddGrad === '2' ? '重大隐患' : '一般隐患' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="隐患类别">{{ hiddDetailRow.hiddType }}</el-descriptions-item>
+        <el-descriptions-item label="所属工程">{{ hiddDetailRow.engName }}</el-descriptions-item>
+        <el-descriptions-item label="排查人">{{ hiddDetailRow.invePers }}</el-descriptions-item>
+        <el-descriptions-item label="排查日期">{{ hiddDetailRow.findDate }}</el-descriptions-item>
+        <el-descriptions-item label="隐患部位">{{ hiddDetailRow.proPart }}</el-descriptions-item>
+        <el-descriptions-item label="隐患描述" :span="2">{{ hiddDetailRow.hiddDesc }}</el-descriptions-item>
+      </el-descriptions>
       <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitReturn">确 定</el-button>
-          <el-button @click="returnOpen = false">取 消</el-button>
-        </div>
+        <el-button @click="hiddDetailOpen = false">关 闭</el-button>
       </template>
     </el-dialog>
 
-    <!-- 撤回对话框 -->
-    <el-dialog title="月报撤回" v-model="revocationOpen" width="600px" append-to-body>
-      <el-form :model="revocationForm" :rules="revocationRules" ref="revocationRef" label-width="100px">
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="撤回原因" prop="revocationDesc">
-              <el-input v-model="revocationForm.revocationDesc" type="textarea" placeholder="请输入撤回原因" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
+    <el-dialog title="隐患核实" v-model="hiddVerifyOpen" width="700px" append-to-body>
+      <el-descriptions :column="2" border v-if="hiddVerifyRow">
+        <el-descriptions-item label="隐患名称" :span="2">{{ hiddVerifyRow.hiddName }}</el-descriptions-item>
+        <el-descriptions-item label="核实日期">{{ hiddVerifyRow.verifyDate }}</el-descriptions-item>
+        <el-descriptions-item label="核实人">{{ hiddVerifyRow.verifyPers }}</el-descriptions-item>
+        <el-descriptions-item label="核实结果">{{ hiddVerifyRow.verifyResult }}</el-descriptions-item>
+        <el-descriptions-item label="核实说明" :span="2">{{ hiddVerifyRow.verifyDesc }}</el-descriptions-item>
+      </el-descriptions>
       <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitRevocation">确 定</el-button>
-          <el-button @click="revocationOpen = false">取 消</el-button>
-        </div>
+        <el-button @click="hiddVerifyOpen = false">关 闭</el-button>
       </template>
     </el-dialog>
 
-    <!-- 导入隐患对话框 -->
-    <el-dialog title="导入隐患" v-model="importOpen" width="800px" append-to-body>
-      <el-table v-loading="importLoading" :data="importList" @selection-change="handleImportSelectionChange">
-        <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="隐患名称" align="center" prop="hiddName" :show-overflow-tooltip="true" />
-        <el-table-column label="隐患等级" align="center" prop="hiddGrad">
-          <template #default="scope">
-            <dict-tag :options="hidd_grad" :value="scope.row.hiddGrad" />
-          </template>
-        </el-table-column>
-        <el-table-column label="隐患状态" align="center" prop="hiddStat">
-          <template #default="scope">
-            <dict-tag :options="hidd_stat" :value="scope.row.hiddStat" />
-          </template>
-        </el-table-column>
-        <el-table-column label="涉及部位" align="center" prop="proPart" :show-overflow-tooltip="true" />
-      </el-table>
+    <el-dialog title="隐患整改落实信息" v-model="rectImplOpen" width="700px" append-to-body>
+      <el-descriptions :column="2" border v-if="rectImplRow">
+        <el-descriptions-item label="隐患名称" :span="2">{{ rectImplRow.hiddName }}</el-descriptions-item>
+        <el-descriptions-item label="整改状态">
+          {{ rectImplRow.hiddStat === '0' ? '未落实整改' : rectImplRow.hiddStat === '1' ? '正在整改' : rectImplRow.hiddStat === '2' ? '完成整改' : '--' }}
+        </el-descriptions-item>
+        <el-descriptions-item label="整改负责人">{{ rectImplRow.rectPers }}</el-descriptions-item>
+        <el-descriptions-item label="要求整改完成日期">{{ rectImplRow.requCompDate }}</el-descriptions-item>
+        <el-descriptions-item label="实际整改完成日期">{{ rectImplRow.factCompDate }}</el-descriptions-item>
+      </el-descriptions>
       <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitImport">确 定</el-button>
-          <el-button @click="importOpen = false">取 消</el-button>
-        </div>
+        <el-button @click="rectImplOpen = false">关 闭</el-button>
       </template>
     </el-dialog>
   </div>
 </template>
 
 <script setup name="MonthDetail">
-import { getBisOrgMonRepPeri, updateBisOrgMonRepPeri, submitMonth, returnMonth, revokeMonth, listBisHiddRecRepWithHidd } from "@/api/slaj/hidd"
-import { listObjHidd } from "@/api/slaj/hidd"
-import { listAttMedBase, delAttMedBase } from "@/api/slaj/hidd"
+import { getBisOrgMonRepPeri, listBisHiddRecRepWithHidd, listAttMedBase, delAttMedBase, batchUnlock, submitMonth, listObjHidd, addAttMedBase, addBisOrgMonRepPeri, getMonthListStats } from "@/api/slaj/hidd"
+import { listAttOrgBase } from "@/api/slaj/hidd"
+import { getToken } from "@/utils/auth"
+import useUserStore from '@/store/modules/user'
 
 const { proxy } = getCurrentInstance()
-const { hidd_grad, hidd_stat, rep_stat } = proxy.useDict("hidd_grad", "hidd_stat", "rep_stat")
-
+const userStore = useUserStore()
 const route = useRoute()
+
+const isAddMode = computed(() => !route.query.guid)
+
 const form = ref({})
 const hiddList = ref([])
 const fileList = ref([])
-const importList = ref([])
-const importSelection = ref([])
-const selectedHiddGuids = ref([])
-
 const hiddLoading = ref(false)
 const fileLoading = ref(false)
-const importLoading = ref(false)
-
-// 上报对话框
-const reportOpen = ref(false)
-const reportForm = ref({})
-const reportRules = {}
-
-// 退回对话框
-const returnOpen = ref(false)
-const returnForm = ref({})
-const returnRules = {
-  returnDesc: [{ required: true, message: "退回原因不能为空", trigger: "blur" }]
+const hiddTotal = ref(0)
+const hiddQueryParams = ref({ pageNum: 1, pageSize: 20 })
+const selectedHiddGuids = ref([])
+const hiddTableRef = ref(null)
+const uploadFileList = ref([])
+
+const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/common/upload'
+const uploadHeaders = { Authorization: 'Bearer ' + getToken() }
+const uploadRef = ref(null)
+
+const selectedYear = ref(new Date().getFullYear())
+const selectedMonth = ref('')
+
+const deptTreeRef = ref(null)
+const deptTreeData = ref([])
+const lockStatus = ref('0')
+
+const selectedDeptId = ref(null)
+
+const hiddDetailOpen = ref(false)
+const hiddDetailRow = ref(null)
+const hiddVerifyOpen = ref(false)
+const hiddVerifyRow = ref(null)
+const rectImplOpen = ref(false)
+const rectImplRow = ref(null)
+
+function loadDeptTree() {
+  listAttOrgBase({}).then(res => {
+    const data = res.data || []
+    deptTreeData.value = buildTreeData(data, null)
+  })
+}
+
+function buildTreeData(list, parentId) {
+  const tree = []
+  list.forEach(item => {
+    if (item.pguid === parentId) {
+      const node = {
+        id: item.guid,
+        label: item.orgName,
+        children: buildTreeData(list, item.guid)
+      }
+      if (node.children.length === 0) delete node.children
+      tree.push(node)
+    }
+  })
+  return tree
 }
 
-// 撤回对话框
-const revocationOpen = ref(false)
-const revocationForm = ref({})
-const revocationRules = {
-  revocationDesc: [{ required: true, message: "撤回原因不能为空", trigger: "blur" }]
+function handleDeptNodeClick(data) {
+  selectedDeptId.value = data.id
+  loadHiddListByDept(data.id)
 }
 
-// 导入对话框
-const importOpen = ref(false)
+function loadHiddListByDept(deptId) {
+  hiddLoading.value = true
+  hiddList.value = []
+  
+  if (form.value.guid) {
+    listBisHiddRecRepWithHidd(form.value.guid).then(repRes => {
+      const allData = repRes.data || []
+      // 如果选择了部门,过滤该部门的数据
+      let filteredData = allData
+      if (deptId) {
+        filteredData = allData.filter(item => item.orgGuid === deptId || item.orgId === deptId)
+      }
+      
+      hiddTotal.value = filteredData.length
+      
+      // 分页处理
+      const start = (hiddQueryParams.value.pageNum - 1) * hiddQueryParams.value.pageSize
+      const end = start + hiddQueryParams.value.pageSize
+      hiddList.value = filteredData.slice(start, end)
+      
+      hiddLoading.value = false
+    }).catch(() => {
+      hiddLoading.value = false
+    })
+  } else {
+    hiddLoading.value = false
+  }
+}
+
+function handleLockChange(val) {
+  const selectedNodes = deptTreeRef.value?.getCheckedKeys() || []
+  if (selectedNodes.length === 0) {
+    proxy.$modal.msgWarning('请先选择需要操作的单位')
+    lockStatus.value = val === '0' ? '1' : '0'
+    return
+  }
+  
+  const msg = val === '0' ? '解锁' : '加锁'
+  proxy.$modal.confirm(`是否确认对选中的${selectedNodes.length}个单位进行${msg}操作?`).then(() => {
+    batchUnlock(selectedNodes).then(() => {
+      proxy.$modal.msgSuccess(`${msg}成功`)
+      loadDeptTree()
+    }).catch(() => {
+      lockStatus.value = val === '0' ? '1' : '0'
+    })
+  }).catch(() => {
+    lockStatus.value = val === '0' ? '1' : '0'
+  })
+}
 
-/** 查询月报详细 */
 function getInfo() {
   const guid = route.query.guid
   if (guid) {
     getBisOrgMonRepPeri(guid).then(response => {
       form.value = response.data
-      getHiddList()
-      getFileList()
+      loadHiddList()
+      loadFileList()
     })
+  } else {
+    // 新增模式:自动创建月报期间
+    const month = route.query.month
+    const year = route.query.year
+    if (month) {
+      initNewPeriod(month, year)
+    }
+    loadHiddList()
   }
 }
 
-/** 查询月报隐患列表 */
-function getHiddList() {
+function initNewPeriod(month, year) {
+  const repTime = month
+  const parts = month.split('-')
+  const startDate = year + '-' + parts[1] + '-07'
+  let endYear = parseInt(parts[0])
+  let endMonth = parseInt(parts[1])
+  if (endMonth === 12) {
+    endYear = endYear + 1
+    endMonth = 1
+  } else {
+    endMonth = endMonth + 1
+  }
+  const endDate = endYear + '-' + String(endMonth).padStart(2, '0') + '-06'
+  
+  // 检查是否已存在
+  getMonthListStats({ repTime: repTime, unitType: '0' }).then(res => {
+    const data = res.data || res.rows || []
+    const existing = data.find(d => d.repTime === repTime)
+    if (existing) {
+      if (existing.repAct === '1') {
+        proxy.$modal.msgWarning('本月数据已上报,不允许重复上报')
+      } else {
+        form.value = { guid: existing.guid, repTime: repTime, startDate: startDate, endDate: endDate, repAct: existing.repAct }
+      }
+    } else {
+      // 创建新的月报期间
+      addBisOrgMonRepPeri({
+        repName: repTime + '隐患期间表',
+        repAct: '2',
+        repType: '0',
+        repTime: repTime,
+        startDate: startDate,
+        endDate: endDate,
+        lockStatus: '1'
+      }).then(addRes => {
+        if (addRes.data && addRes.data.guid) {
+          form.value = { guid: addRes.data.guid, repTime: repTime, startDate: startDate, endDate: endDate, repAct: '2' }
+        }
+      }).catch(() => {})
+    }
+  }).catch(() => {})
+}
+
+function loadHiddList() {
   hiddLoading.value = true
-  listBisHiddRecRepWithHidd(form.value.guid).then(res => {
+  hiddList.value = []
+
+  if (isAddMode.value) {
+    // 新增模式:加载所有隐患
+    listObjHidd({}).then(res => {
+      const allData = res.rows || res.data || []
+      hiddTotal.value = allData.length
+      const start = (hiddQueryParams.value.pageNum - 1) * hiddQueryParams.value.pageSize
+      const end = start + hiddQueryParams.value.pageSize
+      hiddList.value = allData.slice(start, end)
+      hiddLoading.value = false
+    }).catch(() => {
+      hiddLoading.value = false
+    })
+  } else if (form.value.guid) {
+    listBisHiddRecRepWithHidd(form.value.guid).then(repRes => {
+      const allData = repRes.data || []
+      hiddTotal.value = allData.length
+      const start = (hiddQueryParams.value.pageNum - 1) * hiddQueryParams.value.pageSize
+      const end = start + hiddQueryParams.value.pageSize
+      hiddList.value = allData.slice(start, end)
+      hiddLoading.value = false
+    }).catch(() => {
+      hiddLoading.value = false
+    })
+  } else {
     hiddLoading.value = false
-    hiddList.value = res.data
-  })
+  }
 }
 
-/** 查询月报附件 */
-function getFileList() {
-  fileLoading.value = true
-  listAttMedBase({ bizGuid: form.value.guid }).then(res => {
-    fileLoading.value = false
-    fileList.value = res.rows
-  })
+function handleSelectionChange(selection) {
+  selectedHiddGuids.value = selection.map(r => r.guid)
 }
 
-/** 上报按钮 */
 function handleReport() {
-  reportForm.value = {
-    guid: form.value.guid,
-    reportDesc: undefined
+  if (selectedHiddGuids.value.length === 0) {
+    // 零报告:无隐患时也能上报
+    proxy.$modal.confirm('当前没有选择隐患记录,确定进行零报告上报吗?').then(() => {
+      doSubmitMonth([])
+    }).catch(() => {})
+    return
   }
-  reportOpen.value = true
-}
-
-/** 提交上报 */
-function submitReport() {
-  proxy.$refs["reportRef"].validate(valid => {
-    if (valid) {
-      const guids = selectedHiddGuids.value.length > 0 ? selectedHiddGuids.value : []
-      submitMonth(form.value.guid, guids).then(response => {
-        proxy.$modal.msgSuccess("上报成功")
-        reportOpen.value = false
-        getInfo()
-      })
-    }
-  })
+  doSubmitMonth(selectedHiddGuids.value)
 }
 
-/** 退回按钮 */
-function handleReturn() {
-  returnForm.value = {
-    guid: form.value.guid,
-    returnDesc: undefined
+function doSubmitMonth(guids) {
+  if (!form.value.guid) {
+    proxy.$modal.msgWarning('请稍候,月报期间正在创建中...')
+    return
   }
-  returnOpen.value = true
+  submitMonth(form.value.guid, guids).then(() => {
+    proxy.$modal.msgSuccess('上报成功')
+    goBack()
+  }).catch(() => {})
 }
 
-/** 提交退回 */
-function submitReturn() {
-  proxy.$refs["returnRef"].validate(valid => {
-    if (valid) {
-      returnMonth(form.value.guid, returnForm.value.returnDesc).then(response => {
-        proxy.$modal.msgSuccess("退回成功")
-        returnOpen.value = false
-        getInfo()
-      })
-    }
-  })
+function handleUploadSuccess(response, file) {
+  if (response.code === 200) {
+    addAttMedBase({ medName: file.name, medPath: response.fileName, bizGuid: form.value.guid }).then(() => {
+      proxy.$modal.msgSuccess('上传成功')
+    })
+  }
 }
 
-/** 撤回按钮 */
-function handleRevocation() {
-  revocationForm.value = {
-    guid: form.value.guid,
-    revocationDesc: undefined
+function handleUploadRemove(file) {
+  if (file.guid) {
+    delAttMedBase(file.guid)
   }
-  revocationOpen.value = true
 }
 
-/** 提交撤回 */
-function submitRevocation() {
-  proxy.$refs["revocationRef"].validate(valid => {
-    if (valid) {
-      revokeMonth(form.value.guid).then(response => {
-        proxy.$modal.msgSuccess("撤回成功")
-        revocationOpen.value = false
-        getInfo()
-      })
-    }
+function loadFileList() {
+  fileLoading.value = true
+  listAttMedBase({ bizGuid: form.value.guid }).then(res => {
+    fileList.value = res.rows || []
+    fileLoading.value = false
+  }).catch(() => {
+    fileLoading.value = false
   })
 }
 
-/** 导入隐患按钮 */
-function handleAddHidd() {
-  importSelection.value = []
-  importLoading.value = true
-  listObjHidd({ hiddStat: '0' }).then(res => {
-    importLoading.value = false
-    importList.value = res.rows
-    importOpen.value = true
-  })
+function handleHiddNameClick(row) {
+  hiddDetailRow.value = row
+  hiddDetailOpen.value = true
 }
 
-/** 导入选择改变 */
-function handleImportSelectionChange(selection) {
-  importSelection.value = selection
+function handleRectClick(row) {
+  rectImplRow.value = row
+  rectImplOpen.value = true
 }
 
-/** 提交导入 */
-function submitImport() {
-  if (importSelection.value.length === 0) {
-    proxy.$modal.msgError("请选择要导入的隐患")
-    return
-  }
-  const existingHiddGuids = new Set(hiddList.value.map(h => h.hiddGuid))
-  for (const item of importSelection.value) {
-    if (!existingHiddGuids.has(item.guid)) {
-      hiddList.value.push({
-        hiddGuid: item.guid,
-        hiddName: item.hiddName,
-        hiddGrad: item.hiddGrad,
-        hiddStat: item.hiddStat,
-        proPart: item.proPart
-      })
-      selectedHiddGuids.value.push(item.guid)
-    }
-  }
-  proxy.$modal.msgSuccess("导入成功")
-  importOpen.value = false
+function handleVerifyClick(row) {
+  hiddVerifyRow.value = row
+  hiddVerifyOpen.value = true
+}
+
+function handleExport() {
+  const repYear = selectedYear.value
+  const repMonth = form.value.repName || route.query.month || ''
+  const id = form.value.guid || route.query.guid || ''
+  window.location.href = `/hidd/hiddStat/export?repYear=${repYear}&repMonth=${encodeURIComponent(repMonth)}&id=${id}&requestType=1`
 }
 
-/** 下载附件 */
 function handleDownload(row) {
-  proxy.download("common/download", { fileName: row.medPath }, row.medName)
+  proxy.download('common/download', { fileName: row.medPath }, row.medName)
 }
 
-/** 删除附件 */
 function handleDeleteFile(row) {
-  proxy.$modal.confirm('是否确认删除附件"' + row.medName + '"?').then(function () {
+  proxy.$modal.confirm('是否确认删除附件"' + row.medName + '"?').then(() => {
     return delAttMedBase(row.guid)
   }).then(() => {
-    getFileList()
-    proxy.$modal.msgSuccess("删除成功")
+    loadFileList()
+    proxy.$modal.msgSuccess('删除成功')
   }).catch(() => {})
 }
 
-/** 返回列表 */
 function goBack() {
   proxy.$router.push({ path: '/slaj/hidd/month' })
 }
 
 onMounted(() => {
+  loadDeptTree()
   getInfo()
 })
 </script>
 
 <style scoped>
-.card-header {
+.month-detail {
+  display: flex;
+  gap: 10px;
+}
+.tree-panel {
+  width: 200px;
+  min-width: 200px;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  background: #fff;
+}
+.tree-header {
+  padding: 8px 12px;
+  font-size: 13px;
+  font-weight: bold;
+  border-bottom: 1px solid #e4e7ed;
   display: flex;
   justify-content: space-between;
   align-items: center;
 }
-.mt10 {
-  margin-top: 10px;
+.main-area {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+.info-card {
+  flex-shrink: 0;
+}
+.info-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 13px;
+}
+.info-left {
+  font-weight: bold;
+  font-size: 18px;
+}
+.info-buttons {
+  flex-shrink: 0;
+}
+.table-card {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+.upload-card {
+  flex-shrink: 0;
 }
 </style>

+ 708 - 0
gw-ui/src/views/slaj/hidd/orgEngQuery.vue

@@ -0,0 +1,708 @@
+<template>
+  <div class="app-container">
+    <el-tabs v-model="activeTab" type="border-card" @tab-change="handleTabChange">
+      <el-tab-pane label="本单位工程隐患" name="selfEng">
+        <div ref="containerRef" class="table-page-wrap">
+        <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+          <el-form-item label="隐患名称" prop="hiddName">
+            <el-input v-model="queryParams.hiddName" placeholder="请输入" clearable style="width: 200px" @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+          </el-form-item>
+          <el-form-item style="margin-left:auto;">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['hidd:objhidd:add']">新建</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hidd:objhidd:export']">导出</el-button>
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete" v-hasPermi="['hidd:objhidd:remove']">删除</el-button>
+          </el-form-item>
+        </el-form>
+
+        <div class="table-wrapper">
+        <el-table :height="tableHeight" v-loading="loading" :data="list" @selection-change="handleSelectionChange" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="排查单位" align="center" prop="orgName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="隐患名称" align="center" prop="hiddName" min-width="160" :show-overflow-tooltip="true" />
+          <el-table-column label="所属工程" align="center" prop="engName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="隐患级别" align="center" width="100">
+            <template #default="scope">
+              <dict-tag :options="hidd_grad" :value="scope.row.hiddGrad" />
+            </template>
+          </el-table-column>
+          <el-table-column label="隐患类型" align="center" width="100">
+            <template #default="scope">
+              <dict-tag :options="hidd_clas" :value="scope.row.hiddClas" />
+            </template>
+          </el-table-column>
+          <el-table-column label="排查日期" align="center" width="100" prop="inspDate" />
+          <el-table-column label="要求整改完成日期" align="center" width="120" prop="requCompDate" />
+          <el-table-column label="督办状态" align="center" width="90">
+            <template #default="scope">
+              <dict-tag :options="sup_stat" :value="scope.row.supStat" />
+            </template>
+          </el-table-column>
+          <el-table-column label="隐患状态" align="center" width="90">
+            <template #default="scope">
+              <dict-tag :options="hidd_stat" :value="scope.row.hiddStat" />
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="200" fixed="right">
+            <template #default="scope">
+              <el-button link type="primary" @click="handleRectify(scope.row)">整改</el-button>
+              <el-button v-if="scope.row.hiddStat==='2' && scope.row.supStat==='1' && scope.row.cancelState==='0'" link type="warning" @click="handleCancelApply(scope.row)">销号申请</el-button>
+              <span v-else-if="scope.row.hiddStat==='2' && scope.row.cancelState==='1'" style="color:#E6A23C">待销号</span>
+              <span v-else-if="scope.row.hiddStat==='2' && scope.row.cancelState==='2'" style="color:#67C23A">已销号</span>
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
+              <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" />
+            </template>
+          </el-table-column>
+        </el-table>
+        </div>
+
+        <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="下级单位隐患" name="subEng">
+        <div ref="containerRef2" class="table-page-wrap">
+        <el-form :model="queryParams2" :inline="true" v-show="showSearch" label-width="68px">
+          <el-form-item label="工程名称" prop="engName">
+            <el-input v-model="queryParams2.engName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="单位名称" prop="orgName">
+            <el-input v-model="queryParams2.orgName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="采集时间" prop="collTime">
+            <el-date-picker v-model="queryParams2.collTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery2">搜索</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport2">导出</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table :height="tableHeight" v-loading="loading2" :data="list2" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="工程名称" align="center" prop="engName" min-width="150" :show-overflow-tooltip="true" />
+          <el-table-column label="管理单位" align="center" prop="orgName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="总数" align="center" prop="totalCount" width="80" />
+          <el-table-column label="一般隐患" align="center" prop="normalCount" width="90" />
+          <el-table-column label="重大隐患" align="center" prop="majorCount" width="90" />
+          <el-table-column label="已整改隐患" align="center" prop="solvedCount" width="100" />
+        </el-table>
+
+        <pagination :total="total2" v-model:page="queryParams2.pageNum" v-model:limit="queryParams2.pageSize" @pagination="getList2" />
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="本单位标段隐患" name="bidEng">
+        <div class="table-page-wrap">
+        <el-form :model="queryParams3" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="标段名称" prop="engName">
+            <el-input v-model="queryParams3.engName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="单位名称" prop="orgName">
+            <el-input v-model="queryParams3.orgName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="采集时间" prop="collTime">
+            <el-date-picker v-model="queryParams3.collTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery3">搜索</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport3">导出</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table :height="tableHeight" v-loading="loading3" :data="list3" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="标段名称" align="center" prop="engName" min-width="150" :show-overflow-tooltip="true" />
+          <el-table-column label="管理单位" align="center" prop="orgName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="总数" align="center" prop="totalCount" width="80" />
+          <el-table-column label="一般隐患" align="center" prop="normalCount" width="90" />
+          <el-table-column label="重大隐患" align="center" prop="majorCount" width="90" />
+          <el-table-column label="已整改隐患" align="center" prop="solvedCount" width="100" />
+        </el-table>
+
+        <pagination :total="total3" v-model:page="queryParams3.pageNum" v-model:limit="queryParams3.pageSize" @pagination="getList3" />
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="施工单位隐患" name="consEng">
+        <div class="table-page-wrap">
+        <el-form :model="queryParams4" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="工程名称" prop="engName">
+            <el-input v-model="queryParams4.engName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="单位名称" prop="orgName">
+            <el-input v-model="queryParams4.orgName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="采集时间" prop="collTime">
+            <el-date-picker v-model="queryParams4.collTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery4">搜索</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport4">导出</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table :height="tableHeight" v-loading="loading4" :data="list4" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="工程名称" align="center" prop="engName" min-width="150" :show-overflow-tooltip="true" />
+          <el-table-column label="管理单位" align="center" prop="orgName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="总数" align="center" prop="totalCount" width="80" />
+          <el-table-column label="一般隐患" align="center" prop="normalCount" width="90" />
+          <el-table-column label="重大隐患" align="center" prop="majorCount" width="90" />
+          <el-table-column label="已整改隐患" align="center" prop="solvedCount" width="100" />
+        </el-table>
+
+        <pagination :total="total4" v-model:page="queryParams4.pageNum" v-model:limit="queryParams4.pageSize" @pagination="getList4" />
+        </div>
+      </el-tab-pane>
+
+      <el-tab-pane label="参建单位隐患" name="partEng">
+        <div class="table-page-wrap">
+        <el-form :model="queryParams5" :inline="true" v-show="showSearch" label-width="80px">
+          <el-form-item label="工程名称" prop="engName">
+            <el-input v-model="queryParams5.engName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="单位名称" prop="orgName">
+            <el-input v-model="queryParams5.orgName" placeholder="请输入" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="采集时间" prop="collTime">
+            <el-date-picker v-model="queryParams5.collTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery5">搜索</el-button>
+            <el-button type="warning" plain icon="Download" @click="handleExport5">导出</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table :height="tableHeight" v-loading="loading5" :data="list5" border style="width:100%" :header-cell-style="{ 'text-align': 'center' }">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="工程名称" align="center" prop="engName" min-width="150" :show-overflow-tooltip="true" />
+          <el-table-column label="管理单位" align="center" prop="orgName" min-width="140" :show-overflow-tooltip="true" />
+          <el-table-column label="总数" align="center" prop="totalCount" width="80" />
+          <el-table-column label="一般隐患" align="center" prop="normalCount" width="90" />
+          <el-table-column label="重大隐患" align="center" prop="majorCount" width="90" />
+          <el-table-column label="已整改隐患" align="center" prop="solvedCount" width="100" />
+        </el-table>
+
+        <pagination :total="total5" v-model:page="queryParams5.pageNum" v-model:limit="queryParams5.pageSize" @pagination="getList5" />
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+
+    <!-- 整改弹窗 -->
+    <el-dialog :title="rectifyTitle" v-model="rectifyOpen" width="800px" top="5vh" append-to-body>
+      <div class="rectify-section">
+        <div class="rectify-section-title">隐患整改落实</div>
+        <table class="rectify-table">
+          <tr>
+            <td class="td-head">治理责任单位</td>
+            <td>{{ rectForm.goverRespWiunName || '--' }}</td>
+            <td class="td-head">整改责任人</td>
+            <td>{{ rectForm.rectLegPers || '--' }}</td>
+          </tr>
+          <tr>
+            <td class="td-head">责任人电话</td>
+            <td>{{ rectForm.rectPersOffiTel || '--' }}</td>
+            <td class="td-head">整改完成日期</td>
+            <td>{{ rectForm.requCompDate || '--' }}</td>
+          </tr>
+          <tr>
+            <td class="td-head">累计落实治理资金</td>
+            <td colspan="3">{{ rectForm.acimpGoverFund ? rectForm.acimpGoverFund + '元' : '--' }}</td>
+          </tr>
+          <tr>
+            <td class="td-head">治理目标任务</td>
+            <td colspan="3">{{ rectForm.goveObjeTasks || '--' }}</td>
+          </tr>
+          <tr>
+            <td class="td-head">安全措施应急预案</td>
+            <td colspan="3">{{ rectForm.emerPlanSame || '--' }}</td>
+          </tr>
+          <tr>
+            <td class="td-head">整改措施描述</td>
+            <td colspan="3">{{ rectForm.corrMeas || '--' }}</td>
+          </tr>
+        </table>
+      </div>
+
+      <div class="rectify-section">
+        <div class="rectify-section-title">隐患整改进展情况</div>
+        <el-table :data="rectProgList" border size="small">
+          <el-table-column label="序号" align="center" type="index" width="60" />
+          <el-table-column label="进展情况" align="center" prop="rectProg" :show-overflow-tooltip="true" />
+          <el-table-column label="填报人" align="center" prop="recPers" width="100" />
+          <el-table-column label="填报时间" align="center" width="120">
+            <template #default="scope">
+              {{ scope.row.collTime ? scope.row.collTime.substring(0, 10) : '--' }}
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+
+      <div class="rectify-section">
+        <div class="rectify-section-title">隐患整改验收情况</div>
+        <table class="rectify-table">
+          <tr>
+            <td class="td-head">验收责任人</td>
+            <td>{{ rectAcceForm.accepLegPers || '--' }}</td>
+            <td class="td-head">整改完成日期</td>
+            <td>{{ rectAcceForm.requCompDate || '--' }}</td>
+          </tr>
+        </table>
+      </div>
+
+      <template #footer>
+        <el-button @click="rectifyOpen = false">关 闭</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 整改消耗弹窗(验收/销号,对应旧版 openDialog1) -->
+    <el-dialog title="整改消耗信息" v-model="cancelOpen" width="550px" append-to-body>
+      <el-form :model="cancelForm" ref="cancelFormRef" label-width="80px">
+        <el-form-item label="责任人" prop="accepPers" :rules="[{ required: true, message: '请输入责任人', trigger: 'blur' }]">
+          <el-input v-model="cancelForm.accepPers" placeholder="请输入" />
+        </el-form-item>
+        <el-form-item label="消耗时间">
+          <el-date-picker v-model="cancelForm.accepDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" style="width:100%" />
+        </el-form-item>
+        <el-form-item label="验收意见" prop="accepOpin" :rules="[{ required: true, message: '请输入验收意见', trigger: 'blur' }]">
+          <el-input v-model="cancelForm.accepOpin" type="textarea" :rows="3" placeholder="请输入" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button type="primary" @click="submitCancel">确 认</el-button>
+        <el-button @click="cancelOpen = false">取 消</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 隐患详情弹窗(对应旧版 hiddInfo.jsp) -->
+    <el-dialog title="隐患信息" v-model="detailOpen" width="700px" append-to-body>
+      <table class="rectify-table">
+        <tr>
+          <td class="td-head">隐患名称</td>
+          <td>{{ detailForm.hiddName || '--' }}</td>
+          <td class="td-head">所属工程</td>
+          <td>{{ detailForm.engName || '--' }}</td>
+        </tr>
+        <tr>
+          <td class="td-head">排查日期</td>
+          <td>{{ detailForm.inspDate || '--' }}</td>
+          <td class="td-head">隐患级别</td>
+          <td>{{ detailForm.hiddGrad === '2' ? '重大隐患' : '一般隐患' }}</td>
+        </tr>
+        <tr>
+          <td class="td-head">隐患类别</td>
+          <td><dict-tag :options="hidd_clas" :value="detailForm.hiddClas" /></td>
+          <td class="td-head">排查单位</td>
+          <td>{{ detailForm.orgName || '--' }}</td>
+        </tr>
+        <tr>
+          <td class="td-head">涉及部位</td>
+          <td>{{ detailForm.proPart || '--' }}</td>
+          <td class="td-head">隐患状态</td>
+          <td><dict-tag :options="hidd_stat" :value="detailForm.hiddStat" /></td>
+        </tr>
+        <tr>
+          <td class="td-head">隐患描述</td>
+          <td colspan="3">{{ detailForm.otlcolQiffFnvu || '--' }}</td>
+        </tr>
+        <tr>
+          <td class="td-head">备注</td>
+          <td colspan="3">{{ detailForm.note || '--' }}</td>
+        </tr>
+      </table>
+      <template #footer>
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 新建/修改弹窗 -->
+    <el-dialog v-model="formDrawer" :title="formTitle" width="750px" top="5vh" append-to-body>
+      <div class="form-drawer-body">
+        <div class="info-tip">
+          <i class="el-icon-info" style="color:#409EFF;"></i>
+          上传的附件文件命名应为中文,按照多个附件文件,文件名称格式为中文+序号(001,按照增加),例如演练照片001。用于说明该文件内容。文件名称中文部分内容长度不可超过10个文字。文件类型为jpg、jpeg、png、pdf,单个文件大小不能超过10MB。
+        </div>
+
+        <div class="form-section-title">基本信息</div>
+        <table class="form-table">
+          <tr>
+            <td class="label-cell"><span class="required">*</span>隐患名称</td>
+            <td class="value-cell">
+              <div class="input-with-action">
+                <el-input v-model="form.hiddName" placeholder="请输入隐患名称" size="small" />
+                <el-button type="primary" size="small" link>选择</el-button>
+              </div>
+            </td>
+            <td class="label-cell"><span class="required">*</span>所属工程</td>
+            <td class="value-cell">
+              <el-select v-model="form.engName" placeholder="请选择所属工程" size="small" style="width:100%">
+                <el-option v-for="dict in engList" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </td>
+          </tr>
+          <tr>
+            <td class="label-cell"><span class="required">*</span>排查日期</td>
+            <td class="value-cell">
+              <el-date-picker v-model="form.inspDate" type="date" placeholder="请选择排查日期" value-format="YYYY-MM-DD" size="small" style="width:100%" />
+            </td>
+            <td class="label-cell"><span class="required">*</span>隐患级别</td>
+            <td class="value-cell">
+              <el-select v-model="form.hiddGrad" placeholder="请输入隐患级别" size="small" style="width:100%">
+                <el-option v-for="dict in hidd_grad" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </td>
+          </tr>
+            <tr>
+              <td class="label-cell"><span class="required">*</span>所属工程</td>
+              <td class="value-cell">
+                <el-input v-model="form.engName" placeholder="请选择所属工程" size="small" />
+              </td>
+              <td class="label-cell"><span class="required">*</span>排查单位</td>
+              <td class="value-cell">
+                <el-input v-model="form.orgName" placeholder="请输入排查单位" size="small" />
+              </td>
+            </tr>
+          <tr>
+            <td class="label-cell">发现人</td>
+            <td class="value-cell">
+              <el-input v-model="form.inspLeader" placeholder="请输入发现人" size="small" />
+            </td>
+            <td class="label-cell">职务</td>
+            <td class="value-cell">
+              <el-input v-model="form.inspLeaderPost" placeholder="请输入职务" size="small" />
+            </td>
+          </tr>
+          <tr>
+            <td class="label-cell"><span class="required">*</span>隐患部位</td>
+            <td class="value-cell">
+              <el-input v-model="form.proPart" placeholder="请输入隐患部位" size="small" />
+            </td>
+            <td class="label-cell"><span class="required">*</span>隐患情况描述</td>
+            <td class="value-cell">
+              <el-input v-model="form.hiddDesc" placeholder="请输入隐患情况描述" size="small" />
+            </td>
+          </tr>
+          <tr>
+            <td class="label-cell"><span class="required">*</span>现场照片附件</td>
+            <td class="value-cell" colspan="3">
+              <div class="upload-warning">
+                <p>本平台为互联网涉密平台,严禁处理、传输国家秘密</p>
+                <p>严禁在本互联网涉密平台处理、传输国家秘密,请确认以扫描、传输的文件资料不涉及国家秘密。</p>
+              </div>
+              <el-upload ref="uploadRef" action="#" :auto-upload="false" :limit="10" accept=".jpg,.jpeg,.png,.pdf">
+                <el-button type="primary" size="small">添加文件</el-button>
+                <el-button type="success" size="small" @click="uploadFiles">上传文件</el-button>
+                <span style="color:#999;font-size:12px;margin-left:8px;">最多只能上传10个文件</span>
+              </el-upload>
+            </td>
+          </tr>
+        </table>
+      </div>
+      <template #footer>
+        <el-button @click="formDrawer = false">取 消</el-button>
+        <el-button type="primary" @click="submitFormDrawer" :loading="formLoading">保 存</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="OrgEngQuery">
+import { listObjHidd, delObjHidd, addObjHidd, updateObjHidd, compoundSaveHidd, getHiddGroupBy, listBisHiddRectImpl, listBisHiddRectAcce, listBisHiddRectProg } from "@/api/slaj/hidd"
+import { useTableHeight } from '@/hooks/useTableHeight'
+
+const { tableHeight, containerRef } = useTableHeight()
+const { proxy } = getCurrentInstance()
+const { hidd_grad, hidd_stat, sup_stat, hidd_clas } = proxy.useDict("hidd_grad", "hidd_stat", "sup_stat", "hidd_clas")
+
+const activeTab = ref('selfEng')
+const showSearch = ref(true)
+
+// Tab1 本单位工程隐患
+const list = ref([]); const loading = ref(false); const total = ref(0)
+const ids = ref([]); const single = ref(true); const multiple = ref(true)
+const queryParams = reactive({ pageNum: 1, pageSize: 10, hiddSort: '1', hiddName: undefined })
+
+// 整改弹窗
+const rectifyOpen = ref(false)
+const rectifyTitle = ref('隐患整改')
+const rectForm = ref({})
+const rectProgList = ref([])
+const rectAcceForm = ref({})
+
+// 隐患详情弹窗(对应旧版 hiddInfo.jsp)
+const detailOpen = ref(false)
+const detailForm = ref({})
+
+// 整改消耗弹窗
+const cancelOpen = ref(false)
+const cancelForm = ref({})
+const cancelFormRef = ref(null)
+
+function getList() {
+  loading.value = true
+  listObjHidd(queryParams).then(res => {
+    list.value = res.rows || []
+    total.value = res.total || 0
+    loading.value = false
+  }).catch(() => { loading.value = false })
+}
+function handleQuery() { queryParams.pageNum = 1; getList() }
+function handleSelectionChange(selection) { ids.value = selection.map(item => item.guid); single.value = selection.length !== 1; multiple.value = !selection.length }
+// 新建/修改抽屉
+const formDrawer = ref(false)
+const formTitle = ref('新建隐患')
+const form = ref({})
+const formLoading = ref(false)
+const isEditMode = computed(() => !!form.value.guid)
+
+function handleAdd() {
+  formTitle.value = '本级单位工程隐患新增'
+  form.value = { hiddSort: '1', hiddGrad: '1', hiddStat: '0', inspDate: '', inspLeader: '', inspLeaderPost: '', proPart: '', hiddDesc: '', engGuid: '', orgGuid: '' }
+  formDrawer.value = true
+}
+
+function handleUpdate(row) {
+  const guid = row ? row.guid : ids.value[0]
+  if (!guid) { proxy.$modal.msgWarning('请先选择一条数据'); return }
+  listObjHidd({ guid: guid }).then(res => {
+    if (res.rows && res.rows.length > 0) {
+      const data = res.rows[0]
+      form.value = {
+        ...data,
+        inspLeader: data.inspLeader || '',
+        inspLeaderPost: data.inspLeaderPost || '',
+        hiddDesc: data.otlcolQiffFnvu || data.hiddDesc || ''
+      }
+      // 查询整改落实
+      listBisHiddRectImpl({ hiddGuid: guid }).then(rectRes => {
+        if (rectRes.rows && rectRes.rows.length > 0) {
+          const r = rectRes.rows[0]
+          form.value = { ...form.value, ...r, goverRespWiunName: r.goverRespWiunName || r.goverRespWiun || '' }
+        }
+        // 查询整改验收
+        listBisHiddRectAcce({ hiddGuid: guid }).then(acceRes => {
+          if (acceRes.rows && acceRes.rows.length > 0) {
+            const a = acceRes.rows[0]
+            form.value = { ...form.value, accepDate: a.accepDate, accepLegPers: a.accepLegPers, requCompDate: a.requCompDate }
+          }
+        })
+      })
+      formTitle.value = '修改隐患'
+      formDrawer.value = true
+    }
+  })
+}
+
+function uploadFiles() {
+  proxy.$modal.msgInfo('文件上传功能待实现')
+}
+
+function submitFormDrawer() {
+  if (!form.value.hiddName) { proxy.$modal.msgWarning('请输入隐患名称'); return }
+  formLoading.value = true
+  const data = {
+    hiddName: form.value.hiddName,
+    engGuid: form.value.engGuid || '',
+    hiddGrad: form.value.hiddGrad,
+    hiddClas: form.value.hiddClas,
+    hiddStat: form.value.hiddStat || '0',
+    proPart: form.value.proPart,
+    hiddDesc: form.value.hiddDesc || form.value.otlcolQiffFnvu,
+    hiddSort: form.value.hiddSort || '1',
+    orgGuid: form.value.orgGuid || form.value.revoOrgGuid || '',
+    isList: form.value.isList || '0',
+    bisHiddInveDto: [{
+      inspDate: form.value.inspDate ? form.value.inspDate + ' 00:00:00' : '',
+      inspOrgGuid: form.value.orgGuid || form.value.revoOrgGuid || '',
+      recPers: form.value.inspLeader || '',
+      inspLeaderPost: form.value.inspLeaderPost || ''
+    }]
+  }
+  if (form.value.guid) {
+    data.guid = form.value.guid
+  }
+  compoundSaveHidd(data).then(() => {
+    proxy.$modal.msgSuccess(form.value.guid ? '修改成功' : '新增成功')
+    formDrawer.value = false
+    formLoading.value = false
+    getList()
+  }).catch(() => { formLoading.value = false })
+}
+
+function handleExport() { proxy.download("hidd/objhidd/export", { ...queryParams }, `本单位工程隐患_${new Date().getTime()}.xlsx`) }
+
+function handleDelete(row) {
+  const guids = row.guid || ids.value.join(',')
+  proxy.$modal.confirm('是否确认删除?').then(() => delObjHidd(guids)).then(() => { getList(); proxy.$modal.msgSuccess('删除成功') }).catch(() => {})
+}
+
+function handleCancelApply(row) {
+  cancelForm.value = { guid: row.guid, accepPers: '', accepDate: '', accepOpin: '' }
+  cancelOpen.value = true
+}
+function submitCancel() {
+  cancelFormRef.value.validate(valid => {
+    if (!valid) return
+    proxy.$modal.msgSuccess('销号申请已提交')
+    cancelOpen.value = false
+  })
+}
+
+// Tab2-5 统计聚合
+const list2 = ref([]); const loading2 = ref(false); const total2 = ref(0)
+const queryParams2 = reactive({ pageNum: 1, pageSize: 10, hiddSort: '1', engName: undefined, orgName: undefined, collTime: undefined })
+const list3 = ref([]); const loading3 = ref(false); const total3 = ref(0)
+const queryParams3 = reactive({ pageNum: 1, pageSize: 10, hiddSort: '1', engName: undefined, orgName: undefined, collTime: undefined })
+const list4 = ref([]); const loading4 = ref(false); const total4 = ref(0)
+const queryParams4 = reactive({ pageNum: 1, pageSize: 10, hiddSort: '1', engName: undefined, orgName: undefined, collTime: undefined })
+const list5 = ref([]); const loading5 = ref(false); const total5 = ref(0)
+const queryParams5 = reactive({ pageNum: 1, pageSize: 10, hiddSort: '1', engName: undefined, orgName: undefined, collTime: undefined })
+
+function loadGroup(params, listRef, loadingRef, totalRef) {
+  loadingRef.value = true
+  getHiddGroupBy(params).then(res => {
+    listRef.value = res.data || []
+    totalRef.value = listRef.value.length
+    loadingRef.value = false
+  }).catch(() => { loadingRef.value = false })
+}
+function getList2() { loadGroup(queryParams2, list2, loading2, total2) }
+function getList3() { loadGroup(queryParams3, list3, loading3, total3) }
+function getList4() { loadGroup(queryParams4, list4, loading4, total4) }
+function getList5() { loadGroup(queryParams5, list5, loading5, total5) }
+function handleQuery2() { queryParams2.pageNum = 1; getList2() }
+function handleQuery3() { queryParams3.pageNum = 1; getList3() }
+function handleQuery4() { queryParams4.pageNum = 1; getList4() }
+function handleQuery5() { queryParams5.pageNum = 1; getList5() }
+function handleExport2() { proxy.download("hidd/objhidd/export", { ...queryParams2 }, `下级单位隐患_${new Date().getTime()}.xlsx`) }
+function handleExport3() { proxy.download("hidd/objhidd/export", { ...queryParams3 }, `标段隐患_${new Date().getTime()}.xlsx`) }
+function handleExport4() { proxy.download("hidd/objhidd/export", { ...queryParams4 }, `施工单位隐患_${new Date().getTime()}.xlsx`) }
+function handleExport5() { proxy.download("hidd/objhidd/export", { ...queryParams5 }, `参建单位隐患_${new Date().getTime()}.xlsx`) }
+
+function handleRectify(row) {
+  const hiddGuid = row.guid
+  rectifyTitle.value = '隐患整改落实 - ' + (row.hiddName || '')
+  rectForm.value = {}
+  rectProgList.value = []
+  rectAcceForm.value = {}
+  rectifyOpen.value = true
+  // 查询整改落实
+  listBisHiddRectImpl({ hiddGuid: hiddGuid }).then(res => {
+    if (res.rows && res.rows.length > 0) {
+      rectForm.value = res.rows[0]
+    }
+  })
+  // 查询整改验收
+  listBisHiddRectAcce({ hiddGuid: hiddGuid }).then(res => {
+    if (res.rows && res.rows.length > 0) {
+      rectAcceForm.value = res.rows[0]
+    }
+  })
+  // 查询整改进展
+  listBisHiddRectProg({ hiddGuid: hiddGuid }).then(res => {
+    rectProgList.value = res.rows || []
+  })
+}
+
+function handleTabChange() {
+  if (activeTab.value === 'selfEng') getList()
+  else if (activeTab.value === 'subEng') getList2()
+  else if (activeTab.value === 'bidEng') getList3()
+  else if (activeTab.value === 'consEng') getList4()
+  else if (activeTab.value === 'partEng') getList5()
+}
+
+onMounted(() => { getList() })
+</script>
+
+<style scoped>
+.rectify-section {
+  margin-bottom: 16px;
+}
+.rectify-section-title {
+  font-size: 14px;
+  font-weight: bold;
+  margin-bottom: 8px;
+  padding: 6px 12px;
+  background-color: #F2F2F2;
+  border-left: 3px solid #409EFF;
+}
+.rectify-table {
+  width: 100%;
+  border-collapse: collapse;
+  text-align: center;
+}
+.rectify-table td {
+  border: 1px solid #e4e7ed;
+  padding: 8px 12px;
+  font-size: 13px;
+}
+.td-head {
+  font-weight: bold;
+  width: 20%;
+  background-color: #fafafa;
+}
+.form-drawer-body {
+  padding: 0;
+  max-height: 65vh;
+  overflow-y: auto;
+}
+.info-tip {
+  background: #EBF3FF;
+  border: 1px solid #C2D7FF;
+  border-radius: 4px;
+  padding: 8px 12px;
+  margin-bottom: 12px;
+  font-size: 12px;
+  color: #606266;
+  line-height: 1.6;
+}
+.info-tip i {
+  margin-right: 4px;
+}
+.form-section-title {
+  font-size: 14px;
+  font-weight: bold;
+  margin-bottom: 12px;
+  padding-bottom: 8px;
+  border-bottom: 1px solid #e4e7ed;
+}
+.form-table {
+  width: 100%;
+  border-collapse: collapse;
+}
+.form-table td {
+  padding: 6px 8px;
+  font-size: 13px;
+}
+.label-cell {
+  width: 15%;
+  text-align: right;
+  vertical-align: middle;
+  color: #606266;
+  white-space: nowrap;
+}
+.value-cell {
+  width: 35%;
+  vertical-align: middle;
+}
+.required {
+  color: #f56c6c;
+  margin-right: 2px;
+}
+.input-with-action {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+.upload-warning {
+  color: #f56c6c;
+  font-size: 12px;
+  margin-bottom: 8px;
+  line-height: 1.6;
+}
+</style>

+ 64 - 254
gw-ui/src/views/slaj/hidd/stat.vue

@@ -1,158 +1,68 @@
 <template>
   <div ref="containerRef" class="app-container">
-    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="统计年份" prop="statYear">
-        <el-date-picker v-model="queryParams.statYear" type="year" placeholder="选择年份" value-format="YYYY" />
-      </el-form-item>
-      <el-form-item label="统计月份" prop="statMonth">
-        <el-select v-model="queryParams.statMonth" placeholder="请选择统计月份" clearable style="width: 150px">
-          <el-option v-for="item in 12" :key="item" :label="item + '月'" :value="item" />
-        </el-select>
-      </el-form-item>
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px">
       <el-form-item label="单位性质" prop="unitType">
-        <el-select v-model="queryParams.unitType" placeholder="请选择单位性质" clearable style="width: 180px">
+        <el-select v-model="queryParams.unitType" placeholder="请选择" clearable style="width: 180px">
           <el-option label="直属单位" value="1" />
           <el-option label="流域机构" value="2" />
-          <el-option label="下级水行政部门" value="3" />
+          <el-option label="下级水行政主管部门" value="3" />
         </el-select>
       </el-form-item>
-      <el-form-item label="机构名称" prop="orgName">
-        <el-input v-model="queryParams.orgName" placeholder="请输入机构名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
+      <el-form-item label="单位名称" prop="orgName">
+        <el-input v-model="queryParams.orgName" placeholder="请输入" clearable style="width: 180px" />
+      </el-form-item>
+      <el-form-item label="统计时间" prop="createTime">
+        <el-date-picker v-model="queryParams.createTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" clearable style="width: 160px" />
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
 
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hidd:count:export']">导出</el-button>
-      </el-col>
-      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" storageKey="hidd-count-index"></right-toolbar>
-    </el-row>
-
-    <el-row :gutter="20" class="mb8">
-      <el-col :span="4">
-        <el-card shadow="hover">
-          <template #header>
-            <div class="card-header">
-              <span>隐患总数</span>
-            </div>
-          </template>
-          <div class="stat-value">{{ statData.totalHidd }}</div>
-        </el-card>
-      </el-col>
-      <el-col :span="4">
-        <el-card shadow="hover">
-          <template #header>
-            <div class="card-header">
-              <span>已整改</span>
-            </div>
-          </template>
-          <div class="stat-value" style="color: #67C23A">{{ statData.solvedHidd }}</div>
-        </el-card>
-      </el-col>
-      <el-col :span="4">
-        <el-card shadow="hover">
-          <template #header>
-            <div class="card-header">
-              <span>整改中</span>
-            </div>
-          </template>
-          <div class="stat-value" style="color: #E6A23C">{{ statData.solvingHidd }}</div>
-        </el-card>
-      </el-col>
-      <el-col :span="4">
-        <el-card shadow="hover">
-          <template #header>
-            <div class="card-header">
-              <span>未整改</span>
-            </div>
-          </template>
-          <div class="stat-value" style="color: #F56C6C">{{ statData.unsolvedHidd }}</div>
-        </el-card>
-      </el-col>
-      <el-col :span="4">
-        <el-card shadow="hover">
-          <template #header>
-            <div class="card-header">
-              <span>逾期未整改</span>
-            </div>
-          </template>
-          <div class="stat-value" style="color: #F56C6C">{{ statData.overTimeHidd }}</div>
-        </el-card>
-      </el-col>
-      <el-col :span="4">
-        <el-card shadow="hover">
-          <template #header>
-            <div class="card-header">
-              <span>综合整改率</span>
-            </div>
-          </template>
-          <div class="stat-value" style="color: #409EFF">{{ statData.avgSolveRate }}%</div>
-        </el-card>
-      </el-col>
-    </el-row>
-
     <div class="table-wrapper">
-    <el-table :height="tableHeight" v-loading="loading" :data="hiddCountList">
-      <el-table-column label="机构名称" align="center" prop="orgName" :show-overflow-tooltip="true" min-width="150" />
-      <el-table-column label="隐患总数" align="center" prop="totalHidd" width="90" />
-      <el-table-column label="重大隐患数" align="center" prop="zdHidd" width="100" />
-      <el-table-column label="已整改重大" align="center" prop="zgZdHidd" width="100" />
-      <el-table-column label="整改中重大" align="center" prop="zdSolvingHidd" width="100" />
-      <el-table-column label="未整改重大" align="center" prop="zdUnsolvedHidd" width="100" />
-      <el-table-column label="逾期重大" align="center" prop="zdOverTimeHidd" width="90">
-        <template #default="scope">
-          <span :style="{ color: scope.row.zdOverTimeHidd > 0 ? '#F56C6C' : '' }">
-            {{ scope.row.zdOverTimeHidd }}
-          </span>
-        </template>
-      </el-table-column>
-      <el-table-column label="重大整改率" align="center" prop="zdZgl" width="100">
-        <template #default="scope">
-          <span :style="{ color: scope.row.zdZgl >= 80 ? '#67C23A' : scope.row.zdZgl >= 60 ? '#E6A23C' : '#F56C6C' }">
-            {{ scope.row.zdZgl }}%
-          </span>
-        </template>
-      </el-table-column>
-      <el-table-column label="一般隐患数" align="center" prop="ybHidd" width="100" />
-      <el-table-column label="已整改一般" align="center" prop="zgYbHidd" width="100" />
-      <el-table-column label="整改中一般" align="center" prop="ybSolvingHidd" width="100" />
-      <el-table-column label="未整改一般" align="center" prop="ybUnsolvedHidd" width="100" />
-      <el-table-column label="逾期一般" align="center" prop="ybOverTimeHidd" width="90">
-        <template #default="scope">
-          <span :style="{ color: scope.row.ybOverTimeHidd > 0 ? '#F56C6C' : '' }">
-            {{ scope.row.ybOverTimeHidd }}
-          </span>
-        </template>
-      </el-table-column>
-      <el-table-column label="一般整改率" align="center" prop="ybZgl" width="100">
-        <template #default="scope">
-          <span :style="{ color: scope.row.ybZgl >= 80 ? '#67C23A' : scope.row.ybZgl >= 60 ? '#E6A23C' : '#F56C6C' }">
-            {{ scope.row.ybZgl }}%
-          </span>
-        </template>
-      </el-table-column>
-      <el-table-column label="综合整改率" align="center" prop="hiddZgl" width="120">
-        <template #default="scope">
-          <el-progress :percentage="scope.row.hiddZgl" :color="scope.row.hiddZgl >= 80 ? '#67C23A' : scope.row.hiddZgl >= 60 ? '#E6A23C' : '#F56C6C'"></el-progress>
-        </template>
-      </el-table-column>
-      <el-table-column label="排查率" align="center" prop="pcl" width="80">
-        <template #default="scope">
-          <span>{{ scope.row.pcl }}%</span>
-        </template>
+    <el-table :height="tableHeight" v-loading="loading" :data="statList" border style="width:100%"
+      :header-cell-style="{ 'text-align': 'center', 'white-space': 'nowrap' }">
+      <el-table-column label="序号" align="center" type="index" width="60" />
+      <el-table-column label="单位" align="center" min-width="130" :show-overflow-tooltip="true" prop="orgName" />
+      <el-table-column label="隐患排查情况" align="center">
+        <el-table-column label="排查率" align="center" width="70">
+          <template #default="scope">
+            {{ scope.row.pcl != null ? scope.row.pcl + '%' : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="非工程单位" align="center">
+          <el-table-column label="总数" align="center" width="65" prop="oengOrg" />
+          <el-table-column label="已排查" align="center" width="65" prop="hiddOrg" />
+        </el-table-column>
+        <el-table-column label="工程单位" align="center">
+          <el-table-column label="总数" align="center" width="65" prop="engNum" />
+          <el-table-column label="已排查" align="center" width="65" prop="hiddEng" />
+        </el-table-column>
       </el-table-column>
-      <el-table-column label="工程总数" align="center" prop="engNum" width="90" />
-      <el-table-column label="有隐患单位" align="center" prop="hiddOrg" width="100" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="80" fixed="right">
-        <template #default="scope">
-          <el-tooltip content="详情" placement="top">
-            <el-button link type="primary" icon="View" @click="handleDetail(scope.row)"></el-button>
-          </el-tooltip>
-        </template>
+      <el-table-column label="隐患整改情况" align="center">
+        <el-table-column label="综合整改率" align="center" width="80">
+          <template #default="scope">
+            {{ scope.row.hiddZgl != null ? scope.row.hiddZgl + '%' : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="重大隐患" align="center">
+          <el-table-column label="整改率" align="center" width="70">
+            <template #default="scope">
+              {{ scope.row.zdZgl != null ? scope.row.zdZgl + '%' : '-' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="总数" align="center" width="65" prop="zdHidd" />
+          <el-table-column label="已整改" align="center" width="65" prop="zgZdHidd" />
+        </el-table-column>
+        <el-table-column label="一般隐患" align="center">
+          <el-table-column label="整改率" align="center" width="70">
+            <template #default="scope">
+              {{ scope.row.ybZgl != null ? scope.row.ybZgl + '%' : '-' }}
+            </template>
+          </el-table-column>
+          <el-table-column label="总数" align="center" width="65" prop="ybHidd" />
+          <el-table-column label="已整改" align="center" width="65" prop="zgYbHidd" />
+        </el-table-column>
       </el-table-column>
     </el-table>
     </div>
@@ -161,7 +71,7 @@
   </div>
 </template>
 
-<script setup name="TBusiHiddCount">
+<script setup name="HiddStat">
 import { listTBusiHiddCount } from "@/api/slaj/hidd"
 import { useTableHeight } from '@/hooks/useTableHeight'
 
@@ -169,134 +79,34 @@ const { tableHeight, containerRef } = useTableHeight()
 
 const { proxy } = getCurrentInstance()
 
-const hiddCountList = ref([])
-const loading = ref(true)
+const loading = ref(false)
 const showSearch = ref(true)
+const statList = ref([])
 const total = ref(0)
 
-const statData = ref({
-  totalHidd: 0,
-  solvedHidd: 0,
-  solvingHidd: 0,
-  unsolvedHidd: 0,
-  overTimeHidd: 0,
-  avgSolveRate: 0
-})
-
-const columns = ref({
-  orgName: { label: '机构名称', visible: true },
-  totalHidd: { label: '隐患总数', visible: true },
-  zdHidd: { label: '重大隐患数', visible: true },
-  zgZdHidd: { label: '已整改重大', visible: true },
-  zdSolvingHidd: { label: '整改中重大', visible: true },
-  zdUnsolvedHidd: { label: '未整改重大', visible: true },
-  zdOverTimeHidd: { label: '逾期重大', visible: true },
-  zdZgl: { label: '重大整改率', visible: true },
-  ybHidd: { label: '一般隐患数', visible: true },
-  zgYbHidd: { label: '已整改一般', visible: true },
-  ybSolvingHidd: { label: '整改中一般', visible: true },
-  ybUnsolvedHidd: { label: '未整改一般', visible: true },
-  ybOverTimeHidd: { label: '逾期一般', visible: true },
-  ybZgl: { label: '一般整改率', visible: true },
-  hiddZgl: { label: '综合整改率', visible: true },
-  pcl: { label: '排查率', visible: true },
-  engNum: { label: '工程总数', visible: true },
-  hiddOrg: { label: '有隐患单位', visible: true }
-})
-
-const data = reactive({
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    statYear: undefined,
-    statMonth: undefined,
-    orgName: undefined,
-    unitType: undefined
-  }
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  unitType: undefined,
+  orgName: undefined,
+  createTime: undefined
 })
 
-const { queryParams } = toRefs(data)
-
-/** 查询隐患统计列表 */
 function getList() {
   loading.value = true
-  listTBusiHiddCount(queryParams.value).then(res => {
+  listTBusiHiddCount(queryParams).then(res => {
+    statList.value = res.rows || []
+    total.value = res.total || 0
     loading.value = false
-    hiddCountList.value = res.rows
-    total.value = res.total
-    calculateStat()
-  })
-}
-
-/** 计算统计数据 */
-function calculateStat() {
-  let totalHidd = 0
-  let solvedHidd = 0
-  let solvingHidd = 0
-  let unsolvedHidd = 0
-  let overTimeHidd = 0
-  let totalZgl = 0
-  let count = 0
-  hiddCountList.value.forEach(item => {
-    totalHidd += item.totalHidd || 0
-    solvedHidd += item.solvedHidd || 0
-    solvingHidd += item.solvingHidd || 0
-    unsolvedHidd += item.unsolvedHidd || 0
-    overTimeHidd += (item.zdOverTimeHidd || 0) + (item.ybOverTimeHidd || 0)
-    if (item.hiddZgl) {
-      totalZgl += item.hiddZgl
-      count++
-    }
-  })
-  statData.value = {
-    totalHidd,
-    solvedHidd,
-    solvingHidd,
-    unsolvedHidd,
-    overTimeHidd,
-    avgSolveRate: count > 0 ? Math.round(totalZgl / count) : 0
-  }
+  }).catch(() => { loading.value = false })
 }
 
-/** 搜索按钮操作 */
 function handleQuery() {
-  queryParams.value.pageNum = 1
+  queryParams.pageNum = 1
   getList()
 }
 
-/** 重置按钮操作 */
-function resetQuery() {
-  proxy.resetForm("queryRef")
-  handleQuery()
-}
-
-/** 详情按钮操作 */
-function handleDetail(row) {
-  proxy.$router.push({ path: '/slaj/hidd/detailCount', query: { orgGuid: row.orgGuid, statYear: row.statYear, statMonth: row.statMonth } })
-}
-
-/** 导出按钮操作 */
-function handleExport() {
-  proxy.download("hidd/count/export", {
-    ...queryParams.value
-  }, `hiddCount_${new Date().getTime()}.xlsx`)
-}
-
 onMounted(() => {
   getList()
 })
 </script>
-
-<style scoped>
-.card-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-.stat-value {
-  font-size: 28px;
-  font-weight: bold;
-  text-align: center;
-  color: #409EFF;
-}
-</style>

+ 36 - 15
gw-ui/src/views/slaj/hidd/supDetail.vue

@@ -7,24 +7,23 @@
           <el-button plain icon="ArrowLeft" @click="goBack">返回</el-button>
         </div>
       </template>
+
+      <div class="section-title">隐患信息</div>
       <el-descriptions :column="2" border>
         <el-descriptions-item label="隐患名称" :span="2">{{ form.hiddName }}</el-descriptions-item>
-        <el-descriptions-item label="隐患级">
+        <el-descriptions-item label="隐患级">
           <dict-tag :options="hidd_grad" :value="form.hiddGrad" />
         </el-descriptions-item>
-        <el-descriptions-item label="隐患状态">
-          <dict-tag :options="hidd_stat" :value="form.hiddStat" />
-        </el-descriptions-item>
+        <el-descriptions-item label="隐患部位">{{ form.proPart }}</el-descriptions-item>
+        <el-descriptions-item label="所属工程">{{ form.engName }}</el-descriptions-item>
         <el-descriptions-item label="督办文号">{{ form.supLareId }}</el-descriptions-item>
         <el-descriptions-item label="督办日期">{{ form.supDate }}</el-descriptions-item>
-        <el-descriptions-item label="督办单位">{{ form.supWiunName || form.supWiunCode }}</el-descriptions-item>
-        <el-descriptions-item label="督办负责人">{{ form.supLegPers }}</el-descriptions-item>
+        <el-descriptions-item label="督办单位">{{ form.supWiunName }}</el-descriptions-item>
         <el-descriptions-item label="整改期限">{{ form.rectPeri }}</el-descriptions-item>
-        <el-descriptions-item label="是否挂牌">
-          <dict-tag :options="sys_yes_no" :value="form.isList" />
+        <el-descriptions-item label="是否挂牌督办">
+          {{ form.isList === '1' ? '是' : '否' }}
         </el-descriptions-item>
         <el-descriptions-item label="督办意见" :span="2">{{ form.supOpin }}</el-descriptions-item>
-        <el-descriptions-item label="备注" :span="2">{{ form.note }}</el-descriptions-item>
         <el-descriptions-item label="督办附件" :span="2">
           <div v-if="form.medGuid">
             <el-link type="primary" :href="`/common/download?fileName=${form.medTitl}&delete=true`">
@@ -35,18 +34,26 @@
           <span v-else style="color: #909399">暂无附件</span>
         </el-descriptions-item>
       </el-descriptions>
+
+      <div class="section-title">销号信息</div>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="治理完成日期">{{ form.requCompDate }}</el-descriptions-item>
+        <el-descriptions-item label="验收时间">{{ form.accepDate }}</el-descriptions-item>
+        <el-descriptions-item label="验收意见" :span="2">{{ form.accepOpin }}</el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ form.note }}</el-descriptions-item>
+      </el-descriptions>
     </el-card>
   </div>
 </template>
 
 <script setup name="HiddSupDetail">
 import { getBisMajHiddSup } from "@/api/slaj/hidd"
-import { getObjHidd } from "@/api/slaj/hidd"
+import { listBisHiddRectAcce } from "@/api/slaj/hidd"
 
 const { proxy } = getCurrentInstance()
 const route = useRoute()
 const router = useRouter()
-const { hidd_grad, hidd_stat, sys_yes_no } = proxy.useDict("hidd_grad", "hidd_stat", "sys_yes_no")
+const { hidd_grad, hidd_stat } = proxy.useDict("hidd_grad", "hidd_stat")
 
 const form = ref({})
 
@@ -54,11 +61,18 @@ function getInfo() {
   const guid = route.query.guid
   if (guid) {
     getBisMajHiddSup(guid).then(response => {
-      form.value = response.data
-      if (response.data.hiddGuid) {
-        getObjHidd(response.data.hiddGuid).then(hiddRes => {
-          form.value = { ...form.value, ...hiddRes.data }
+      const supData = response.data
+      const hiddGuid = supData.hiddGuid
+      
+      if (hiddGuid) {
+        listBisHiddRectAcce({ hiddGuid: hiddGuid }).then(acceRes => {
+          const acceData = (acceRes.rows && acceRes.rows.length > 0) ? acceRes.rows[0] : {}
+          form.value = { ...supData, ...acceData }
+        }).catch(() => {
+          form.value = supData
         })
+      } else {
+        form.value = supData
       }
     })
   }
@@ -79,4 +93,11 @@ onMounted(() => {
   justify-content: space-between;
   align-items: center;
 }
+.section-title {
+  font-size: 14px;
+  font-weight: bold;
+  margin: 16px 0 12px 0;
+  padding-left: 8px;
+  border-left: 3px solid #409eff;
+}
 </style>

+ 268 - 66
gw-ui/src/views/slaj/hidd/supList.vue

@@ -1,74 +1,78 @@
 <template>
   <div ref="containerRef" class="app-container">
-    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="隐患名称" prop="hiddName">
-        <el-input v-model="queryParams.hiddName" placeholder="请输入隐患名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="70px" class="compact-form">
+      <el-form-item label="工程类别" prop="engType">
+        <el-select v-model="queryParams.engType" placeholder="请选择" clearable style="width: 130px">
+          <el-option v-for="dict in eng_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="单位名称" prop="orgName">
+        <el-input v-model="queryParams.orgName" placeholder="请输入" clearable style="width: 130px" @keyup.enter="handleQuery" />
       </el-form-item>
-      <el-form-item label="隐患所属单位" prop="hiddUnit">
-        <el-select v-model="queryParams.hiddUnit" placeholder="请选择单位类型" clearable style="width: 200px">
-          <el-option label="直属单位" value="0" />
-          <el-option label="下级水行政部门" value="1" />
-          <el-option label="流域机构" value="2" />
+      <el-form-item label="单位性质" prop="orgNature">
+        <el-select v-model="queryParams.orgNature" placeholder="请选择" clearable style="width: 130px">
+          <el-option v-for="dict in org_nature" :key="dict.value" :label="dict.label" :value="dict.value" />
         </el-select>
       </el-form-item>
       <el-form-item label="督办状态" prop="supStat">
-        <el-select v-model="queryParams.supStat" placeholder="请选择督办状态" clearable style="width: 200px">
+        <el-select v-model="queryParams.supStat" placeholder="请选择" clearable style="width: 130px">
           <el-option v-for="dict in sup_stat" :key="dict.value" :label="dict.label" :value="dict.value" />
         </el-select>
       </el-form-item>
-      <el-form-item label="时间范围" style="width: 308px">
-        <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
+      <el-form-item label="隐患类别" prop="hiddClas">
+        <el-select v-model="queryParams.hiddClas" placeholder="请选择" clearable style="width: 130px">
+          <el-option v-for="dict in hidd_clas" :key="dict.value" :label="dict.label" :value="dict.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="整改情况" prop="hiddStat">
+        <el-select v-model="queryParams.hiddStat" placeholder="请选择" clearable style="width: 130px">
+          <el-option v-for="dict in hidd_stat" :key="dict.value" :label="dict.label" :value="dict.value" />
+        </el-select>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hidd:majhiddsup:export']">导出</el-button>
       </el-form-item>
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['hidd:majhiddsup:export']">导出</el-button>
-      </el-col>
       <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns" storageKey="hidd-majhiddsup-index"></right-toolbar>
     </el-row>
 
     <div class="table-wrapper">
     <el-table :height="tableHeight" v-loading="loading" :data="supList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="隐患名称" align="center" prop="hiddName" v-if="columns.hiddName.visible" :show-overflow-tooltip="true" />
-      <el-table-column label="隐患级" align="center" prop="hiddGrad" v-if="columns.hiddGrad.visible">
+      <el-table-column label="序号" align="center" type="index" width="60" />
+      <el-table-column label="隐患所属单位" align="center" prop="orgName" v-if="columns.orgName.visible" :show-overflow-tooltip="true" min-width="120" />
+      <el-table-column label="隐患级" align="center" prop="hiddGrad" v-if="columns.hiddGrad.visible" min-width="80">
         <template #default="scope">
           <dict-tag :options="hidd_grad" :value="scope.row.hiddGrad" />
         </template>
       </el-table-column>
-      <el-table-column label="发现日期" align="center" prop="collTime" v-if="columns.collTime.visible" width="120" />
-      <el-table-column label="督办情况" align="center" prop="supStat" v-if="columns.supStat.visible">
+      <el-table-column label="隐患名称" align="center" prop="hiddName" v-if="columns.hiddName.visible" :show-overflow-tooltip="true" min-width="150">
+        <template #default="scope">
+          <el-link type="primary" @click="handleDetail(scope.row)">{{ scope.row.hiddName }}</el-link>
+        </template>
+      </el-table-column>
+      <el-table-column label="发现日期" align="center" prop="collTime" v-if="columns.collTime.visible" min-width="100">
+        <template #default="scope">
+          {{ formatDate(scope.row.collTime) }}
+        </template>
+      </el-table-column>
+      <el-table-column label="督办情况" align="center" prop="supStat" v-if="columns.supStat.visible" min-width="80">
         <template #default="scope">
           <dict-tag :options="sup_stat" :value="scope.row.supStat" />
         </template>
       </el-table-column>
-      <el-table-column label="整改情况" align="center" prop="hiddStat" v-if="columns.hiddStat.visible">
+      <el-table-column label="整改情况" align="center" prop="hiddStat" v-if="columns.hiddStat.visible" min-width="80">
         <template #default="scope">
           <dict-tag :options="hidd_stat" :value="scope.row.hiddStat" />
         </template>
       </el-table-column>
-      <el-table-column label="督办日期" align="center" prop="supDate" v-if="columns.supDate.visible" width="120" />
-      <el-table-column label="督办单位" align="center" prop="supWiunCode" v-if="columns.supWiunCode.visible" :show-overflow-tooltip="true" />
-      <el-table-column label="督办负责人" align="center" prop="supLegPers" v-if="columns.supLegPers.visible" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" min-width="150">
         <template #default="scope">
-          <el-tooltip content="督办" placement="top" v-if="scope.row.supStat === '0'">
-            <el-button link type="primary" icon="AlarmClock" @click="handleSup(scope.row)" v-hasPermi="['hidd:majhiddsup:add']"></el-button>
-          </el-tooltip>
-          <el-tooltip content="详情" placement="top" v-if="scope.row.supStat === '1' || scope.row.supStat === '3'">
-            <el-button link type="primary" icon="View" @click="handleDetail(scope.row)"></el-button>
-          </el-tooltip>
-          <el-tooltip content="销号" placement="top" v-if="scope.row.supStat === '2'">
-            <el-button link type="primary" icon="CircleCheck" @click="handleWriteOff(scope.row)" v-hasPermi="['hidd:majhiddsup:edit']"></el-button>
-          </el-tooltip>
-          <el-tooltip content="撤销督办" placement="top" v-if="scope.row.supStat === '1'">
-            <el-button link type="danger" icon="CircleClose" @click="handleCancel(scope.row)" v-hasPermi="['hidd:majhiddsup:remove']"></el-button>
-          </el-tooltip>
+          <el-button link type="primary" v-if="scope.row.supStat === '0' && scope.row.hiddStat !== '2'" @click="handleSup(scope.row)" v-hasPermi="['hidd:majhiddsup:add']">督办</el-button>
+          <el-button link type="primary" v-if="scope.row.supStat === '2'" @click="handleWriteOff(scope.row)" v-hasPermi="['hidd:majhiddsup:edit']">销号</el-button>
+          <el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -76,20 +80,93 @@
 
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
 
-    <el-dialog title="隐患督办" v-model="supOpen" width="600px" append-to-body>
+    <el-dialog title="隐患督办" v-model="supOpen" width="700px" append-to-body>
       <el-form :model="supForm" :rules="supRules" ref="supRef" label-width="100px">
-        <el-form-item label="隐患名称">
-          <el-input v-model="supForm.hiddName" disabled />
-        </el-form-item>
-        <el-form-item label="督办意见" prop="supOpin">
-          <el-input v-model="supForm.supOpin" type="textarea" :rows="4" placeholder="请输入督办意见" />
-        </el-form-item>
-        <el-form-item label="文号" prop="supLareId">
-          <el-input v-model="supForm.supLareId" placeholder="请输入文号" />
-        </el-form-item>
-        <el-form-item label="督办期限" prop="rectPeri">
-          <el-date-picker v-model="supForm.rectPeri" type="date" value-format="YYYY-MM-DD" placeholder="请选择期限" style="width: 100%" />
-        </el-form-item>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="隐患名称">
+              <el-input v-model="supForm.hiddName" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="隐患级别">
+              <el-select v-model="supForm.hiddGrad" disabled style="width: 100%">
+                <el-option v-for="dict in hidd_grad" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="隐患部位">
+              <el-input v-model="supForm.proPart" disabled />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="所属工程">
+              <el-input v-model="supForm.engName" disabled />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="督办文号" prop="supLareId">
+              <el-input v-model="supForm.supLareId" placeholder="请输入督办文号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="督办日期">
+              <el-date-picker v-model="supForm.supDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择督办日期" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="督办单位">
+              <el-input v-model="supForm.supWiunName" placeholder="请输入督办单位" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="整改期限" prop="rectPeri">
+              <el-date-picker v-model="supForm.rectPeri" type="date" value-format="YYYY-MM-DD" placeholder="请选择整改期限" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="是否挂牌督办">
+              <el-radio-group v-model="supForm.isList">
+                <el-radio value="1">是</el-radio>
+                <el-radio value="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="督办意见" prop="supOpin">
+              <el-input v-model="supForm.supOpin" type="textarea" :rows="4" placeholder="请输入督办意见" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="督办附件">
+              <span style="color: #f56c6c; margin-right: 5px;">*</span>
+              <el-upload
+                ref="upload"
+                :action="uploadUrl"
+                :headers="uploadHeaders"
+                :on-success="handleUploadSuccess"
+                :on-remove="handleUploadRemove"
+                :file-list="fileList"
+                :limit="1"
+              >
+                <el-button type="primary" size="small">选择附件</el-button>
+              </el-upload>
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
@@ -99,10 +176,53 @@
       </template>
     </el-dialog>
 
-    <el-dialog title="销号确认" v-model="writeOffOpen" width="400px" append-to-body>
-      <div style="text-align: center; padding: 20px;">
-        <el-icon style="font-size: 48px; color: #e6a23c;"><WarningFilled /></el-icon>
-        <p style="margin-top: 16px; font-size: 16px;">确认对该隐患进行销号操作?</p>
+    <el-dialog title="详情" v-model="detailOpen" width="800px" append-to-body>
+      <div style="margin-bottom: 16px;">
+        <div class="detail-section-header">隐患信息</div>
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="隐患名称" :span="2">{{ detailForm.hiddName }}</el-descriptions-item>
+          <el-descriptions-item label="隐患级别">
+            <dict-tag :options="hidd_grad" :value="detailForm.hiddGrad" />
+          </el-descriptions-item>
+          <el-descriptions-item label="隐患部位">{{ detailForm.proPart }}</el-descriptions-item>
+          <el-descriptions-item label="所属工程">{{ detailForm.engName }}</el-descriptions-item>
+          <el-descriptions-item label="督办文号">{{ detailForm.supLareId }}</el-descriptions-item>
+          <el-descriptions-item label="督办日期">{{ detailForm.supDate }}</el-descriptions-item>
+          <el-descriptions-item label="督办单位">{{ detailForm.supWiunName }}</el-descriptions-item>
+          <el-descriptions-item label="整改期限">{{ detailForm.rectPeri }}</el-descriptions-item>
+          <el-descriptions-item label="是否挂牌督办">
+            {{ detailForm.isList === '1' ? '是' : '否' }}
+          </el-descriptions-item>
+          <el-descriptions-item label="督办意见" :span="2">{{ detailForm.supOpin }}</el-descriptions-item>
+          <el-descriptions-item label="督办附件" :span="2">
+            <div v-if="detailForm.medGuid">
+              <el-link type="primary" :href="`/common/download?fileName=${detailForm.medTitl}&delete=true`">
+                <el-icon><Download /></el-icon>
+                {{ detailForm.medTitl || '附件' }}
+              </el-link>
+            </div>
+            <span v-else style="color: #909399">暂无附件</span>
+          </el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <div>
+        <div class="detail-section-header">销号信息</div>
+        <el-descriptions :column="2" border>
+          <el-descriptions-item label="治理完成日期">{{ detailForm.requCompDate }}</el-descriptions-item>
+          <el-descriptions-item label="验收时间">{{ detailForm.accepDate }}</el-descriptions-item>
+          <el-descriptions-item label="验收意见" :span="2">{{ detailForm.accepOpin }}</el-descriptions-item>
+          <el-descriptions-item label="备注" :span="2">{{ detailForm.note }}</el-descriptions-item>
+        </el-descriptions>
+      </div>
+      <template #footer>
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="销号确认" v-model="writeOffOpen" width="400px" append-to-body align-center class="write-off-dialog">
+      <div style="text-align: center; padding: 20px; display: flex; align-items: center; justify-content: center; gap: 8px;">
+        <el-icon style="font-size: 24px; color: #e6a23c;"><WarningFilled /></el-icon>
+        <span style="font-size: 16px;">确认对该隐患进行销号操作?</span>
       </div>
       <template #footer>
         <div class="dialog-footer">
@@ -129,14 +249,23 @@
 </template>
 
 <script setup name="BisMajHiddSup">
-import { listBisMajHiddSup, getBisMajHiddSup, addBisMajHiddSup, updateBisMajHiddSup, delBisMajHiddSup, writeOffBisMajHiddSup, cancelBisMajHiddSup } from "@/api/slaj/hidd"
+import { listBisMajHiddSup, getBisMajHiddSup, addBisMajHiddSup, updateBisMajHiddSup, delBisMajHiddSup, writeOffBisMajHiddSup, cancelBisMajHiddSup, listBisHiddRectAcce } from "@/api/slaj/hidd"
 import { useTableHeight } from '@/hooks/useTableHeight'
 import { listObjHidd, getObjHidd } from "@/api/slaj/hidd"
 
 const { tableHeight, containerRef } = useTableHeight()
 
+import useUserStore from '@/store/modules/user'
+
+const userStore = useUserStore()
+const token = computed(() => userStore.token)
+
+const uploadUrl = ref('/common/upload')
+const uploadHeaders = computed(() => ({ Authorization: 'Bearer ' + token.value }))
+const fileList = ref([])
+
 const { proxy } = getCurrentInstance()
-const { hidd_grad, hidd_stat, sup_stat } = proxy.useDict("hidd_grad", "hidd_stat", "sup_stat")
+const { hidd_grad, hidd_stat, sup_stat, hidd_clas, eng_type, org_nature } = proxy.useDict("hidd_grad", "hidd_stat", "sup_stat", "hidd_clas", "eng_type", "org_nature")
 
 const supList = ref([])
 const loading = ref(true)
@@ -161,15 +290,16 @@ const writeOffRow = ref({})
 const cancelOpen = ref(false)
 const cancelRow = ref({})
 
+const detailOpen = ref(false)
+const detailForm = ref({})
+
 const columns = ref({
+  orgName: { label: '隐患所属单位', visible: true },
+  hiddGrad: { label: '隐患级别', visible: true },
   hiddName: { label: '隐患名称', visible: true },
-  hiddGrad: { label: '隐患等级', visible: true },
   collTime: { label: '发现日期', visible: true },
   supStat: { label: '督办情况', visible: true },
-  hiddStat: { label: '整改情况', visible: true },
-  supDate: { label: '督办日期', visible: true },
-  supWiunCode: { label: '督办单位', visible: true },
-  supLegPers: { label: '督办负责人', visible: true }
+  hiddStat: { label: '整改情况', visible: true }
 })
 
 const data = reactive({
@@ -177,9 +307,12 @@ const data = reactive({
   queryParams: {
     pageNum: 1,
     pageSize: 10,
-    hiddName: undefined,
+    engType: undefined,
+    orgName: undefined,
+    orgNature: undefined,
     supStat: undefined,
-    hiddUnit: undefined
+    hiddClas: undefined,
+    hiddStat: undefined
   },
   rules: {}
 })
@@ -216,17 +349,32 @@ function handleSup(row) {
   supForm.value = {
     hiddGuid: row.guid,
     hiddName: row.hiddName,
+    hiddGrad: row.hiddGrad,
+    proPart: row.proPart || '',
+    engName: row.engName || '',
+    supDate: '',
+    supWiunName: row.supWiunName || '',
+    supWiunCode: row.supWiunCode || '',
     supOpin: undefined,
     supLareId: undefined,
-    rectPeri: undefined
+    rectPeri: undefined,
+    isList: '0',
+    medGuid: undefined,
+    medTitl: undefined
   }
+  fileList.value = []
   supOpen.value = true
 }
 
 function submitSup() {
   proxy.$refs["supRef"].validate(valid => {
     if (valid) {
-      addBisMajHiddSup(supForm.value).then(response => {
+      const submitData = {
+        ...supForm.value,
+        medGuid: supForm.value.medGuid || (fileList.value.length > 0 ? fileList.value[0].response ? fileList.value[0].response.msg : '' : ''),
+        medTitl: supForm.value.medTitl || (fileList.value.length > 0 ? fileList.value[0].name : '')
+      }
+      addBisMajHiddSup(submitData).then(response => {
         proxy.$modal.msgSuccess("督办成功")
         supOpen.value = false
         getList()
@@ -235,9 +383,35 @@ function submitSup() {
   })
 }
 
+function handleUploadSuccess(response, file, fileList) {
+  if (response.code === 200) {
+    supForm.value.medGuid = response.msg
+    supForm.value.medTitl = file.name
+  }
+}
+
+function handleUploadRemove(file, fileList) {
+  supForm.value.medGuid = undefined
+  supForm.value.medTitl = undefined
+}
+
 function handleDetail(row) {
   const guid = row.guid || ids.value
-  proxy.$router.push({ path: '/slaj/hidd/supDetail', query: { guid: guid } })
+  getBisMajHiddSup(guid).then(response => {
+    const supData = response.data
+    const hiddGuid = supData.hiddGuid
+    if (hiddGuid) {
+      listBisHiddRectAcce({ hiddGuid: hiddGuid }).then(acceRes => {
+        const acceData = (acceRes.rows && acceRes.rows.length > 0) ? acceRes.rows[0] : {}
+        detailForm.value = { ...supData, ...acceData }
+      }).catch(() => {
+        detailForm.value = supData
+      })
+    } else {
+      detailForm.value = supData
+    }
+    detailOpen.value = true
+  })
 }
 
 function handleWriteOff(row) {
@@ -272,7 +446,35 @@ function handleExport() {
   }, `majHiddSup_${new Date().getTime()}.xlsx`)
 }
 
+function formatDate(dateStr) {
+  if (!dateStr) return ''
+  return dateStr.substring(0, 10)
+}
+
 onMounted(() => {
   getList()
 })
 </script>
+
+<style scoped>
+.compact-form :deep(.el-form-item) {
+  margin-bottom: 10px;
+  margin-right: 5px;
+}
+.compact-form :deep(.el-form-item__label) {
+  padding-right: 4px;
+}
+.detail-section-header {
+  font-size: 14px;
+  font-weight: bold;
+  margin-bottom: 12px;
+  padding-left: 8px;
+  border-left: 3px solid #409eff;
+}
+</style>
+
+<style>
+.write-off-dialog {
+  margin-top: 0 !important;
+}
+</style>

+ 7 - 0
pom.xml

@@ -199,6 +199,13 @@
                     <source>${java.version}</source>
                     <target>${java.version}</target>
                     <encoding>${project.build.sourceEncoding}</encoding>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                            <version>${lombok.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
                 </configuration>
             </plugin>
             <plugin>