|
|
@@ -0,0 +1,445 @@
|
|
|
+package com.jeesite.modules.mes.util;
|
|
|
+
|
|
|
+import com.google.zxing.BarcodeFormat;
|
|
|
+import com.google.zxing.EncodeHintType;
|
|
|
+import com.google.zxing.MultiFormatWriter;
|
|
|
+import com.google.zxing.WriterException;
|
|
|
+import com.google.zxing.client.j2se.MatrixToImageWriter;
|
|
|
+import com.google.zxing.common.BitMatrix;
|
|
|
+import com.jeesite.modules.erp.entity.MesMaterialErp;
|
|
|
+import com.jeesite.modules.erp.entity.MesMaterialOrder;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+
|
|
|
+import javax.print.PrintService;
|
|
|
+import javax.print.PrintServiceLookup;
|
|
|
+import javax.print.attribute.HashPrintRequestAttributeSet;
|
|
|
+import javax.print.attribute.PrintRequestAttributeSet;
|
|
|
+import javax.print.attribute.standard.MediaPrintableArea;
|
|
|
+import java.awt.*;
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
+import java.awt.print.PageFormat;
|
|
|
+import java.awt.print.Printable;
|
|
|
+import java.awt.print.PrinterJob;
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+public class PrintUtil {
|
|
|
+ public static final Logger log = LoggerFactory.getLogger(PrintUtil.class);
|
|
|
+ private static final String DEFAULT_PRINTER_NAME = "QR-888";
|
|
|
+ /** 物理纸 100×80mm 时,单条物料仅在上方 100×40mm 可视区域内排版,下半张留白 */
|
|
|
+ private static final double SINGLE_MATERIAL_ZONE_HEIGHT_MM = 40;
|
|
|
+
|
|
|
+ public static void printLabel(String barCode){
|
|
|
+ log.info("sn:"+barCode);
|
|
|
+ // 获取所有打印服务(打印机)
|
|
|
+ PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
|
|
|
+ if (services.length == 0) {
|
|
|
+ log.info("No printers found.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ String printerName = "QR-888";
|
|
|
+ PrintService selectedService = Arrays.stream(services).filter(s -> s.getName().equals(printerName)).findFirst().orElse(null);
|
|
|
+ if (selectedService == null) { // 没有找到指定名称的打印机,则退出程序或使用默认打印机等处理方式。
|
|
|
+ log.info(printerName+":Printer not found.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try{
|
|
|
+ PrinterJob job = PrinterJob.getPrinterJob(); // 使用默认的PrinterJob对象,然后设置服务。
|
|
|
+ job.setPrintService(selectedService); // 设置选定的打印机服务。
|
|
|
+ job.setPrintable(new Printable() { // 设置打印内容。
|
|
|
+ public int print(Graphics g, PageFormat pf, int page) {
|
|
|
+ if (page > 0) { // 只打印一页。
|
|
|
+ return Printable.NO_SUCH_PAGE;
|
|
|
+ } else { // 绘制内容。
|
|
|
+ int fontSize = Integer.valueOf("14");
|
|
|
+ int labelx = Integer.valueOf("45");
|
|
|
+ int labely = Integer.valueOf("35");
|
|
|
+ int labelLineSpace = Integer.valueOf("10");
|
|
|
+ g.setFont(new Font("Serif", Font.PLAIN, fontSize)); // 设置字体和大小
|
|
|
+ String line1 = barCode;
|
|
|
+ g.drawString(line1, labelx, labely); // 打印第一行文本
|
|
|
+// g.drawString(sn, labelx, labely + labelLineSpace); // 打印第二行文本
|
|
|
+// String line3 = param1 + " " + param2;
|
|
|
+// g.drawString(line3, labelx, labely + 2*labelLineSpace);
|
|
|
+ try{
|
|
|
+ g.drawImage(PrintUtil.generateQRCodeImage(line1,120,120),labelx+35,labely + labelLineSpace,35,35,null);
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return Printable.PAGE_EXISTS;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ int x = 100;
|
|
|
+ int y = 30;
|
|
|
+ // 设置打印参数
|
|
|
+ PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
|
|
|
+
|
|
|
+ // 设置纸张大小 , 实际测试没有这个功能, 还是要标签打印机设置
|
|
|
+ MediaPrintableArea area = new MediaPrintableArea(0, 0, x, y, MediaPrintableArea.MM);
|
|
|
+ aset.add(area);
|
|
|
+
|
|
|
+ job.print(aset);
|
|
|
+ System.out.println("Printer finish.");
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static BufferedImage generateQRCodeImage(String text, int width, int height) throws WriterException, IOException {
|
|
|
+ Map<EncodeHintType, Object> hints = new HashMap<>();
|
|
|
+ hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
|
|
+ BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
|
|
|
+ return MatrixToImageWriter.toBufferedImage(bitMatrix);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 打印领料单模板(订单号+领料单号+物料明细)
|
|
|
+ */
|
|
|
+ public static void printMaterialOrder(MesMaterialOrder order, List<MesMaterialErp> items) {
|
|
|
+ List<MaterialOrderPrintTask> tasks = new ArrayList<>();
|
|
|
+ tasks.add(new MaterialOrderPrintTask(order, items));
|
|
|
+ printMaterialOrders(tasks);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量打印:一次提交到打印机(多页打印)
|
|
|
+ */
|
|
|
+ public static void printMaterialOrders(List<MaterialOrderPrintTask> tasks) {
|
|
|
+ if (tasks == null || tasks.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<MaterialOrderPrintTask> validTasks = new ArrayList<>();
|
|
|
+ for (MaterialOrderPrintTask task : tasks) {
|
|
|
+ if (task != null && task.getOrder() != null) {
|
|
|
+ validTasks.add(task);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (validTasks.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ PrintService selectedService = findPrinter(DEFAULT_PRINTER_NAME);
|
|
|
+ if (selectedService == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ PrinterJob job = PrinterJob.getPrinterJob();
|
|
|
+ job.setPrintService(selectedService);
|
|
|
+ // 纸张: 100mm(宽) x 80mm(高)
|
|
|
+ final double paperWidthPt = mmToPoint(100);
|
|
|
+ final double paperHeightPt = mmToPoint(80);
|
|
|
+ final double marginPt = mmToPoint(2); // 2mm边距
|
|
|
+ PageFormat pageFormat = job.defaultPage();
|
|
|
+ java.awt.print.Paper paper = new java.awt.print.Paper();
|
|
|
+ paper.setSize(paperWidthPt, paperHeightPt);
|
|
|
+ paper.setImageableArea(marginPt, marginPt, paperWidthPt - marginPt * 2, paperHeightPt - marginPt * 2);
|
|
|
+ pageFormat.setPaper(paper);
|
|
|
+
|
|
|
+ job.setPrintable(new Printable() {
|
|
|
+ @Override
|
|
|
+ public int print(Graphics g, PageFormat pf, int page) {
|
|
|
+ if (page < 0 || page >= validTasks.size()) {
|
|
|
+ return Printable.NO_SUCH_PAGE;
|
|
|
+ }
|
|
|
+ MaterialOrderPrintTask task = validTasks.get(page);
|
|
|
+ renderMaterialOrderPage((Graphics2D) g, pf, task.getOrder(), task.getItems());
|
|
|
+ return Printable.PAGE_EXISTS;
|
|
|
+ }
|
|
|
+ }, pageFormat);
|
|
|
+
|
|
|
+ PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
|
|
|
+ aset.add(new MediaPrintableArea(0, 0, 100, 80, MediaPrintableArea.MM));
|
|
|
+ job.print(aset);
|
|
|
+ log.info("Batch print material order finish, count={}", validTasks.size());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("Batch print material order failed", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void renderMaterialOrderPage(Graphics2D g2, PageFormat pf, MesMaterialOrder order, List<MesMaterialErp> printItems) {
|
|
|
+ int itemCount = printItems == null ? 0 : printItems.size();
|
|
|
+ int numRows = Math.max(1, itemCount);
|
|
|
+ if (numRows <= 1) {
|
|
|
+ renderMaterialOrderPageTopZone40mm(g2, pf, order, printItems);
|
|
|
+ } else {
|
|
|
+ renderMaterialOrderPageMultiRow(g2, pf, order, printItems, itemCount, numRows);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 单物料:在可打印区顶部 40mm 高度内排版(等效 100×40mm 标签区),物理纸仍为 100×80mm 时下半部分留白。
|
|
|
+ */
|
|
|
+ private static void renderMaterialOrderPageTopZone40mm(Graphics2D g2, PageFormat pf, MesMaterialOrder order, List<MesMaterialErp> printItems) {
|
|
|
+ final String orderId = safe(order.getOrderId());
|
|
|
+ final String requisitionNo = safe(order.getRequisitionNo());
|
|
|
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
|
+ g2.setFont(new Font("SimSun", Font.PLAIN, 10));
|
|
|
+
|
|
|
+ int left = (int) pf.getImageableX();
|
|
|
+ int top = (int) pf.getImageableY();
|
|
|
+ int contentW = (int) pf.getImageableWidth();
|
|
|
+ int imageableBottom = (int) (pf.getImageableY() + pf.getImageableHeight());
|
|
|
+ int zoneLimitY = Math.min(top + (int) mmToPoint(SINGLE_MATERIAL_ZONE_HEIGHT_MM), imageableBottom);
|
|
|
+
|
|
|
+ // 左右略缩进,整体视觉上更靠纸面中间
|
|
|
+ int hPad = (int) mmToPoint(4);
|
|
|
+ int drawLeft = left + hPad;
|
|
|
+ int drawW = Math.max(1, contentW - 2 * hPad);
|
|
|
+ // 上缘略下移,在 40mm 区内略偏中
|
|
|
+ int contentTop = top + (int) mmToPoint(2);
|
|
|
+
|
|
|
+ int qrSize = (int) mmToPoint(18);
|
|
|
+ int qrGap = (int) mmToPoint(2);
|
|
|
+ // 生产订单、领料单两格同宽(左侧至二维码前整块)
|
|
|
+ int labelBoxW = Math.max(1, drawW - qrSize - qrGap);
|
|
|
+
|
|
|
+ int boxH = (int) mmToPoint(8.5);
|
|
|
+ int gapY = (int) mmToPoint(2.5);
|
|
|
+ int innerPadX = (int) mmToPoint(2);
|
|
|
+ int leftTextPadX = innerPadX + (int) mmToPoint(0.8);
|
|
|
+ int textBaseInBox = (int) mmToPoint(6.2);
|
|
|
+
|
|
|
+ g2.drawRect(drawLeft, contentTop, labelBoxW, boxH);
|
|
|
+ drawStringFitCell(g2, "生产订单编号: " + orderId, drawLeft, labelBoxW, leftTextPadX, innerPadX,
|
|
|
+ contentTop + textBaseInBox, 10, 6);
|
|
|
+
|
|
|
+ g2.drawRect(drawLeft, contentTop + boxH + gapY, labelBoxW, boxH);
|
|
|
+ drawStringFitCell(g2, "领料单编号: " + requisitionNo, drawLeft, labelBoxW, leftTextPadX, innerPadX,
|
|
|
+ contentTop + boxH + gapY + textBaseInBox, 10, 6);
|
|
|
+
|
|
|
+ int qrX = drawLeft + drawW - qrSize;
|
|
|
+ int qrY = contentTop;
|
|
|
+ g2.drawRect(qrX, qrY, qrSize, qrSize);
|
|
|
+ if (!requisitionNo.isEmpty()) {
|
|
|
+ try {
|
|
|
+ int qrPad = (int) mmToPoint(1.2);
|
|
|
+ g2.drawImage(generateQRCodeImage(requisitionNo, 200, 200), qrX + qrPad, qrY + qrPad, qrSize - qrPad * 2, qrSize - qrPad * 2, null);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("Generate QR code failed, requisitionNo={}", requisitionNo, ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int headBandBottom = contentTop + boxH + gapY + boxH;
|
|
|
+ int qrBottom = qrY + qrSize;
|
|
|
+ int tableY = Math.max(headBandBottom, qrBottom) + (int) mmToPoint(1.5);
|
|
|
+ int headerH = (int) mmToPoint(7);
|
|
|
+ int rowGap = (int) mmToPoint(1);
|
|
|
+ // 行高:表头+数据行底部不超出 40mm 区下沿
|
|
|
+ int maxRowH = zoneLimitY - tableY - headerH - rowGap;
|
|
|
+ if (maxRowH < 1) {
|
|
|
+ maxRowH = 1;
|
|
|
+ }
|
|
|
+ int rowH = Math.min((int) mmToPoint(9), maxRowH);
|
|
|
+
|
|
|
+ // c1 物料编号、c2 名称、c3 数量;右侧余宽为规格(收窄规格、加宽编号与名称)
|
|
|
+ int c1 = (int) mmToPoint(30);
|
|
|
+ int c2 = (int) mmToPoint(28);
|
|
|
+ int c3 = (int) mmToPoint(12);
|
|
|
+
|
|
|
+ g2.drawRect(drawLeft, tableY, drawW, headerH);
|
|
|
+ g2.drawLine(drawLeft + c1, tableY, drawLeft + c1, tableY + headerH);
|
|
|
+ g2.drawLine(drawLeft + c1 + c2, tableY, drawLeft + c1 + c2, tableY + headerH);
|
|
|
+ g2.drawLine(drawLeft + c1 + c2 + c3, tableY, drawLeft + c1 + c2 + c3, tableY + headerH);
|
|
|
+ int headerTextY = tableY + (int) mmToPoint(5.2);
|
|
|
+ g2.drawString("物料编号", drawLeft + leftTextPadX, headerTextY);
|
|
|
+ g2.drawString("名称", drawLeft + c1 + innerPadX, headerTextY);
|
|
|
+ g2.drawString("数量", drawLeft + c1 + c2 + innerPadX, headerTextY);
|
|
|
+ g2.drawString("规格", drawLeft + c1 + c2 + c3 + innerPadX, headerTextY);
|
|
|
+
|
|
|
+ int rowY = tableY + headerH + rowGap;
|
|
|
+ MesMaterialErp item = (printItems != null && !printItems.isEmpty()) ? printItems.get(0) : null;
|
|
|
+ g2.drawRect(drawLeft, rowY, drawW, rowH);
|
|
|
+ g2.drawLine(drawLeft + c1, rowY, drawLeft + c1, rowY + rowH);
|
|
|
+ g2.drawLine(drawLeft + c1 + c2, rowY, drawLeft + c1 + c2, rowY + rowH);
|
|
|
+ g2.drawLine(drawLeft + c1 + c2 + c3, rowY, drawLeft + c1 + c2 + c3, rowY + rowH);
|
|
|
+ if (item != null) {
|
|
|
+ int textBaseline = rowY + Math.max((int) mmToPoint(3), (rowH * 5) / 8);
|
|
|
+ drawStringFitCell(g2, item.getMaterialCode(), drawLeft, c1, leftTextPadX, innerPadX, textBaseline, 10, 5);
|
|
|
+ drawStringFitCell(g2, item.getMaterialName(), drawLeft + c1, c2, innerPadX, innerPadX, textBaseline, 10, 5);
|
|
|
+ g2.setFont(new Font("SimSun", Font.PLAIN, 10));
|
|
|
+ g2.drawString(clip(safe(item.getMaterialNumber()), 8), drawLeft + c1 + c2 + innerPadX, textBaseline);
|
|
|
+ g2.drawString(clip(safe(item.getMateriarSize()), 14), drawLeft + c1 + c2 + c3 + innerPadX, textBaseline);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 多条物料:沿用原全高布局,占满可打印区域 */
|
|
|
+ private static void renderMaterialOrderPageMultiRow(Graphics2D g2, PageFormat pf, MesMaterialOrder order, List<MesMaterialErp> printItems,
|
|
|
+ int itemCount, int numRows) {
|
|
|
+ final String orderId = safe(order.getOrderId());
|
|
|
+ final String requisitionNo = safe(order.getRequisitionNo());
|
|
|
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
|
+ g2.setFont(new Font("SimSun", Font.PLAIN, 8));
|
|
|
+
|
|
|
+ int left = (int) pf.getImageableX();
|
|
|
+ int top = (int) pf.getImageableY();
|
|
|
+ int contentW = (int) pf.getImageableWidth();
|
|
|
+
|
|
|
+ int qrSize = (int) mmToPoint(26);
|
|
|
+ int qrGap = (int) mmToPoint(2);
|
|
|
+ int labelBoxW = Math.max(1, contentW - qrSize - qrGap);
|
|
|
+
|
|
|
+ int boxH = (int) mmToPoint(11);
|
|
|
+ int gapY = (int) mmToPoint(4);
|
|
|
+ int innerPadX = (int) mmToPoint(2);
|
|
|
+ int leftTextPadX = innerPadX + (int) mmToPoint(1);
|
|
|
+ int textBase = (int) mmToPoint(7.5);
|
|
|
+
|
|
|
+ g2.drawRect(left, top, labelBoxW, boxH);
|
|
|
+ drawStringFitCell(g2, "生产订单编号: " + orderId, left, labelBoxW, leftTextPadX, innerPadX, top + textBase, 8, 5);
|
|
|
+
|
|
|
+ g2.drawRect(left, top + boxH + gapY, labelBoxW, boxH);
|
|
|
+ drawStringFitCell(g2, "领料单编号: " + requisitionNo, left, labelBoxW, leftTextPadX, innerPadX, top + boxH + gapY + textBase, 8, 5);
|
|
|
+
|
|
|
+ int qrX = left + contentW - qrSize;
|
|
|
+ int qrY = top;
|
|
|
+ g2.drawRect(qrX, qrY, qrSize, qrSize);
|
|
|
+ if (!requisitionNo.isEmpty()) {
|
|
|
+ try {
|
|
|
+ int qrPad = (int) mmToPoint(1.8);
|
|
|
+ g2.drawImage(generateQRCodeImage(requisitionNo, 200, 200), qrX + qrPad, qrY + qrPad, qrSize - qrPad * 2, qrSize - qrPad * 2, null);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("Generate QR code failed, requisitionNo={}", requisitionNo, ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int tableY = top + boxH * 2 + gapY + (int) mmToPoint(4);
|
|
|
+ int headerH = (int) mmToPoint(9);
|
|
|
+ int preferredRowH = (int) mmToPoint(14);
|
|
|
+ int c1 = (int) mmToPoint(30);
|
|
|
+ int c2 = (int) mmToPoint(28);
|
|
|
+ int c3 = (int) mmToPoint(12);
|
|
|
+
|
|
|
+ g2.drawRect(left, tableY, contentW, headerH);
|
|
|
+ g2.drawLine(left + c1, tableY, left + c1, tableY + headerH);
|
|
|
+ g2.drawLine(left + c1 + c2, tableY, left + c1 + c2, tableY + headerH);
|
|
|
+ g2.drawLine(left + c1 + c2 + c3, tableY, left + c1 + c2 + c3, tableY + headerH);
|
|
|
+ g2.drawString("物料编号", left + leftTextPadX, tableY + (int) mmToPoint(6));
|
|
|
+ g2.drawString("名称", left + c1 + innerPadX, tableY + (int) mmToPoint(6));
|
|
|
+ g2.drawString("数量", left + c1 + c2 + innerPadX, tableY + (int) mmToPoint(6));
|
|
|
+ g2.drawString("规格", left + c1 + c2 + c3 + innerPadX, tableY + (int) mmToPoint(6));
|
|
|
+
|
|
|
+ int rowY = tableY + headerH + (int) mmToPoint(3);
|
|
|
+ int imageableBottom = (int) (pf.getImageableY() + pf.getImageableHeight());
|
|
|
+ int bottomPad = (int) mmToPoint(1);
|
|
|
+ int availableForRows = Math.max((int) mmToPoint(5), imageableBottom - bottomPad - rowY);
|
|
|
+ int rowH = Math.min(preferredRowH, availableForRows / numRows);
|
|
|
+ if (rowH < 1) {
|
|
|
+ rowH = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < numRows; i++) {
|
|
|
+ MesMaterialErp item = i < itemCount ? printItems.get(i) : null;
|
|
|
+ g2.drawRect(left, rowY + i * rowH, contentW, rowH);
|
|
|
+ g2.drawLine(left + c1, rowY + i * rowH, left + c1, rowY + (i + 1) * rowH);
|
|
|
+ g2.drawLine(left + c1 + c2, rowY + i * rowH, left + c1 + c2, rowY + (i + 1) * rowH);
|
|
|
+ g2.drawLine(left + c1 + c2 + c3, rowY + i * rowH, left + c1 + c2 + c3, rowY + (i + 1) * rowH);
|
|
|
+ if (item != null) {
|
|
|
+ int textBaseline = rowY + i * rowH + Math.max((int) mmToPoint(3), (rowH * 5) / 8);
|
|
|
+ drawStringFitCell(g2, item.getMaterialCode(), left, c1, leftTextPadX, innerPadX, textBaseline, 8, 5);
|
|
|
+ drawStringFitCell(g2, item.getMaterialName(), left + c1, c2, innerPadX, innerPadX, textBaseline, 8, 5);
|
|
|
+ g2.setFont(new Font("SimSun", Font.PLAIN, 8));
|
|
|
+ g2.drawString(clip(safe(item.getMaterialNumber()), 6), left + c1 + c2 + innerPadX, textBaseline);
|
|
|
+ g2.drawString(clip(safe(item.getMateriarSize()), 12), left + c1 + c2 + c3 + innerPadX, textBaseline);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static PrintService findPrinter(String printerName) {
|
|
|
+ PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
|
|
|
+ if (services.length == 0) {
|
|
|
+ log.info("No printers found.");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ PrintService selectedService = Arrays.stream(services)
|
|
|
+ .filter(s -> s.getName().equals(printerName))
|
|
|
+ .findFirst()
|
|
|
+ .orElse(null);
|
|
|
+ if (selectedService == null) {
|
|
|
+ log.info("{}:Printer not found.", printerName);
|
|
|
+ }
|
|
|
+ return selectedService;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String safe(String value) {
|
|
|
+ return value == null ? "" : value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String clip(String value, int maxLen) {
|
|
|
+ if (value == null || value.length() <= maxLen) {
|
|
|
+ return safe(value);
|
|
|
+ }
|
|
|
+ return value.substring(0, maxLen);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 在单元格宽度内绘制文本:从 max 字号递减直至能放下全文;仍放不下则在最小字号下按宽度截断。
|
|
|
+ */
|
|
|
+ private static void drawStringFitCell(Graphics2D g2, String text, int cellX, int cellWidth, int padLeft, int padRight,
|
|
|
+ int baselineY, int maxFontSize, int minFontSize) {
|
|
|
+ String s = safe(text);
|
|
|
+ int avail = cellWidth - padLeft - padRight;
|
|
|
+ if (avail < 1) {
|
|
|
+ avail = 1;
|
|
|
+ }
|
|
|
+ Font old = g2.getFont();
|
|
|
+ int size = maxFontSize;
|
|
|
+ g2.setFont(new Font("SimSun", Font.PLAIN, size));
|
|
|
+ FontMetrics fm = g2.getFontMetrics();
|
|
|
+ while (size > minFontSize && fm.stringWidth(s) > avail) {
|
|
|
+ size--;
|
|
|
+ g2.setFont(new Font("SimSun", Font.PLAIN, size));
|
|
|
+ fm = g2.getFontMetrics();
|
|
|
+ }
|
|
|
+ String draw = s;
|
|
|
+ if (fm.stringWidth(draw) > avail) {
|
|
|
+ int lo = 0;
|
|
|
+ int hi = draw.length();
|
|
|
+ while (lo < hi) {
|
|
|
+ int mid = (lo + hi + 1) / 2;
|
|
|
+ if (fm.stringWidth(draw.substring(0, mid)) <= avail) {
|
|
|
+ lo = mid;
|
|
|
+ } else {
|
|
|
+ hi = mid - 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ draw = lo > 0 ? draw.substring(0, lo) : "";
|
|
|
+ }
|
|
|
+ g2.drawString(draw, cellX + padLeft, baselineY);
|
|
|
+ g2.setFont(old);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double mmToPoint(double mm) {
|
|
|
+ return mm * 72d / 25.4d;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class MaterialOrderPrintTask {
|
|
|
+ private final MesMaterialOrder order;
|
|
|
+ private final List<MesMaterialErp> items;
|
|
|
+
|
|
|
+ public MaterialOrderPrintTask(MesMaterialOrder order, List<MesMaterialErp> items) {
|
|
|
+ this.order = order;
|
|
|
+ this.items = items;
|
|
|
+ }
|
|
|
+
|
|
|
+ public MesMaterialOrder getOrder() {
|
|
|
+ return order;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<MesMaterialErp> getItems() {
|
|
|
+ return items;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|