package com.ruoyi.stock.word; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.service.IProductService; import com.ruoyi.stock.dto.StockInRecordDto; import org.apache.poi.xwpf.usermodel.*; import org.apache.poi.xwpf.usermodel.XWPFTable.XWPFBorderType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * 磅单Word文档生成器 */ @Component public class WeighbridgeDocGenerator { @Value("${file.upload-dir}") private String uploadDir; @Autowired private IProductService productService; /** * 生成磅单Word文档 * @param dto 入库记录DTO * @return 文件保存的绝对路径,生成失败返回null */ public String generateWeighbridgeDoc(StockInRecordDto dto) { // 参数校验 if (dto == null) { return null; } FileOutputStream out = null; XWPFDocument document = null; try { // 创建新文档 document = new XWPFDocument(); // 构建文档内容 buildDocumentContent(document, dto); // 构建文件保存路径(绝对路径) String absolutePath = buildAbsoluteFilePath(dto); File file = new File(absolutePath); // 确保目录存在 file.getParentFile().mkdirs(); // 写入文件 out = new FileOutputStream(file); document.write(out); out.flush(); // 返回绝对路径(用于数据库存储) return absolutePath; } catch (Exception e) { e.printStackTrace(); return null; } finally { // 关闭资源 try { if (out != null) { out.close(); } if (document != null) { document.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * 构建文档内容 */ private void buildDocumentContent(XWPFDocument document, StockInRecordDto dto) { // 1. 添加标题 "磅码单" - 使用黑体 XWPFParagraph titlePara = document.createParagraph(); titlePara.setAlignment(ParagraphAlignment.CENTER); titlePara.setSpacingAfter(200); XWPFRun titleRun = titlePara.createRun(); titleRun.setText("磅码单"); titleRun.setBold(true); titleRun.setFontSize(28); titleRun.setFontFamily("黑体"); // 2. 空一行 document.createParagraph(); // 3. 头部信息(年月日和计量单位合并在一行)- 使用宋体 XWPFParagraph headerPara = document.createParagraph(); headerPara.setSpacingAfter(200); XWPFRun headerRun = headerPara.createRun(); // 格式化日期为 yyyy-MM-dd String weighDate = ""; if (dto.getWeighingDate() != null) { try { // 假设 weighingDate 是 LocalDateTime 类型 weighDate = dto.getWeighingDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); } catch (Exception e) { // 如果是字符串类型,尝试转换 weighDate = dto.getWeighingDate().toString(); if (weighDate.length() > 10) { weighDate = weighDate.substring(0, 10); } } } headerRun.setText("年月日:" + weighDate + " 计量单位:(吨)"); headerRun.setFontSize(12); headerRun.setFontFamily("宋体"); // 4. 创建主表格 - 4行6列(表头1行+数据1行+合计1行+空行1行) XWPFTable table = document.createTable(4, 6); // 设置表格宽度 table.setWidth("100%"); // 设置表格边框加粗(边框宽度设为2) table.setInsideHBorder(XWPFBorderType.SINGLE, 2, 0, "000000"); table.setInsideVBorder(XWPFBorderType.SINGLE, 2, 0, "000000"); table.setTopBorder(XWPFBorderType.SINGLE, 2, 0, "000000"); table.setBottomBorder(XWPFBorderType.SINGLE, 2, 0, "000000"); table.setLeftBorder(XWPFBorderType.SINGLE, 2, 0, "000000"); table.setRightBorder(XWPFBorderType.SINGLE, 2, 0, "000000"); // 设置行高 table.getRow(0).setHeight(400); table.getRow(1).setHeight(400); table.getRow(2).setHeight(400); table.getRow(3).setHeight(400); // 设置表头 - 使用黑体加粗 String[] headers = {"车号", "品名", "毛重", "皮重", "净重", "备注"}; XWPFTableRow headerRow = table.getRow(0); for (int i = 0; i < headers.length; i++) { XWPFTableCell cell = headerRow.getCell(i); cell.setText(headers[i]); cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); XWPFParagraph cellPara = cell.getParagraphs().get(0); cellPara.setAlignment(ParagraphAlignment.CENTER); XWPFRun cellRun = cellPara.getRuns().get(0); cellRun.setBold(true); cellRun.setFontSize(12); cellRun.setFontFamily("黑体"); } // 设置数据行 - 使用宋体 XWPFTableRow dataRow = table.getRow(1); String netWeight = dto.getNetWeight() != null ? dto.getNetWeight().toString() : ""; String grossWeight = dto.getGrossWeight() != null ? dto.getGrossWeight().toString() : ""; String tareWeight = dto.getTareWeight() != null ? dto.getTareWeight().toString() : ""; String[] data = { dto.getLicensePlateNo() != null ? dto.getLicensePlateNo() : "", getProductModelName(dto.getProductId()), grossWeight + "t", tareWeight + "t", netWeight + "t", dto.getRemark() != null ? dto.getRemark() : "" }; for (int i = 0; i < data.length; i++) { XWPFTableCell cell = dataRow.getCell(i); cell.setText(data[i]); cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); XWPFParagraph cellPara = cell.getParagraphs().get(0); cellPara.setAlignment(ParagraphAlignment.CENTER); XWPFRun cellRun = cellPara.getRuns().get(0); cellRun.setFontSize(12); cellRun.setFontFamily("宋体"); } // 合计行 - 第3行 XWPFTableRow totalRow = table.getRow(2); // 第1列显示"合计(大写)" XWPFTableCell totalLabelCell = totalRow.getCell(0); totalLabelCell.setText("合计(大写)"); totalLabelCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); XWPFParagraph totalLabelPara = totalLabelCell.getParagraphs().get(0); totalLabelPara.setAlignment(ParagraphAlignment.CENTER); XWPFRun totalLabelRun = totalLabelPara.getRuns().get(0); totalLabelRun.setBold(true); totalLabelRun.setFontSize(12); totalLabelRun.setFontFamily("宋体"); XWPFTableCell contentCell = totalRow.getCell(1); String netWeightChinese = ChineseNumberUtil.numberToChinese( dto.getNetWeight() != null ? dto.getNetWeight() : BigDecimal.ZERO ); contentCell.setText(netWeightChinese + "吨"); contentCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); XWPFParagraph contentPara = contentCell.getParagraphs().get(0); contentPara.setAlignment(ParagraphAlignment.LEFT); XWPFRun contentRun = contentPara.getRuns().get(0); contentRun.setFontSize(12); contentRun.setFontFamily("宋体"); // 合并第3-6列到第2列 for (int i = 2; i < 6; i++) { XWPFTableCell cell = totalRow.getCell(i); // 设置这些单元格为合并状态(继承自第2列) cell.getCTTc().addNewTcPr().addNewHMerge().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge.CONTINUE); } // 6. 创建过磅员行(单独一行,左对齐) XWPFParagraph operatorPara = document.createParagraph(); operatorPara.setSpacingAfter(100); operatorPara.setAlignment(ParagraphAlignment.LEFT); XWPFRun operatorRun = operatorPara.createRun(); String operator = dto.getWeighingOperator() != null ? dto.getWeighingOperator() : ""; operatorRun.setText("过磅员:" + operator); operatorRun.setFontSize(8); operatorRun.setFontFamily("宋体"); } /** * 构建文件保存的绝对路径 */ private String buildAbsoluteFilePath(StockInRecordDto dto) { LocalDateTime now = LocalDateTime.now(); String year = String.valueOf(now.getYear()); String month = String.format("%02d", now.getMonthValue()); String day = String.format("%02d", now.getDayOfMonth()); // 文件名格式:磅单_车牌号_年月日时分秒.docx String fileName = String.format("磅单_%s_%s.docx", dto.getLicensePlateNo() != null ? dto.getLicensePlateNo() : "未知车牌", now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); return uploadDir + File.separator + year + File.separator + month + File.separator + day + File.separator + fileName; } /** * 获取产品型号名称 */ private String getProductModelName(Long productModelId) { if (productModelId == null) { return "未知产品"; } try { Product product = productService.getById(productModelId); return product != null ? product.getProductName() : "未知产品"; } catch (Exception e) { e.printStackTrace(); return "未知产品"; } } }