|
@@ -0,0 +1,154 @@
|
|
|
|
|
+package com.yc.ship.module.trade.utils.excel;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.excel.write.handler.CellWriteHandler;
|
|
|
|
|
+import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
|
|
|
|
|
+import org.apache.poi.ss.usermodel.*;
|
|
|
|
|
+import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+public class ExcelStyleHandler implements CellWriteHandler {
|
|
|
|
|
+ private final int templateRowIndex;
|
|
|
|
|
+ private final Map<Integer, CellStyle> templateStyles = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 保存模板行的合并信息:列索引 -> [起始列, 结束列]
|
|
|
|
|
+ private final Map<Integer, int[]> templateMergeInfo = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ private boolean templateProcessed = false;
|
|
|
|
|
+
|
|
|
|
|
+ public ExcelStyleHandler(int templateRowIndex) {
|
|
|
|
|
+ this.templateRowIndex = templateRowIndex;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void afterCellDispose(CellWriteHandlerContext context) {
|
|
|
|
|
+ if (Boolean.TRUE.equals(context.getHead())) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Cell cell = context.getCell();
|
|
|
|
|
+ Row currentRow = cell.getRow();
|
|
|
|
|
+ int currentRowIndex = currentRow.getRowNum();
|
|
|
|
|
+ int colIndex = cell.getColumnIndex();
|
|
|
|
|
+ Sheet sheet = context.getWriteSheetHolder().getSheet();
|
|
|
|
|
+ Workbook workbook = sheet.getWorkbook();
|
|
|
|
|
+
|
|
|
|
|
+ // 处理模板行:保存样式和合并信息
|
|
|
|
|
+ if (currentRowIndex == templateRowIndex) {
|
|
|
|
|
+ if (!templateProcessed) {
|
|
|
|
|
+ // 保存样式
|
|
|
|
|
+ saveTemplateStyles(currentRow, workbook);
|
|
|
|
|
+
|
|
|
|
|
+ // 保存合并信息
|
|
|
|
|
+ saveTemplateMergeInfo(sheet);
|
|
|
|
|
+
|
|
|
|
|
+ templateProcessed = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 跳过模板行之前的行
|
|
|
|
|
+ if (currentRowIndex < templateRowIndex) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 为所有单元格设置样式(包括合并区域内的)=====
|
|
|
|
|
+ // CellStyle newStyle = workbook.createCellStyle();
|
|
|
|
|
+
|
|
|
|
|
+// 应用样式
|
|
|
|
|
+ if (templateStyles.containsKey(colIndex)) {
|
|
|
|
|
+ //newStyle.cloneStyleFrom(templateStyles.get(colIndex));
|
|
|
|
|
+
|
|
|
|
|
+ cell.setCellStyle(templateStyles.get(colIndex));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 如果这个列在合并区域内,设置边框
|
|
|
|
|
+ /*if (templateMergeInfo.containsKey(colIndex)) {
|
|
|
|
|
+ int[] range = templateMergeInfo.get(colIndex);
|
|
|
|
|
+ int firstCol = range[0];
|
|
|
|
|
+ int lastCol = range[1];
|
|
|
|
|
+
|
|
|
|
|
+ // 根据在合并区域中的位置设置边框
|
|
|
|
|
+ setMergeCellBorders(newStyle, colIndex, firstCol, lastCol);
|
|
|
|
|
+ }*/
|
|
|
|
|
+
|
|
|
|
|
+ // cell.setCellStyle(newStyle);
|
|
|
|
|
+
|
|
|
|
|
+ // 应用合并(只处理合并区域的第一个列)
|
|
|
|
|
+ if (templateMergeInfo.containsKey(colIndex)) {
|
|
|
|
|
+ int[] range = templateMergeInfo.get(colIndex);
|
|
|
|
|
+ int firstCol = range[0];
|
|
|
|
|
+ int lastCol = range[1];
|
|
|
|
|
+
|
|
|
|
|
+ // 只在当前列是合并区域的第一个列时创建合并
|
|
|
|
|
+ if (colIndex == firstCol) {
|
|
|
|
|
+ CellRangeAddress cra = new CellRangeAddress(
|
|
|
|
|
+ currentRowIndex, currentRowIndex, firstCol, lastCol
|
|
|
|
|
+ );
|
|
|
|
|
+ sheet.addMergedRegion(cra);
|
|
|
|
|
+
|
|
|
|
|
+ // 为合并区域设置完整边框
|
|
|
|
|
+ setMergeCellBorders(sheet.getColumnStyle(colIndex), colIndex, firstCol, lastCol);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 为合并区域的单元格设置边框
|
|
|
|
|
+ * @param style 单元格样式
|
|
|
|
|
+ * @param colIndex 当前列索引
|
|
|
|
|
+ * @param firstCol 合并区域起始列
|
|
|
|
|
+ * @param lastCol 合并区域结束列
|
|
|
|
|
+ */
|
|
|
|
|
+ private void setMergeCellBorders(CellStyle style, int colIndex, int firstCol, int lastCol) {
|
|
|
|
|
+ // 设置所有边框为细线
|
|
|
|
|
+ style.setBorderTop(BorderStyle.THIN);
|
|
|
|
|
+ style.setBorderBottom(BorderStyle.THIN);
|
|
|
|
|
+ style.setBorderLeft(BorderStyle.THIN);
|
|
|
|
|
+ style.setBorderRight(BorderStyle.THIN);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果有特殊需求,可以根据位置设置不同边框:
|
|
|
|
|
+ // - 合并区域的第一个单元格:左、上、下边框
|
|
|
|
|
+ // - 合并区域的最后一个单元格:右、上、下边框
|
|
|
|
|
+ // - 中间的单元格:上、下边框
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存模板行的合并信息
|
|
|
|
|
+ */
|
|
|
|
|
+ private void saveTemplateMergeInfo(Sheet sheet) {
|
|
|
|
|
+ List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
|
|
|
|
|
+ for (CellRangeAddress cra : mergedRegions) {
|
|
|
|
|
+ // 只处理模板行上的横向合并
|
|
|
|
|
+ if (cra.getFirstRow() == templateRowIndex && cra.getLastRow() == templateRowIndex) {
|
|
|
|
|
+ int firstCol = cra.getFirstColumn();
|
|
|
|
|
+ int lastCol = cra.getLastColumn();
|
|
|
|
|
+
|
|
|
|
|
+ // 记录这个合并区域涉及的所有列
|
|
|
|
|
+ for (int col = firstCol; col <= lastCol; col++) {
|
|
|
|
|
+ templateMergeInfo.put(col, new int[]{firstCol, lastCol});
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void saveTemplateStyles(Row templateRow, Workbook workbook) {
|
|
|
|
|
+ for (Cell cell : templateRow) {
|
|
|
|
|
+ if (cell != null && cell.getCellStyle() != null) {
|
|
|
|
|
+ CellStyle newStyle = workbook.createCellStyle();
|
|
|
|
|
+ newStyle.cloneStyleFrom(cell.getCellStyle());
|
|
|
|
|
+ templateStyles.put(cell.getColumnIndex(), newStyle);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|