Showing
6 changed files
with
127 additions
and
15 deletions
xingyun-sc/src/main/java/com/lframework/xingyun/sc/controller/order/PurchaseOrderInfoController.java
| ... | ... | @@ -419,7 +419,7 @@ public class PurchaseOrderInfoController extends DefaultBaseController { |
| 419 | 419 | |
| 420 | 420 | String latex = LatexFormulaExcelExporterUtil.convertToContractSpecLatexSingleLineFixed3(formulaComponentList); |
| 421 | 421 | if (StringUtils.isNotBlank(latex)) { |
| 422 | - LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 4, 1, 7); | |
| 422 | + LatexFormulaExcelExporterUtil.insertLatexImageToCellLeftAligned(workbook, sheet, latex, startRow, 4, 1, 7); | |
| 423 | 423 | } |
| 424 | 424 | |
| 425 | 425 | setCellValue(sheet, startRow, 11, currentOrderLine.getStatus()); |
| ... | ... | @@ -491,6 +491,7 @@ public class PurchaseOrderInfoController extends DefaultBaseController { |
| 491 | 491 | |
| 492 | 492 | if ("PDF".equals(exportType)) { |
| 493 | 493 | ExcelUtil.adjustVerticalTitleForPdf(workbook, sheet, "具体质量要求", true); |
| 494 | + ExcelUtil.adjustVerticalTitleForPdf(workbook, sheet, "备注", true); | |
| 494 | 495 | ExcelUtil.adjustVerticalTitleForPdf(workbook, sheet, "生产工艺", false); |
| 495 | 496 | ResponseUtil.setPDFResponseHead(response, data.getOrderNo() + "-" |
| 496 | 497 | + data.getOrderingUnitName() + "-" + data.getWorkshopName() + "-订货单打印.pdf"); | ... | ... |
| ... | ... | @@ -281,6 +281,7 @@ public class BusinessDataExportHandler implements ExportHandler { |
| 281 | 281 | String createTime = orderInfo.getCreateTime().format(dateTimeFormatter); |
| 282 | 282 | if ("PDF".equals(queryVo.getExportFileType())) { |
| 283 | 283 | ExcelUtil.adjustVerticalTitleForPdf(workbook, sheet, "具体质量要求", true); |
| 284 | + ExcelUtil.adjustVerticalTitleForPdf(workbook, sheet, "备注", true); | |
| 284 | 285 | ExcelUtil.adjustVerticalTitleForPdf(workbook, sheet, "生产工艺", false); |
| 285 | 286 | // 输出PDF |
| 286 | 287 | File tempExcel = File.createTempFile("purchase_order_" + orderInfo.getOrderNo(), ".xlsx"); | ... | ... |
| ... | ... | @@ -292,17 +292,6 @@ public class ExcelUtil { |
| 292 | 292 | |
| 293 | 293 | cell.setCellValue(buildVerticalText(text)); |
| 294 | 294 | |
| 295 | - CellStyle baseStyle = cell.getCellStyle(); | |
| 296 | - CellStyle pdfStyle = workbook.createCellStyle(); | |
| 297 | - if (baseStyle != null) { | |
| 298 | - pdfStyle.cloneStyleFrom(baseStyle); | |
| 299 | - } | |
| 300 | - pdfStyle.setAlignment(HorizontalAlignment.CENTER); | |
| 301 | - pdfStyle.setVerticalAlignment(VerticalAlignment.CENTER); | |
| 302 | - pdfStyle.setWrapText(true); | |
| 303 | - pdfStyle.setRotation((short) 0); | |
| 304 | - pdfStyle.setIndention((short) 0); | |
| 305 | - | |
| 306 | 295 | if (mergedCell) { |
| 307 | 296 | CellRangeAddress mergedRegion = findMergedRegion(sheet, cell.getRowIndex(), cell.getColumnIndex()); |
| 308 | 297 | if (mergedRegion != null) { |
| ... | ... | @@ -316,20 +305,36 @@ public class ExcelUtil { |
| 316 | 305 | if (currentCell == null) { |
| 317 | 306 | currentCell = currentRow.createCell(c); |
| 318 | 307 | } |
| 319 | - currentCell.setCellStyle(pdfStyle); | |
| 308 | + currentCell.setCellStyle(buildPdfVerticalTitleStyle(workbook, currentCell.getCellStyle())); | |
| 320 | 309 | } |
| 321 | 310 | } |
| 322 | 311 | } else { |
| 323 | - cell.setCellStyle(pdfStyle); | |
| 312 | + cell.setCellStyle(buildPdfVerticalTitleStyle(workbook, cell.getCellStyle())); | |
| 324 | 313 | } |
| 325 | 314 | } else { |
| 326 | - cell.setCellStyle(pdfStyle); | |
| 315 | + cell.setCellStyle(buildPdfVerticalTitleStyle(workbook, cell.getCellStyle())); | |
| 327 | 316 | } |
| 328 | 317 | return; |
| 329 | 318 | } |
| 330 | 319 | } |
| 331 | 320 | } |
| 332 | 321 | |
| 322 | + /** | |
| 323 | + * 构建 PDF 竖排标题样式,保留原单元格边框等样式,只覆盖对齐和换行属性。 | |
| 324 | + */ | |
| 325 | + private static CellStyle buildPdfVerticalTitleStyle(Workbook workbook, CellStyle baseStyle) { | |
| 326 | + CellStyle pdfStyle = workbook.createCellStyle(); | |
| 327 | + if (baseStyle != null) { | |
| 328 | + pdfStyle.cloneStyleFrom(baseStyle); | |
| 329 | + } | |
| 330 | + pdfStyle.setAlignment(HorizontalAlignment.CENTER); | |
| 331 | + pdfStyle.setVerticalAlignment(VerticalAlignment.CENTER); | |
| 332 | + pdfStyle.setWrapText(true); | |
| 333 | + pdfStyle.setRotation((short) 0); | |
| 334 | + pdfStyle.setIndention((short) 0); | |
| 335 | + return pdfStyle; | |
| 336 | + } | |
| 337 | + | |
| 333 | 338 | private static String buildVerticalText(String text) { |
| 334 | 339 | StringBuilder builder = new StringBuilder(); |
| 335 | 340 | for (int i = 0; i < text.length(); i++) { | ... | ... |
| ... | ... | @@ -319,6 +319,14 @@ public class LatexFormulaExcelExporterUtil { |
| 319 | 319 | } |
| 320 | 320 | |
| 321 | 321 | /** |
| 322 | + * 将 LaTeX 公式作为图片左对齐插入到指定单元格区域内,并确保图片不会超出区域边界。 | |
| 323 | + */ | |
| 324 | + public static void insertLatexImageToCellLeftAligned(Workbook workbook, Sheet sheet, String latex, | |
| 325 | + int rowIndex, int colIndex, int rowRange, int colRange) throws IOException { | |
| 326 | + insertLatexImageToRegionLeftAligned(workbook, sheet, latex, rowIndex, colIndex, rowRange, colRange, 16, null); | |
| 327 | + } | |
| 328 | + | |
| 329 | + /** | |
| 322 | 330 | * 合同规格专用:按照模板单元格区域高度优先铺满,并根据区域大小动态选择更合适的渲染字号。 |
| 323 | 331 | */ |
| 324 | 332 | public static void insertContractLatexImageToCellFillTemplate(Workbook workbook, Sheet sheet, String latex, |
| ... | ... | @@ -562,6 +570,103 @@ public class LatexFormulaExcelExporterUtil { |
| 562 | 570 | drawing.createPicture(anchor, pictureIdx); |
| 563 | 571 | } |
| 564 | 572 | |
| 573 | + /** | |
| 574 | + * 将 LaTeX 公式作为图片左对齐插入到指定区域,并保留左右留白避免压线。 | |
| 575 | + */ | |
| 576 | + private static void insertLatexImageToRegionLeftAligned(Workbook workbook, Sheet sheet, String latex, | |
| 577 | + int rowIndex, int colIndex, int rowRange, int colRange, | |
| 578 | + int fontSize, Double maxScale) throws IOException { | |
| 579 | + byte[] imageBytes = latexToImageBytes(latex, fontSize); | |
| 580 | + BufferedImage image; | |
| 581 | + try (ByteArrayInputStream in = new ByteArrayInputStream(imageBytes)) { | |
| 582 | + image = ImageIO.read(in); | |
| 583 | + } | |
| 584 | + | |
| 585 | + if (image == null) { | |
| 586 | + return; | |
| 587 | + } | |
| 588 | + | |
| 589 | + int regionWidthPx = 0; | |
| 590 | + for (int c = colIndex; c < colIndex + colRange; c++) { | |
| 591 | + regionWidthPx += getColumnWidthPx(sheet, c); | |
| 592 | + } | |
| 593 | + int regionHeightPx = 0; | |
| 594 | + for (int r = rowIndex; r < rowIndex + rowRange; r++) { | |
| 595 | + regionHeightPx += getRowHeightPx(sheet, r); | |
| 596 | + } | |
| 597 | + | |
| 598 | + int paddingXPx = 6; | |
| 599 | + int paddingYPx = 2; | |
| 600 | + double scale = Math.min( | |
| 601 | + (double) (regionWidthPx - paddingXPx * 2) / Math.max(1, image.getWidth()), | |
| 602 | + (double) (regionHeightPx - paddingYPx * 2) / Math.max(1, image.getHeight()) | |
| 603 | + ); | |
| 604 | + scale = Math.min(scale, 1.0); | |
| 605 | + if (maxScale != null) { | |
| 606 | + scale = Math.min(scale, maxScale); | |
| 607 | + } | |
| 608 | + | |
| 609 | + int scaledWidthPx = Math.max(1, (int) Math.round(image.getWidth() * scale)); | |
| 610 | + int scaledHeightPx = Math.max(1, (int) Math.round(image.getHeight() * scale)); | |
| 611 | + | |
| 612 | + int offsetXPx = paddingXPx; | |
| 613 | + int offsetYPx = Math.max(paddingYPx, (regionHeightPx - scaledHeightPx) / 2); | |
| 614 | + | |
| 615 | + int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG); | |
| 616 | + Drawing<?> drawing = sheet.createDrawingPatriarch(); | |
| 617 | + | |
| 618 | + ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor(); | |
| 619 | + anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE); | |
| 620 | + | |
| 621 | + AnchorCoord x1 = resolveAnchorX(sheet, colIndex, colRange, offsetXPx); | |
| 622 | + AnchorCoord x2 = resolveAnchorX(sheet, colIndex, colRange, offsetXPx + scaledWidthPx); | |
| 623 | + AnchorCoord y1 = resolveAnchorY(sheet, rowIndex, rowRange, offsetYPx); | |
| 624 | + AnchorCoord y2 = resolveAnchorY(sheet, rowIndex, rowRange, offsetYPx + scaledHeightPx); | |
| 625 | + | |
| 626 | + anchor.setCol1(x1.index); | |
| 627 | + anchor.setCol2(x2.index); | |
| 628 | + anchor.setRow1(y1.index); | |
| 629 | + anchor.setRow2(y2.index); | |
| 630 | + | |
| 631 | + if (anchor instanceof org.apache.poi.hssf.usermodel.HSSFClientAnchor) { | |
| 632 | + int dx1 = pxToHssfDx(sheet, x1.index, x1.offsetPx); | |
| 633 | + int dx2 = pxToHssfDx(sheet, x2.index, x2.offsetPx); | |
| 634 | + int dy1 = pxToHssfDy(sheet, y1.index, y1.offsetPx); | |
| 635 | + int dy2 = pxToHssfDy(sheet, y2.index, y2.offsetPx); | |
| 636 | + | |
| 637 | + if (x2.index == x1.index && dx2 <= dx1) { | |
| 638 | + dx2 = Math.min(1023, dx1 + 1); | |
| 639 | + } | |
| 640 | + if (y2.index == y1.index && dy2 <= dy1) { | |
| 641 | + dy2 = Math.min(255, dy1 + 1); | |
| 642 | + } | |
| 643 | + | |
| 644 | + anchor.setDx1(dx1); | |
| 645 | + anchor.setDx2(dx2); | |
| 646 | + anchor.setDy1(dy1); | |
| 647 | + anchor.setDy2(dy2); | |
| 648 | + } else { | |
| 649 | + int dx1 = x1.offsetPx * EMU_PER_PX; | |
| 650 | + int dx2 = x2.offsetPx * EMU_PER_PX; | |
| 651 | + int dy1 = y1.offsetPx * EMU_PER_PX; | |
| 652 | + int dy2 = y2.offsetPx * EMU_PER_PX; | |
| 653 | + | |
| 654 | + if (x2.index == x1.index && dx2 <= dx1) { | |
| 655 | + dx2 = dx1 + 1; | |
| 656 | + } | |
| 657 | + if (y2.index == y1.index && dy2 <= dy1) { | |
| 658 | + dy2 = dy1 + 1; | |
| 659 | + } | |
| 660 | + | |
| 661 | + anchor.setDx1(dx1); | |
| 662 | + anchor.setDx2(dx2); | |
| 663 | + anchor.setDy1(dy1); | |
| 664 | + anchor.setDy2(dy2); | |
| 665 | + } | |
| 666 | + | |
| 667 | + drawing.createPicture(anchor, pictureIdx); | |
| 668 | + } | |
| 669 | + | |
| 565 | 670 | private static void insertContractLatexImageToRegionFillTemplate(Workbook workbook, Sheet sheet, String latex, |
| 566 | 671 | int rowIndex, int colIndex, int rowRange, int colRange, |
| 567 | 672 | int baseFontSize, Double maxScale) throws IOException { | ... | ... |
No preview for this file type
No preview for this file type