|
|
|
@ -24,10 +24,14 @@ import jakarta.servlet.http.HttpServletResponse; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.apache.commons.lang.StringUtils; |
|
|
|
import org.apache.ibatis.session.SqlSession; |
|
|
|
import org.apache.poi.ooxml.POIXMLDocumentPart; |
|
|
|
import org.apache.poi.ss.usermodel.*; |
|
|
|
import org.apache.poi.ss.util.CellRangeAddress; |
|
|
|
import org.apache.poi.xssf.usermodel.*; |
|
|
|
import org.apache.shiro.SecurityUtils; |
|
|
|
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing; |
|
|
|
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTOneCellAnchor; |
|
|
|
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.core.io.ClassPathResource; |
|
|
|
import org.springframework.stereotype.Service; |
|
|
|
@ -49,6 +53,11 @@ import java.util.stream.Collectors; |
|
|
|
@Slf4j |
|
|
|
public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { |
|
|
|
|
|
|
|
/** |
|
|
|
* 公章通常位于模板较下方区域,这里按锚点起始行做筛选删除。 |
|
|
|
*/ |
|
|
|
private static final int SEAL_ANCHOR_MIN_ROW = 10; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private CoDelMapper coDelMapper; |
|
|
|
@Autowired |
|
|
|
@ -1946,6 +1955,7 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { |
|
|
|
|
|
|
|
if (onlyInvoicePackingPdf) { |
|
|
|
retainFirstSheets(excelWorkbook, 2); |
|
|
|
removeInvoicePackingSealPictures(excelWorkbook); |
|
|
|
} |
|
|
|
compactLoadingNoRowIfNeeded(excelWorkbook); |
|
|
|
// 将Excel转换为PDF |
|
|
|
@ -1984,6 +1994,62 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 仅导出发票/箱单PDF时,移除前两页下方区域的图片公章。 |
|
|
|
*/ |
|
|
|
private void removeInvoicePackingSealPictures(XSSFWorkbook workbook) { |
|
|
|
if (workbook == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
int targetSheetCount = Math.min(2, workbook.getNumberOfSheets()); |
|
|
|
for (int i = 0; i < targetSheetCount; i++) { |
|
|
|
XSSFSheet sheet = workbook.getSheetAt(i); |
|
|
|
if (sheet == null) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
removeSealPicturesFromSheet(sheet); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 删除sheet中锚点起始行大于阈值的图片(主要用于移除公章)。 |
|
|
|
*/ |
|
|
|
private void removeSealPicturesFromSheet(XSSFSheet sheet) { |
|
|
|
for (POIXMLDocumentPart relation : sheet.getRelations()) { |
|
|
|
if (!(relation instanceof XSSFDrawing)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
XSSFDrawing drawing = (XSSFDrawing) relation; |
|
|
|
CTDrawing ctDrawing = drawing.getCTDrawing(); |
|
|
|
removeSealPicturesFromTwoCellAnchors(ctDrawing); |
|
|
|
removeSealPicturesFromOneCellAnchors(ctDrawing); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void removeSealPicturesFromTwoCellAnchors(CTDrawing ctDrawing) { |
|
|
|
for (int i = ctDrawing.sizeOfTwoCellAnchorArray() - 1; i >= 0; i--) { |
|
|
|
CTTwoCellAnchor anchor = ctDrawing.getTwoCellAnchorArray(i); |
|
|
|
if (anchor != null |
|
|
|
&& anchor.isSetPic() |
|
|
|
&& anchor.getFrom() != null |
|
|
|
&& anchor.getFrom().getRow() > SEAL_ANCHOR_MIN_ROW) { |
|
|
|
ctDrawing.removeTwoCellAnchor(i); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void removeSealPicturesFromOneCellAnchors(CTDrawing ctDrawing) { |
|
|
|
for (int i = ctDrawing.sizeOfOneCellAnchorArray() - 1; i >= 0; i--) { |
|
|
|
CTOneCellAnchor anchor = ctDrawing.getOneCellAnchorArray(i); |
|
|
|
if (anchor != null |
|
|
|
&& anchor.isSetPic() |
|
|
|
&& anchor.getFrom() != null |
|
|
|
&& anchor.getFrom().getRow() > SEAL_ANCHOR_MIN_ROW) { |
|
|
|
ctDrawing.removeOneCellAnchor(i); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 将Excel工作簿转换为PDF字节数组 |
|
|
|
*/ |
|
|
|
|