| | |
| | | import com.ruoyi.stock.dto.StockInRecordDto; |
| | | import org.apache.poi.xwpf.usermodel.*; |
| | | import org.apache.poi.xwpf.usermodel.XWPFTable.XWPFBorderType; |
| | | import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.stereotype.Component; |
| | |
| | | import java.io.FileOutputStream; |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.math.BigInteger; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | |
| | |
| | | document.write(out); |
| | | out.flush(); |
| | | |
| | | // 返回绝对路径(用于数据库存储) |
| | | // 返回绝对路径 |
| | | return absolutePath; |
| | | |
| | | } catch (Exception e) { |
| | |
| | | |
| | | /** |
| | | * 构建文档内容 |
| | | * @param document Word文档对象 |
| | | * @param dto 入库记录DTO |
| | | */ |
| | | private void buildDocumentContent(XWPFDocument document, StockInRecordDto dto) { |
| | | // 1. 添加标题 "磅码单" - 使用黑体 |
| | | |
| | | // 设置纸张大小为A5横向 |
| | | CTSectPr sectPr = document.getDocument().getBody().isSetSectPr() |
| | | ? document.getDocument().getBody().getSectPr() |
| | | : document.getDocument().getBody().addNewSectPr(); |
| | | |
| | | CTPageSz pageSize = sectPr.isSetPgSz() ? sectPr.getPgSz() : sectPr.addNewPgSz(); |
| | | pageSize.setW(BigInteger.valueOf(11906)); // A5横向宽度 210mm |
| | | pageSize.setH(BigInteger.valueOf(8392)); // A5横向高度 148mm |
| | | pageSize.setOrient(STPageOrientation.LANDSCAPE); |
| | | |
| | | // 标题 "磅码单" |
| | | XWPFParagraph titlePara = document.createParagraph(); |
| | | titlePara.setAlignment(ParagraphAlignment.CENTER); |
| | | titlePara.setSpacingAfter(200); |
| | |
| | | titleRun.setFontSize(28); |
| | | titleRun.setFontFamily("黑体"); |
| | | |
| | | // 2. 空一行 |
| | | document.createParagraph(); |
| | | // 定义统一的页面宽度值(所有表格使用相同的总宽度) |
| | | int pageWidth = 9000; // 统一的页面宽度值 |
| | | |
| | | // 3. 头部信息(年月日和计量单位合并在一行)- 使用宋体 |
| | | XWPFParagraph headerPara = document.createParagraph(); |
| | | headerPara.setSpacingAfter(200); |
| | | XWPFRun headerRun = headerPara.createRun(); |
| | | // 创建一行两列表格来放置日期和计量单位 |
| | | XWPFTable headerTable = document.createTable(1, 2); |
| | | headerTable.setWidth("100%"); |
| | | |
| | | // 格式化日期为 yyyy-MM-dd |
| | | // 设置表格无边框 |
| | | headerTable.setInsideHBorder(XWPFBorderType.NONE, 0, 0, "000000"); |
| | | headerTable.setInsideVBorder(XWPFBorderType.NONE, 0, 0, "000000"); |
| | | headerTable.setTopBorder(XWPFBorderType.NONE, 0, 0, "000000"); |
| | | headerTable.setBottomBorder(XWPFBorderType.NONE, 0, 0, "000000"); |
| | | headerTable.setLeftBorder(XWPFBorderType.NONE, 0, 0, "000000"); |
| | | headerTable.setRightBorder(XWPFBorderType.NONE, 0, 0, "000000"); |
| | | |
| | | // 设置表头表格列宽:日期列50%,计量单位列50% |
| | | CTTbl headerTbl = headerTable.getCTTbl(); |
| | | CTTblGrid headerTblGrid = headerTbl.addNewTblGrid(); |
| | | |
| | | // 使用统一的页面宽度 |
| | | int headerColWidth = pageWidth / 2; // 4500 |
| | | |
| | | CTTblGridCol col1 = headerTblGrid.addNewGridCol(); |
| | | col1.setW(BigInteger.valueOf(headerColWidth)); |
| | | |
| | | CTTblGridCol col2 = headerTblGrid.addNewGridCol(); |
| | | col2.setW(BigInteger.valueOf(headerColWidth)); |
| | | |
| | | // 设置行高 |
| | | headerTable.getRow(0).setHeight(300); |
| | | |
| | | // 为表头表格的每个单元格设置宽度 |
| | | for (int colIndex = 0; colIndex < 2; colIndex++) { |
| | | XWPFTableCell cell = headerTable.getRow(0).getCell(colIndex); |
| | | CTTcPr tcPr = cell.getCTTc().addNewTcPr(); |
| | | CTTblWidth cellWidth = tcPr.addNewTcW(); |
| | | cellWidth.setType(STTblWidth.DXA); |
| | | cellWidth.setW(BigInteger.valueOf(headerColWidth)); |
| | | } |
| | | |
| | | // 左侧单元格:日期(左对齐) |
| | | XWPFTableCell dateCell = headerTable.getRow(0).getCell(0); |
| | | dateCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); |
| | | |
| | | // 清除单元格中可能存在的默认段落 |
| | | for (int i = dateCell.getParagraphs().size() - 1; i > 0; i--) { |
| | | dateCell.removeParagraph(i); |
| | | } |
| | | |
| | | XWPFParagraph datePara = dateCell.getParagraphs().get(0); |
| | | datePara.setAlignment(ParagraphAlignment.LEFT); |
| | | |
| | | // 清除段落中可能存在的默认Run |
| | | for (int i = datePara.getRuns().size() - 1; i > 0; i--) { |
| | | datePara.removeRun(i); |
| | | } |
| | | |
| | | XWPFRun dateRun = datePara.createRun(); |
| | | |
| | | // 格式化日期 |
| | | 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("宋体"); |
| | | dateRun.setText("日 期:" + weighDate); |
| | | dateRun.setFontSize(12); |
| | | dateRun.setFontFamily("宋体"); |
| | | |
| | | // 4. 创建主表格 - 4行6列(表头1行+数据1行+合计1行+空行1行) |
| | | XWPFTable table = document.createTable(4, 6); |
| | | // 计量单位(右对齐) |
| | | XWPFTableCell unitCell = headerTable.getRow(0).getCell(1); |
| | | unitCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); |
| | | |
| | | for (int i = unitCell.getParagraphs().size() - 1; i > 0; i--) { |
| | | unitCell.removeParagraph(i); |
| | | } |
| | | |
| | | XWPFParagraph unitPara = unitCell.getParagraphs().get(0); |
| | | unitPara.setAlignment(ParagraphAlignment.RIGHT); |
| | | |
| | | for (int i = unitPara.getRuns().size() - 1; i > 0; i--) { |
| | | unitPara.removeRun(i); |
| | | } |
| | | |
| | | XWPFRun unitRun = unitPara.createRun(); |
| | | unitRun.setText("计量单位:" + dto.getUnit()); |
| | | unitRun.setFontSize(12); |
| | | unitRun.setFontFamily("宋体"); |
| | | |
| | | // 创建主表格 - 3行6列 |
| | | XWPFTable table = document.createTable(3, 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.getRow(0).setHeight(400); |
| | | table.getRow(1).setHeight(400); |
| | | table.getRow(2).setHeight(400); |
| | | table.getRow(3).setHeight(400); |
| | | |
| | | // 设置主表格列宽网格 - 使用相同的总宽度 pageWidth |
| | | CTTbl mainTbl = table.getCTTbl(); |
| | | CTTblGrid mainTblGrid = mainTbl.addNewTblGrid(); |
| | | |
| | | // 列宽比例 |
| | | int[] colWidths = { |
| | | (int)(pageWidth * 0.20), |
| | | (int)(pageWidth * 0.24), |
| | | (int)(pageWidth * 0.14), |
| | | (int)(pageWidth * 0.14), |
| | | (int)(pageWidth * 0.14), |
| | | (int)(pageWidth * 0.14) |
| | | }; |
| | | |
| | | // 确保总和等于pageWidth |
| | | int sum = 0; |
| | | for (int width : colWidths) { |
| | | sum += width; |
| | | } |
| | | // 如果有误差,调整最后一列 |
| | | if (sum != pageWidth) { |
| | | colWidths[5] += (pageWidth - sum); |
| | | } |
| | | |
| | | for (int width : colWidths) { |
| | | CTTblGridCol col = mainTblGrid.addNewGridCol(); |
| | | col.setW(BigInteger.valueOf(width)); |
| | | } |
| | | |
| | | // 为每一行的每个单元格设置具体的宽度 |
| | | for (int rowIndex = 0; rowIndex < 3; rowIndex++) { |
| | | XWPFTableRow row = table.getRow(rowIndex); |
| | | for (int colIndex = 0; colIndex < 6; colIndex++) { |
| | | XWPFTableCell cell = row.getCell(colIndex); |
| | | CTTcPr tcPr = cell.getCTTc().addNewTcPr(); |
| | | CTTblWidth cellWidth = tcPr.addNewTcW(); |
| | | cellWidth.setType(STTblWidth.DXA); |
| | | cellWidth.setW(BigInteger.valueOf(colWidths[colIndex])); |
| | | } |
| | | } |
| | | |
| | | // 设置表头 - 使用黑体加粗 |
| | | String[] headers = {"车号", "品名", "毛重", "皮重", "净重", "备注"}; |
| | |
| | | cell.setText(headers[i]); |
| | | cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); |
| | | |
| | | // 清除可能存在的多余段落 |
| | | while (cell.getParagraphs().size() > 1) { |
| | | cell.removeParagraph(1); |
| | | } |
| | | |
| | | XWPFParagraph cellPara = cell.getParagraphs().get(0); |
| | | cellPara.setAlignment(ParagraphAlignment.CENTER); |
| | | |
| | | while (cellPara.getRuns().size() > 1) { |
| | | cellPara.removeRun(1); |
| | | } |
| | | |
| | | XWPFRun cellRun = cellPara.getRuns().get(0); |
| | | cellRun.setBold(true); |
| | | cellRun.setFontSize(12); |
| | |
| | | String[] data = { |
| | | dto.getLicensePlateNo() != null ? dto.getLicensePlateNo() : "", |
| | | getProductModelName(dto.getProductId()), |
| | | grossWeight + "t", |
| | | tareWeight + "t", |
| | | netWeight + "t", |
| | | grossWeight + dto.getUnit(), |
| | | tareWeight + dto.getUnit(), |
| | | netWeight + dto.getUnit(), |
| | | dto.getRemark() != null ? dto.getRemark() : "" |
| | | }; |
| | | |
| | |
| | | cell.setText(data[i]); |
| | | cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); |
| | | |
| | | while (cell.getParagraphs().size() > 1) { |
| | | cell.removeParagraph(1); |
| | | } |
| | | |
| | | XWPFParagraph cellPara = cell.getParagraphs().get(0); |
| | | cellPara.setAlignment(ParagraphAlignment.CENTER); |
| | | |
| | | while (cellPara.getRuns().size() > 1) { |
| | | cellPara.removeRun(1); |
| | | } |
| | | |
| | | XWPFRun cellRun = cellPara.getRuns().get(0); |
| | | cellRun.setFontSize(12); |
| | | cellRun.setFontFamily("宋体"); |
| | |
| | | XWPFTableCell totalLabelCell = totalRow.getCell(0); |
| | | totalLabelCell.setText("合计(大写)"); |
| | | totalLabelCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); |
| | | |
| | | // 清除可能存在的多余段落 |
| | | while (totalLabelCell.getParagraphs().size() > 1) { |
| | | totalLabelCell.removeParagraph(1); |
| | | } |
| | | |
| | | XWPFParagraph totalLabelPara = totalLabelCell.getParagraphs().get(0); |
| | | totalLabelPara.setAlignment(ParagraphAlignment.CENTER); |
| | | |
| | | // 清除可能存在的多余Run |
| | | while (totalLabelPara.getRuns().size() > 1) { |
| | | totalLabelPara.removeRun(1); |
| | | } |
| | | |
| | | XWPFRun totalLabelRun = totalLabelPara.getRuns().get(0); |
| | | totalLabelRun.setBold(true); |
| | | totalLabelRun.setFontSize(12); |
| | | totalLabelRun.setFontFamily("宋体"); |
| | | 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); |
| | | XWPFTableCell startCell = totalRow.getCell(1); |
| | | startCell.setText(netWeightChinese + dto.getUnit()); |
| | | startCell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); |
| | | |
| | | while (startCell.getParagraphs().size() > 1) { |
| | | startCell.removeParagraph(1); |
| | | } |
| | | |
| | | // 6. 创建过磅员行(单独一行,左对齐) |
| | | XWPFParagraph startPara = startCell.getParagraphs().get(0); |
| | | startPara.setAlignment(ParagraphAlignment.CENTER); |
| | | |
| | | while (startPara.getRuns().size() > 1) { |
| | | startPara.removeRun(1); |
| | | } |
| | | |
| | | XWPFRun startRun = startPara.getRuns().get(0); |
| | | startRun.setFontSize(12); |
| | | startRun.setFontFamily("宋体"); |
| | | |
| | | // 标记第2列为合并起始 |
| | | startCell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART); |
| | | |
| | | // 第3-6列合并 |
| | | for (int i = 2; i < 6; i++) { |
| | | XWPFTableCell cell = totalRow.getCell(i); |
| | | cell.setText(""); |
| | | cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); |
| | | } |
| | | |
| | | // 创建过磅员行(单独一行,左对齐) |
| | | 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.setFontSize(12); |
| | | operatorRun.setFontFamily("宋体"); |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | String month = String.format("%02d", now.getMonthValue()); |
| | | String day = String.format("%02d", now.getDayOfMonth()); |
| | | |
| | | // 文件名格式:磅单_车牌号_年月日时分秒.docx |
| | | // 文件名格式:磅单_车牌号_年月日.docx |
| | | String fileName = String.format("磅单_%s_%s.docx", |
| | | dto.getLicensePlateNo() != null ? dto.getLicensePlateNo() : "未知车牌", |
| | | now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); |
| | | now.format(DateTimeFormatter.ofPattern("yyyyMMdd"))); |
| | | |
| | | return uploadDir + File.separator + year + File.separator + month + File.separator + day + File.separator + fileName; |
| | | } |