diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java index 0b03b326..b01610b6 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusProjectController.java @@ -21,6 +21,8 @@ import org.dromara.manager.weathermanager.vo.WeatherVo; import org.dromara.project.domain.dto.project.*; import org.dromara.project.domain.vo.project.*; import org.dromara.project.service.IBusProjectService; +import org.dromara.project.service.impl.BusTestServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -39,6 +41,8 @@ public class BusProjectController extends BaseController { @Resource private IBusProjectService projectService; + @Autowired + private BusTestServiceImpl busTestService; /** * 切换项目 @@ -215,4 +219,20 @@ public class BusProjectController extends BaseController { return R.ok(projectService.getSafetyDay(id)); } + /** + * 生成模板 + */ + @GetMapping("/generateTemplate") + public R generateTemplate() { + return R.ok(projectService.testExcel()); + } + + /** + * 生成模板 + */ + @GetMapping("/generateTemplate/dp") + public R generateTemplateDP() { + return R.ok(busTestService.testExcel()); + } + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java index 1128d552..577bc5a2 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusProjectService.java @@ -257,6 +257,6 @@ public interface IBusProjectService extends IService { /** * 生成项目周报模板 */ -// String testExcel(); + String testExcel(); } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java index 17e7c8a5..03c7e222 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusProjectServiceImpl.java @@ -7,6 +7,10 @@ import cn.hutool.core.convert.Convert; import cn.hutool.core.util.PhoneUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -16,6 +20,9 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.dromara.bigscreen.domain.dto.ProjectUpdateDto; import org.dromara.bigscreen.domain.dto.TanchuangInfoReq; import org.dromara.bigscreen.domain.vo.MilestoneVo; @@ -66,6 +73,7 @@ import org.dromara.system.service.ISysDictDataService; import org.dromara.workflow.service.IFlwDefinitionService; import org.dromara.xzd.utilS.IdWorker; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; import org.springframework.data.redis.core.StringRedisTemplate; @@ -74,6 +82,9 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.math.BigDecimal; import java.time.LocalDate; import java.util.*; @@ -95,6 +106,15 @@ import static org.dromara.common.satoken.utils.LoginHelper.LOGIN_USER_KEY; public class BusProjectServiceImpl extends ServiceImpl implements IBusProjectService, ProjectService { + // 全局行高常量(满足需求1:第二列高度翻倍相关) + private static final float DOUBLE_ROW_HEIGHT = 50; // 第二列关联行高(翻倍后) + private static final float NORMAL_ROW_HEIGHT = 25; // 常规行高 + private static final float PROGRESS_ROW_HEIGHT = 45; // 进度模块行高(需求3:第六与第七行一致) + private static final float DATA_ROW_HEIGHT = 22; // 表格数据行高 + + @Autowired + private BusTestServiceImpl busTestService; + @Lazy @Resource private IBusUserProjectRelevancyService userProjectRelevancyService; @@ -1678,4 +1698,1061 @@ public class BusProjectServiceImpl extends ServiceImpl(), writeSheet); + excelWriter.finish(); // 完成EasyExcel写入 + excelWriter = null; // 置空,避免重复关闭 + + // 6. 关键:等待文件IO完成(确保磁盘写入完毕) + Thread.sleep(500); + + // 7. 验证文件有效性 + if (!targetFile.exists() || targetFile.length() < 1024) { // 至少1KB才是有效Excel + throw new IOException("EasyExcel生成的文件无效,可能是写入失败"); + } + + // 8. POI接管:创建新工作簿处理复杂格式(避免读取损坏文件) + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("项目周报"); + + // 9. 构建完整模板结构(顺序:先基础样式 → 再创建内容 → 最后设置行高) + setupSheetBasicStyle(sheet); // 1. 设置基础样式(满足需求1、2) + buildTemplateFullStructure(sheet, workbook); // 2. 创建所有内容(满足需求3-12) + setKeyRowHeights(sheet); // 3. 设置行高(确保需求1、3生效) + + // 10. 写入最终文件 + outputStream = new FileOutputStream(targetFile); + workbook.write(outputStream); + outputStream.flush(); // 强制刷新缓存 + + // 11. 关闭POI资源 + workbook.close(); + System.out.println("模板格式处理完成"); + + } catch (Exception e) { + // 异常恢复:删除可能损坏的文件 + File targetFile = new File(outputFilePath); + if (targetFile.exists()) { + targetFile.delete(); + System.err.println("异常时已清理损坏文件"); + } + throw new Exception("模板生成流程失败:" + e.getMessage(), e); + } finally { + // 强制关闭所有流资源 + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + System.err.println("输出流关闭异常:" + e.getMessage()); + } + } + if (excelWriter != null) { + try { + excelWriter.close(); + } catch (Exception e) { + System.err.println("ExcelWriter关闭异常:" + e.getMessage()); + } + } + } + } + + /** + * 生成EasyExcel所需的表头(仅用于初始化12列结构) + */ + private static List> generateTemplateHeader() { + List> headerList = new ArrayList<>(); + // 创建12列空表头(列名无实际意义,后续会被POI覆盖) + for (int i = 0; i < 12; i++) { + List column = new ArrayList<>(); + column.add("COL_" + (i + 1)); + headerList.add(column); + } + return headerList; + } + + /** + * 设置工作表基础样式(满足需求1:第二列高度翻倍;需求2:统一样式有边框) + */ + private static void setupSheetBasicStyle(Sheet sheet) { + // 1. 设置12列的宽度(需求1:第二列(索引1)宽度翻倍,从18→36) + int[] columnWidths = {6, 36, 35, 15, 8, 12, 12, 12, 12, 12, 12, 15}; + for (int i = 0; i < columnWidths.length; i++) { + sheet.setColumnWidth(i, columnWidths[i] * 256); // Excel列宽单位:1/256字符宽度 + } + + // 2. 设置默认行高 + sheet.setDefaultRowHeightInPoints(NORMAL_ROW_HEIGHT); + + // 3. 设置打印配置 + sheet.setPrintGridlines(true); + sheet.setFitToPage(true); + } + + /** + * 构建模板完整结构(满足需求3-12的核心方法) + */ + private static void buildTemplateFullStructure(Sheet sheet, Workbook workbook) { + // 1. 创建所有需要的样式(需求2:所有样式都带边框) + CellStyle titleStyle = createTitleCellStyle(workbook); + CellStyle headerStyle = createHeaderCellStyle(workbook); + CellStyle contentStyle = createContentCellStyle(workbook); + CellStyle tableHeaderStyle = createTableHeaderCellStyle(workbook); + + // 2. 第1行:模板标题(A1:L1合并) + createTitleRow(sheet, titleStyle); + + // 3. 第2行:项目基本信息行(需求1:第二列高度翻倍;需求2:统一样式) + createProjectInfoRow(sheet, headerStyle, contentStyle); + + // 4. 第3行:主表头(B3:I3合并) + createMainHeaderRow(sheet, headerStyle, contentStyle); + + // 补充:第2行J列与第3行J列合并,第2行K列与第3行K列合并 + addMergedRegionSafe(sheet, 1, 2, 9, 9); // J2:J3合并 + addMergedRegionSafe(sheet, 1, 2, 10, 10); // K2:K3合并 + + // 5. 第4-5行:项目基本信息模块 + createProjectBasicInfoModule(sheet, workbook, 3, headerStyle, contentStyle); + + // 6. 第6行:本周进度模块(需求3:C-L合并,行高与第7行一致) + createWeeklyProgressModule(sheet, workbook, 5, headerStyle, contentStyle); + + // 7. 第7行:下周计划模块(需求4:A=3,B=标题,C-L合并) + createNextWeekPlanModule(sheet, workbook, 6, headerStyle, contentStyle); + + // 8. 第8行:质量情况模块(需求5:A=4,B=标题,C-L合并) + createQualityStatusModule(sheet, workbook, 7, headerStyle, contentStyle); + + // 9. 第9行:人员设备模块(需求6:A=5,B=标题,C-L合并) + createPersonnelEquipmentModule(sheet, workbook, 8, headerStyle, contentStyle); + + // 需求7:删除10-14行(直接跳过,不创建对应行) + + // 10. 第15行开始:施工进度统计表(需求8-10) + createConstructionProgressTable(sheet, workbook, 9, headerStyle, contentStyle, tableHeaderStyle); + + // 11. 第24行开始:材料到货统计表(需求11-12) + createMaterialArrivalTable(sheet, workbook, 17, headerStyle, contentStyle, tableHeaderStyle); + + // 12. 第29行:照片展示模块 + createPhotoDisplayModule(sheet, workbook, 22, headerStyle, contentStyle); + + // 13. 第30行:填报审核模块 + createApprovalModule(sheet, workbook, 24, headerStyle, contentStyle); + + // 14. 补充缺失的合并单元格 + addMissingMergedRegions(sheet); + } + + // ------------------------------ 模块创建方法(完整实现12点需求)------------------------------ + + /** + * 1. 创建标题行(第1行) + */ + private static void createTitleRow(Sheet sheet, CellStyle titleStyle) { + Row titleRow = sheet.createRow(0); + titleRow.setHeightInPoints(45); // 标题行高 + + // 创建标题单元格(A1) + Cell titleCell = titleRow.createCell(0); + titleCell.setCellValue("田东县乡村振兴分布式光伏发电项目周报"); + titleCell.setCellStyle(titleStyle); + + // 合并A1:L1 + addMergedRegionSafe(sheet, 0, 0, 0, 11); + } + + /** + * 2. 创建项目信息行(第2行,需求1:第二列高度翻倍;需求2:统一样式) + */ + private static void createProjectInfoRow(Sheet sheet, CellStyle headerStyle, CellStyle contentStyle) { + Row infoRow = sheet.createRow(1); + infoRow.setHeightInPoints(DOUBLE_ROW_HEIGHT); // 需求1:第二列关联行高翻倍 + + // A2:B2合并(项目名称标签) + Cell nameLabelCell = infoRow.createCell(0); + nameLabelCell.setCellValue("项目名称:"); + nameLabelCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, 1, 1, 0, 1); // A2:B2合并 + + // C2:G2 项目名称内容 + Cell projectNameCell = infoRow.createCell(2); + projectNameCell.setCellValue("田东县乡村振兴分布式光伏发电项目(一、二期)"); + projectNameCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, 1, 1, 2, 6); // C2:G2合并 + + // H2: 周报期数标签 + Cell reportNoLabel = infoRow.createCell(7); + reportNoLabel.setCellValue("周报期数:"); + reportNoLabel.setCellStyle(headerStyle); + + // I2: 周报期数内容 + Cell reportNoValue = infoRow.createCell(8); + reportNoValue.setCellValue("第___期"); + reportNoValue.setCellStyle(contentStyle); + + // J2: 日期标签(后续与J3合并) + Cell dateLabel = infoRow.createCell(9); + dateLabel.setCellValue("日期:"); + dateLabel.setCellStyle(headerStyle); + + // K2: 日期内容(后续与K3合并) + Cell dateValue = infoRow.createCell(10); + dateValue.setCellValue("____年__月__日"); + dateValue.setCellStyle(contentStyle); + + // L2: 空单元格(需求2:带边框) + Cell emptyL2 = infoRow.createCell(11); + emptyL2.setCellStyle(contentStyle); + } + + /** + * 3. 创建主表头行(第3行) + */ + private static void createMainHeaderRow(Sheet sheet, CellStyle headerStyle, CellStyle contentStyle) { + Row mainHeaderRow = sheet.createRow(2); + mainHeaderRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + + // A3: 序号 + Cell seqHeader = mainHeaderRow.createCell(0); + seqHeader.setCellValue("序号"); + seqHeader.setCellStyle(headerStyle); + + // B3:I3合并(工程实施主要情况) + Cell contentHeader = mainHeaderRow.createCell(1); + contentHeader.setCellValue("工程实施主要情况"); + contentHeader.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, 2, 2, 1, 8); // B3:I3合并 + + // J3: 空单元格(与J2合并,需求2:带边框) + Cell emptyJ3 = mainHeaderRow.createCell(9); + emptyJ3.setCellStyle(contentStyle); + + // K3: 空单元格(与K2合并,需求2:带边框) + Cell emptyK3 = mainHeaderRow.createCell(10); + emptyK3.setCellStyle(contentStyle); + + // L3: 空单元格(需求2:带边框) + Cell emptyL3 = mainHeaderRow.createCell(11); + emptyL3.setCellStyle(contentStyle); + } + + /** + * 4. 项目基本信息模块(完整实现改进1:D4:E5合并) + */ + private static void createProjectBasicInfoModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + // 第4行(startRow=3,对应Excel第4行) + Row row1 = sheet.createRow(startRow); + row1.setHeightInPoints(NORMAL_ROW_HEIGHT); + // 第5行(startRow+1=4,对应Excel第5行) + Row row2 = sheet.createRow(startRow + 1); + row2.setHeightInPoints(NORMAL_ROW_HEIGHT); + + // A4:A5合并(序号1) + Cell seqCell = row1.createCell(0); + seqCell.setCellValue("1"); + seqCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 0, 0); // A4:A5合并 + + // B4:B5合并(模块标题) + Cell titleCell = row1.createCell(1); + titleCell.setCellValue("项目基本信息"); + titleCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 1, 1); // B4:B5合并 + + // C4:C5合并(备案/设计容量) + Cell capacityCell = row1.createCell(2); + capacityCell.setCellValue("备案容量:\n设计容量:"); + capacityCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 2, 2); // C4:C5合并 + + // 改进1:D4:E5合并(原D4:D5与E4:E5合并为一个区域,覆盖开工日期) + Cell startDateCell = row1.createCell(3); // D列单元格 + startDateCell.setCellValue("开工日期:____.__.__"); + startDateCell.setCellStyle(contentStyle); + // 合并范围:D4:E5(Excel第4-5行,D-E列) + addMergedRegionSafe(sheet, startRow, startRow + 1, 3, 4); // D4:E5合并 + // E列无需单独创建单元格(已包含在D4:E5合并中) + + // F4:H5合并(计划并网日期) + Cell gridDateCell = row1.createCell(5); + gridDateCell.setCellValue("计划并网日期:____.__.__"); + gridDateCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 5, 7); // F4:H5合并 + + // I4:I5合并(总进度完成:) + Cell progressLabelCell = row1.createCell(8); + progressLabelCell.setCellValue("总进度完成:"); + progressLabelCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 8, 8); // I4:I5合并 + + // J4:K5合并(空内容) + Cell emptyJKCell = row1.createCell(9); + emptyJKCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 9, 10); // J4:K5合并 + + // L4:L5空单元格(带边框) + Cell emptyL4 = row1.createCell(11); + emptyL4.setCellStyle(contentStyle); + Cell emptyL5 = row2.createCell(11); + emptyL5.setCellStyle(contentStyle); + } + + /** + * 5. 本周进度模块(第6行,需求3:C-L合并,行高与第7行一致) + */ + private static void createWeeklyProgressModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row progressRow = sheet.createRow(startRow); + progressRow.setHeightInPoints(PROGRESS_ROW_HEIGHT); // 需求3:与第7行(下周计划)行高一致 + + // A6: 序号2 + Cell seqCell = progressRow.createCell(0); + seqCell.setCellValue("2"); + seqCell.setCellStyle(headerStyle); + + // B6: 模块标题 + Cell titleCell = progressRow.createCell(1); + titleCell.setCellValue("本周完成主要形象进度"); + titleCell.setCellStyle(headerStyle); + + // 需求3:C6:L6合并为一个单元格 + Cell contentCell = progressRow.createCell(2); + contentCell.setCellValue("本周天气情况:\n" + + "本周完成量:清表___亩,累计完成___亩;\n" + + "钻孔___个,累计完成___个;\n" + + "灌注桩浇筑___个,累计完成___个;\n" + + "安装支架___组,累计完成___组;\n" + + "安装光伏组件___组,累计完成___组;\n" + + "电缆敷设:___km,累计完成___km;\n" + + "接地系统:___km,累计完成___km;\n" + + "场区道路:___%,累计___%。"); + contentCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); // C6:L6合并 + } + + /** + * 6. 下周计划模块(完整实现改进2:A7/B7取消合并) + */ + private static void createNextWeekPlanModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + // 第7行(startRow=6,对应Excel第7行) + Row planRow = sheet.createRow(startRow); + planRow.setHeightInPoints(PROGRESS_ROW_HEIGHT); // 与第6行行高一致 + + // 改进2:A7单独设置,不合并,内容=3 + Cell seqCell = planRow.createCell(0); + seqCell.setCellValue("3"); + seqCell.setCellStyle(headerStyle); // 应用表头样式(蓝色背景、粗体) + + // 改进2:B7单独设置,不合并,内容=下周计划主要形象进度 + Cell titleCell = planRow.createCell(1); + titleCell.setCellValue("下周计划主要形象进度"); + titleCell.setCellStyle(headerStyle); // 应用表头样式 + + // C7:L7合并为一个单元格(进度内容区) + Cell contentCell = planRow.createCell(2); + contentCell.setCellValue("计划完成:钻孔___个,灌注桩浇筑___个,支架安装___组,\n" + + "光伏组件安装___组,电缆敷设___km,接地系统___km等工作。"); + contentCell.setCellStyle(contentStyle); // 应用内容样式(自动换行、带边框) + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); // C7:L7合并 + } + + /** + * 7. 质量情况模块(完整实现改进3:A8/B8取消合并) + */ + private static void createQualityStatusModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + // 第8行(startRow=7,对应Excel第8行) + Row qualityRow = sheet.createRow(startRow); + qualityRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + + // 改进3:A8单独设置,不合并,内容=4 + Cell seqCell = qualityRow.createCell(0); + seqCell.setCellValue("4"); + seqCell.setCellStyle(headerStyle); // 应用表头样式 + + // 改进3:B8单独设置,不合并,内容=质量(施工质量、设备材料到货验收)情况 + Cell titleCell = qualityRow.createCell(1); + titleCell.setCellValue("质量(施工质量、设备材料到货验收)情况"); + titleCell.setCellStyle(headerStyle); // 应用表头样式 + + // C8:L8合并为一个单元格(质量内容区) + Cell contentCell = qualityRow.createCell(2); + contentCell.setCellValue("1、施工质量问题:\n" + + "2、设备材料验收情况:\n" + + "3、整改情况:"); + contentCell.setCellStyle(contentStyle); // 应用内容样式 + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); // C8:L8合并 + } + + /** + * 8. 人员设备模块(完整实现改进4:A9/B9取消合并) + */ + private static void createPersonnelEquipmentModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + // 第9行(startRow=8,对应Excel第9行) + Row personnelRow = sheet.createRow(startRow); + personnelRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + + // 改进4:A9单独设置,不合并,内容=5 + Cell seqCell = personnelRow.createCell(0); + seqCell.setCellValue("5"); + seqCell.setCellStyle(headerStyle); // 应用表头样式 + + // 改进4:B9单独设置,不合并,内容=人员到位情况及施工器具 + Cell titleCell = personnelRow.createCell(1); + titleCell.setCellValue("人员到位情况及施工器具"); + titleCell.setCellStyle(headerStyle); // 应用表头样式 + + // C9:L9合并为一个单元格(人员设备内容区) + Cell contentCell = personnelRow.createCell(2); + contentCell.setCellValue("本周施工人员___人,共投入光伏钻机___台,小蜜蜂钻机___台,\n" + + "履带式潜孔钻机___台,柴油发动空压机___台,无人机___台,\n" + + "振捣棒___台,小型电动工具一批。"); + contentCell.setCellStyle(contentStyle); // 应用内容样式 + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); // C9:L9合并 + } + + /** + * 9. 施工进度统计表(完整实现改进5-6:A10:A18合并、B/C列调整) + */ + private static void createConstructionProgressTable(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle, + CellStyle tableHeaderStyle) { + // 改进5:A10:A18合并(Excel第10-18行,共9行),内容=6 + // 第10行(startRow=9,对应Excel第10行)- 作为A列合并的标题行 + Row aMergeTitleRow = sheet.createRow(startRow); + aMergeTitleRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + // A列合并单元格(A10:A18) + Cell aMergeCell = aMergeTitleRow.createCell(0); + aMergeCell.setCellValue("6"); + aMergeCell.setCellStyle(headerStyle); // 应用表头样式(蓝色背景、粗体居中) + addMergedRegionSafe(sheet, startRow, startRow + 8, 0, 0); // A10:A18合并 + + // 改进5:B列设置(B10=类别,B11:B18合并=标题) + // B10=类别(Excel第10行B列,表格表头) + Cell b10Cell = aMergeTitleRow.createCell(1); + b10Cell.setCellValue("类别"); + b10Cell.setCellStyle(tableHeaderStyle); // 应用表格表头样式(绿色背景、粗体) + // B11:B18合并(Excel第11-18行B列),内容=施工进度说明 + Row bMergeRow = sheet.createRow(startRow + 1); // B列合并的标题行(Excel第11行) + bMergeRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + Cell bMergeCell = bMergeRow.createCell(1); + bMergeCell.setCellValue("施工进度(根据项目类型及进度情况自行分项,不用太细,能体现整体进度即可)"); + bMergeCell.setCellStyle(headerStyle); // 应用表头样式 + addMergedRegionSafe(sheet, startRow + 1, startRow + 8, 1, 1); // B11:B18合并 + + // 改进6:C10=名称(Excel第10行C列,表格表头) + Cell c10Cell = aMergeTitleRow.createCell(2); + c10Cell.setCellValue("名称"); + c10Cell.setCellStyle(tableHeaderStyle); // 应用表格表头样式 + + // C列数据行(C11:C18,对应Excel第11-18行C列,各类别名称) + String[] cColumnNames = {"基础", "支架", "组件", "清表", "放线", "塔基", "组塔", "电缆敷设", "接地系统"}; + for (int i = 0; i < cColumnNames.length; i++) { + int currentRowNum = startRow + 1 + i; // 从Excel第11行开始 + Row cDataRow = sheet.getRow(currentRowNum); + if (cDataRow == null) { + cDataRow = sheet.createRow(currentRowNum); + } + cDataRow.setHeightInPoints(DATA_ROW_HEIGHT); // 数据行高 + // C列单元格赋值 + Cell cDataCell = cDataRow.createCell(2); + cDataCell.setCellValue(cColumnNames[i]); + cDataCell.setCellStyle(contentStyle); // 应用内容样式 + } + + // D列设置(D10=单位,D11:D18合并分区域) + // D10=单位(Excel第10行D列,表格表头) + Cell d10Cell = aMergeTitleRow.createCell(3); + d10Cell.setCellValue("单位"); + d10Cell.setCellStyle(tableHeaderStyle); + // D11:D14合并=光伏区(Excel第11-14行D列) + Row dPvRow = sheet.getRow(startRow + 1); + Cell dPvCell = dPvRow.createCell(3); + dPvCell.setCellValue("光伏区"); + dPvCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow + 1, startRow + 4, 3, 3); // D11:D14合并 + // D15:D18合并=线路工程(Excel第15-18行D列) + Row dLineRow = sheet.getRow(startRow + 5); + Cell dLineCell = dLineRow.createCell(3); + dLineCell.setCellValue("线路工程"); + dLineCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow + 5, startRow + 8, 3, 3); // D15:D18合并 + + // E-L列设置(表格数据列,均为输入区) + String[] otherHeaders = {"设计数量", "本周完成", "累计完成", "完成率(%)", "计划完成", "实际完成", "备注1", "备注2"}; + int[] otherColumns = {4, 5, 6, 7, 8, 9, 10, 11}; // E-L列索引 + // 表头赋值(E10:L10,Excel第10行) + for (int i = 0; i < otherHeaders.length; i++) { + Cell headerCell = aMergeTitleRow.createCell(otherColumns[i]); + headerCell.setCellValue(otherHeaders[i]); + headerCell.setCellStyle(tableHeaderStyle); + } + // 数据行空单元格填充(E11:L18,带边框) + for (int rowIdx = 0; rowIdx < 8; rowIdx++) { + int currentRow = startRow + 1 + rowIdx; + Row dataRow = sheet.getRow(currentRow); + if (dataRow == null) { + dataRow = sheet.createRow(currentRow); + } + for (int colIdx = 0; colIdx < otherColumns.length; colIdx++) { + Cell dataCell = dataRow.createCell(otherColumns[colIdx]); + dataCell.setCellStyle(contentStyle); + } + } + + // K-L列合并(改进5配套调整) + // K10:L10合并(Excel第10行K-L列,表头备注合并) + addMergedRegionSafe(sheet, startRow, startRow, 10, 11); // K10:L10合并 + // K11:L18合并(Excel第11-18行K-L列,备注输入区) + addMergedRegionSafe(sheet, startRow + 1, startRow + 8, 10, 11); // K11:L18合并 + } + + /** + * 10. 材料到货统计表(第24-28行,需求11-12) + */ + private static void createMaterialArrivalTable(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle, + CellStyle tableHeaderStyle) { + // 第24行(startRow=17):空行 + Row emptyRow24 = sheet.createRow(startRow); + emptyRow24.setHeightInPoints(NORMAL_ROW_HEIGHT); + for (int i = 0; i < 12; i++) { + Cell cell = emptyRow24.createCell(i); + cell.setCellStyle(contentStyle); + } + + // 25行(startRow+1=18):标题行 + Row row25 = sheet.createRow(startRow + 1); + // 26行(startRow+2=19):檩条、斜撑 + Row row26 = sheet.createRow(startRow + 2); + // 27行(startRow+3=20):立杆 + Row row27 = sheet.createRow(startRow + 3); + // 28行(startRow+4=21):光伏组件 + Row row28 = sheet.createRow(startRow + 4); + // 29行(startRow+5=22):预埋件(单独处理,不包含在A/B列合并中) + Row row29 = sheet.createRow(startRow + 5); + + // 设置行高 + row25.setHeightInPoints(NORMAL_ROW_HEIGHT); + row26.setHeightInPoints(DATA_ROW_HEIGHT); + row27.setHeightInPoints(DATA_ROW_HEIGHT); + row28.setHeightInPoints(DATA_ROW_HEIGHT); + row29.setHeightInPoints(DATA_ROW_HEIGHT); + + // A19:A22合并(25-28行),内容=7 + Cell seqCell = row25.createCell(0); + seqCell.setCellValue("7"); + seqCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, startRow + 1, startRow + 4, 0, 0); // A19:A22合并 + + // B19:B22合并(25-28行),内容=标题 + Cell titleCell = row25.createCell(1); + titleCell.setCellValue("主要设备材料到货情况(列出主要材料即可)"); + titleCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, startRow + 1, startRow + 4, 1, 1); // B19:B22合并 + + // 25行K-L合并(需求12) + addMergedRegionSafe(sheet, startRow + 1, startRow + 1, 10, 11); // K19:L19合并 + + // 填充26-28行材料数据 + // 26行(檩条、斜撑) + Cell row26C = row26.createCell(2); + row26C.setCellValue("檩条、斜撑"); + row26C.setCellStyle(contentStyle); + Cell row26D = row26.createCell(3); + row26D.setCellValue("根"); + row26D.setCellStyle(contentStyle); + // 27行(立杆) + Cell row27C = row27.createCell(2); + row27C.setCellValue("立杆"); + row27C.setCellStyle(contentStyle); + Cell row27D = row27.createCell(3); + row27D.setCellValue("根"); + row27D.setCellStyle(contentStyle); + // 28行(光伏组件) + Cell row28C = row28.createCell(2); + row28C.setCellValue("光伏组件"); + row28C.setCellStyle(contentStyle); + Cell row28D = row28.createCell(3); + row28D.setCellValue("块"); + row28D.setCellStyle(contentStyle); + + // 填充26-28行其他列空单元格 + List materialRows = List.of(row25, row26, row27, row28); + for (Row row : materialRows) { + for (int i = 4; i < 12; i++) { + Cell cell = row.createCell(i); + cell.setCellStyle(contentStyle); + } + } + + // 单独处理29行(预埋件) + Cell row29A = row29.createCell(0); + row29A.setCellStyle(contentStyle); + Cell row29B = row29.createCell(1); + row29B.setCellStyle(contentStyle); + Cell row29C = row29.createCell(2); + row29C.setCellValue("预埋件"); + row29C.setCellStyle(contentStyle); + Cell row29D = row29.createCell(3); + row29D.setCellValue("套"); + row29D.setCellStyle(contentStyle); + for (int i = 4; i < 12; i++) { + Cell cell = row29.createCell(i); + cell.setCellStyle(contentStyle); + } + } + + /** + * 11. 照片展示模块(第29行-30行) + */ + private static void createPhotoDisplayModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + // 第29行(startRow=22,Excel第29行):标题行 + Row titleRow = sheet.createRow(startRow); + titleRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + + // A23: 序号8 + Cell seqCell = titleRow.createCell(0); + seqCell.setCellValue("8"); + seqCell.setCellStyle(headerStyle); + + // B23: 模块标题 + Cell titleCell = titleRow.createCell(1); + titleCell.setCellValue("照片"); + titleCell.setCellStyle(headerStyle); + + // A23:B23合并(无重叠,正常添加) + addMergedRegionSafe(sheet, startRow, startRow, 0, 1); + + // C23:L23合并(提示文本) + Cell tipCell = titleRow.createCell(2); + tipCell.setCellValue("(此处粘贴项目现场照片,每张照片附简要说明)"); + tipCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + + // 第30行(startRow+1=23,Excel第30行):照片区域 + Row photoRow = sheet.createRow(startRow + 1); + photoRow.setHeightInPoints(120); + + // A30:B30合并 + addMergedRegionSafe(sheet, startRow + 1, startRow + 1, 0, 1); + Cell abCell = photoRow.createCell(0); + abCell.setCellStyle(contentStyle); + + // C30:L30合并 + addMergedRegionSafe(sheet, startRow + 1, startRow + 1, 2, 11); + Cell photoCell = photoRow.createCell(2); + photoCell.setCellStyle(contentStyle); + } + + /** + * 12. 填报审核模块(第31行) + */ + private static void createApprovalModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row approvalRow = sheet.createRow(startRow); + approvalRow.setHeightInPoints(NORMAL_ROW_HEIGHT); + + // A31: 序号10 + Cell seqCell = approvalRow.createCell(0); + seqCell.setCellValue("9"); + seqCell.setCellStyle(headerStyle); + + // B31: 填报标签 + Cell fillLabel = approvalRow.createCell(1); + fillLabel.setCellValue("填报:"); + fillLabel.setCellStyle(headerStyle); + + // C31:D31合并(填报人) + Cell fillerCell = approvalRow.createCell(2); + fillerCell.setCellValue("________"); + fillerCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 3); // C31:D31合并 + + // E31: 审核标签 + Cell checkLabel = approvalRow.createCell(4); + checkLabel.setCellValue("审核:"); + checkLabel.setCellStyle(headerStyle); + + // F31: 空单元格 + Cell emptyF31 = approvalRow.createCell(5); + emptyF31.setCellStyle(contentStyle); + + // G31:H31合并(审核人) + Cell checkerCell = approvalRow.createCell(6); + checkerCell.setCellValue("________"); + checkerCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 6, 7); // G31:H31合并 + + // I31:L31空单元格(需求2:带边框) + for (int i = 8; i < 12; i++) { + Cell cell = approvalRow.createCell(i); + cell.setCellStyle(contentStyle); + } + } + + // ------------------------------ 样式创建方法(需求2:所有样式带边框)------------------------------ + + /** + * 创建标题样式(蓝色背景、16号粗体,需求2:带边框) + */ + private static CellStyle createTitleCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 字体设置 + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)16); + font.setBold(true); + style.setFont(font); + + // 对齐方式 + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + // 需求2:强制添加所有边框 + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 背景色(浅蓝色) + style.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + return style; + } + + /** + * 创建表头样式(浅蓝色背景、11号粗体,需求2:带边框) + */ + private static CellStyle createHeaderCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 字体设置 + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)11); + font.setBold(true); + style.setFont(font); + + // 对齐方式 + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + // 需求2:强制添加所有边框 + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 背景色(浅蓝紫色) + style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + return style; + } + + /** + * 创建内容样式(统一样式,需求2:带边框) + */ + private static CellStyle createContentCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 字体设置(与原始模板一致) + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)10); + style.setFont(font); + + // 对齐方式(垂直居中对齐) + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + // 需求2:强制添加所有边框(解决部分单元格无边框问题) + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 自动换行 + style.setWrapText(true); + + // 背景色(白色) + style.setFillForegroundColor(IndexedColors.WHITE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + return style; + } + + /** + * 创建表格表头样式(浅绿色背景、10号粗体,需求2:带边框) + */ + private static CellStyle createTableHeaderCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 字体设置 + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)10); + font.setBold(true); + style.setFont(font); + + // 对齐方式 + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + // 需求2:强制添加所有边框 + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 背景色(浅绿色) + style.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + return style; + } + + /** + * 创建空行单元格样式(需求2:带边框) + */ + private static CellStyle createEmptyCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 需求2:强制添加所有边框(与其他单元格保持一致) + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 背景色(白色) + style.setFillForegroundColor(IndexedColors.WHITE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + return style; + } + + // ------------------------------ 辅助方法(确保需求生效)------------------------------ + + /** + * 补充缺失的合并单元格 + */ + private static void addMissingMergedRegions(Sheet sheet) { + // 各模块序号列合并(A列和B列) + addMergedRegionSafe(sheet, 6, 6, 0, 1); // 下周计划行:A7:B7合并 + addMergedRegionSafe(sheet, 7, 7, 0, 1); // 质量情况行:A8:B8合并 + addMergedRegionSafe(sheet, 8, 8, 0, 1); // 人员设备行:A9:B9合并 + + // 关键修复:删除重复的A23:B23合并(已在createPhotoDisplayModule中添加) + // addMergedRegionSafe(sheet, 22, 22, 0, 1); // 照片标题行:A29:B29合并(删除此行) + + addMergedRegionSafe(sheet, 24, 24, 0, 1); // 填报审核行:A31:B31合并 + } + + /** + * 设置关键行的行高(确保需求1、3生效) + */ + private static void setKeyRowHeights(Sheet sheet) { + // 第1行:标题行 + setRowHeightSafe(sheet, 0, 45); + + // 第2行:项目信息行(需求1:第二列高度翻倍) + setRowHeightSafe(sheet, 1, DOUBLE_ROW_HEIGHT); + + // 第3行:表头行 + setRowHeightSafe(sheet, 2, NORMAL_ROW_HEIGHT); + + // 第4-5行:项目基本信息行 + setRowHeightSafe(sheet, 3, NORMAL_ROW_HEIGHT); + setRowHeightSafe(sheet, 4, NORMAL_ROW_HEIGHT); + + // 第6行:本周进度行(需求3:与第7行一致) + setRowHeightSafe(sheet, 5, PROGRESS_ROW_HEIGHT); + + // 第7行:下周计划行(需求3:与第6行一致) + setRowHeightSafe(sheet, 6, PROGRESS_ROW_HEIGHT); + + // 第8-9行:质量情况、人员设备行 + setRowHeightSafe(sheet, 7, NORMAL_ROW_HEIGHT); + setRowHeightSafe(sheet, 8, NORMAL_ROW_HEIGHT); + + // 第10-14行:已删除(需求7) + + // 第15-23行:施工进度表 + setRowHeightSafe(sheet, 9, NORMAL_ROW_HEIGHT); // 第15行空行 + setRowHeightSafe(sheet, 10, NORMAL_ROW_HEIGHT); // 第16行 + setRowHeightSafe(sheet, 11, NORMAL_ROW_HEIGHT); // 第17行 + for (int i = 12; i <= 17; i++) { + setRowHeightSafe(sheet, i, DATA_ROW_HEIGHT); // 第18-23行数据行 + } + + // 第24-29行:材料到货表 + setRowHeightSafe(sheet, 17, NORMAL_ROW_HEIGHT); // 第24行空行 + setRowHeightSafe(sheet, 18, NORMAL_ROW_HEIGHT); // 第25行标题行 + for (int i = 19; i <= 22; i++) { + setRowHeightSafe(sheet, i, DATA_ROW_HEIGHT); // 第26-29行数据行 + } + + // 第30-31行:照片模块 + setRowHeightSafe(sheet, 22, NORMAL_ROW_HEIGHT); // 第29行标题行 + setRowHeightSafe(sheet, 23, 120); // 第30行照片区 + + // 第32行:填报审核行 + setRowHeightSafe(sheet, 24, NORMAL_ROW_HEIGHT); + } + + /** + * 安全设置行高(添加非空判断) + */ + private static void setRowHeightSafe(Sheet sheet, int rowIndex, float height) { + if (rowIndex < 0 || height <= 0) { + return; + } + // 如果Row不存在,先创建Row对象 + Row row = sheet.getRow(rowIndex); + if (row == null) { + row = sheet.createRow(rowIndex); + } + row.setHeightInPoints(height); + } + + /** + * 补充缺失的空行(倒序插入,避免行号混乱) + */ + private static void addMissingEmptyRows(Sheet sheet) { + // 倒序插入空行,避免影响已创建的行 + insertEmptyRow(sheet, 27); // 照片模块后 + insertEmptyRow(sheet, 22); // 材料到货表后 + insertEmptyRow(sheet, 17); // 施工进度表后 + insertEmptyRow(sheet, 9); // 人员设备模块后 + } + + /** + * 插入空行(安全版,需求2:带边框) + */ + private static void insertEmptyRow(Sheet sheet, int rowIndex) { + // 检查行号合法性 + if (rowIndex < 0 || rowIndex > sheet.getLastRowNum() + 1) { + return; + } + // 移动现有行(向下移动1行) + sheet.shiftRows(rowIndex, sheet.getLastRowNum(), 1, true, true); + // 创建新的空行 + Row emptyRow = sheet.createRow(rowIndex); + emptyRow.setHeightInPoints(15); // 空行高度 + + // 设置空行样式(需求2:带边框) + CellStyle emptyStyle = createEmptyCellStyle(sheet.getWorkbook()); + for (int i = 0; i < 12; i++) { + Cell cell = emptyRow.createCell(i); + cell.setCellStyle(emptyStyle); + } + } + + /** + * 检查新合并区域是否与现有区域重叠 + */ + private static boolean isRegionOverlapped(Sheet sheet, CellRangeAddress newRegion) { + // 获取所有已存在的合并区域 + List existingRegions = sheet.getMergedRegions(); + + for (CellRangeAddress existing : existingRegions) { + // 检查是否重叠(新区域与现有区域有交集) + boolean overlapped = !(newRegion.getLastRow() < existing.getFirstRow() || + newRegion.getFirstRow() > existing.getLastRow() || + newRegion.getLastColumn() < existing.getFirstColumn() || + newRegion.getFirstColumn() > existing.getLastColumn()); + + if (overlapped) { + System.err.println("检测到合并区域重叠:" + + newRegion.formatAsString() + " 与 " + + existing.formatAsString()); + return true; + } + } + return false; + } + + /** + * 安全添加合并区域(检查重叠,避免重复) + */ + private static void addMergedRegionSafe(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + // 1. 检查合并区域有效性(至少2个单元格) + if (firstRow == lastRow && firstCol == lastCol) { + System.err.println("跳过无效合并区域:" + firstRow + "," + firstCol + + "(仅单个单元格)"); + return; + } + + // 2. 检查是否重叠 + CellRangeAddress newRegion = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); + if (isRegionOverlapped(sheet, newRegion)) { + System.err.println("跳过重叠合并区域:" + newRegion.formatAsString()); + return; + } + + // 3. 安全添加 + sheet.addMergedRegion(newRegion); + } + + } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusTestServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusTestServiceImpl.java new file mode 100644 index 00000000..da6367e7 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusTestServiceImpl.java @@ -0,0 +1,847 @@ +package org.dromara.project.service.impl; + +import com.alibaba.excel.ExcelWriter; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; + +@Component +public class BusTestServiceImpl { + + + /** + * 测试生成Excel模板 + */ + public String testExcel() { + // 生成Excel模板文件 + String outputFilePath = "C:\\Users\\Administrator\\Desktop\\周报模板.xlsx"; + try { + generateWeeklyReportTemplate(outputFilePath); + System.out.println("Excel模板生成完成!文件路径:" + outputFilePath); + } catch (Exception e) { + System.err.println("Excel模板生成失败:" + e.getMessage()); + e.printStackTrace(); + } + return outputFilePath; + } + + /** + * 生成项目周报Excel模板(完整实现,匹配示例Excel结构) + * @param outputFilePath 输出文件路径 + * @throws Exception 异常抛出 + */ + public static void generateWeeklyReportTemplate(String outputFilePath) throws Exception { + ExcelWriter excelWriter = null; + FileOutputStream outputStream = null; + + try { + // 1. 预处理:删除已存在的文件 + File targetFile = new File(outputFilePath); + if (targetFile.exists()) { + if (!targetFile.delete()) { + throw new IOException("无法删除旧文件,请检查文件权限:" + outputFilePath); + } + } + + // 2. 使用POI直接创建复杂格式(不再使用EasyExcel混合模式) + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("9.13"); + + // 3. 构建完整模板结构 + setupSheetBasicStyle(sheet); // 设置基础样式 + buildTemplateFullStructure(sheet, workbook); // 创建所有内容 + setKeyRowHeights(sheet); // 设置行高 + + // 4. 写入最终文件 + outputStream = new FileOutputStream(targetFile); + workbook.write(outputStream); + outputStream.flush(); + + // 5. 关闭资源 + workbook.close(); + System.out.println("项目周报模板生成完成:" + outputFilePath); + + } catch (Exception e) { + // 异常恢复:删除可能损坏的文件 + File targetFile = new File(outputFilePath); + if (targetFile.exists()) { + targetFile.delete(); + System.err.println("异常时已清理损坏文件"); + } + throw new Exception("模板生成流程失败:" + e.getMessage(), e); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + System.err.println("输出流关闭异常:" + e.getMessage()); + } + } + } + } + + /** + * 设置工作表基础样式 + */ + private static void setupSheetBasicStyle(Sheet sheet) { + // 设置列宽(根据示例Excel调整) + int[] columnWidths = {8, 18, 35, 15, 8, 12, 12, 12, 12, 12, 12, 20}; + for (int i = 0; i < columnWidths.length; i++) { + sheet.setColumnWidth(i, columnWidths[i] * 256); + } + sheet.setDefaultRowHeightInPoints(20f); + } + + /** + * 构建模板完整结构(修正行号) + */ + private static void buildTemplateFullStructure(Sheet sheet, Workbook workbook) { + // 创建所有需要的样式 + CellStyle titleStyle = createTitleCellStyle(workbook); + CellStyle headerStyle = createHeaderCellStyle(workbook); + CellStyle contentStyle = createContentCellStyle(workbook); + CellStyle tableHeaderStyle = createTableHeaderCellStyle(workbook); + + // 1. 标题行(第1行)- 合并第1-2行 + createTitleRow(sheet, titleStyle); + + // 2. 关键修复:在创建任何内容之前,先设置所有小范围的合并区域 + setupAllSmallMergeRegions(sheet); + + // 3. 项目信息行(第3行)- A,B列合并 + createProjectInfoRow(sheet, headerStyle, contentStyle); + + // 4. 主表头行(第4行) + createMainHeaderRow(sheet, headerStyle, contentStyle); + + // 5. 项目基本信息模块(第5-6行)- 修正合并区域 + createProjectBasicInfoModule(sheet, workbook, 4, headerStyle, contentStyle); + + // 6. 本周进度模块(第7行)- 调整行高 + createWeeklyProgressModule(sheet, workbook, 6, headerStyle, contentStyle); + + // 7. 下周计划模块(第8行) + createNextWeekPlanModule(sheet, workbook, 7, headerStyle, contentStyle); + + // 8. 质量情况模块(第9行)- 调整行高 + createQualityStatusModule(sheet, workbook, 8, headerStyle, contentStyle); + + // 9. 人员设备模块(第10行)- 合并F-L列 + createPersonnelEquipmentModule(sheet, workbook, 9, headerStyle, contentStyle); + + // 10. 施工进度统计表(第11-18行)- 修正为7行数据 + createConstructionProgressTable(sheet, workbook, 10, headerStyle, contentStyle, tableHeaderStyle); + + // 11. 设备材料表格(第19-23行)- 修正表头结构 + createEquipmentMaterialTable(sheet, workbook, 18, headerStyle, contentStyle, tableHeaderStyle); + + // 12. 存在问题模块(第24行) + createProblemsModule(sheet, workbook, 23, headerStyle, contentStyle); + + // 13. 照片模块(第25行) + createPhotoModule(sheet, workbook, 24, headerStyle, contentStyle); + + // 14. 填报审核模块(第26行) + createApprovalModule(sheet, workbook, 25, headerStyle, contentStyle); + + // 15. 确保所有单元格都有边框 + ensureAllCellsHaveBorders(sheet, workbook); + } + + /** + * 创建标题行(第1行)- 合并第1-2行 + */ + private static void createTitleRow(Sheet sheet, CellStyle titleStyle) { + // 第1行 + Row titleRow1 = sheet.createRow(0); + titleRow1.setHeightInPoints(25); + + Cell titleCell1 = titleRow1.createCell(0); + titleCell1.setCellValue("田东县乡村振兴分布式光伏发电项目周报"); + titleCell1.setCellStyle(titleStyle); + + // 第2行(空行,但需要边框) + Row titleRow2 = sheet.createRow(1); + titleRow2.setHeightInPoints(15); + for (int i = 0; i < 12; i++) { + Cell cell = titleRow2.createCell(i); + cell.setCellStyle(createEmptyCellStyle(sheet.getWorkbook())); + } + + // 合并第1-2行 + addMergedRegionSafe(sheet, 0, 1, 0, 11); + } + + /** + * 项目信息行(第3行)- 修正合并区域 + */ + private static void createProjectInfoRow(Sheet sheet, CellStyle headerStyle, CellStyle contentStyle) { + Row infoRow = sheet.getRow(2); + + // A3:B3合并(项目名称标签) + Cell nameLabelCell = infoRow.createCell(0); + nameLabelCell.setCellValue("项目名称:"); + nameLabelCell.setCellStyle(headerStyle); + + // 项目名称内容 + Cell projectNameCell = infoRow.createCell(2); + projectNameCell.setCellValue("田东县乡村振兴分布式光伏发电项目(一、二期)"); + projectNameCell.setCellStyle(contentStyle); + + // 周报期数 + Cell reportNoLabel = infoRow.createCell(7); + reportNoLabel.setCellValue("周报期数"); + reportNoLabel.setCellStyle(headerStyle); + + Cell reportNoValue = infoRow.createCell(8); + reportNoValue.setCellValue("34"); + reportNoValue.setCellStyle(contentStyle); + + // 日期 - K3:L4合并 + Cell dateLabel = infoRow.createCell(9); + dateLabel.setCellValue("日期:"); + dateLabel.setCellStyle(headerStyle); + + Cell dateValue = infoRow.createCell(10); + dateValue.setCellValue("45955"); + dateValue.setCellStyle(contentStyle); + } + + /** + * 创建主表头行(第4行)- 彻底修复合并区域冲突 + */ + private static void createMainHeaderRow(Sheet sheet, CellStyle headerStyle, CellStyle contentStyle) { + Row headerRow = sheet.createRow(3); + + Cell seqHeader = headerRow.createCell(0); + seqHeader.setCellValue("序号"); + seqHeader.setCellStyle(headerStyle); + + Cell contentHeader = headerRow.createCell(1); + contentHeader.setCellValue("工程实施主要情况"); + contentHeader.setCellStyle(headerStyle); + + // 关键修复:先设置B4:I4合并,避免与J3:J4、K3:K4冲突 + addMergedRegionSafe(sheet, 3, 3, 1, 8); // B4:I4合并 + + // J4和K4单独设置(不合并) + Cell emptyJ4 = headerRow.createCell(9); + emptyJ4.setCellValue(""); // 设置空值 + emptyJ4.setCellStyle(contentStyle); + + Cell emptyK4 = headerRow.createCell(10); + emptyK4.setCellValue(""); // 设置空值 + emptyK4.setCellStyle(contentStyle); + + // L4单元格 + Cell emptyL4 = headerRow.createCell(11); + emptyL4.setCellStyle(contentStyle); + + // 注意:J3:J4和K3:K4合并已经在setupDateMergeRegions中设置,这里不再重复设置 + } + + /** + * 项目基本信息模块(第5-6行)- 修正合并区域 + */ + private static void createProjectBasicInfoModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row row1 = sheet.createRow(startRow); + Row row2 = sheet.createRow(startRow + 1); + + // A5:A6合并(序号1) + Cell seqCell = row1.createCell(0); + seqCell.setCellValue("1"); + seqCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 0, 0); + + // B5:B6合并(项目基本信息) + Cell titleCell = row1.createCell(1); + titleCell.setCellValue("项目基本信息"); + titleCell.setCellStyle(headerStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 1, 1); + + // C5:C6合并(备案容量/设计容量) + Cell capacityCell = row1.createCell(2); + capacityCell.setCellValue("备案容量:\n设计容量:"); + capacityCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 2, 2); + + // D5:E6合并(开工日期) + Cell startDateCell = row1.createCell(3); + startDateCell.setCellValue("开工日期:2025.3.19"); + startDateCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 3, 4); + + // F5:H6合并(计划并网日期)- 修正:第5-6行F-H列合并 + Cell gridDateCell = row1.createCell(5); + gridDateCell.setCellValue("计划并网日期:2025.12.30"); + gridDateCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 5, 7); + + // I5:I6合并(总进度完成) + Cell progressCell = row1.createCell(8); + progressCell.setCellValue("总进度完成:"); + progressCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 8, 8); + + // J5:L6合并(空)- 修正:J5-L6合并 + Cell emptyJK = row1.createCell(9); + emptyJK.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow + 1, 9, 11); + } + + /** + * 本周进度模块(第7行) + */ + private static void createWeeklyProgressModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row progressRow = sheet.createRow(startRow); + progressRow.setHeightInPoints(60); + + Cell seqCell = progressRow.createCell(0); + seqCell.setCellValue("2"); + seqCell.setCellStyle(headerStyle); + + Cell titleCell = progressRow.createCell(1); + titleCell.setCellValue("本周完成主要形象进度"); + titleCell.setCellStyle(headerStyle); + + Cell contentCell = progressRow.createCell(2); + contentCell.setCellValue("本周有1天因下雨全部停工;\n" + + "本周完成量:清表0亩,累计完成4104亩;钻孔4875个,累计完成119985个,灌注桩浇筑3955个,累计完成104434个桩,安装支架644组,累计完成6412组,安装光伏组件409组,累计完成4902组;\n" + + "直流电缆电池至逆变器电缆 H1Z2Z2-k-1×4mm2约10km,累计完成55km;1×6mm2约10km,累计完成32km;接地扁钢40*4约2km,累计完成7km;50*5约1km,累计完成4km;接地角钢100根,累计完成250根;场区道路改扩建10%,累计30%。"); + contentCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + } + + /** + * 修正其他模块的行号(去掉空行后) + */ + private static void createNextWeekPlanModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row planRow = sheet.createRow(startRow); + + Cell seqCell = planRow.createCell(0); + seqCell.setCellValue("3"); + seqCell.setCellStyle(headerStyle); + + Cell titleCell = planRow.createCell(1); + titleCell.setCellValue("下周计划主要形象进度"); + titleCell.setCellStyle(headerStyle); + + Cell contentCell = planRow.createCell(2); + contentCell.setCellValue("继续钻孔、安装钢筋笼、浇筑混凝土、支架安装、光伏组件安装、接地扁铁安装、电缆沟开挖等工作。"); + contentCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + } + + private static void createQualityStatusModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row qualityRow = sheet.createRow(startRow); + + Cell seqCell = qualityRow.createCell(0); + seqCell.setCellValue("4"); + seqCell.setCellStyle(headerStyle); + + Cell titleCell = qualityRow.createCell(1); + titleCell.setCellValue("质量(施工质量、设备材料到货验收)情况"); + titleCell.setCellStyle(headerStyle); + + Cell contentCell = qualityRow.createCell(2); + contentCell.setCellValue("1、三工区基础浇筑时未严格按照技术交底施工,造成部分基础拆模后有蜂窝麻面产生;\n" + + "2、四工区部分接地电缆沟开挖深度未达到设计值;\n" + + "3、二工区部分支架安装区域柱间拉条未按设计长度使用;\n" + + "以上问题已经现场对班组提出整改意见,班组已经按照要求全部整改完成并经过项目部管理人员复核。"); + contentCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + } + + /** + * 人员设备模块(第10行)- 恢复原来的合并范围 + */ + private static void createPersonnelEquipmentModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row personnelRow = sheet.createRow(startRow); + personnelRow.setHeightInPoints(25); + + Cell seqCell = personnelRow.createCell(0); + seqCell.setCellValue("5"); + seqCell.setCellStyle(headerStyle); + + Cell titleCell = personnelRow.createCell(1); + titleCell.setCellValue("人员到位情况及施工器具"); + titleCell.setCellStyle(headerStyle); + + Cell contentCell = personnelRow.createCell(2); + contentCell.setCellValue("本周施工人员633人,共投入光伏钻机21台,小蜜蜂钻机6台,履带式潜孔钻机4台,柴油发动空压机6台,无人机18台,汽油发动振捣棒20台,小型电动工具一批。"); + contentCell.setCellStyle(contentStyle); + + // 恢复原来的合并范围:C-L列 + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + } + + /** + * 施工进度统计表(第11-18行)- 修正表头合并和内容 + */ + private static void createConstructionProgressTable(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle, + CellStyle tableHeaderStyle) { + // 表头行(第11行) + Row headerRow = sheet.createRow(startRow); + + // A11与A12:A18合并,内容为6 + Cell a11Cell = headerRow.createCell(0); + a11Cell.setCellValue("6"); + a11Cell.setCellStyle(headerStyle); + + // B11与B12:B18合并 + Cell b11Cell = headerRow.createCell(1); + b11Cell.setCellValue("施工进度(根据项目类型及进度情况自行分项,不用太细,能体现整体进度即可)"); + b11Cell.setCellStyle(headerStyle); + + // C11内容为:名称 + Cell c11Cell = headerRow.createCell(2); + c11Cell.setCellValue("名称"); + c11Cell.setCellStyle(tableHeaderStyle); + + // 其他表头 - 从D列开始 + String[] headers = {"位置", "单位", "设计数量", "本周完成量", "累计完成量", "累计完成率"}; + for (int i = 0; i < headers.length; i++) { + Cell cell = headerRow.createCell(i + 3); // D列开始 + cell.setCellValue(headers[i]); + cell.setCellStyle(tableHeaderStyle); + } + + // J11:K11合并,内容为:下周计划完成 + Cell j11Cell = headerRow.createCell(9); + j11Cell.setCellValue("下周计划完成"); + j11Cell.setCellStyle(tableHeaderStyle); + addMergedRegionSafe(sheet, startRow, startRow, 9, 10); + + // L11内容为:备注,背景颜色与左边保持一致 + Cell l11Cell = headerRow.createCell(11); + l11Cell.setCellValue("备注"); + l11Cell.setCellStyle(tableHeaderStyle); + + // 数据行(第12-18行,共7行)- 修正数据位置 + String[][] progressData = { + {"基础", "光伏区", "个", "164728", "3955", "104434", "63.4%", "6000", "设计值为根据7.18日最新电子版图纸统计,包含未开工的五工区,总设计容量约为357.5Mpw。"}, + {"支架", "", "组", "20591", "644", "6412", "31.1%", "1050", ""}, + {"组件", "", "组", "20591", "409", "4902", "23.8%", "850", ""}, + {"清表", "", "亩", "4517", "0", "4104", "90.8%", "100", ""}, + {"塔基", "线路工程", "", "", "", "", "", "", ""}, + {"组塔", "", "", "", "", "", "", "", ""}, + {"放线", "", "", "", "", "", "", "", ""} + }; + + for (int i = 0; i < progressData.length; i++) { + Row row = sheet.createRow(startRow + 1 + i); + row.setHeightInPoints(20); + + // A列和B列不设置内容(在合并区域中) + + // 从C列开始设置数据 + for (int j = 0; j < progressData[i].length; j++) { + Cell cell = row.createCell(j + 2); // C列开始 + cell.setCellValue(progressData[i][j]); + cell.setCellStyle(contentStyle); + } + } + + // 设置合并区域 + try { + // A11:A18合并(序号6) + sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 7, 0, 0)); + // B11:B18合并(标题) + sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 7, 1, 1)); + // D12:D15合并(光伏区) + sheet.addMergedRegion(new CellRangeAddress(startRow + 1, startRow + 4, 3, 3)); + // D16:D18合并(线路工程) + sheet.addMergedRegion(new CellRangeAddress(startRow + 5, startRow + 7, 3, 3)); + // L12:L18合并(备注) + sheet.addMergedRegion(new CellRangeAddress(startRow + 1, startRow + 7, 11, 11)); + // 注意:取消了J12:K18的合并,现在J,K列在数据行是分开的 + } catch (IllegalStateException e) { + System.err.println("施工进度表合并区域设置失败: " + e.getMessage()); + } + } + + /** + * 设备材料表格(第19-23行)- 修正表头合并和内容 + */ + private static void createEquipmentMaterialTable(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle, + CellStyle tableHeaderStyle) { + // 表头行(第19行) + Row headerRow = sheet.createRow(startRow); + + // A19与A20:A23合并,内容为7 + Cell a19Cell = headerRow.createCell(0); + a19Cell.setCellValue("7"); + a19Cell.setCellStyle(headerStyle); + + // B19与B20:B23合并,内容为:主要设备材料到货情况(列出主要材料即可) + Cell b19Cell = headerRow.createCell(1); + b19Cell.setCellValue("主要设备材料到货情况(列出主要材料即可)"); + b19Cell.setCellStyle(headerStyle); + + // C19内容为:设备材料名称 + Cell c19Cell = headerRow.createCell(2); + c19Cell.setCellValue("设备材料名称"); + c19Cell.setCellStyle(tableHeaderStyle); + + // 其他表头 - 从D列开始 + String[] headers = {"", "单位", "设计数量", "本周到货量", "累计到货量", "累计到货率"}; + for (int i = 0; i < headers.length; i++) { + Cell cell = headerRow.createCell(i + 3); // D列开始 + cell.setCellValue(headers[i]); + cell.setCellStyle(tableHeaderStyle); + } + + // J19:K19合并,内容为:计划到货日期 + Cell j19Cell = headerRow.createCell(9); + j19Cell.setCellValue("计划到货日期"); + j19Cell.setCellStyle(tableHeaderStyle); + addMergedRegionSafe(sheet, startRow, startRow, 9, 10); + + // L19内容为:备注,背景颜色与左边保持一致 + Cell l19Cell = headerRow.createCell(11); + l19Cell.setCellValue("备注"); + l19Cell.setCellStyle(tableHeaderStyle); + + // 数据行 - 从第20行开始(共4行数据)- 修正数据位置 + String[][] materialData = { + {"檩条、斜撑", "", "根", "131728", "3752", "106745", "81.0%", "", ""}, + {"立杆", "", "根", "133841", "5549", "53372", "39.9%", "", ""}, + {"光伏组件", "", "块", "576548", "25880", "177360", "30.8%", "", ""}, + {"预埋件", "", "套", "164728", "0", "113000", "68.6%", "", ""} + }; + + for (int i = 0; i < materialData.length; i++) { + Row row = sheet.createRow(startRow + 1 + i); + row.setHeightInPoints(20); + + // A列和B列不设置内容(在合并区域中) + + // 从C列开始设置数据 + for (int j = 0; j < materialData[i].length; j++) { + Cell cell = row.createCell(j + 2); // C列开始 + cell.setCellValue(materialData[i][j]); + cell.setCellStyle(contentStyle); + } + } + + // 设置合并区域 + try { + // A19:A23合并(序号7) + sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 4, 0, 0)); + // B19:B23合并(标题) + sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + 4, 1, 1)); + // L20:L23合并(备注) + sheet.addMergedRegion(new CellRangeAddress(startRow + 1, startRow + 4, 11, 11)); + // 注意:取消了J20:K23的合并,现在J,K列在数据行是分开的 + } catch (IllegalStateException e) { + System.err.println("设备材料表合并区域设置失败: " + e.getMessage()); + } + } + + /** + * 修正其他相关模块的行号引用 + */ + private static void createProblemsModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row problemsRow = sheet.createRow(startRow); + + Cell seqCell = problemsRow.createCell(0); + seqCell.setCellValue("8"); + seqCell.setCellStyle(headerStyle); + + Cell titleCell = problemsRow.createCell(1); + titleCell.setCellValue("存在问题及需要协调的事项"); + titleCell.setCellStyle(headerStyle); + + Cell contentCell = problemsRow.createCell(2); + contentCell.setCellValue("1、场区围栏选型问题一直未能确定,班组迟迟不能采购;\n" + + "2、道路青赔费用本月需支付20万、外苏三户村名青赔增加费用30万需支付;\n" + + "3、管理人员工资8、9两月需支付;\n" + + "4、班组应付款项未能及时支付,造成班组材料采购都成问题。"); + contentCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + } + + /** + * 照片模块(第26行)- 修正序号 + */ + private static void createPhotoModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row photoRow = sheet.createRow(startRow); + + Cell seqCell = photoRow.createCell(0); + seqCell.setCellValue("9"); + seqCell.setCellStyle(headerStyle); + + Cell titleCell = photoRow.createCell(1); + titleCell.setCellValue("照片"); + titleCell.setCellStyle(headerStyle); + + Cell contentCell = photoRow.createCell(2); + contentCell.setCellStyle(contentStyle); + addMergedRegionSafe(sheet, startRow, startRow, 2, 11); + } + + /** + * 填报审核模块(第26行)- 合并F-L列 + */ + private static void createApprovalModule(Sheet sheet, Workbook workbook, int startRow, + CellStyle headerStyle, CellStyle contentStyle) { + Row approvalRow = sheet.createRow(startRow); + + Cell seqCell = approvalRow.createCell(0); + seqCell.setCellValue("10"); + seqCell.setCellStyle(headerStyle); + + Cell fillLabel = approvalRow.createCell(1); + fillLabel.setCellValue("填报:"); + fillLabel.setCellStyle(headerStyle); + + Cell fillerCell = approvalRow.createCell(2); + fillerCell.setCellValue("伍雪飞"); + fillerCell.setCellStyle(contentStyle); + + Cell checkLabel = approvalRow.createCell(4); + checkLabel.setCellValue("审核:"); + checkLabel.setCellStyle(headerStyle); + + Cell checkerCell = approvalRow.createCell(5); + checkerCell.setCellValue("张等红"); + checkerCell.setCellStyle(contentStyle); + + // 合并F-L列 + addMergedRegionSafe(sheet, startRow, startRow, 5, 11); + + // 为F-L列设置空单元格和边框 + for (int i = 5; i <= 11; i++) { + Cell cell = approvalRow.getCell(i); + if (cell == null) { + cell = approvalRow.createCell(i); + cell.setCellStyle(contentStyle); + } + } + } + + // 样式创建方法保持不变 + private static CellStyle createTitleCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)16); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + return style; + } + + private static CellStyle createHeaderCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)11); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + return style; + } + + private static CellStyle createContentCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)10); + style.setFont(font); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + style.setWrapText(true); + return style; + } + + private static CellStyle createTableHeaderCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short)10); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + style.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + return style; + } + + /** + * 安全添加合并区域(简化版,只用于后续的大范围合并) + */ + private static void addMergedRegionSafe(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + if (firstRow == lastRow && firstCol == lastCol) { + return; + } + + CellRangeAddress newRegion = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol); + + // 检查是否与现有合并区域重叠 + List mergedRegions = sheet.getMergedRegions(); + for (CellRangeAddress existingRegion : mergedRegions) { + if (regionsOverlap(newRegion, existingRegion)) { + System.err.println("跳过重叠的合并区域: " + newRegion.formatAsString() + + " 与 " + existingRegion.formatAsString()); + return; + } + } + + try { + sheet.addMergedRegion(newRegion); + System.out.println("成功添加合并区域: " + newRegion.formatAsString()); + } catch (IllegalStateException e) { + System.err.println("添加合并区域失败: " + newRegion.formatAsString() + " - " + e.getMessage()); + } + } + + /** + * 创建空单元格样式(带边框) + */ + private static CellStyle createEmptyCellStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + return style; + } + + /** + * 设置关键行的行高(调整行高设置,修正第24行高度) + */ + private static void setKeyRowHeights(Sheet sheet) { + setRowHeightSafe(sheet, 0, 25); // 标题行 + setRowHeightSafe(sheet, 1, 15); // 第2行(空行) + setRowHeightSafe(sheet, 2, 20); // 项目信息行 + setRowHeightSafe(sheet, 3, 20); // 表头行 + setRowHeightSafe(sheet, 4, 30); // 项目基本信息行1 + setRowHeightSafe(sheet, 5, 30); // 项目基本信息行2 + setRowHeightSafe(sheet, 6, 60); // 本周进度行 + setRowHeightSafe(sheet, 7, 30); // 下周计划行 + setRowHeightSafe(sheet, 8, 45); // 质量情况行 + setRowHeightSafe(sheet, 9, 25); // 人员设备行 + + // 设置表格行高 + for (int i = 10; i <= 17; i++) { // 第11-18行(施工进度表) + setRowHeightSafe(sheet, i, 20); + } + for (int i = 18; i <= 22; i++) { // 第19-23行(设备材料表) + setRowHeightSafe(sheet, i, 20); + } + + setRowHeightSafe(sheet, 23, 135); // 存在问题行(第24行)- 设置为原来的3倍(45*3=135) + setRowHeightSafe(sheet, 24, 20); // 照片行 + setRowHeightSafe(sheet, 25, 20); // 填报审核行 + } + + private static void setRowHeightSafe(Sheet sheet, int rowIndex, float height) { + Row row = sheet.getRow(rowIndex); + if (row == null) { + row = sheet.createRow(rowIndex); + } + row.setHeightInPoints(height); + } + + /** + * 检查两个合并区域是否重叠 + */ + private static boolean regionsOverlap(CellRangeAddress region1, CellRangeAddress region2) { + return !(region1.getLastRow() < region2.getFirstRow() || + region1.getFirstRow() > region2.getLastRow() || + region1.getLastColumn() < region2.getFirstColumn() || + region1.getFirstColumn() > region2.getLastColumn()); + } + + /** + * 设置所有小范围的合并区域 - 修正日期合并区域 + */ + private static void setupAllSmallMergeRegions(Sheet sheet) { + // 创建必要的行 + for (int i = 0; i <= 3; i++) { + if (sheet.getRow(i) == null) { + sheet.createRow(i); + } + } + + // 按从小到大的顺序设置合并区域 + try { + // 1. 最小的合并区域先设置 + sheet.addMergedRegion(new CellRangeAddress(2, 3, 9, 11)); // K3:L4合并 + System.out.println("设置小合并区域: K3:L4"); + + // 2. 中等范围的合并区域 + sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, 1)); // A3:B3 + sheet.addMergedRegion(new CellRangeAddress(2, 2, 2, 6)); // C3:G3 + System.out.println("设置中等合并区域: A3:B3, C3:G3"); + + // 3. 较大范围的合并区域 + sheet.addMergedRegion(new CellRangeAddress(3, 3, 1, 8)); // B4:I4 + System.out.println("设置大合并区域: B4:I4"); + + } catch (IllegalStateException e) { + System.err.println("小范围合并区域设置失败: " + e.getMessage()); + } + } + + /** + * 确保所有单元格都有边框 + */ + private static void ensureAllCellsHaveBorders(Sheet sheet, Workbook workbook) { + CellStyle borderStyle = createContentCellStyle(workbook); + + // 遍历所有行和列,确保每个单元格都有边框 + for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) { + Row row = sheet.getRow(rowNum); + if (row != null) { + for (int colNum = 0; colNum < 12; colNum++) { + Cell cell = row.getCell(colNum); + if (cell == null) { + cell = row.createCell(colNum); + cell.setCellStyle(borderStyle); + } else if (cell.getCellStyle() == null) { + cell.setCellStyle(borderStyle); + } + } + } + } + } + +}