Browse Source

修改手动、月报表、年报表导出,管理员导出所有装置-系统的联锁信息,修改联锁总数为0,投用率计算报错问题,修改没有数据的时候,表格合并报错问题

sl 7 months ago
parent
commit
7321e69e6f

+ 2 - 2
jeecg-module-interlock/src/main/java/org/jeecg/modules/history/controller/InterlockDetailHistoryController.java

@@ -334,9 +334,9 @@ public class InterlockDetailHistoryController extends JeecgController<InterlockD
 		}
 		InterlockUser interlockUser = interlockUserService.getInterlockUserByUserName(wiseUser);//获取当前用户信息
 		if(interlockUser.getRole().equals("0")){//如果当前用户是系统管理员
-			zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryListByAdmin(dto);
+			zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryListByAdmin();
 		}else{//如果当前用户是普通用户
-			zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryListByUserPermission(dto, wiseUser);
+			zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryListByUserPermission(wiseUser);
 		}
 
 		Workbook workbook = new XSSFWorkbook();

+ 2 - 2
jeecg-module-interlock/src/main/java/org/jeecg/modules/history/mapper/InterlockSummaryHistoryMapper.java

@@ -66,12 +66,12 @@ public interface InterlockSummaryHistoryMapper extends BaseMapper<InterlockSumma
     /**
      * 根据查询条件查所有不重复的系统及其所属装置 系统管理员
      */
-    List<InterlockHistoryDistinctZZXTVO> getDistinctZZXTSummaryListByAdmin(InterlockHistoryQueryDTO dto);
+    List<InterlockHistoryDistinctZZXTVO> getDistinctZZXTSummaryListByAdmin();
 
     /**
      * 根据查询条件以及用户权限查所有不重复的系统及其所属装置 普通用户
      */
-    List<InterlockHistoryDistinctZZXTVO> getDistinctZZXTSummaryListByUserPermission(InterlockHistoryQueryDTO dto, String wiseUser);
+    List<InterlockHistoryDistinctZZXTVO> getDistinctZZXTSummaryListByUserPermission(String wiseUser);
 
 
 }

+ 13 - 61
jeecg-module-interlock/src/main/java/org/jeecg/modules/history/mapper/xml/InterlockSummaryHistoryMapper.xml

@@ -161,72 +161,24 @@
 
 
     <!--    根据查询条件查所有不重复的系统及其所属装置   系统管理员   -->
-    <select id="getDistinctZZXTSummaryListByAdmin" parameterType="org.jeecg.modules.history.dto.InterlockHistoryQueryDTO" resultType="org.jeecg.modules.history.vo.InterlockHistoryDistinctZZXTVO">
-        select distinct s.interlock_system_id, system_base.interlock_name AS interlockSystemName,
-        s.interlock_apparatus_id, apparatus_base.interlock_name AS interlockApparatusName
-        from interlock_detail_history d
-        LEFT JOIN interlock_summary_history s on d.summaryid = s.id
-        INNER JOIN
-        interlock_base system_base ON s.interlock_system_id = system_base.id AND system_base.interlock_type = '1'
-        INNER JOIN
-        interlock_base apparatus_base ON s.interlock_apparatus_id = apparatus_base.id AND apparatus_base.interlock_type = '0'
-        <where>
-            <if test="interlockSystemId != null and interlockSystemId != ''"> and s.interlock_system_id =  #{interlockSystemId}</if>
-            <if test="interlockApparatusId != null and interlockApparatusId != ''"> and s.interlock_apparatus_id =  #{interlockApparatusId}</if>
-
-            <if test="interlockname != null and interlockname != ''"> and d.interlockname like concat('%', #{interlockname}, '%')</if>
-            <if test="interlockCondition != null and interlockCondition != ''"> and d.interlock_condition = #{interlockCondition}</if>
-            <if test="interlockConditionTag != null and interlockConditionTag != ''"> and d.interlock_condition_tag like concat('%',#{interlockConditionTag},'%')</if>
-            <if test="instrumentStatus != null and instrumentStatus != ''"> and d.instrument_status = #{instrumentStatus}</if>
-            <if test="controlSystemStatus != null and controlSystemStatus != ''"> and d.control_system_status = #{controlSystemStatus}</if>
-            <if test="interlockStatus != null and interlockStatus != ''"> and s.interlock_status = #{interlockStatus}</if>
-            <if test="loopHealthLevel != null and loopHealthLevel != ''"> and s.loop_health_level = #{loopHealthLevel}</if>
-            <!--            <if test="beginTime != null">-->
-            <!--                <![CDATA[ AND TO_TIMESTAMP(s.tag_time, 'YYYY-MM-DD HH24:MI:SS') > #{beginTime} ]]>-->
-            <!--            </if>-->
-            <!--            <if test="endTime != null">-->
-            <!--                <![CDATA[ AND TO_TIMESTAMP(s.tag_time, 'YYYY-MM-DD HH24:MI:SS') < #{endTime} ]]>-->
-            <!--            </if>-->
-            and s.interlock_system_id IS NOT NULL
-            AND s.interlock_apparatus_id IS NOT NULL
-        </where>
-        order by s.interlock_apparatus_id
+    <select id="getDistinctZZXTSummaryListByAdmin" resultType="org.jeecg.modules.history.vo.InterlockHistoryDistinctZZXTVO">
+        select distinct b1.id as interlockSystemId, b1.interlock_name as interlockSystemName, b2.id as interlockApparatusId, b2.interlock_name as interlockApparatusName
+        from interlock_base b
+        inner join interlock_base b1 on b.id = b1.id and b1.interlock_type = '1'
+        inner join interlock_base b2 on b2.id = b1.pid and b2.interlock_type = '0'
+        order by b2.id
     </select>
 
     <!--    根据查询条件以及用户权限查所有不重复的系统及其所属装置 普通用户      -->
     <select id="getDistinctZZXTSummaryListByUserPermission" resultType="org.jeecg.modules.history.vo.InterlockHistoryDistinctZZXTVO">
-        select distinct s.interlock_system_id, system_base.interlock_name AS interlockSystemName,
-        s.interlock_apparatus_id, apparatus_base.interlock_name AS interlockApparatusName
-        from interlock_detail_history d
-        LEFT JOIN interlock_summary_history s on d.summaryid = s.id
-        INNER JOIN
-        interlock_base system_base ON s.interlock_system_id = system_base.id AND system_base.interlock_type = '1'
-        INNER JOIN
-        interlock_base apparatus_base ON s.interlock_apparatus_id = apparatus_base.id AND apparatus_base.interlock_type = '0'
+        select distinct b1.id as interlockSystemId, b1.interlock_name as interlockSystemName, b2.id as interlockApparatusId, b2.interlock_name as interlockApparatusName
+        from interlock_base b
+        inner join interlock_base b1 on b.id = b1.id and b1.interlock_type = '1'
+        inner join interlock_base b2 on b2.id = b1.pid and b2.interlock_type = '0'
         LEFT JOIN (select l.* from interlock_system_limit l where l.interlock_user_id in
-        (select u.id from interlock_user u where u.username=#{wiseUser})) qxnr on qxnr.interlock_system_id = s.interlock_system_id
-        <where>
-            <if test="interlockSystemId != null and interlockSystemId != ''"> and s.interlock_system_id =  #{interlockSystemId}</if>
-            <if test="interlockApparatusId != null and interlockApparatusId != ''"> and s.interlock_apparatus_id =  #{interlockApparatusId}</if>
-
-            <if test="interlockname != null and interlockname != ''"> and d.interlockname like concat('%', #{interlockname}, '%')</if>
-            <if test="interlockCondition != null and interlockCondition != ''"> and d.interlock_condition = #{interlockCondition}</if>
-            <if test="interlockConditionTag != null and interlockConditionTag != ''"> and d.interlock_condition_tag like concat('%',#{interlockConditionTag},'%')</if>
-            <if test="instrumentStatus != null and instrumentStatus != ''"> and d.instrument_status = #{instrumentStatus}</if>
-            <if test="controlSystemStatus != null and controlSystemStatus != ''"> and d.control_system_status = #{controlSystemStatus}</if>
-            <if test="interlockStatus != null and interlockStatus != ''"> and s.interlock_status = #{interlockStatus}</if>
-            <if test="loopHealthLevel != null and loopHealthLevel != ''"> and s.loop_health_level = #{loopHealthLevel}</if>
-            <!--            <if test="beginTime != null">-->
-            <!--                <![CDATA[ AND TO_TIMESTAMP(s.tag_time, 'YYYY-MM-DD HH24:MI:SS') > #{beginTime} ]]>-->
-            <!--            </if>-->
-            <!--            <if test="endTime != null">-->
-            <!--                <![CDATA[ AND TO_TIMESTAMP(s.tag_time, 'YYYY-MM-DD HH24:MI:SS') < #{endTime} ]]>-->
-            <!--            </if>-->
-            and s.interlock_system_id IS NOT NULL
-            AND s.interlock_apparatus_id IS NOT NULL
-            and (qxnr.limit_type='0' or qxnr.limit_type='1')
-        </where>
-        order by s.interlock_apparatus_id
+        (select u.id from interlock_user u where u.username=#{wiseUser})) qxnr on qxnr.interlock_system_id = b1.id
+        where qxnr.limit_type='0' or qxnr.limit_type='1'
+        order by b2.id
     </select>
 
 

+ 3 - 2
jeecg-module-interlock/src/main/java/org/jeecg/modules/history/quartz/ReportJobMonth.java

@@ -130,13 +130,14 @@ public class ReportJobMonth implements Job {
 
         String filePath = fileUrlPrex  + fileName;
 
-        List< InterlockHistoryDistinctZZXTVO > zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryList(dto);
+//        List< InterlockHistoryDistinctZZXTVO > zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryList(dto);
+        List<InterlockHistoryDistinctZZXTVO> zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryListByAdmin();//目前按全部装置-系统数据进行导出
 
         if(zzxtvoList == null || zzxtvoList.size()==0) return;
         else {
             Workbook workbook = new XSSFWorkbook();
             try {
-                workbook = interlockDetailHistoryService.exportXlsToFile(dto, zzxtvoList, InterlockSummaryHistoryVO.class,"1");
+                workbook = interlockDetailHistoryService.exportXlsToFile1(dto, zzxtvoList, InterlockSummaryHistoryVO.class,"1");
             } catch (IOException e) {
                 e.printStackTrace();
             }

+ 120 - 0
jeecg-module-interlock/src/main/java/org/jeecg/modules/history/quartz/ReportJobYear.java

@@ -59,6 +59,8 @@ public class ReportJobYear implements Job {
         this.parameter = parameter;
     }
 
+    /*
+    //备份之前LLL版本
     @Override
     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
         log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey());
@@ -173,4 +175,122 @@ public class ReportJobYear implements Job {
             e.printStackTrace();
         }
     }
+
+     */
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey());
+
+        String separator = "/";
+        String filePrex = this.parameter;
+        String reportType = "";
+
+        InterlockHistoryQueryDTO dto = new InterlockHistoryQueryDTO();
+        Calendar start = Calendar.getInstance();
+        start.set(Calendar.HOUR_OF_DAY, 0);
+        start.set(Calendar.MINUTE, 0);
+        start.set(Calendar.SECOND, 0);
+
+        Calendar end = Calendar.getInstance();
+        end.set(Calendar.HOUR_OF_DAY, 23);
+        end.set(Calendar.MINUTE, 59);
+        end.set(Calendar.SECOND, 59);
+
+        if(this.parameter.equals("day")) {
+            // 昨天凌晨00:00:00
+            start.add(Calendar.DAY_OF_MONTH, -1);
+            // 昨天晚上23:59:59
+            end.add(Calendar.DAY_OF_MONTH, -1);
+
+            reportType = "0";
+
+        }else if(this.parameter.equals("month")){
+            // 上个月的第一天凌晨00:00:00
+            start.add(Calendar.MONTH, -1);
+            start.set(Calendar.DAY_OF_MONTH, 1);
+            // 上个月的最后一天晚上23:59:59
+            end.set(Calendar.DAY_OF_MONTH, 1);
+            end.add(Calendar.DAY_OF_MONTH, -1);
+
+            reportType = "1";
+
+        }else if(this.parameter.equals("year")){
+            // 去年的第一天凌晨00:00:00
+            start.add(Calendar.YEAR, -1);
+            start.set(Calendar.MONTH, 0);
+            start.set(Calendar.DAY_OF_MONTH, 1);
+            // 去年的最后一天晚上23:59:59
+            end.set(Calendar.MONTH, 0);
+            end.set(Calendar.DAY_OF_MONTH, 1);
+            end.add(Calendar.DAY_OF_MONTH, -1);
+
+            reportType = "2";
+        }
+
+        Date beginTime = start.getTime();
+        Date endTime = end.getTime();
+
+        log.info(String.format(" **********导出" + filePrex + "历史数据**********  时间:" + beginTime + "——" + endTime));
+
+        dto.setBeginTime(beginTime);
+        dto.setEndTime(endTime);
+
+        // 文件路径,如"D:/ttt/opt/upFiles/"
+        String fileUrlPrex = upLoadPath + separator + filePrex + separator;
+        File saveFile = new File(fileUrlPrex);
+        if (!saveFile.exists()) {
+            saveFile.mkdirs();
+        }
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+        String timestamp = dateFormat.format(new Date());
+        String fileName = String.format("联锁历史数据_" + filePrex + "报表_%s.xlsx", timestamp);
+
+        String filePath = fileUrlPrex  + fileName;
+
+//        List<InterlockHistoryDistinctZZXTVO> zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryList(dto);
+        List<InterlockHistoryDistinctZZXTVO> zzxtvoList = summaryHistoryMapper.getDistinctZZXTSummaryListByAdmin();//目前按全部装置-系统数据进行导出
+
+        if(zzxtvoList == null || zzxtvoList.size()==0) return;
+        else {
+            Workbook workbook = new XSSFWorkbook();
+            try {
+                workbook = interlockDetailHistoryService.exportXlsToFile1(dto, zzxtvoList, InterlockSummaryHistoryVO.class,"1");
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+            try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
+                workbook.write(fileOut);
+            } catch (IOException e) {
+                // 处理异常
+                e.printStackTrace();
+            } finally {
+                try {
+                    if (workbook != null) {
+                        workbook.close();
+                    }
+                } catch (IOException e) {
+                    // 处理关闭 workbook 时可能发生的异常
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        //新增报表记录
+        InterlockDataReport report = new InterlockDataReport();
+        report.setReportName(fileName);
+        report.setReportType(reportType); // 0日报表1月报表2年报表
+        report.setReportUrl(filePath);
+        reportService.save(report);
+
+        // IoTEdge-发送邮件
+        try {
+            restClientService.sendEmali(fileName,fileUrlPrex);
+            log.info(String.format(" **********发送" + filePrex + "历史数据导出邮件通知**********  "));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
 }

+ 65 - 59
jeecg-module-interlock/src/main/java/org/jeecg/modules/history/service/impl/InterlockDetailHistoryServiceImpl.java

@@ -551,8 +551,12 @@ public class InterlockDetailHistoryServiceImpl extends ServiceImpl<InterlockDeta
         int ty = summaryHistoryMapper.cocuntTY11(dto);
         int wty = summaryHistoryMapper.cocuntWTY11(dto);
         int total = ty + wty; // 总数量
-        double tyl = (double) ty / total * 100;
-        String tylPercentage = String.format("%.2f%%", tyl); // 将百分比转换为百分数形式,保留两位小数
+        String tylPercentage = "0.00%";//如果没有历史数据,投用率为0
+        if(total!=0){
+            double tyl = (double) ty / total * 100;
+            tylPercentage = String.format("%.2f%%", tyl); // 将百分比转换为百分数形式,保留两位小数
+        }
+
 
         //第一行:联锁历史数据报表
         int rowNum = 0;
@@ -627,72 +631,74 @@ public class InterlockDetailHistoryServiceImpl extends ServiceImpl<InterlockDeta
         int loopHealthLevelCol = 7;
         createCellOfRowWithValueStyle(columnRow,s9,cellStyleMap.get("centerAlignStyle"));
 
-
-        // 合并单元格的起始行索引
-        int startTagTimeRow = 0;
-        int startInterlockNameRow = 0;
-        int startInterlockStatusRow = 0;
-        int startLoopHealthLevelRow = 0;
-
-        for (int idx = 0; idx < exportList.size(); idx++)  {
-            InterlockSummaryHistoryVO record = exportList.get(idx);
-
-            //创建单元格、设置格式、填充数据
-            Row row = sheet.createRow(rowNum);
-            String[] s = {record.getTagTime(), record.getInterlockname(), record.getInterlockConditionTag(), record.getInstrumentStatusName(), record.getControlSystemStatusName(), record.getBypassName(), record.getInterlockStatusName(), record.getLoopHealthLevel()};
-            createCellOfRowWithValueStyle(row,s,cellStyleMap.get("centerAlignStyle3"));
-
-            // 合并 "采集时间" 列单元格
-            if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname()) ) {
-                if (idx > 0 && (rowNum - startTagTimeRow) > 1) {
-                    sheet.addMergedRegion(new CellRangeAddress(startTagTimeRow, rowNum - 1, tagTimeCol, tagTimeCol));
+        //如果有历史数据进行数据合并
+        if(exportList.size()!=0){
+            // 合并单元格的起始行索引
+            int startTagTimeRow = 0;
+            int startInterlockNameRow = 0;
+            int startInterlockStatusRow = 0;
+            int startLoopHealthLevelRow = 0;
+
+            for (int idx = 0; idx < exportList.size(); idx++)  {
+                InterlockSummaryHistoryVO record = exportList.get(idx);
+
+                //创建单元格、设置格式、填充数据
+                Row row = sheet.createRow(rowNum);
+                String[] s = {record.getTagTime(), record.getInterlockname(), record.getInterlockConditionTag(), record.getInstrumentStatusName(), record.getControlSystemStatusName(), record.getBypassName(), record.getInterlockStatusName(), record.getLoopHealthLevel()};
+                createCellOfRowWithValueStyle(row,s,cellStyleMap.get("centerAlignStyle3"));
+
+                // 合并 "采集时间" 列单元格
+                if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname()) ) {
+                    if (idx > 0 && (rowNum - startTagTimeRow) > 1) {
+                        sheet.addMergedRegion(new CellRangeAddress(startTagTimeRow, rowNum - 1, tagTimeCol, tagTimeCol));
+                    }
+                    startTagTimeRow = rowNum;
                 }
-                startTagTimeRow = rowNum;
-            }
 
-            // 合并 "联锁名称" 列单元格,基于 "采集时间"
-            if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname()) ) {
-                if (idx > 0 && (rowNum - startInterlockNameRow) > 1) {
-                    sheet.addMergedRegion(new CellRangeAddress(startInterlockNameRow, rowNum - 1, interlockNameCol, interlockNameCol));
+                // 合并 "联锁名称" 列单元格,基于 "采集时间"
+                if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname()) ) {
+                    if (idx > 0 && (rowNum - startInterlockNameRow) > 1) {
+                        sheet.addMergedRegion(new CellRangeAddress(startInterlockNameRow, rowNum - 1, interlockNameCol, interlockNameCol));
+                    }
+                    startInterlockNameRow = rowNum;
                 }
-                startInterlockNameRow = rowNum;
-            }
 
-            // 合并 "联锁状态" 列单元格,基于 "采集时间"
-            if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname())) {
-                if (idx > 0 && (rowNum - startInterlockStatusRow) > 1) {
-                    sheet.addMergedRegion(new CellRangeAddress(startInterlockStatusRow, rowNum - 1, interlockStatusCol, interlockStatusCol));
+                // 合并 "联锁状态" 列单元格,基于 "采集时间"
+                if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname())) {
+                    if (idx > 0 && (rowNum - startInterlockStatusRow) > 1) {
+                        sheet.addMergedRegion(new CellRangeAddress(startInterlockStatusRow, rowNum - 1, interlockStatusCol, interlockStatusCol));
+                    }
+                    startInterlockStatusRow = rowNum;
                 }
-                startInterlockStatusRow = rowNum;
-            }
 
-            // 合并 "回路健康状态" 列单元格,基于 "采集时间"
-            if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname())) {
-                if (idx > 0 && (rowNum - startLoopHealthLevelRow) > 1) {
-                    sheet.addMergedRegion(new CellRangeAddress(startLoopHealthLevelRow, rowNum - 1, loopHealthLevelCol, loopHealthLevelCol));
+                // 合并 "回路健康状态" 列单元格,基于 "采集时间"
+                if (idx == 0 || !record.getTagTime().equals(exportList.get(idx - 1).getTagTime()) || !record.getInterlockname().equals(exportList.get(idx - 1).getInterlockname())) {
+                    if (idx > 0 && (rowNum - startLoopHealthLevelRow) > 1) {
+                        sheet.addMergedRegion(new CellRangeAddress(startLoopHealthLevelRow, rowNum - 1, loopHealthLevelCol, loopHealthLevelCol));
+                    }
+                    startLoopHealthLevelRow = rowNum;
                 }
-                startLoopHealthLevelRow = rowNum;
-            }
 
-            rowNum++;
-        }
+                rowNum++;
+            }
 
-        // 最后一组合并区域的处理
-        // 合并 "采集时间" 列的最后一组
-        if ((rowNum - startTagTimeRow) > 1) {
-            sheet.addMergedRegion(new CellRangeAddress(startTagTimeRow, rowNum - 1, tagTimeCol, tagTimeCol));
-        }
-        // 合并 "联锁名称" 列的最后一组
-        if ((rowNum - startInterlockNameRow) > 1) {
-            sheet.addMergedRegion(new CellRangeAddress(startInterlockNameRow, rowNum - 1, interlockNameCol, interlockNameCol));
-        }
-        // 合并 "联锁状态" 列的最后一组
-        if ((rowNum - startInterlockStatusRow) > 1) {
-            sheet.addMergedRegion(new CellRangeAddress(startInterlockStatusRow, rowNum - 1, interlockStatusCol, interlockStatusCol));
-        }
-        // 合并 "回路健康状态" 列的最后一组
-        if ((rowNum - startLoopHealthLevelRow) > 1) {
-            sheet.addMergedRegion(new CellRangeAddress(startLoopHealthLevelRow, rowNum - 1, loopHealthLevelCol, loopHealthLevelCol));
+            // 最后一组合并区域的处理
+            // 合并 "采集时间" 列的最后一组
+            if ((rowNum - startTagTimeRow) > 1) {
+                sheet.addMergedRegion(new CellRangeAddress(startTagTimeRow, rowNum - 1, tagTimeCol, tagTimeCol));
+            }
+            // 合并 "联锁名称" 列的最后一组
+            if ((rowNum - startInterlockNameRow) > 1) {
+                sheet.addMergedRegion(new CellRangeAddress(startInterlockNameRow, rowNum - 1, interlockNameCol, interlockNameCol));
+            }
+            // 合并 "联锁状态" 列的最后一组
+            if ((rowNum - startInterlockStatusRow) > 1) {
+                sheet.addMergedRegion(new CellRangeAddress(startInterlockStatusRow, rowNum - 1, interlockStatusCol, interlockStatusCol));
+            }
+            // 合并 "回路健康状态" 列的最后一组
+            if ((rowNum - startLoopHealthLevelRow) > 1) {
+                sheet.addMergedRegion(new CellRangeAddress(startLoopHealthLevelRow, rowNum - 1, loopHealthLevelCol, loopHealthLevelCol));
+            }
         }
         System.out.println("系统结束-----------------------------------------------------------------------------------"+zzxtvo.getInterlockSystemName());