fei
1 天以前 ca4b62abd2560b6dcffbf3ff43da1b04427b494b
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtilManySheet.java
@@ -316,14 +316,16 @@
                    printSetup.setLandscape(false);  // 纵向打印
                    // 设置页边距
                    sheet.setMargin(Sheet.LeftMargin, 0.5);
                    sheet.setMargin(Sheet.RightMargin, 0.5);
                    sheet.setMargin(Sheet.LeftMargin, 0.65);
                    sheet.setMargin(Sheet.RightMargin, 0.65);
                    sheet.setMargin(Sheet.TopMargin,0.31);
                    sheet.setMargin(Sheet.BottomMargin, 0.31);
                    // 设置打印区域,从第0行到第1000行,第0列到第20列(根据实际情况调整)
                 //   sheet.setPrintArea(0, 0, 20, 0, 1000);
                    // 如果是index为1的sheet,设置顶端标题行
                        // 将第1行(索引为0)设置为每页重复的标题行
                        sheet.setRepeatingRows(CellRangeAddress.valueOf("$1:$4"));
                        sheet.setRepeatingRows(CellRangeAddress.valueOf("$1:$5"));
                     row = sheet.createRow(0);
                    row.setHeight((short) (37*20));
@@ -334,17 +336,22 @@
                      //  if (Files.exists(Paths.get(imagePath))) {
                          //  byte[] imageBytes = Files.readAllBytes(Paths.get(imagePath));
                            // 将byte数组转换成inputstream,以便插入到Excel中
                            ClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 100, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 5),
                                    cell.getRow().getRowNum() + 1);
                            ClientAnchor anchor = new HSSFClientAnchor(813, 0, 787, 71, (short) 2, 0, (short) 4,
                                    1);
//                    ClientAnchor anchor = new HSSFClientAnchor(813, 0, 787, 71, (short) 2, 0, (short) 4,
//                            2);
                            // 设置锚点类型为MOVE_AND_RESIZE,使图片可以随单元格调整大小
                            anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
                                    // 计算居中位置
                    int col1 = 3; // 中间列
                    int col2 = col1 + 2;
                    anchor.setCol1(col1);
                    anchor.setCol2(col2);
                    anchor.setRow1(0);
                    anchor.setRow2(1);
//                    int col1 = 3; // 中间列
//                    int col2 = col1 + 2;
//                    anchor.setCol1(col1);
//                    anchor.setCol2(col2);
//                    anchor.setRow1(0);
//                    anchor.setRow2(1);
//                            anchor.set
//                            anchor.setHorizontallyCenter(true);
@@ -401,7 +408,7 @@
                    CellStyle underlineStyle = wb.createCellStyle();
                    Font underlineFont = wb.createFont();
                    underlineFont.setFontName("宋体");
                    underlineFont.setFontHeightInPoints((short) 11);
                    underlineFont.setFontHeightInPoints((short) 12);
                    underlineFont.setUnderline(Font.U_SINGLE); // 设置下划线
                    underlineStyle.setFont(underlineFont);
                    recordIdCell.setCellStyle(underlineStyle);
@@ -520,11 +527,19 @@
    public void fillExcelData(int index, Row row) {
//        int startNo = index * sheetSize;
//        int endNo = Math.min(startNo + sheetSize, list.size());
        int startRow = (index == 1) ? 5 : 1;
        for (int i = 0; i < list.size(); i++) {
            if(index==1)
                row = sheet.createRow(i + 5 );
            else
                row = sheet.createRow(i + 1 );
            // 第一步:让POI自动计算适配内容的行高
         //   sheet.autoSizeRow(0);
            // 第二步:获取自动计算后的行高
        //    row.setHeight((short) -1); // 先设为自动,由addCell计算后覆盖
            // 得到导出对象.
            T vo = (T) list.get(i);
            int column = 0;
@@ -534,10 +549,182 @@
                // 设置实体类私有属性可访问
                field.setAccessible(true);
                this.addCell(excel, row, vo, field, column++);
            }
            // 批量调整行高(数据填充完成后)
            if (list.size() > 0) {
                int lastRow = startRow + list.size() - 1;
                batchAdjustRowHeights(sheet, startRow, lastRow);
            }
        }
    }
    /**
     * 批量处理行高(在数据填充完成后统一计算)
     */
    /**
     * 批量处理行高(在数据填充完成后统一计算)
     */
    private String getCellStringValue(Cell cell) {
        if (cell == null) return null;
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return String.valueOf(cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return cell.getStringCellValue();
                } catch (Exception e) {
                    return String.valueOf(cell.getNumericCellValue());
                }
            default:
                return null;
        }
    }
    private void batchAdjustRowHeights(Sheet sheet, int startRow, int endRow) {
        Workbook workbook = sheet.getWorkbook();
        for (int rowNum = startRow; rowNum <= endRow; rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row == null) continue;
            int maxLinesInRow = 1; // 记录该行所有单元格中的最大行数
            // 第一步:遍历该行的所有单元格,找到最大行数需求
            for (int colNum = 0; colNum < row.getLastCellNum(); colNum++) {
                Cell cell = row.getCell(colNum);
                if (cell == null) continue;
                // 获取单元格内容
                String content = getCellStringValue(cell);
                if (content == null || content.isEmpty()) continue;
                // 获取列宽
                int columnWidth = sheet.getColumnWidth(colNum) / 256;
                if (columnWidth <= 0) columnWidth = 10; // 默认列宽
                // 计算该单元格内容需要的行数
                int contentLines = calculateContentLines(content, columnWidth);
                // 更新最大行数
                maxLinesInRow = Math.max(maxLinesInRow, contentLines);
            }
            // 第二步:根据最大行数设置行高(关键修复)
            if (maxLinesInRow > 1) {
                // 基础行高:一行文本的高度
                int baseHeightPerLine = 400; // 20点 = 400单位(建议值)
                // 计算总高度 = 行数 × 每行高度
                int newHeight = maxLinesInRow * baseHeightPerLine + 600;
                // 限制最小和最大高度
                int minHeight = 300;   // 15点
                int maxHeight = 10000; // 500点
                newHeight = Math.max(minHeight, Math.min(newHeight, maxHeight));
                // 设置行高
                row.setHeight((short) newHeight);
                // 可选:记录调整信息用于调试
                log.debug("Row {} adjusted: maxLines={}, height={}",
                        rowNum, maxLinesInRow, newHeight);
            }
        }
    }
    /**
     * 计算文本的有效字符宽度
     */
    private double calculateEffectiveWidth(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }
        double totalWidth = 0;
        for (char c : text.toCharArray()) {
            if (isChineseChar(c)) {
                // 中文字符:1.0宽度
                totalWidth += 2.0;
            } else if (Character.isDigit(c)) {
                // 数字:0.6宽度
                totalWidth += 0.6;
            } else if (Character.isUpperCase(c)) {
                // 大写字母:0.7宽度
                totalWidth += 0.7;
            } else if (Character.isLowerCase(c)) {
                // 小写字母:0.5宽度
                totalWidth += 0.5;
            } else if (c == '.' || c == ',') {
                // 点号、逗号:0.3宽度
                totalWidth += 0.3;
            } else if (c == '-' || c == '_') {
                // 连字符、下划线:0.35宽度
                totalWidth += 0.35;
            } else if (c == ' ') {
                // 空格:0.3宽度
                totalWidth += 0.3;
            } else if (c == '\t') {
                // 制表符:4.0宽度
                totalWidth += 4.0;
            } else {
                // 其他字符:默认0.6宽度
                totalWidth += 0.6;
            }
        }
        return totalWidth;
    }
    /**
     * 计算单元格内容所需行数(更精确的版本)
     */
    private int calculateContentLines(String content, int columnWidthChars) {
        if (content == null || content.isEmpty() || columnWidthChars <= 0) {
            return 1;
        }
        int totalLines = 0;
        String[] lines = content.split("\n");
        for (String line : lines) {
            if (line.trim().isEmpty()) {
                totalLines++; // 空行也算一行
                continue;
            }
            // 计算该行需要的字符宽度
            // 考虑中英文字符宽度差异
            double effectiveLength = 0;
            effectiveLength += calculateEffectiveWidth(line); // 中文字符占1个宽度
            // 计算需要的行数
            int linesForText = (int) Math.ceil(effectiveLength / columnWidthChars);
            totalLines += Math.max(1, linesForText);
        }
        return Math.max(totalLines, 1);
    }
    /**
     * 判断是否为中文字符
     */
    private boolean isChineseChar(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS;
    }
    /**
     * 创建表格样式
     *
@@ -551,17 +738,17 @@
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        // 设置自动换行
        style.setWrapText(true);
        Font dataFont = wb.createFont();
        dataFont.setFontName("Arial");
        dataFont.setFontName("宋体");
        dataFont.setFontHeightInPoints((short) 12);
        style.setFont(dataFont);
        styles.put("data", style);
@@ -600,7 +787,7 @@
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        Font totalFont = wb.createFont();
        totalFont.setFontName("Arial");
        totalFont.setFontName("宋体");
        totalFont.setFontHeightInPoints((short) 12);
        style.setFont(totalFont);
        // 总计行也设置自动换行
@@ -737,7 +924,14 @@
                } else if (align == HorizontalAlignment.RIGHT) {
                    styleKey = "data3";
                }
                cell.setCellStyle(styles.get(styleKey));
                System.out.println(styleKey);
                // 获取并修改样式
                CellStyle style = styles.get(styleKey);
                Workbook workbook = row.getSheet().getWorkbook();
                CellStyle newStyle = workbook.createCellStyle();
                newStyle.cloneStyleFrom(style);
                newStyle.setWrapText(true); // 关键:启用自动换行
                cell.setCellStyle(newStyle);
                // 用于读取对象中的属性
                Object value = getTargetValue(vo, field, attr);
@@ -754,6 +948,17 @@
                    // 设置列类型
                    setCellVo(value, attr, cell);
                }
                System.out.println(row.getHeight());
//             //   adjustRowHeightAfterSetValue(row, cell, value);
//                int defaultRowHeight = row.getHeight() / 20; // 原始行高(转成点数)
//                if(value==null)
//                    value="";
//                System.out.println(sheet.getColumnWidth(column));
//                int contentLines = getContentLines(value.toString(), sheet.getColumnWidth(column), style); // 计算换行后的行数
//                int newHeight = defaultRowHeight * contentLines; // 按行数调整行高(可加少量冗余)
//                row.setHeightInPoints((short) (newHeight)); // 提高行高(+2 是冗余,避免内容被截断)
                addStatisticsData(column, Convert.toStr(value), attr);
            }
        } catch (Exception e) {
@@ -1090,11 +1295,11 @@
            HSSFSheet hssfSheet = hssfWb.getSheetAt(index);
            HSSFHeader header = hssfSheet.getHeader();
            // 设置页眉字体
           // header.setFontName("宋体");
           // header.setFontName("宋体");4
           // header.setFontSize((short) 10);
            // 设置页眉内容
            hssfSheet.setMargin(Sheet.HeaderMargin, 2.1);
            header.setRight("共 &N 页   第 &P页");
            hssfSheet.setMargin(Sheet.HeaderMargin, 1.43);
            header.setRight("&\"宋体,Bold\"共 &N 页   第 &P 页");
        }
        // 如果是index为1的sheet,设置顶端标题行
        if (index == 1) {