package cn.iocoder.yudao.module.crm.service.quotation; import cn.iocoder.yudao.module.crm.controller.admin.quotation.vo.CrmSaleQuotationRespVO; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.core.io.ClassPathResource; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigDecimal; import java.time.format.DateTimeFormatter; /** 使用客户提供的 Excel 模板生成单张销售报价单。 */ public final class CrmSaleQuotationExcelRenderer { private static final String TEMPLATE = "templates/quotation/sale-quotation.xlsx"; private static final String DEFAULT_COMPANY = "苏珩线缆南通有限公司"; private CrmSaleQuotationExcelRenderer() { } public static byte[] render(CrmSaleQuotationRespVO quotation, String companyName, String address, String contactName, String contactPhone) throws IOException { if (quotation == null || quotation.getItems() == null || quotation.getItems().isEmpty()) { throw new IllegalArgumentException("报价单不存在或没有产品明细,无法生成报价文件"); } String company = companyName == null || companyName.isBlank() ? DEFAULT_COMPANY : companyName; try (var input = new ClassPathResource(TEMPLATE).getInputStream(); var workbook = new XSSFWorkbook(input); var output = new ByteArrayOutputStream()) { var sheet = workbook.getSheetAt(0); int extraRows = quotation.getItems().size() - 1; if (extraRows > 0) { sheet.shiftRows(11, sheet.getLastRowNum(), extraRows, true, false); } var templateRow = sheet.getRow(10); for (int i = 0; i < quotation.getItems().size(); i++) { var row = i == 0 ? templateRow : sheet.createRow(10 + i); if (i > 0) { row.setHeight(templateRow.getHeight()); for (int col = 0; col < 8; col++) { row.createCell(col).setCellStyle(templateRow.getCell(col).getCellStyle()); } } var item = quotation.getItems().get(i); string(row.getCell(0), item.getItemName() == null || item.getItemName().isBlank() ? item.getItemCode() : item.getItemName()); string(row.getCell(1), item.getItemSpecification()); string(row.getCell(2), item.getItemUnitName()); number(row.getCell(3), item.getCount()); number(row.getCell(4), item.getQuotationPrice()); BigDecimal amount = item.getTotalPrice(); if (amount == null && item.getCount() != null && item.getQuotationPrice() != null) { amount = item.getCount().multiply(item.getQuotationPrice()); } number(row.getCell(5), amount); string(row.getCell(6), null); // 调价没有对应的系统字段 string(row.getCell(7), item.getRemark()); } string(sheet.getRow(0).getCell(0), company); string(sheet.getRow(2).getCell(0), "编号:" + text(quotation.getNo())); string(sheet.getRow(4).getCell(1), quotation.getCustomerName()); string(sheet.getRow(5).getCell(1), address); string(sheet.getRow(6).getCell(1), contactName); string(sheet.getRow(7).getCell(1), contactPhone); string(sheet.getRow(13 + extraRows).getCell(6), "报价单位:" + company); string(sheet.getRow(14 + extraRows).getCell(6), "联 系 人:" + text(quotation.getOwnerUserName())); string(sheet.getRow(15 + extraRows).getCell(6), "报价日期:" + (quotation.getQuotationTime() == null ? "" : quotation.getQuotationTime().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")))); workbook.setPrintArea(0, 0, 7, 0, 17 + extraRows); int picture = workbook.addPicture(CrmSaleQuotationDocumentRenderer.renderSeal(company), Workbook.PICTURE_TYPE_PNG); var anchor = workbook.getCreationHelper().createClientAnchor(); anchor.setCol1(3); anchor.setCol2(5); anchor.setRow1(13 + extraRows); anchor.setRow2(17 + extraRows); sheet.createDrawingPatriarch().createPicture(anchor, picture); workbook.write(output); return output.toByteArray(); } } private static void string(Cell cell, String value) { cell.setCellValue(text(value)); } private static void number(Cell cell, BigDecimal value) { if (value == null) { cell.setBlank(); } else { cell.setCellValue(value.doubleValue()); } } private static String text(String value) { return value == null ? "" : value; } }