From 0f11bea64e963b2231875760bd4e9103e99b8a63 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 09 十月 2026 16:00:17 +0800
Subject: [PATCH] refactor(mes): 重构二维码标签生成逻辑

---
 yudao-server/src/main/resources/static/trace.html                                                 |   24 +------
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/QrCodeImageUtils.java |  149 ++++++++-----------------------------------------
 yudao-server/src/main/resources/application-local.yaml                                            |    2 
 3 files changed, 30 insertions(+), 145 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/QrCodeImageUtils.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/QrCodeImageUtils.java
index a3fa297..c35c287 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/QrCodeImageUtils.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/QrCodeImageUtils.java
@@ -17,10 +17,7 @@
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -28,9 +25,7 @@
 /**
  * 浜岀淮鐮佹爣绛惧浘鐗囧伐鍏风被
  * <p>
- * 鐢熸垚"浜岀淮鐮� + 鍙充晶鍙鏂囨湰"鐨勫悎鎴愬浘鐗囷細浜岀淮鐮佺紪鐮佸唴瀹圭敱璋冪敤鏂逛紶鍏ワ紙閰嶇疆浜嗘函婧愬湴鍧�鏃朵负
- * 甯� code 鍙傛暟鐨勬函婧� URL锛屾湭閰嶇疆鏃朵负绾爜鍊硷級锛屽彸渚у彔鍔犲叧閿俊鎭枃鏈紝
- * 鍗充娇鏁版嵁搴撲涪澶变篃鑳戒粠鎵撳嵃鍥剧墖杩樺師鍏抽敭淇℃伅銆�
+ * 鐢熸垚浜岀淮鐮佸湪涓娿�佺爜鍊煎湪涓嬬殑绱у噾鏍囩銆備簩缁寸爜鍐呭浠嶄娇鐢ㄨ皟鐢ㄦ柟浼犲叆鐨勬函婧愰摼鎺ャ��
  */
 @Slf4j
 public final class QrCodeImageUtils {
@@ -46,15 +41,11 @@
     /** 鍥剧墖鍥涘懆鐣欑櫧 */
     private static final int PADDING = 16;
     /** 浜岀淮鐮佷笌鏂囨湰闂磋窛 */
-    private static final int GAP = 24;
-    /** 鏂囨湰鍖哄煙瀹藉害 */
-    private static final int TEXT_WIDTH = 380;
+    private static final int GAP = 4;
     /** 瀛椾綋澶у皬 */
-    private static final int FONT_SIZE = 15;
+    private static final int FONT_SIZE = 24;
     /** 琛岄珮 */
-    private static final int LINE_HEIGHT = 24;
-    /** 瀛楁闂磋窛 */
-    private static final int FIELD_GAP = 6;
+    private static final int LINE_HEIGHT = 32;
 
     /**
      * 涓枃瀛椾綋鍊欓�夛紙鎸変紭鍏堢骇锛夈��
@@ -76,43 +67,39 @@
     /**
      * 鐢熸垚浜岀淮鐮佹爣绛惧浘鐗�
      *
-     * @param code      浜岀淮鐮佸唴瀹癸紙绾爜鍊硷級
-     * @param keyValues 鍙犲姞鐨勫彲璇绘枃鏈紙椤哄簭鍗崇粯鍒堕『搴忥級
+     * @param code        浜岀淮鐮佸唴瀹癸紙婧簮閾炬帴鎴栫函鐮佸�硷級
+     * @param displayCode 浜岀淮鐮佷笅鏂规樉绀虹殑鍘熷鐮佸��
      * @return 鍚堟垚鍥剧墖
      */
-    public static BufferedImage createQrLabel(String code, LinkedHashMap<String, String> keyValues) {
-        // 鏃犱腑鏂囧瓧浣撴椂鐩存帴澶辫触锛岄伩鍏嶅鍑轰腑鏂囦负鏂规鐨勬爣绛�
-        assertCjkFontAvailable();
+    public static BufferedImage createQrLabel(String code, String displayCode) {
         QrConfig config = new QrConfig();
-        config.setErrorCorrection(ErrorCorrectionLevel.H); // 鎵撳嵃鏍囩鏄撶(鎹燂紝鐢ㄩ珮瀹归敊
-        config.setMargin(1); // 淇濊瘉闈欏尯锛屾壂鐮佺巼
+        config.setErrorCorrection(ErrorCorrectionLevel.H);
+        config.setMargin(4); // 淇濈暀浜岀淮鐮侀潤鍖猴紝淇濊瘉鎵撳嵃鍚庣殑璇嗚鐜�
         config.setWidth(QR_SIZE);
         config.setHeight(QR_SIZE);
         BufferedImage qrImage = QrCodeUtil.generate(code, config);
 
-        Font labelFont = new Font(FONT_NAME, Font.BOLD, FONT_SIZE);
-        Font valueFont = new Font(FONT_NAME, Font.PLAIN, FONT_SIZE);
-
-        // 绗竴閬嶏細娴嬮噺鏂囨湰鍧楁�婚珮搴︼紝鐢ㄤ簬纭畾鍥剧墖楂樺害
-        int textHeight = measureTextHeight(keyValues, labelFont, valueFont);
-
-        int height = PADDING * 2 + Math.max(QR_SIZE, textHeight);
-        int width = PADDING * 2 + QR_SIZE + GAP + TEXT_WIDTH;
-
+        int width = PADDING * 2 + QR_SIZE;
+        int height = PADDING * 2 + QR_SIZE + GAP + LINE_HEIGHT;
         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
         Graphics2D g = image.createGraphics();
         try {
-            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
             g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
             g.setColor(Color.WHITE);
             g.fillRect(0, 0, width, height);
-            // 浜岀淮鐮侊紙鍨傜洿灞呬腑锛�
-            int qrY = (height - QR_SIZE) / 2;
-            g.drawImage(qrImage, PADDING, qrY, null);
-            // 鍙鏂囨湰
-            int textX = PADDING + QR_SIZE + GAP;
-            int textY = (height - textHeight) / 2;
-            drawKeyValues(g, keyValues, labelFont, valueFont, textX, textY);
+            g.drawImage(qrImage, PADDING, PADDING, null);
+            String text = StrUtil.nullToEmpty(displayCode);
+            int fontSize = FONT_SIZE;
+            g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, fontSize));
+            while (g.getFontMetrics().stringWidth(text) > QR_SIZE && fontSize > 1) {
+                g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, --fontSize));
+            }
+            FontMetrics metrics = g.getFontMetrics();
+            int textX = (width - metrics.stringWidth(text)) / 2;
+            int textY = PADDING + QR_SIZE + GAP
+                    + (LINE_HEIGHT - metrics.getHeight()) / 2 + metrics.getAscent();
+            g.setColor(Color.BLACK);
+            g.drawString(text, textX, textY);
         } finally {
             g.dispose();
         }
@@ -133,7 +120,7 @@
         ZipOutputStream zip = new ZipOutputStream(response.getOutputStream());
         try {
             for (QrLabelInfo label : labels) {
-                BufferedImage image = createQrLabel(label.getCode(), label.getKeyValues());
+                BufferedImage image = createQrLabel(label.getCode(), label.getFileName());
                 zip.putNextEntry(new ZipEntry(label.getFileName() + ".png"));
                 ImageIO.write(image, "png", zip);
                 zip.closeEntry();
@@ -187,92 +174,6 @@
             throw new IllegalStateException("褰撳墠鐜娌℃湁浠讳綍鍙覆鏌撲腑鏂囩殑瀛椾綋锛屼簩缁寸爜鏍囩鐨勪腑鏂囧皢鏄剧ず涓烘柟妗嗭紝"
                     + "鎷掔粷鐢熸垚鏍囩銆傝鍦ㄦ湇鍔″櫒瀹夎涓枃瀛椾綋锛堝 fonts-noto-cjk锛夊悗閲嶅惎銆�");
         }
-    }
-
-    private static int measureTextHeight(LinkedHashMap<String, String> keyValues, Font labelFont, Font valueFont) {
-        BufferedImage scratch = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
-        Graphics2D g = scratch.createGraphics();
-        try {
-            return measureKeyValuesHeight(g, keyValues, labelFont, valueFont);
-        } finally {
-            g.dispose();
-        }
-    }
-
-    private static int measureKeyValuesHeight(Graphics2D g, LinkedHashMap<String, String> keyValues,
-                                              Font labelFont, Font valueFont) {
-        int total = 0;
-        for (Map.Entry<String, String> entry : keyValues.entrySet()) {
-            String label = StrUtil.emptyToDefault(entry.getKey(), "") + "锛�";
-            String value = StrUtil.emptyToDefault(entry.getValue(), "");
-            g.setFont(labelFont);
-            int labelWidth = g.getFontMetrics().stringWidth(label);
-            g.setFont(valueFont);
-            List<String> lines = wrapText(g, value, TEXT_WIDTH - labelWidth);
-            total += Math.max(1, lines.size()) * LINE_HEIGHT + FIELD_GAP;
-        }
-        return total;
-    }
-
-    private static void drawKeyValues(Graphics2D g, LinkedHashMap<String, String> keyValues,
-                                      Font labelFont, Font valueFont, int x, int y) {
-        FontMetrics labelMetrics = g.getFontMetrics(labelFont);
-        int baselineOffset = labelMetrics.getAscent(); // drawString 鐨� y 鏄熀绾匡紝鍏堜笅绉讳竴涓� ascent
-        int baseline = y + baselineOffset;
-        for (Map.Entry<String, String> entry : keyValues.entrySet()) {
-            String label = StrUtil.emptyToDefault(entry.getKey(), "") + "锛�";
-            String value = StrUtil.emptyToDefault(entry.getValue(), "");
-
-            g.setFont(labelFont);
-            int labelWidth = g.getFontMetrics().stringWidth(label);
-            g.setColor(Color.BLACK);
-            g.drawString(label, x, baseline);
-
-            g.setFont(valueFont);
-            int remainingWidth = TEXT_WIDTH - labelWidth;
-            List<String> lines = wrapText(g, value, remainingWidth);
-            if (!lines.isEmpty()) {
-                g.drawString(lines.get(0), x + labelWidth, baseline);
-                baseline += LINE_HEIGHT;
-                for (int i = 1; i < lines.size(); i++) {
-                    g.drawString(lines.get(i), x, baseline);
-                    baseline += LINE_HEIGHT;
-                }
-            } else {
-                baseline += LINE_HEIGHT;
-            }
-            baseline += FIELD_GAP;
-        }
-    }
-
-    /**
-     * 鏂囨湰鎸夋渶澶у搴︽崲琛岋紙閫愬瓧娴嬮噺锛屽吋瀹逛腑鏂囷級
-     */
-    private static List<String> wrapText(Graphics2D g, String text, int maxWidth) {
-        List<String> lines = new ArrayList<>();
-        if (StrUtil.isEmpty(text)) {
-            return lines;
-        }
-        if (maxWidth <= 0) {
-            lines.add(text);
-            return lines;
-        }
-        StringBuilder current = new StringBuilder();
-        FontMetrics metrics = g.getFontMetrics();
-        for (int i = 0; i < text.length(); i++) {
-            char ch = text.charAt(i);
-            String test = current.toString() + ch;
-            if (metrics.stringWidth(test) > maxWidth && current.length() > 0) {
-                lines.add(current.toString());
-                current = new StringBuilder().append(ch);
-            } else {
-                current.append(ch);
-            }
-        }
-        if (current.length() > 0) {
-            lines.add(current.toString());
-        }
-        return lines;
     }
 
 }
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index b2adc31..9650226 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -4,7 +4,7 @@
 # 绉嶅瓙鏍囩涓� H5 婧簮椤甸厤缃�
 mes:
   # 杩芥函缃戝潃锛堜簩缁寸爜鍐呭鍓嶇紑锛夛紝闇�涓哄叕浼楁壂鐮佸彲璁块棶鐨勫湴鍧�
-  trace-base-url: http://192.168.1.7:48080/trace.html
+  trace-base-url: http://192.168.0.10:48080/trace.html
   # 鐢熶骇缁忚惀鑰呭悕绉帮紙绉嶅瓙鏍囩鍥涜绱犱箣涓�锛屾爣绛句笌婧簮椤电粺涓�鍙栨鍊硷紱鏈厤缃垯鏃犳硶瀵煎嚭鏍囩锛�
   operator-name: 鏂扮枂濉旈噷鏈ㄦ渤绉嶄笟鑲′唤鏈夐檺鍏徃
 
diff --git a/yudao-server/src/main/resources/static/trace.html b/yudao-server/src/main/resources/static/trace.html
index 128d955..7579fb3 100644
--- a/yudao-server/src/main/resources/static/trace.html
+++ b/yudao-server/src/main/resources/static/trace.html
@@ -323,7 +323,7 @@
         </div>
         <div class="contact-item">
           <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 1.9.7 2.8a2 2 0 0 1-.5 2.1L8.1 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.6 2.8.7a2 2 0 0 1 1.7 2z"/></svg></span>
-          <span class="txt"><span class="lbl">鑱旂郴鐢佃瘽</span><div class="val">琛屾斂绠$悊閮細<a href="tel:09974615802">0997-4615802</a></div></span>
+          <span class="txt"><span class="lbl">鑱旂郴鐢佃瘽</span><div class="val">缁煎悎绠$悊閮細<a href="tel:09974615802">0997-4615802</a></div></span>
         </div>
         <div class="contact-item">
           <span class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5 12 3l9 6.5V20a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9.5 22v-6h5v6"/></svg></span>
@@ -501,8 +501,8 @@
     var html = '';
     html += sec('闃蹭吉鏌ヨ', null, fakePanel(d), null);
     html += sec('杩芥函鏌ヨ', null, tracePanel(d), null);
-    // 鐢熶骇鏄庣粏鎶樺彔鍖猴細鍥芥爣瑕佹眰杩芥函缃戝潃鍙煡璇€�岀瀛愬姞宸ユ壒娆°�嶅強銆岀墿娴侀攢鍞俊鎭�嶏紝鏁呭澶栧睍绀�
-    // 锛堝姞宸ユ壒娆°�佺瀛愭祦鍚戙�佸姞宸ユ祦杞紱鎶樺彔涓嶅睍寮�锛夈�傝川妫�/浜哄憳/鎵樼洏/琚嬬爜/閲囪喘鏉ユ簮绛夊唴閮ㄦ槑缁嗕笉瀵瑰灞曠ず锛�
+    // 鐢熶骇鏄庣粏鎶樺彔鍖猴細瀵瑰灞曠ず绉嶅瓙娴佸悜銆佸姞宸ユ祦杞紝鐢熶骇鎵规淇℃伅涓嶅睍绀恒��
+    // 璐ㄦ/浜哄憳/鎵樼洏/琚嬬爜/閲囪喘鏉ユ簮绛夊唴閮ㄦ槑缁嗕笉瀵瑰灞曠ず锛�
     // 濡傞渶涓�骞跺睍绀猴紝鏀逛负 detailSections(d, true) 鍗冲彲銆�
     html += detailSections(d, false);
     STATE.innerHTML = html || '<div class="empty-tip">鏆傛棤杩芥函鏁版嵁</div>';
@@ -592,25 +592,9 @@
 
   // 鍖哄潡3~锛氱敓浜ф槑缁嗭紙鎶樺彔锛屾湁鏁版嵁鎵嶅睍绀猴級
   // full=true 鏃跺睍绀哄叏閮ㄦ槑缁嗭紙璐ㄦ/浜哄憳/鎵樼洏/琚嬬爜/閲囪喘鏉ユ簮锛夛紱
-  // 榛樿鍙睍绀哄浗鏍囪姹傜殑銆屽姞宸ユ壒娆°�嶄笌銆岀墿娴侀攢鍞紙绉嶅瓙娴佸悜锛夈�嶄俊鎭紝鍏朵綑鍖哄潡涓嶅澶栧睍绀恒��
+  // 榛樿鍙睍绀虹墿娴侀攢鍞紙绉嶅瓙娴佸悜锛変俊鎭紝鍏朵綑鍖哄潡涓嶅澶栧睍绀恒��
   function detailSections(d, full) {
     var html = '';
-
-    // 鐢熶骇鎵规淇℃伅锛堝浗鏍囪姹傦細杩芥函缃戝潃搴斿彲鏌ヨ绉嶅瓙鍔犲伐鎵规锛�
-    // 鏈綍鍏ユ壒娆℃椂涓嶅睍绀虹┖鍖哄潡锛岄伩鍏嶇粰鍑�"鏃犲姞宸ユ壒娆′俊鎭�"鐨勯敊璇殫绀�
-    if (d.batchBound !== false) {
-      var batchBody =
-        kv('鎵规鍙�', text(d.batchCode)) +
-        kv('鎵规鐘舵��', d.batchStatusName ? statusBadge({ v: [d.batchStatusName, 'blue'] }, 'v') : text(d.batchStatus)) +
-        kv('鐢熶骇鏃ユ湡', fmtDate(d.produceDate)) +
-        kv('浜х嚎', text(d.lineName || d.lineCode)) +
-        kv('璁″垝鏁伴噺', fmtNum(d.planQuantity)) +
-        kv('宸茬敓鎴愯鐮�', fmtNum(d.bagQuantity)) +
-        kv('宸茬敓鎴愭墭鐩�', fmtNum(d.palletQuantity)) +
-        kv('鍏ュ簱鏃堕棿', fmtDate(d.inboundTime)) +
-        kv('澶囨敞', text(d.remark));
-      html += sec('鐢熶骇鎵规淇℃伅', null, batchBody, { collapsible: true, open: false });
-    }
 
     // 璐ㄦ淇℃伅锛堜粎瀹屾暣妯″紡灞曠ず锛�
     if (full && d.quality) {

--
Gitblit v1.9.3