Commit 506522ed by jianan

新单跟进72

parent cd9ce964
......@@ -12,19 +12,18 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.common.enums.CommonEnum;
import com.yd.common.exception.BusinessException;
import com.yd.common.result.Result;
import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.dto.CommissionExcelDTO;
import com.yd.csf.api.dto.PolicyExcelDTO;
import com.yd.csf.api.dto.PolicyFollowDTO;
import com.yd.csf.api.listener.PolicyDataListener;
import com.yd.csf.api.service.ApiExpectedFortuneService;
import com.yd.csf.service.common.ErrorCode;
import com.yd.csf.service.dto.*;
import com.yd.csf.service.enums.PolicyFollowStatusEnum;
import com.yd.csf.service.model.*;
import com.yd.csf.service.service.*;
import com.yd.csf.service.utils.AsyncQueryUtil;
import com.yd.csf.service.vo.PolicyFollowDetailVO;
import com.yd.csf.service.vo.PolicyFollowRecordVO;
import com.yd.csf.service.vo.PolicyFollowVO;
......@@ -35,13 +34,15 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;
......@@ -82,6 +83,10 @@ public class ApiPolicyFollowController {
private PolicyFollowFileService policyFollowFileService;
@Resource
private PolicyReportPdfService policyReportPdfService;
@PostMapping("/upload/excel")
@Transactional(rollbackFor = Exception.class)
public Result<Boolean> uploadExcel(@RequestParam("file") MultipartFile file) throws Exception {
......@@ -549,4 +554,89 @@ public class ApiPolicyFollowController {
List<PolicyFollowRecord> policyFollowStatusList = policyFollowRecordService.list(queryWrapper);
return Result.success(policyFollowRecordService.getVOList(policyFollowStatusList));
}
/**
* 生成签约单
*/
@GetMapping(value = "/report/download", produces = "application/pdf")
@Operation(summary = "生成签约单")
public void previewPolicyReport(@RequestParam("policyBizId") String policyBizId,
HttpServletResponse response) {
PolicyFollow policyFollow = policyFollowService.getByPolicyBizId(policyBizId);
if (policyFollow == null) {
throw new BusinessException(ErrorCode.NOT_FOUND_ERROR.getCode(), ErrorCode.NOT_FOUND_ERROR.getMessage());
}
PolicyReportData reportData = new PolicyReportData();
// 填充数据
// reportData.setStartTime("2025-10-30");
// reportData.setEndTime("2025-10-30");
// reportData.setLocation("香港");
// reportData.setServiceManager("Vickie");
// reportData.setPolicyHolder(policyFollow.getPolicyHolder());
// reportData.setPolicyNumber(policyFollow.getPolicyNo());
// reportData.setInsuranceCompany(policyFollow.getInsurer());
// reportData.setInsuredPerson(policyFollow.getInsured());
// reportData.setInsurancePlan(policyFollow.getProductName());
// reportData.setInsuredAge(0);
// reportData.setCurrency(policyFollow.getCurrency());
// reportData.setPaymentPeriod((Integer) policyFollow.getPaymentTerm());
// reportData.setAnnualAmount(policyFollow.getPaymentPremium());
// reportData.setTotalPrepayment(BigDecimal.ZERO);
// reportData.setPremiumFee(BigDecimal.ZERO);
reportData.setStartTime("2025-10-30");
reportData.setEndTime("2025-10-30");
reportData.setLocation("香港");
reportData.setServiceManager("Vickie");
reportData.setPolicyHolder("policyHolder");
reportData.setPolicyNumber("B635379588");
reportData.setInsuranceCompany("友邦保险");
reportData.setInsuredPerson("insuredPerson");
reportData.setInsurancePlan("环宇盈活储蓄保险计划");
reportData.setInsuredAge(1);
reportData.setCurrency("HKD");
reportData.setPaymentPeriod(5);
reportData.setAnnualAmount(BigDecimal.valueOf(30000.08));
reportData.setTotalPrepayment(BigDecimal.valueOf(150064.70));
reportData.setPremiumFee(BigDecimal.valueOf(12.86));
try {
log.info("收到PDF生成请求: {}", reportData);
log.info("PolicyReportData 内容检查:");
log.info("startTime: {}", reportData.getStartTime());
log.info("endTime: {}", reportData.getEndTime());
log.info("location: {}", reportData.getLocation());
log.info("serviceManager: {}", reportData.getServiceManager());
byte[] pdfBytes = policyReportPdfService.generatePolicyReport(reportData);
if (pdfBytes == null || pdfBytes.length == 0) {
log.error("生成的PDF为空");
throw new BusinessException("生成的PDF内容为空");
}
log.info("PDF生成成功,大小: {} bytes", pdfBytes.length);
// 设置下载响应头
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=policy-report-" +
reportData.getPolicyNumber() + ".pdf");
response.setContentLength(pdfBytes.length);
// 写入响应流
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(pdfBytes);
outputStream.flush();
log.info("PDF响应发送完成");
} catch (Exception e) {
log.error("PDF预览失败", e);
throw new BusinessException("PDF预览失败: " + e.getMessage());
}
}
}
\ No newline at end of file
......@@ -12,6 +12,20 @@
<artifactId>yd-csf-service</artifactId>
<dependencies>
<!-- 公共工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- itextpdf -->
<dependency>
<groupId>com.github.librepdf</groupId>
<artifactId>openpdf</artifactId>
<version>1.3.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
......@@ -104,5 +118,10 @@
<artifactId>yd-feign</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 添加AOP依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
</project>
package com.yd.csf.service.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class PolicyReportData {
// 基本信息
private String startTime;
private String endTime;
private String location;
private String serviceManager;
// 保单详细信息
private String policyHolder;
private String policyNumber;
private String insuranceCompany;
private String insuredPerson;
private String insurancePlan;
private Integer insuredAge;
private String currency;
private Integer paymentPeriod;
private BigDecimal annualAmount;
private BigDecimal totalPrepayment;
private BigDecimal premiumFee;
// 附加险信息
private List<AdditionalInsurance> additionalInsurances;
@Data
public static class AdditionalInsurance {
private String name;
private String paymentTerm;
private String currency;
private BigDecimal firstYearAmount;
}
}
package com.yd.csf.service.service;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.yd.common.exception.BusinessException;
import com.yd.csf.service.dto.PolicyReportData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
@Service
@Slf4j
public class PolicyReportPdfService {
private Font chineseFont;
private Font chineseBoldFont;
private Font chineseTitleFont;
private Font chineseRedTitleFont;
// 颜色定义
private static final Color RED_TITLE_COLOR = new Color(255, 0, 0);
private static final Color TEXT_COLOR = new Color(102, 102, 102);
private static final Color FOOTNOTE_COLOR = new Color(153, 153, 153);
private static final Color LINE_COLOR = new Color(226, 226, 226);
// 调整字号常量
private static final float MAIN_TITLE_FONT_SIZE = 28f; // 增大主标题字号
private static final float SECTION_TITLE_FONT_SIZE = 16f; // 调整章节标题字号
private static final float CONTENT_FONT_SIZE = 12f; // 调整内容文字字号
private static final float FOOTNOTE_FONT_SIZE = 10f; // 调整备注文字字号
// 调整间距常量
private static final float MAIN_TITLE_MARGIN_BOTTOM = 20f; // 增大主标题下方间距
private static final float LINE_MARGIN_BOTTOM = 18f; // 调整水平线间距
private static final float ROW_SPACING = 12f; // 调整行间距
public byte[] generatePolicyReport(PolicyReportData reportData) throws DocumentException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
Document document = new Document(PageSize.A4, 40, 40, 40, 40);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
initChineseFont();
// 1. 主标题
addMainTitle(document, "簽單完成報告");
// 2. 主标题下方水平线
addHorizontalLine(document, writer);
// 3. 基本信息表格
addBasicInfo(document, reportData);
// 4. 保单详细信息标题
addPolicyDetailTitle(document, reportData);
// 5. 保单详细信息标题下方水平线
addHorizontalLine(document, writer);
// 6. 保单详细字段表格(包含备注和保費徵費)
addPolicyDetailFields(document, reportData);
// 7. 附加险表头
addAdditionalInsuranceHeader(document);
// 8. 详细信息下方水平线
addHorizontalLine(document, writer);
// 移除了原来的备注说明,因为现在备注已经整合到保单详细字段中
document.close();
return outputStream.toByteArray();
} catch (Exception e) {
log.error("PDF生成失败", e);
throw new BusinessException("生成报告失败: " + e.getMessage());
}
}
/**
* 主标题 - 放大并居中
*/
private void addMainTitle(Document document, String title) throws DocumentException {
// 创建更大的红色标题字体
Font largeTitleFont = new Font(chineseRedTitleFont.getBaseFont(), MAIN_TITLE_FONT_SIZE, Font.BOLD, RED_TITLE_COLOR);
Paragraph titleParagraph = new Paragraph(title, largeTitleFont);
titleParagraph.setAlignment(Paragraph.ALIGN_CENTER); // 设置为居中
titleParagraph.setSpacingAfter(MAIN_TITLE_MARGIN_BOTTOM);
document.add(titleParagraph);
}
/**
* 水平线 - 调整位置
*/
private void addHorizontalLine(Document document, PdfWriter writer) throws DocumentException {
// 绘制直线
PdfContentByte canvas = writer.getDirectContent();
canvas.saveState();
canvas.setColorStroke(LINE_COLOR);
canvas.setLineWidth(1f);
float y = writer.getVerticalPosition(false) - 5f;
canvas.moveTo(40, y);
canvas.lineTo(PageSize.A4.getWidth() - 40, y);
canvas.stroke();
canvas.restoreState();
// 添加额外间距
Paragraph extraSpacing = new Paragraph(" ");
extraSpacing.setSpacingAfter(8f);
document.add(extraSpacing);
}
/**
* 保单详细信息标题 - 调整字体大小
*/
private void addPolicyDetailTitle(Document document, PolicyReportData data) throws DocumentException {
PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(100);
table.setWidths(new float[]{25, 25, 25, 25});
table.setSpacingBefore(0f);
table.setSpacingAfter(ROW_SPACING);
// 使用更大的字体和红色
Font sectionTitleFont = new Font(chineseRedTitleFont.getBaseFont(), SECTION_TITLE_FONT_SIZE, Font.BOLD, RED_TITLE_COLOR);
Paragraph titlePara = new Paragraph("保單詳細信息", sectionTitleFont);
com.lowagie.text.pdf.PdfPCell titleCell = new com.lowagie.text.pdf.PdfPCell(titlePara);
titleCell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
titleCell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_LEFT);
// 第二列:空
com.lowagie.text.pdf.PdfPCell emptyCell1 = new com.lowagie.text.pdf.PdfPCell(new Paragraph(" "));
emptyCell1.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
// 第三列:保單編號标签
Paragraph numberLabelPara = new Paragraph("保單編號", chineseFont);
com.lowagie.text.pdf.PdfPCell numberLabelCell = new com.lowagie.text.pdf.PdfPCell(numberLabelPara);
numberLabelCell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
numberLabelCell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_LEFT);
// 第四列:保单编号值
Paragraph numberValuePara = new Paragraph(data.getPolicyNumber() != null ? data.getPolicyNumber() : "", chineseFont);
com.lowagie.text.pdf.PdfPCell numberValueCell = new com.lowagie.text.pdf.PdfPCell(numberValuePara);
numberValueCell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
numberValueCell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_LEFT);
table.addCell(titleCell);
table.addCell(emptyCell1);
table.addCell(numberLabelCell);
table.addCell(numberValueCell);
document.add(table);
}
/**
* 保单详细字段 - 修正保費徵費位置
*/
private void addPolicyDetailFields(Document document, PolicyReportData data) throws DocumentException {
PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(100);
table.setWidths(new float[]{20, 30, 20, 30});
table.setSpacingBefore(0f);
table.setSpacingAfter(ROW_SPACING);
// 第一行:保單持有人 | 持有人值 | 保險公司 | 公司值
addTableHeaderCellNoBorder(table, "保單持有人");
addTableCellNoBorder(table, data.getPolicyHolder() != null ? data.getPolicyHolder() : "");
addTableHeaderCellNoBorder(table, "保險公司");
addTableCellNoBorder(table, data.getInsuranceCompany() != null ? data.getInsuranceCompany() : "");
// 第二行:保單受保人 | 受保人值 | 受保人年齡 | 年齡值
addTableHeaderCellNoBorder(table, "保單受保人");
addTableCellNoBorder(table, data.getInsuredPerson() != null ? data.getInsuredPerson() : "");
addTableHeaderCellNoBorder(table, "受保人年齡");
addTableCellNoBorder(table, data.getInsuredAge() != null ? String.valueOf(data.getInsuredAge()) : "");
// 第三行:保險計劃 | 計劃值 | 繳費年期 | 年期值
addTableHeaderCellNoBorder(table, "保險計劃");
addTableCellNoBorder(table, data.getInsurancePlan() != null ? data.getInsurancePlan() : "");
addTableHeaderCellNoBorder(table, "繳費年期");
addTableCellNoBorder(table, data.getPaymentPeriod() != null ? String.valueOf(data.getPaymentPeriod()) : "");
// 第四行:保單貨幣 | 貨幣值 | 备注 | 备注(跨列)
addTableHeaderCellNoBorder(table, "保單貨幣");
addTableCellNoBorder(table, data.getCurrency() != null ? data.getCurrency() : "");
// 备注单元格 - 跨第3、4列,与保單貨幣同一行
Font footnoteFont = new Font(chineseFont.getBaseFont(), FOOTNOTE_FONT_SIZE, Font.NORMAL, FOOTNOTE_COLOR);
Paragraph footnotePara = new Paragraph(
"*此徵費為香港政府收取,續期時亦須繳納,但不納入本報告金額統計。澳門保單毋需繳納此費用。",
footnoteFont
);
com.lowagie.text.pdf.PdfPCell footnoteCell = new com.lowagie.text.pdf.PdfPCell(footnotePara);
footnoteCell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
footnoteCell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_LEFT);
footnoteCell.setVerticalAlignment(com.lowagie.text.Element.ALIGN_TOP);
footnoteCell.setColspan(2); // 跨2列
footnoteCell.setPadding(2f);
table.addCell(footnoteCell);
// 第五行:年繳金額 | 金額值 | 保費徵費 | 費用值
addTableHeaderCellNoBorder(table, "年繳金額");
addTableCellNoBorder(table, formatAmount(data.getAnnualAmount()));
addTableHeaderCellNoBorder(table, "保費徵費");
addTableCellNoBorder(table, formatAmount(data.getPremiumFee()));
// 第六行:合預繳息金額 | 金額值 | (空) | (空)
addTableHeaderCellNoBorder(table, "合預繳息金額");
addTableCellNoBorder(table, formatAmount(data.getTotalPrepayment()));
addTableCellNoBorder(table, "");
addTableCellNoBorder(table, "");
document.add(table);
}
/**
* 添加无边框的表头单元格
*/
private void addTableHeaderCellNoBorder(PdfPTable table, String text) {
Paragraph para = new Paragraph(text, chineseFont);
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell(para);
cell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
cell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_LEFT);
cell.setVerticalAlignment(com.lowagie.text.Element.ALIGN_MIDDLE);
cell.setPadding(2f);
table.addCell(cell);
}
/**
* 添加无边框的内容单元格
*/
private void addTableCellNoBorder(PdfPTable table, String text) {
Paragraph para = new Paragraph(text, chineseFont);
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell(para);
cell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
cell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_LEFT);
cell.setVerticalAlignment(com.lowagie.text.Element.ALIGN_MIDDLE);
cell.setPadding(2f);
table.addCell(cell);
}
/**
* 基本信息 - 调整行间距
*/
private void addBasicInfo(Document document, PolicyReportData data) throws DocumentException {
PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(100);
table.setWidths(new float[]{20, 30, 20, 30}); // 调整列宽比例
table.setSpacingBefore(0f);
table.setSpacingAfter(ROW_SPACING);
// 第一行
addTableHeaderCellNoBorder(table, "開始時間");
addTableCellNoBorder(table, data.getStartTime() != null ? data.getStartTime() : "");
addTableHeaderCellNoBorder(table, "結束時間");
addTableCellNoBorder(table, data.getEndTime() != null ? data.getEndTime() : "");
// 第二行
addTableHeaderCellNoBorder(table, "簽單地點");
addTableCellNoBorder(table, data.getLocation() != null ? data.getLocation() : "");
addTableHeaderCellNoBorder(table, "服務主管");
addTableCellNoBorder(table, data.getServiceManager() != null ? data.getServiceManager() : "");
document.add(table);
}
/**
* 附加险表头 - 去掉边框
*/
private void addAdditionalInsuranceHeader(Document document) throws DocumentException {
PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(100);
table.setWidths(new float[]{25, 25, 25, 25});
table.setSpacingBefore(10f);
table.setSpacingAfter(10f);
// 创建居中对齐的无边框单元格
addTableCenterHeaderCellNoBorder(table, "附加险名称");
addTableCenterHeaderCellNoBorder(table, "缴费期限");
addTableCenterHeaderCellNoBorder(table, "幣种");
addTableCenterHeaderCellNoBorder(table, "首年金额");
document.add(table);
}
/**
* 添加居中对齐的无边框表头单元格
*/
private void addTableCenterHeaderCellNoBorder(PdfPTable table, String text) {
Paragraph para = new Paragraph(text, chineseBoldFont);
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell(para);
cell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
cell.setHorizontalAlignment(com.lowagie.text.Element.ALIGN_CENTER);
cell.setVerticalAlignment(com.lowagie.text.Element.ALIGN_MIDDLE);
cell.setPadding(2f);
table.addCell(cell);
}
/**
* 备注说明
*/
private void addFootnote(Document document) throws DocumentException {
Font footnoteFont = new Font(chineseFont.getBaseFont(), FOOTNOTE_FONT_SIZE, Font.NORMAL, FOOTNOTE_COLOR);
Paragraph footnote = new Paragraph(
"*此徵費為香港政府收取,續期時亦須繳納,但不納入本報告金額統計。澳門保單毋需繳納此費用。",
footnoteFont
);
footnote.setAlignment(Paragraph.ALIGN_LEFT);
footnote.setSpacingBefore(10f);
document.add(footnote);
}
/**
* 添加表格表头单元格
*/
private void addTableHeaderCell(PdfPTable table, String text) {
Paragraph para = new Paragraph(text, chineseFont);
table.addCell(createCell(para, false));
}
/**
* 添加表格内容单元格
*/
private void addTableCell(PdfPTable table, String text) {
Paragraph para = new Paragraph(text, chineseFont);
table.addCell(createCell(para, false));
}
/**
* 添加居中对齐的表头单元格
*/
private void addTableCenterHeaderCell(PdfPTable table, String text) {
Paragraph para = new Paragraph(text, chineseBoldFont);
table.addCell(createCell(para, true));
}
/**
* 创建单元格
*/
private com.lowagie.text.pdf.PdfPCell createCell(Paragraph paragraph, boolean centerAlign) {
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell(paragraph);
cell.setBorder(com.lowagie.text.Rectangle.NO_BORDER);
cell.setHorizontalAlignment(centerAlign ? com.lowagie.text.Element.ALIGN_CENTER : com.lowagie.text.Element.ALIGN_LEFT);
cell.setVerticalAlignment(com.lowagie.text.Element.ALIGN_MIDDLE);
cell.setPadding(5f);
return cell;
}
/**
* 初始化中文字体 - 从classpath资源加载
*/
private void initChineseFont() throws IOException, DocumentException {
try {
BaseFont baseFont = null;
// 方法1: 使用绝对路径
String absolutePath = "D:\\IdeaProjects\\yd-csf\\yd-csf-service\\src\\main\\resources\\font\\DFKai-SB.ttf";
// 方法2: 使用classpath相对路径(如果字体文件在resources目录下)
String resourcePath = "font/DFKai-SB.ttf";
java.io.File fontFile = new java.io.File(absolutePath);
if (fontFile.exists()) {
try {
baseFont = BaseFont.createFont(absolutePath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
log.info("成功从绝对路径加载繁体楷体: {}", absolutePath);
} catch (Exception e) {
log.warn("绝对路径加载失败,尝试classpath路径");
// 尝试从classpath加载
try {
baseFont = BaseFont.createFont(resourcePath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
log.info("成功从classpath加载繁体楷体: {}", resourcePath);
} catch (IOException ioException) {
log.error("classpath路径加载失败,使用备用字体", ioException);
}
}
}
// 如果还是失败,使用备用字体
if (baseFont == null) {
log.warn("繁体楷体加载失败,使用STSong-Light");
baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
}
// 创建字体样式
this.chineseFont = new Font(baseFont, CONTENT_FONT_SIZE, Font.NORMAL, TEXT_COLOR);
this.chineseBoldFont = new Font(baseFont, CONTENT_FONT_SIZE, Font.BOLD, TEXT_COLOR);
this.chineseTitleFont = new Font(baseFont, SECTION_TITLE_FONT_SIZE, Font.BOLD, TEXT_COLOR);
this.chineseRedTitleFont = new Font(baseFont, MAIN_TITLE_FONT_SIZE, Font.BOLD, RED_TITLE_COLOR); // 使用主标题字号
} catch (Exception e) {
log.error("字体初始化失败", e);
throw new DocumentException("字体初始化失败: " + e.getMessage());
}
}
/**
* 金额格式化
*/
private String formatAmount(BigDecimal amount) {
if (amount == null) return "";
return String.format("%.2f", amount);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment