refactor(pdfExport): 重构PDF导出Service以支持多语言和样式优化
- 替换原有翻译列表为翻译映射,避免重复查找,提升性能 - 统一使用Map<String, String>管理翻译文本,简化方法参数 - 增加多种字体和颜色定义,优化PDF中字体样式和文本颜色 - 改进字体加载方式,使用try-with-resources确保流关闭 - 采用HttpClient实例变量复用,提升图片下载效率和稳定性 - 重构PDF文档结构,拆分逻辑为多个私有方法,提高代码可读性 - 优化表格、段落格式及间距,提升PDF排版效果 - 修复空指针和空集合检查,保证运行时稳定性 - 增强单元格内容对齐和样式一致性 - 规范价格格式化,使用线程安全的DecimalFormat实例 - 替换旧版AtomicInteger计数为普通整数变量控制索引 - 调整方法调用链,确保PDF流正确关闭避免资源泄露
This commit is contained in:
parent
805f2474ba
commit
fa252a23d4
|
|
@ -44,7 +44,6 @@ import java.text.DecimalFormat;
|
|||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
|
|
@ -86,7 +85,18 @@ public class PdfExportService {
|
|||
|
||||
private final BaseFont bfChinese = getChineseFont();
|
||||
private final Font normalFont = new Font(bfChinese, 12);
|
||||
private final DecimalFormat df = new DecimalFormat("#,###.##");
|
||||
private final Font boldFont13 = new Font(bfChinese, 13, Font.BOLD);
|
||||
private final Font normalFont13 = new Font(bfChinese, 13, Font.NORMAL);
|
||||
private final Font boldFont15 = new Font(bfChinese, 15, Font.BOLD);
|
||||
private final Font titleFont = new Font(bfChinese, 28, Font.BOLD, new Color(0x3F, 0x3F, 0x3F));
|
||||
private final Color redColor = new Color(0xC0, 0x00, 0x00);
|
||||
private final Font redBoldFont20 = new Font(bfChinese, 20, Font.BOLD, redColor);
|
||||
private final Font redBoldFont15 = new Font(bfChinese, 15, Font.BOLD, redColor);
|
||||
private final ThreadLocal<DecimalFormat> decimalFormatLocal = ThreadLocal.withInitial(() -> new DecimalFormat("#,###.##"));
|
||||
private final HttpClient httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.followRedirects(HttpClient.Redirect.NORMAL)
|
||||
.build();
|
||||
private byte[] defaultPic;
|
||||
|
||||
@PostConstruct
|
||||
|
|
@ -103,19 +113,48 @@ public class PdfExportService {
|
|||
response.setHeader("Pragma", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
|
||||
List<WebComponentTranslateVO> translates = webComponentTranslateService.getListByCode("QuotationSystem", MultilingualUtil.getLanguage());
|
||||
List<WebComponentTranslateVO> translateList = webComponentTranslateService.getListByCode("QuotationSystem", MultilingualUtil.getLanguage());
|
||||
Map<String, String> translateMap = translateList.stream()
|
||||
.collect(Collectors.toMap(WebComponentTranslateVO::getComponentCode, WebComponentTranslateVO::getValue, (a, b) -> a));
|
||||
Document document = new Document(PageSize.A4);
|
||||
PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
|
||||
writer.setPageEvent(new HeaderFooterEvent("images/head.png"));
|
||||
document.open();
|
||||
try {
|
||||
document.open();
|
||||
//第一页
|
||||
addCoverPage(document, order, translateMap);
|
||||
document.add(Chunk.NEXTPAGE);
|
||||
//客户信息
|
||||
addCustomerInfoTable(document, order, translateMap);
|
||||
Paragraph spacer = new Paragraph();
|
||||
spacer.setSpacingBefore(40f);
|
||||
document.add(spacer);
|
||||
//报价清单
|
||||
addQuoteList(document, order, translateMap);
|
||||
//机型信息
|
||||
List<QuotationShoppingCartDTO> carts = quotationShoppingOrderService.getCarts(order.getId());
|
||||
addProductModelInfo(document, carts, order, translateMap);
|
||||
//备注
|
||||
document.add(new Paragraph(new Chunk(order.getRemark(), normalFont)));
|
||||
//付款方式
|
||||
Paragraph paymentParagraph = new Paragraph();
|
||||
paymentParagraph.add(new Chunk(getText(translateMap, "PaymentMethods") + ":", boldFont13));
|
||||
paymentParagraph.add(new Chunk(order.getPaymentMethod(), normalFont13));
|
||||
document.add(paymentParagraph);
|
||||
} finally {
|
||||
document.close();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void addCoverPage(Document document, QuotationShoppingOrder order, Map<String, String> translateMap) throws IOException {
|
||||
Rectangle pageSize = document.getPageSize();
|
||||
//第一页
|
||||
PdfPTable footerTable = new PdfPTable(1);
|
||||
footerTable.setTotalWidth(pageSize.getWidth() - document.leftMargin() - document.rightMargin());
|
||||
footerTable.setLockedWidth(true);
|
||||
|
||||
Chunk chunk1 = new Chunk(getText(translates, "title"), new Font(bfChinese, 28, Font.BOLD, new Color(0x3F, 0x3F, 0x3F)));
|
||||
chunk1.setUnderline(new Color(0xC0, 0x00, 0x00), 5f, 0f, -15f, 0f, PdfContentByte.LINE_CAP_BUTT);
|
||||
Chunk chunk1 = new Chunk(getText(translateMap, "title"), titleFont);
|
||||
chunk1.setUnderline(redColor, 5f, 0f, -15f, 0f, PdfContentByte.LINE_CAP_BUTT);
|
||||
PdfPCell cell1 = new PdfPCell(new Phrase(chunk1));
|
||||
cell1.setHorizontalAlignment(Element.ALIGN_RIGHT);
|
||||
cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
|
||||
|
|
@ -124,18 +163,16 @@ public class PdfExportService {
|
|||
cell1.setBorder(Rectangle.NO_BORDER);
|
||||
footerTable.addCell(cell1);
|
||||
|
||||
PdfPCell cell2 = new PdfPCell(new Phrase(getText(translates, "QuotationDate") + ":"
|
||||
+ DateTimeUtil.format(order.getCreateTime(), "yyyy-MM-dd"), new Font(bfChinese, 15, Font.BOLD)));
|
||||
PdfPCell cell2 = new PdfPCell(new Phrase(getText(translateMap, "QuotationDate") + ":"
|
||||
+ DateTimeUtil.format(order.getCreateTime(), "yyyy-MM-dd"), boldFont15));
|
||||
cell2.setHorizontalAlignment(Element.ALIGN_RIGHT);
|
||||
cell2.setPaddingTop(40);
|
||||
cell2.setBorder(Rectangle.NO_BORDER);
|
||||
footerTable.addCell(cell2);
|
||||
|
||||
Phrase phrase = new Phrase();
|
||||
Chunk chunk2 = new Chunk(getText(translates, "Validity") + ":", new Font(bfChinese, 15, Font.BOLD));
|
||||
phrase.add(chunk2);
|
||||
Chunk chunk3 = new Chunk(getText(translates, "Validity1"), new Font(bfChinese, 15, Font.BOLD, new Color(0xC0, 0x00, 0x00)));
|
||||
phrase.add(chunk3);
|
||||
phrase.add(new Chunk(getText(translateMap, "Validity") + ":", boldFont15));
|
||||
phrase.add(new Chunk(getText(translateMap, "Validity1"), redBoldFont15));
|
||||
PdfPCell cell3 = new PdfPCell(phrase);
|
||||
cell3.setHorizontalAlignment(Element.ALIGN_RIGHT);
|
||||
cell3.setPaddingTop(3);
|
||||
|
|
@ -143,39 +180,39 @@ public class PdfExportService {
|
|||
footerTable.addCell(cell3);
|
||||
|
||||
List<DictionaryItem> images = dictionaryItemService.getListByDictionaryCode("PDFCoverImage", MultilingualUtil.getLanguage());
|
||||
PdfPTable outerTable = new PdfPTable(images.size());
|
||||
outerTable.setWidthPercentage(100);
|
||||
List<Float> widths = new ArrayList<>();
|
||||
images.forEach(method -> {
|
||||
widths.add(1f);
|
||||
});
|
||||
outerTable.setWidths(Floats.toArray(widths));
|
||||
for (int i = 0; i < images.size(); i++) {
|
||||
PdfPCell cell = new PdfPCell();
|
||||
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
|
||||
cell.setVerticalAlignment(Element.ALIGN_TOP);
|
||||
if (i != 0) {
|
||||
cell.setPaddingLeft(5);
|
||||
if (CollectionUtil.isNotEmpty(images)) {
|
||||
PdfPTable outerTable = new PdfPTable(images.size());
|
||||
outerTable.setWidthPercentage(100);
|
||||
List<Float> widths = new ArrayList<>();
|
||||
images.forEach(method -> widths.add(1f));
|
||||
outerTable.setWidths(Floats.toArray(widths));
|
||||
for (int i = 0; i < images.size(); i++) {
|
||||
PdfPCell cell = new PdfPCell();
|
||||
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
|
||||
cell.setVerticalAlignment(Element.ALIGN_TOP);
|
||||
if (i != 0) {
|
||||
cell.setPaddingLeft(5);
|
||||
}
|
||||
cell.setBorder(Rectangle.NO_BORDER);
|
||||
cell.setBorderColor(Color.WHITE);
|
||||
cell.setBorderWidth(5f);
|
||||
Image image = Image.getInstance(downloadImage(images.get(i).getValue()));
|
||||
image.scaleToFit(125f, 1000f);
|
||||
image.setAlignment(Element.ALIGN_CENTER);
|
||||
Paragraph caption = new Paragraph(images.get(i).getName(), new Font(bfChinese, 12, Font.BOLD));
|
||||
caption.setAlignment(Element.ALIGN_CENTER);
|
||||
caption.setSpacingBefore(4f);
|
||||
cell.addElement(image);
|
||||
cell.addElement(caption);
|
||||
outerTable.addCell(cell);
|
||||
}
|
||||
cell.setBorder(Rectangle.NO_BORDER);
|
||||
cell.setBorderColor(Color.WHITE);
|
||||
cell.setBorderWidth(5f);
|
||||
Image image = Image.getInstance(downloadImage(images.get(i).getValue()));
|
||||
image.scaleToFit(125f, 1000f);
|
||||
image.setAlignment(Element.ALIGN_CENTER);
|
||||
Paragraph caption = new Paragraph(images.get(i).getName(), new Font(bfChinese, 12, Font.BOLD));
|
||||
caption.setAlignment(Element.ALIGN_CENTER);
|
||||
caption.setSpacingBefore(4f);
|
||||
cell.addElement(image);
|
||||
cell.addElement(caption);
|
||||
outerTable.addCell(cell);
|
||||
PdfPCell cell4 = new PdfPCell(outerTable);
|
||||
cell4.setPaddingTop(250);
|
||||
cell4.setBorder(Rectangle.NO_BORDER);
|
||||
footerTable.addCell(cell4);
|
||||
}
|
||||
PdfPCell cell4 = new PdfPCell(outerTable);
|
||||
cell4.setPaddingTop(250);
|
||||
cell4.setBorder(Rectangle.NO_BORDER);
|
||||
footerTable.addCell(cell4);
|
||||
|
||||
PdfPCell cell5 = new PdfPCell(new Phrase(new Chunk(getText(translates, "more"), new Font(bfChinese, 20, Font.BOLD, new Color(0xC0, 0x00, 0x00)))));
|
||||
PdfPCell cell5 = new PdfPCell(new Phrase(new Chunk(getText(translateMap, "more"), redBoldFont20)));
|
||||
cell5.setPaddingTop(80);
|
||||
cell5.setVerticalAlignment(Element.ALIGN_MIDDLE);
|
||||
cell5.setHorizontalAlignment(Element.ALIGN_CENTER);
|
||||
|
|
@ -183,160 +220,108 @@ public class PdfExportService {
|
|||
footerTable.addCell(cell5);
|
||||
|
||||
document.add(footerTable);
|
||||
document.add(Chunk.NEXTPAGE);
|
||||
//开始正文
|
||||
String userName, userPhone, userEmail;
|
||||
}
|
||||
|
||||
private void addCustomerInfoTable(Document document, QuotationShoppingOrder order, Map<String, String> translateMap) {
|
||||
String userName = "", userPhone = "", userEmail = "";
|
||||
if (order.getCreateByType() == 0) {
|
||||
AdminUser adminUser = adminUserService.getById(order.getCreateById());
|
||||
userName = adminUser.getUserName();
|
||||
userPhone = adminUser.getPhone();
|
||||
userEmail = adminUser.getEmail();
|
||||
if (Objects.nonNull(adminUser)) {
|
||||
userName = adminUser.getUserName();
|
||||
userPhone = adminUser.getPhone();
|
||||
userEmail = adminUser.getEmail();
|
||||
}
|
||||
} else {
|
||||
AppUser appUser = appUserService.getById(order.getCreateById());
|
||||
userName = appUser.getName();
|
||||
userPhone = appUser.getPhone();
|
||||
userEmail = appUser.getEmail();
|
||||
if (Objects.nonNull(appUser)) {
|
||||
userName = appUser.getName();
|
||||
userPhone = appUser.getPhone();
|
||||
userEmail = appUser.getEmail();
|
||||
}
|
||||
}
|
||||
Font labelFont = new Font(bfChinese, 12, Font.BOLD);
|
||||
Font valueFont = new Font(bfChinese, 12, Font.NORMAL);
|
||||
PdfPTable table = new PdfPTable(4);
|
||||
table.setWidthPercentage(100);
|
||||
table.setWidths(new float[]{1.5f, 2f, 1.5f, 3f});
|
||||
PdfPCell label1_1 = createLabelCell(getText(translates, "Customer") + ":", labelFont);
|
||||
table.addCell(label1_1);
|
||||
PdfPCell value1_1 = createValueCell(order.getCustomerName(), valueFont);
|
||||
table.addCell(value1_1);
|
||||
PdfPCell label1_2 = createLabelCell(getText(translates, "Supplier") + ":", labelFont);
|
||||
table.addCell(label1_2);
|
||||
PdfPCell value1_2 = createValueCell(getText(translates, "nflg"), valueFont);
|
||||
table.addCell(value1_2);
|
||||
PdfPCell label2_1 = createLabelCell(getText(translates, "ContactPerson") + ":", labelFont);
|
||||
table.addCell(label2_1);
|
||||
PdfPCell value2_1 = createValueCell(order.getContactPerson(), valueFont);
|
||||
table.addCell(value2_1);
|
||||
PdfPCell label2_2 = createLabelCell(getText(translates, "ContactPerson") + ":", labelFont);
|
||||
table.addCell(label2_2);
|
||||
PdfPCell value2_2 = createValueCell(userName, valueFont);
|
||||
table.addCell(value2_2);
|
||||
PdfPCell label3_1 = createLabelCell(getText(translates, "ContactInformation") + ":", labelFont);
|
||||
table.addCell(label3_1);
|
||||
PdfPCell value3_1 = createValueCell(order.getContactInformation(), valueFont);
|
||||
table.addCell(value3_1);
|
||||
PdfPCell label3_2 = createLabelCell(getText(translates, "ContactInformation") + ":", labelFont);
|
||||
table.addCell(label3_2);
|
||||
PdfPCell value3_2 = createValueCell(userPhone, valueFont);
|
||||
table.addCell(value3_2);
|
||||
PdfPCell label4_1 = createLabelCell(getText(translates, "Email") + ":", labelFont);
|
||||
table.addCell(label4_1);
|
||||
PdfPCell value4_1 = createValueCell(order.getContactEmail(), valueFont);
|
||||
table.addCell(value4_1);
|
||||
PdfPCell label4_2 = createLabelCell(getText(translates, "Email") + ":", labelFont);
|
||||
table.addCell(label4_2);
|
||||
PdfPCell value4_2 = createValueCell(userEmail, valueFont);
|
||||
table.addCell(value4_2);
|
||||
PdfPCell label5_1 = createLabelCell(getText(translates, "Country") + ":", labelFont);
|
||||
table.addCell(label5_1);
|
||||
PdfPCell value5_1 = createValueCell(order.getContactCountry(), valueFont);
|
||||
table.addCell(value5_1);
|
||||
PdfPCell label5_2 = createLabelCell(getText(translates, "QuotationNo") + ":", labelFont);
|
||||
table.addCell(label5_2);
|
||||
PdfPCell value5_2 = createValueCell(order.getNo(), valueFont);
|
||||
table.addCell(value5_2);
|
||||
table.addCell(createLabelCell(getText(translateMap, "Customer") + ":", labelFont));
|
||||
table.addCell(createValueCell(order.getCustomerName(), valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "Supplier") + ":", labelFont));
|
||||
table.addCell(createValueCell(getText(translateMap, "nflg"), valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "ContactPerson") + ":", labelFont));
|
||||
table.addCell(createValueCell(order.getContactPerson(), valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "ContactPerson") + ":", labelFont));
|
||||
table.addCell(createValueCell(userName, valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "ContactInformation") + ":", labelFont));
|
||||
table.addCell(createValueCell(order.getContactInformation(), valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "ContactInformation") + ":", labelFont));
|
||||
table.addCell(createValueCell(userPhone, valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "Email") + ":", labelFont));
|
||||
table.addCell(createValueCell(order.getContactEmail(), valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "Email") + ":", labelFont));
|
||||
table.addCell(createValueCell(userEmail, valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "Country") + ":", labelFont));
|
||||
table.addCell(createValueCell(order.getContactCountry(), valueFont));
|
||||
table.addCell(createLabelCell(getText(translateMap, "QuotationNo") + ":", labelFont));
|
||||
table.addCell(createValueCell(order.getNo(), valueFont));
|
||||
document.add(table);
|
||||
Paragraph spacer = new Paragraph();
|
||||
spacer.setSpacingBefore(40f);
|
||||
document.add(spacer);
|
||||
//报价清单
|
||||
PdfPTable tableBJQD = new PdfPTable(5);
|
||||
tableBJQD.setWidthPercentage(100);
|
||||
tableBJQD.setWidths(new float[]{10f, 40f, 20f, 15f, 15f});
|
||||
PdfPCell headBJQD = createBJQDCell(getText(translates, "QuoteList"), 5, normalFont);
|
||||
tableBJQD.addCell(headBJQD);
|
||||
PdfPCell cellBJQDH1 = createBJQDCell(getText(translates, "Index"), 1, normalFont);
|
||||
tableBJQD.addCell(cellBJQDH1);
|
||||
PdfPCell cellBJQDH2 = createBJQDCell(getText(translates, "DeviceName"), 1, normalFont);
|
||||
tableBJQD.addCell(cellBJQDH2);
|
||||
PdfPCell cellBJQDH3 = createBJQDCell(getText(translates, "DeviceModel"), 1, normalFont);
|
||||
tableBJQD.addCell(cellBJQDH3);
|
||||
PdfPCell cellBJQDH4 = createBJQDCell(getText(translates, "Quantity"), 1, normalFont);
|
||||
tableBJQD.addCell(cellBJQDH4);
|
||||
PdfPCell cellBJQDH5 = createBJQDCell(getText(translates, "Price"), 1, normalFont);
|
||||
tableBJQD.addCell(cellBJQDH5);
|
||||
List<QuotationShoppingCartDTO> carts = quotationShoppingOrderService.getCarts(order.getId());
|
||||
AtomicInteger i = new AtomicInteger(1);
|
||||
carts.forEach(cart -> {
|
||||
PdfPCell cellR1 = createBJQDCell(String.valueOf(i.getAndIncrement()), 1, normalFont);
|
||||
tableBJQD.addCell(cellR1);
|
||||
PdfPCell cellR2 = createBJQDCell(cart.getTypeName(), 1, normalFont);
|
||||
tableBJQD.addCell(cellR2);
|
||||
PdfPCell cellR3 = createBJQDCell(cart.getModelNo(), 1, normalFont);
|
||||
tableBJQD.addCell(cellR3);
|
||||
PdfPCell cellR4 = createBJQDCell("1", 1, normalFont);
|
||||
tableBJQD.addCell(cellR4);
|
||||
PdfPCell cellR5 = createBJQDCell(format(cart.getStandardFee()), 1, normalFont);
|
||||
tableBJQD.addCell(cellR5);
|
||||
});
|
||||
PdfPCell cellZBFF = createBJQDCell(getText(translates, "WarrantyService"), 4, normalFont);
|
||||
tableBJQD.addCell(cellZBFF);
|
||||
PdfPCell cellZBFF1 = createBJQDCell(format(
|
||||
carts.stream()
|
||||
.map(QuotationShoppingCartDTO::getWarrantyServiceFee)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
), 1, normalFont);
|
||||
tableBJQD.addCell(cellZBFF1);
|
||||
PdfPCell cellJJFF = createBJQDCell(getText(translates, "HandoverService"), 4, normalFont);
|
||||
tableBJQD.addCell(cellJJFF);
|
||||
PdfPCell cellJJFF1 = createBJQDCell(format(carts.stream()
|
||||
.map(QuotationShoppingCartDTO::getServiceFee)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
), 1, normalFont);
|
||||
tableBJQD.addCell(cellJJFF1);
|
||||
PdfPCell cellBJ = createBJQDCell(getText(translates, "Parts"), 4, normalFont);
|
||||
tableBJQD.addCell(cellBJ);
|
||||
PdfPCell cellBJ1 = createBJQDCell(format(carts.stream()
|
||||
.map(QuotationShoppingCartDTO::getAccessoryFee)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
), 1, normalFont);
|
||||
tableBJQD.addCell(cellBJ1);
|
||||
PdfPCell cellBZ = createBJQDCell(order.getAdditionalNotes(), 5, normalFont);
|
||||
cellBZ.setHorizontalAlignment(Element.ALIGN_LEFT);
|
||||
tableBJQD.addCell(cellBZ);
|
||||
document.add(tableBJQD);
|
||||
//机型信息
|
||||
addProductModelInfo(document, carts, order, translates);
|
||||
//备注
|
||||
document.add(new Paragraph(new Chunk(order.getRemark(), normalFont)));
|
||||
//付款方式
|
||||
Paragraph fkfs = new Paragraph();
|
||||
fkfs.add(new Chunk(getText(translates, "PaymentMethods") + ":", new Font(bfChinese, 13, Font.BOLD)));
|
||||
fkfs.add(new Chunk(order.getPaymentMethod(), new Font(bfChinese, 13, Font.NORMAL)));
|
||||
document.add(fkfs);
|
||||
|
||||
document.close();
|
||||
}
|
||||
|
||||
private String getText(List<WebComponentTranslateVO> translates, String code) {
|
||||
return translates.stream()
|
||||
.filter(translate -> StrUtil.equals(translate.getComponentCode(), code))
|
||||
.findFirst()
|
||||
.map(WebComponentTranslateVO::getValue)
|
||||
.orElse("");
|
||||
private void addQuoteList(Document document, QuotationShoppingOrder order, Map<String, String> translateMap) {
|
||||
PdfPTable quoteTable = new PdfPTable(5);
|
||||
quoteTable.setWidthPercentage(100);
|
||||
quoteTable.setWidths(new float[]{10f, 40f, 20f, 15f, 15f});
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "QuoteList"), 5, boldFont13));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "Index"), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "DeviceName"), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "DeviceModel"), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "Quantity"), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "Price"), 1, normalFont));
|
||||
List<QuotationShoppingCartDTO> carts = quotationShoppingOrderService.getCarts(order.getId());
|
||||
int index = 1;
|
||||
for (QuotationShoppingCartDTO cart : carts) {
|
||||
quoteTable.addCell(createBJQDCell(String.valueOf(index++), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(cart.getTypeName(), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(cart.getModelNo(), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell("1", 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(format(cart.getStandardFee()), 1, normalFont));
|
||||
}
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "WarrantyService"), 4, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(format(
|
||||
carts.stream().map(QuotationShoppingCartDTO::getWarrantyServiceFee)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "HandoverService"), 4, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(format(
|
||||
carts.stream().map(QuotationShoppingCartDTO::getServiceFee)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)), 1, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(getText(translateMap, "Parts"), 4, normalFont));
|
||||
quoteTable.addCell(createBJQDCell(format(
|
||||
carts.stream().map(QuotationShoppingCartDTO::getAccessoryFee)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)), 1, normalFont));
|
||||
PdfPCell notesCell = createBJQDCell(order.getAdditionalNotes(), 5, normalFont);
|
||||
notesCell.setHorizontalAlignment(Element.ALIGN_LEFT);
|
||||
quoteTable.addCell(notesCell);
|
||||
document.add(quoteTable);
|
||||
}
|
||||
|
||||
private String getText(Map<String, String> translateMap, String code) {
|
||||
return translateMap.getOrDefault(code, "");
|
||||
}
|
||||
|
||||
private void addRandomAccessories(Document document, List<QuotationShoppingCartAccessory> accessories
|
||||
, List<WebComponentTranslateVO> translates) {
|
||||
, Map<String, String> translateMap) {
|
||||
if (CollectionUtil.isNotEmpty(accessories)) {
|
||||
document.add(new Paragraph(new Chunk(getText(translates, "RandomAccessories"), new Font(bfChinese, 13, Font.BOLD))));
|
||||
document.add(new Paragraph(new Chunk(getText(translateMap, "RandomAccessories"), boldFont13)));
|
||||
PdfPTable table = new PdfPTable(5);
|
||||
table.setWidthPercentage(100);
|
||||
table.setSpacingBefore(10f);
|
||||
table.setWidths(new float[]{20f, 20f, 20f, 20f, 20f});
|
||||
//表头
|
||||
table.addCell(createBJQDCell(getText(translates, "MaterialNo"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "MaterialName"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "Num"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "Price"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "TotalPrice"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "MaterialNo"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "MaterialName"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Num"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Price"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "TotalPrice"), 1, normalFont));
|
||||
accessories.forEach(accessory -> {
|
||||
table.addCell(createBJQDCell(accessory.getMaterialNo(), 1, normalFont));
|
||||
table.addCell(createBJQDCell(accessory.getName(), 1, normalFont));
|
||||
|
|
@ -348,20 +333,20 @@ public class PdfExportService {
|
|||
}
|
||||
}
|
||||
|
||||
private void addJJFF(Document document, List<QuotationShoppingCartService> services, List<WebComponentTranslateVO> translates) {
|
||||
private void addJJFF(Document document, List<QuotationShoppingCartService> services, Map<String, String> translateMap) {
|
||||
if (CollectionUtil.isNotEmpty(services)) {
|
||||
document.add(new Paragraph(new Chunk(getText(translates, "HandoverService"), new Font(bfChinese, 13, Font.BOLD))));
|
||||
document.add(new Paragraph(new Chunk(getText(translateMap, "HandoverService"), boldFont13)));
|
||||
PdfPTable table = new PdfPTable(6);
|
||||
table.setWidthPercentage(100);
|
||||
table.setSpacingBefore(10f);
|
||||
table.setWidths(new float[]{15f, 15f, 15f, 15f, 20f, 20f});
|
||||
//表头
|
||||
table.addCell(createBJQDCell(getText(translates, "Numberofpeople"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "Days"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "Price"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "TotalPrice"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "Address"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translates, "Remark"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Numberofpeople"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Days"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Price"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "TotalPrice"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Address"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Remark"), 1, normalFont));
|
||||
for (QuotationShoppingCartService service : services) {
|
||||
table.addCell(createBJQDCell(String.valueOf(service.getUserNum()), 1, normalFont));
|
||||
table.addCell(createBJQDCell(String.valueOf(service.getDays()), 1, normalFont));
|
||||
|
|
@ -376,7 +361,10 @@ public class PdfExportService {
|
|||
|
||||
private void addPriceInfo(Document document, List<OrderDeliveryMethodDTO> deliveryMethods
|
||||
, List<ModelConfigEffectiveDTO> parts, QuotationShoppingOrder order, QuotationShoppingCartDTO cart
|
||||
, List<WebComponentTranslateVO> translates) {
|
||||
, Map<String, String> translateMap) {
|
||||
if (CollectionUtil.isEmpty(deliveryMethods)) {
|
||||
return;
|
||||
}
|
||||
PdfPTable table = new PdfPTable(deliveryMethods.size() + 1);
|
||||
table.setWidthPercentage(100);
|
||||
table.setKeepTogether(true);
|
||||
|
|
@ -384,9 +372,7 @@ public class PdfExportService {
|
|||
List<Float> widths = new ArrayList<>();
|
||||
widths.add(20f);
|
||||
Float width = 80f / deliveryMethods.size();
|
||||
deliveryMethods.forEach(method -> {
|
||||
widths.add(width);
|
||||
});
|
||||
deliveryMethods.forEach(method -> widths.add(width));
|
||||
table.setWidths(Floats.toArray(widths));
|
||||
//列头
|
||||
table.addCell(createBJQDCell("", 1, normalFont));
|
||||
|
|
@ -394,33 +380,34 @@ public class PdfExportService {
|
|||
table.addCell(createBJQDCell(method.getDeliveryMethodName() + " " + order.getContactCountry(), 1, normalFont))
|
||||
);
|
||||
DictionaryItem currency = dictionaryItemService.getById(order.getCurrency());
|
||||
String currencyValue = Objects.nonNull(currency) ? currency.getValue() : "";
|
||||
//标准配置
|
||||
table.addCell(createBJQDCell(getText(translates, "StandardConfiguration"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "StandardConfiguration"), 1, normalFont));
|
||||
BigDecimal totalPrice = cart.getStandardFee();
|
||||
deliveryMethods.forEach(method ->
|
||||
table.addCell(createBJQDCell(
|
||||
format(totalPrice.add(method.getDeliveryFee()).multiply(order.getExchangeRate())) + " " + currency.getValue()
|
||||
format(totalPrice.add(method.getDeliveryFee()).multiply(order.getExchangeRate())) + " " + currencyValue
|
||||
, 1
|
||||
, normalFont)
|
||||
)
|
||||
);
|
||||
//可选配置
|
||||
PdfPCell ckx = createBJQDCell(getText(translates, "OptionalConfiguration"), table.getNumberOfColumns(), normalFont);
|
||||
ckx.setHorizontalAlignment(Element.ALIGN_LEFT);
|
||||
ckx.setPaddingLeft(25);
|
||||
table.addCell(ckx);
|
||||
PdfPCell optionalCell = createBJQDCell(getText(translateMap, "OptionalConfiguration"), table.getNumberOfColumns(), normalFont);
|
||||
optionalCell.setHorizontalAlignment(Element.ALIGN_LEFT);
|
||||
optionalCell.setPaddingLeft(25);
|
||||
table.addCell(optionalCell);
|
||||
parts.forEach(part -> {
|
||||
table.addCell(createBJQDCell(part.getPartName(), 1, normalFont));
|
||||
deliveryMethods.forEach(method ->
|
||||
table.addCell(createBJQDCell(
|
||||
format(part.getAmount().add(method.getDeliveryFee()).multiply(order.getExchangeRate())) + " " + currency.getValue()
|
||||
format(part.getAmount().add(method.getDeliveryFee()).multiply(order.getExchangeRate())) + " " + currencyValue
|
||||
, 1
|
||||
, normalFont)
|
||||
)
|
||||
);
|
||||
});
|
||||
//合计
|
||||
table.addCell(createBJQDCell(getText(translates, "Total"), 1, normalFont));
|
||||
table.addCell(createBJQDCell(getText(translateMap, "Total"), 1, normalFont));
|
||||
deliveryMethods.forEach(method ->
|
||||
table.addCell(createBJQDCell(
|
||||
format(
|
||||
|
|
@ -431,7 +418,7 @@ public class PdfExportService {
|
|||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
)
|
||||
).add(method.getDeliveryFee()).multiply(order.getExchangeRate())
|
||||
) + " " + currency.getValue()
|
||||
) + " " + currencyValue
|
||||
, 1
|
||||
, normalFont)
|
||||
)
|
||||
|
|
@ -444,8 +431,9 @@ public class PdfExportService {
|
|||
}
|
||||
|
||||
private void addProductModelInfo(Document document, List<QuotationShoppingCartDTO> carts
|
||||
, QuotationShoppingOrder order, List<WebComponentTranslateVO> translates) throws IOException {
|
||||
, QuotationShoppingOrder order, Map<String, String> translateMap) throws IOException {
|
||||
document.add(Chunk.NEXTPAGE);
|
||||
List<OrderDeliveryMethodDTO> deliveryMethods = shoppingOrderDeliveryMethodService.getList(order.getId());
|
||||
for (QuotationShoppingCartDTO cart : carts) {
|
||||
document.add(new Paragraph(new Chunk(cart.getTypeName(), new Font(bfChinese, 18, Font.NORMAL))));
|
||||
document.add(new Paragraph(new Chunk(cart.getModelNo(), new Font(bfChinese, 14, Font.BOLD))));
|
||||
|
|
@ -453,7 +441,7 @@ public class PdfExportService {
|
|||
image.scaleToFit(getMaxContentWidth(document), 1000f);
|
||||
document.add(image);
|
||||
ProductModelIntroItem introItem = productModelIntroItemService.getByModelId(cart.getModelId(), MultilingualUtil.getLanguage());
|
||||
if (StrUtil.isNotBlank(introItem.getDesc())) {
|
||||
if (Objects.nonNull(introItem) && StrUtil.isNotBlank(introItem.getDesc())) {
|
||||
addHtmlContent(document, introItem.getDesc());
|
||||
}
|
||||
//部件
|
||||
|
|
@ -476,15 +464,15 @@ public class PdfExportService {
|
|||
);
|
||||
});
|
||||
//运输信息
|
||||
Paragraph yscc = new Paragraph();
|
||||
yscc.add(new Chunk(getText(translates, "ShippingDimensions") + ":", new Font(bfChinese, 13, Font.BOLD)));
|
||||
yscc.add(new Chunk(parts.stream()
|
||||
Paragraph shippingDimParagraph = new Paragraph();
|
||||
shippingDimParagraph.add(new Chunk(getText(translateMap, "ShippingDimensions") + ":", boldFont13));
|
||||
shippingDimParagraph.add(new Chunk(parts.stream()
|
||||
.max(Comparator.comparingLong(ModelConfigEffectiveDTO::getShippingDimensionsValue))
|
||||
.get()
|
||||
.getShippingDimensions()
|
||||
, new Font(bfChinese, 13, Font.NORMAL)));
|
||||
yscc.setSpacingBefore(40f);
|
||||
document.add(yscc);
|
||||
.map(ModelConfigEffectiveDTO::getShippingDimensions)
|
||||
.orElse("")
|
||||
, normalFont13));
|
||||
shippingDimParagraph.setSpacingBefore(40f);
|
||||
document.add(shippingDimParagraph);
|
||||
BigDecimal weight = BigDecimal.ZERO;
|
||||
for (ModelConfigEffectiveDTO part : parts) {
|
||||
if (Objects.nonNull(part.getWeight())) {
|
||||
|
|
@ -493,45 +481,47 @@ public class PdfExportService {
|
|||
}
|
||||
}
|
||||
}
|
||||
Paragraph zl = new Paragraph();
|
||||
zl.add(new Chunk(getText(translates, "Weight") + ":", new Font(bfChinese, 13, Font.BOLD)));
|
||||
zl.add(new Chunk(format(weight) + "kg", new Font(bfChinese, 13, Font.NORMAL)));
|
||||
document.add(zl);
|
||||
Paragraph weightParagraph = new Paragraph();
|
||||
weightParagraph.add(new Chunk(getText(translateMap, "Weight") + ":", boldFont13));
|
||||
weightParagraph.add(new Chunk(format(weight) + "kg", normalFont13));
|
||||
document.add(weightParagraph);
|
||||
//质保服务
|
||||
String zbfwText = cart.getWarrantyServiceDesc();
|
||||
boolean iss = false;
|
||||
String warrantyText = cart.getWarrantyServiceDesc();
|
||||
boolean hasDicWarranty = false;
|
||||
if (Objects.nonNull(cart.getWarrantyServiceDicId())) {
|
||||
DictionaryItem warrantyService = dictionaryItemService.getByIdAndLanguage(cart.getWarrantyServiceDicId(), MultilingualUtil.getLanguage());
|
||||
zbfwText = warrantyService.getName();
|
||||
iss = true;
|
||||
if (Objects.nonNull(warrantyService)) {
|
||||
warrantyText = warrantyService.getName();
|
||||
hasDicWarranty = true;
|
||||
}
|
||||
}
|
||||
Paragraph zbfw = new Paragraph();
|
||||
zbfw.add(new Chunk(getText(translates, "WarrantyService") + ":", new Font(bfChinese, 13, Font.BOLD)));
|
||||
if (iss) {
|
||||
zbfw.add(new Chunk(zbfwText, new Font(bfChinese, 13, Font.NORMAL)));
|
||||
Paragraph warrantyParagraph = new Paragraph();
|
||||
warrantyParagraph.add(new Chunk(getText(translateMap, "WarrantyService") + ":", boldFont13));
|
||||
if (hasDicWarranty) {
|
||||
warrantyParagraph.add(new Chunk(warrantyText, normalFont13));
|
||||
} else {
|
||||
zbfw.add(new Chunk(zbfwText + "," + format(cart.getWarrantyServiceFee()) + " CNY", new Font(bfChinese, 13, Font.NORMAL)));
|
||||
warrantyParagraph.add(new Chunk(warrantyText + "," + format(cart.getWarrantyServiceFee()) + " CNY", normalFont13));
|
||||
}
|
||||
document.add(zbfw);
|
||||
document.add(warrantyParagraph);
|
||||
//交机服务
|
||||
addJJFF(document, shoppingCartServiceService.lambdaQuery()
|
||||
.eq(QuotationShoppingCartService::getCartId, cart.getId())
|
||||
.list(), translates
|
||||
.list(), translateMap
|
||||
);
|
||||
//随机配件
|
||||
addRandomAccessories(document, shoppingCartAccessoryService.lambdaQuery()
|
||||
.eq(QuotationShoppingCartAccessory::getCartId, cart.getId())
|
||||
.list(), translates
|
||||
.list(), translateMap
|
||||
);
|
||||
//价格信息
|
||||
addPriceInfo(document
|
||||
, shoppingOrderDeliveryMethodService.getList(order.getId())
|
||||
, deliveryMethods
|
||||
, parts.stream()
|
||||
.filter(part -> part.getParentId() > 0 && part.getType() == 1 && Objects.equals(part.getOptionalType(), 0))
|
||||
.collect(Collectors.toList())
|
||||
, order
|
||||
, cart
|
||||
, translates);
|
||||
, translateMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -585,13 +575,6 @@ public class PdfExportService {
|
|||
return cell;
|
||||
}
|
||||
|
||||
private PdfPCell createPartTextCell(String name, String value, Font font) {
|
||||
PdfPCell cell = new PdfPCell(new Phrase(name + ":" + value, font));
|
||||
cell.setBorder(Rectangle.NO_BORDER);
|
||||
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
|
||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
|
||||
return cell;
|
||||
}
|
||||
|
||||
private void addHtmlContent(Document document, String html) throws IOException {
|
||||
StyleSheet styles = new StyleSheet();
|
||||
|
|
@ -654,25 +637,21 @@ public class PdfExportService {
|
|||
|
||||
private BaseFont getChineseFont() {
|
||||
try {
|
||||
// 1. 从 classpath 获取字体流
|
||||
String fontPath = "fonts/simhei.ttf"; // 对应 resources/fonts/simsun.ttf
|
||||
InputStream inputStream = QuotationApplication.class.getClassLoader().getResourceAsStream(fontPath);
|
||||
if (inputStream == null) {
|
||||
throw new RuntimeException("找不到字体文件: " + fontPath);
|
||||
String fontPath = "fonts/simhei.ttf";
|
||||
try (InputStream inputStream = QuotationApplication.class.getClassLoader().getResourceAsStream(fontPath)) {
|
||||
if (inputStream == null) {
|
||||
throw new RuntimeException("找不到字体文件: " + fontPath);
|
||||
}
|
||||
byte[] fontBytes = inputStream.readAllBytes();
|
||||
return BaseFont.createFont("simhei.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, fontBytes, null);
|
||||
}
|
||||
// 2. 将流转换为 byte 数组 (Java 9+ 写法)
|
||||
byte[] fontBytes = inputStream.readAllBytes();
|
||||
inputStream.close();
|
||||
// 3. 使用 byte 数组创建 BaseFont
|
||||
// 参数说明:字体名称(随便起), 编码, 嵌入PDF, 缓存, 字体字节流, PFB字节流(null)
|
||||
return BaseFont.createFont("simhei.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, fontBytes, null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("加载中文字体失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String format(BigDecimal price) {
|
||||
return df.format(price);
|
||||
return decimalFormatLocal.get().format(price);
|
||||
}
|
||||
|
||||
private byte[] downloadImage(String urlStr) {
|
||||
|
|
@ -680,17 +659,12 @@ public class PdfExportService {
|
|||
return defaultPic;
|
||||
}
|
||||
try {
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10)) // 连接超时 10秒
|
||||
.followRedirects(HttpClient.Redirect.NORMAL) // 自动处理重定向
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(urlStr))
|
||||
.timeout(Duration.ofSeconds(15)) // 读取超时 15秒
|
||||
// 某些图片服务器有防盗链,可以模拟浏览器 User-Agent
|
||||
.timeout(Duration.ofSeconds(15))
|
||||
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
|
||||
.build();
|
||||
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
if (response.statusCode() == 200) {
|
||||
return response.body();
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in New Issue