From 4ca4444ad33a2a1a51f5c06e78ee9365dfb1eed6 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 08 十月 2026 17:11:11 +0800
Subject: [PATCH] feat(mes): 种子二维码标签国标四要素合规改造
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java | 202 ++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 187 insertions(+), 15 deletions(-)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java
index 822e040..65b9938 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/framework/qrcode/MesProQrLabelBuilder.java
@@ -2,22 +2,123 @@
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.regex.Pattern;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_LABEL_ITEM_NAME_MISSING;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_LABEL_OPERATOR_MISSING;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_LABEL_TRACE_URL_NOT_CONFIGURED;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_LABEL_UNIT_CODE_INVALID;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PRO_QR_LABEL_UNIT_CODE_MISSING;
/**
- * MES 浜岀淮鐮佹爣绛炬瀯寤哄櫒锛氱粺涓�"浜岀淮鐮佺紪鐮佺函鐮佸�� + 鍥剧墖鍙犲姞鍙鏂囨湰"鐨勬枃鏈粍瑁呰鍒欙紝
- * 淇濊瘉鎵规銆佹墭鐩樸�佽鐮佷笁绉嶆爣绛剧殑鍏抽敭淇℃伅淇濈暀涓�鑷�
+ * MES 浜岀淮鐮佹爣绛炬瀯寤哄櫒锛氱粺涓�"浜岀淮鐮佺紪鐮佸唴瀹� + 鍥剧墖鍙犲姞鍙鏂囨湰"鐨勬枃鏈粍瑁呰鍒欍��
+ * <p>
+ * 绉嶅瓙鏍囩鍙椼�婂啘浣滅墿绉嶅瓙鏍囩浜岀淮鐮佺紪鐮佽鍒欍�嬩笌銆婂啘浣滅墿绉嶅瓙鏍囩閫氬垯銆嬶紙GB 20464-2024锛夌害鏉燂紝
+ * 鏈�灏忛攢鍞崟鍏冪殑鏍囩蹇呴』鍖呭惈鍥涢」淇℃伅涓旀寜鍥哄畾椤哄簭鎺掑垪锛�
+ * <ol>
+ * <li>鍝佺鍚嶇О</li>
+ * <li>鐢熶骇缁忚惀鑰呭悕绉帮紙杩涘彛绉嶅瓙涓鸿繘鍙e晢鍚嶇О锛�</li>
+ * <li>鍗曞厓璇嗗埆浠g爜锛堜笉瓒呰繃 20 涓瓧绗︼紝鏁板瓧鎴栧瓧姣嶆暟瀛楃粍鍚堬級</li>
+ * <li>杩芥函缃戝潃</li>
+ * </ol>
+ * 鍥涜绱犵己澶卞嵆鏋勬垚涓嶅悎瑙勬爣绛撅紝鍥犳杩欓噷閲囧彇銆岀己澶卞嵆鎶涘紓甯搞�佹嫆缁濆鍑恒�嶇殑绛栫暐锛岀粷涓嶉潤榛樿烦杩団�斺��
+ * 闈欓粯璺宠繃姝f槸鏍囩缂洪」娴佸叆鍗板埛鐜妭鐨勬牴鍥犮��
+ * <p>
+ * 浜岀淮鐮佸唴瀹瑰湪閰嶇疆浜� {@code mes.trace-base-url} 鏃朵负甯� code 鍙傛暟鐨勬函婧� URL锛屽惁鍒欐寜
+ * {@code mes.allow-plain-qr-code} 鍐冲畾鏄惁闄嶇骇涓虹函鐮佸�硷紙浠呴檺鏈湴鍏煎鍘嗗彶鐮侊級銆�
*/
public final class MesProQrLabelBuilder {
private MesProQrLabelBuilder() {
+ }
+
+ /**
+ * 鍗曞厓璇嗗埆浠g爜鏍煎紡锛�1~20 浣嶆暟瀛楁垨瀛楁瘝鏁板瓧缁勫悎锛堝浗鏍囪姹傦紝涓嶅惈杩炲瓧绗︾瓑绗﹀彿锛�
+ */
+ private static final Pattern UNIT_CODE_PATTERN = Pattern.compile("^[0-9A-Za-z]{1,20}$");
+
+ /** H5 婧簮椤甸潰鍩虹鍦板潃锛岀敱 {@code MesQrCodeConfig} 鍚姩鏃舵敞鍏ワ紱涓虹┖鏃朵簩缁寸爜缂栫爜绾爜鍊� */
+ private static volatile String traceBaseUrl = "";
+ /** 鐢熶骇缁忚惀鑰呭悕绉帮紝鐢� {@code MesQrCodeConfig} 鍚姩鏃舵敞鍏� */
+ private static volatile String operatorName = "";
+ /** 杩涘彛鍟嗗悕绉帮紝杩涘彛绉嶅瓙鍦烘櫙浣跨敤 */
+ private static volatile String importerName = "";
+ /** 鏄惁杩涘彛绉嶅瓙鍦烘櫙 */
+ private static volatile boolean imported = false;
+ /** 鏄惁鍏佽浜岀淮鐮侀檷绾х紪鐮佺函鐮佸�硷紙浠呴檺鏈湴鍏煎鍘嗗彶鐮侊級 */
+ private static volatile boolean allowPlainQrCode = false;
+
+ public static void setTraceBaseUrl(String traceBaseUrl) {
+ MesProQrLabelBuilder.traceBaseUrl = StrUtil.blankToDefault(traceBaseUrl, "");
+ }
+
+ public static void setOperatorName(String operatorName) {
+ MesProQrLabelBuilder.operatorName = StrUtil.blankToDefault(operatorName, "");
+ }
+
+ public static void setImporterName(String importerName) {
+ MesProQrLabelBuilder.importerName = StrUtil.blankToDefault(importerName, "");
+ }
+
+ public static void setImported(boolean imported) {
+ MesProQrLabelBuilder.imported = imported;
+ }
+
+ public static void setAllowPlainQrCode(boolean allowPlainQrCode) {
+ MesProQrLabelBuilder.allowPlainQrCode = allowPlainQrCode;
+ }
+
+ /**
+ * 褰撳墠搴旀爣娉ㄧ殑鐢熶骇缁忚惀鑰呭悕绉帮細杩涘彛绉嶅瓙鍦烘櫙浼樺厛鍙栬繘鍙e晢鍚嶇О锛屽惁鍒欏彇鐢熶骇缁忚惀鑰呭悕绉�
+ *
+ * @return 鍚嶇О锛屾湭閰嶇疆鏃惰繑鍥炵┖涓�
+ */
+ public static String resolveOperatorName() {
+ if (imported && StrUtil.isNotBlank(importerName)) {
+ return importerName;
+ }
+ return operatorName;
+ }
+
+ /**
+ * 杩芥函缃戝潃锛堝澶栧睍绀虹敤锛屼笉鍚� code 鍙傛暟锛�
+ */
+ public static String resolveTraceUrl() {
+ return traceBaseUrl;
+ }
+
+ /**
+ * 鏄惁杩涘彛绉嶅瓙鍦烘櫙锛氫负 true 鏃舵爣绛句笌婧簮椤靛簲灞曠ず銆岃繘鍙e晢鍚嶇О銆�
+ */
+ public static boolean isImported() {
+ return imported;
+ }
+
+ /**
+ * 缁勮浜岀淮鐮佸唴瀹癸細閰嶇疆浜嗘函婧愬湴鍧�鍒欐嫾 URL锛屽惁鍒欐寜寮�鍏冲喅瀹氭槸鍚﹂檷绾т负绾爜鍊�
+ * <p>
+ * 鏈厤缃函婧愬湴鍧�涓旀湭寮�鍚檷绾у紑鍏虫椂鐩存帴鎶ラ敊锛岄伩鍏嶅嵃鍑轰笉鍚拷婧綉鍧�鐨勬爣绛俱��
+ */
+ private static String buildQrCodeContent(String code) {
+ if (StrUtil.isEmpty(traceBaseUrl)) {
+ if (allowPlainQrCode) {
+ return code;
+ }
+ throw exception(PRO_QR_LABEL_TRACE_URL_NOT_CONFIGURED);
+ }
+ return traceBaseUrl + "?code=" + URLEncoder.encode(code, StandardCharsets.UTF_8);
}
/**
@@ -51,7 +152,7 @@
if (user != null) {
keyValues.put("璐d换浜�", user.getNickname());
}
- return QrLabelInfo.builder().fileName(code).code(code).keyValues(keyValues).build();
+ return QrLabelInfo.builder().fileName(code).code(buildQrCodeContent(code)).keyValues(keyValues).build();
}
/**
@@ -76,44 +177,115 @@
keyValues.put("宸茶琚嬫暟", String.valueOf(pallet.getBagCount()));
}
if (batch != null) {
+ // 鍝佺鍗曠嫭鍙栨壒娆″搧绉嶏細fillBatchKeyValues 宸蹭笉鍐嶅啓鍏ュ搧绉嶏紝閬垮厤涓庤鐮佸搧绉嶄簰鐩歌鐩�
+ MesMdmItemDO batchItem = itemMap.get(batch.getItemId());
+ if (batchItem != null && StrUtil.isNotEmpty(batchItem.getName())) {
+ keyValues.put("鍝佺", batchItem.getName());
+ }
fillBatchKeyValues(keyValues, batch, itemMap, userMap);
}
- return QrLabelInfo.builder().fileName(code).code(code).keyValues(keyValues).build();
+ return QrLabelInfo.builder().fileName(code).code(buildQrCodeContent(code)).keyValues(keyValues).build();
}
/**
- * 琚嬬爜浜岀淮鐮佹爣绛�
+ * 琚嬬爜浜岀淮鐮佹爣绛撅紙鏈�灏忛攢鍞崟鍏冿級
+ * <p>
+ * 鎸夊浗鏍囪姹傦紝鍥涜绱犵疆浜庢爣绛炬渶鍓嶅苟鎸夊浐瀹氶『搴忔帓鍒楋細鍝佺鍚嶇О 鈫� 鐢熶骇缁忚惀鑰� 鈫� 鍗曞厓璇嗗埆浠g爜 鈫� 杩芥函缃戝潃锛�
+ * 琚嬪簭鍙枫�佹壒娆″彿銆佷骇绾裤�佽矗浠讳汉绛夌敓浜т俊鎭綔涓鸿緟鍔╁唴瀹规帓鍒楀湪鍏跺悗銆傚洓瑕佺礌浠讳竴缂哄け鍗虫姏寮傚父锛屾嫆缁濆鍑恒��
*/
public static QrLabelInfo buildBagCodeLabel(MesProBagCodeDO bagCode,
MesProBatchDO batch,
Map<Long, MesMdmItemDO> itemMap,
Map<Long, AdminUserRespDTO> userMap) {
LinkedHashMap<String, String> keyValues = new LinkedHashMap<>();
- keyValues.put("琚嬬爜", bagCode.getCode());
- keyValues.put("琚嬪簭鍙�", bagCode.getBagNo() == null ? "" : String.valueOf(bagCode.getBagNo()));
- keyValues.put("鎵规鍙�", bagCode.getBatchCode());
+
+ // ===== 鍥涜绱狅紙鍥芥爣瑕佹眰锛岄『搴忓浐瀹氾紝缂哄け鍗抽樆鏂鍑猴級=====
+ putRequired(keyValues, "鍝佺鍚嶇О", resolveItemName(bagCode, batch, itemMap),
+ PRO_QR_LABEL_ITEM_NAME_MISSING);
+ putRequired(keyValues, imported ? "杩涘彛鍟嗗悕绉�" : "鐢熶骇缁忚惀鑰呭悕绉�", resolveOperatorName(),
+ PRO_QR_LABEL_OPERATOR_MISSING);
+ putRequired(keyValues, "鍗曞厓璇嗗埆浠g爜", resolveUnitCode(bagCode.getCode()),
+ PRO_QR_LABEL_UNIT_CODE_MISSING);
+ putRequired(keyValues, "杩芥函缃戝潃", resolveTraceUrl(), PRO_QR_LABEL_TRACE_URL_NOT_CONFIGURED);
+
+ // ===== 浠ヤ笅涓鸿緟鍔╃敓浜т俊鎭� =====
+ if (bagCode.getBagNo() != null) {
+ keyValues.put("琚嬪簭鍙�", String.valueOf(bagCode.getBagNo()));
+ }
+ if (StrUtil.isNotEmpty(bagCode.getBatchCode())) {
+ keyValues.put("鎵规鍙�", bagCode.getBatchCode());
+ }
if (StrUtil.isNotEmpty(bagCode.getPalletCode())) {
keyValues.put("缁戝畾鎵樼洏", bagCode.getPalletCode());
}
if (batch != null) {
fillBatchKeyValues(keyValues, batch, itemMap, userMap);
}
- return QrLabelInfo.builder().fileName(bagCode.getCode()).code(bagCode.getCode()).keyValues(keyValues).build();
+ return QrLabelInfo.builder()
+ .fileName(bagCode.getCode())
+ .code(buildQrCodeContent(bagCode.getCode()))
+ .keyValues(keyValues)
+ .build();
}
/**
- * 濉厖鎵规鍏叡鍙鏂囨湰锛堝搧绉嶃�佽鏍笺�佷骇绾裤�佺敓浜ф棩鏈熴�佽矗浠讳汉锛�
+ * 鍐欏叆蹇呭~瀛楁锛氬�间负绌烘椂鎶涘嚭瀵瑰簲寮傚父锛岀粷涓嶉潤榛樿烦杩�
+ */
+ private static void putRequired(LinkedHashMap<String, String> keyValues, String label,
+ String value, ErrorCode errorCode) {
+ if (StrUtil.isBlank(value)) {
+ throw exception(errorCode);
+ }
+ keyValues.put(label, value.trim());
+ }
+
+ /**
+ * 瑙f瀽鍝佺鍚嶇О锛氫紭鍏堝彇琚嬬爜鑷韩缁戝畾鐨勫搧绉嶏紙鏁版嵁鍖呯敓鎴愭椂鍐欏叆锛屾湭褰曟壒娆′篃鍙嵃鍒凤級锛�
+ * 琚嬬爜鏈粦瀹氬搧绉嶆椂鍥為��鎵规鍝佺銆�
+ */
+ private static String resolveItemName(MesProBagCodeDO bagCode, MesProBatchDO batch,
+ Map<Long, MesMdmItemDO> itemMap) {
+ if (StrUtil.isNotBlank(bagCode.getItemName())) {
+ return bagCode.getItemName();
+ }
+ if (batch == null) {
+ return null;
+ }
+ MesMdmItemDO item = itemMap.get(batch.getItemId());
+ return item == null ? null : item.getName();
+ }
+
+ /**
+ * 鏍¢獙骞惰繑鍥炲崟鍏冭瘑鍒唬鐮侊紙鍥芥爣锛氫笉瓒呰繃 20 涓瓧绗︼紝鏁板瓧鎴栧瓧姣嶆暟瀛楃粍鍚堬級
+ */
+ private static String resolveUnitCode(String code) {
+ if (StrUtil.isBlank(code)) {
+ return null;
+ }
+ if (!UNIT_CODE_PATTERN.matcher(code).matches()) {
+ throw exception(PRO_QR_LABEL_UNIT_CODE_INVALID);
+ }
+ return code;
+ }
+
+ /**
+ * 濉厖鎵规鍏叡鍙鏂囨湰锛堣鏍笺�佷骇绾裤�佺敓浜ф棩鏈熴�佽矗浠讳汉锛�
+ * <p>
+ * 娉ㄦ剰锛氭澶勪笉鍐嶅啓鍏ャ�屽搧绉嶃�嶏紝鍝佺鍚嶇О缁熶竴鐢� {@link #resolveItemName} 瑙f瀽锛�
+ * 閬垮厤鎵规鍝佺瑕嗙洊琚嬬爜鍝佺瀵艰嚧鏍囩涓庢函婧愰〉灞曠ず涓嶄竴鑷淬��
*/
private static void fillBatchKeyValues(LinkedHashMap<String, String> keyValues, MesProBatchDO batch,
Map<Long, MesMdmItemDO> itemMap, Map<Long, AdminUserRespDTO> userMap) {
MesMdmItemDO item = itemMap.get(batch.getItemId());
- if (item != null) {
- keyValues.put("鍝佺", item.getName());
+ if (item != null && StrUtil.isNotEmpty(item.getSpecification())) {
keyValues.put("瑙勬牸", item.getSpecification());
}
- keyValues.put("浜х嚎", StrUtil.join(" / ", batch.getLineName(), batch.getLineCode()));
- keyValues.put("鐢熶骇鏃ユ湡", batch.getProduceDate() == null ? ""
- : LocalDateTimeUtil.format(batch.getProduceDate(), "yyyy-MM-dd HH:mm"));
+ if (StrUtil.isNotEmpty(batch.getLineName()) || StrUtil.isNotEmpty(batch.getLineCode())) {
+ keyValues.put("浜х嚎", StrUtil.join(" / ", batch.getLineName(), batch.getLineCode()));
+ }
+ if (batch.getProduceDate() != null) {
+ keyValues.put("鐢熶骇鏃ユ湡", LocalDateTimeUtil.format(batch.getProduceDate(), "yyyy-MM-dd HH:mm"));
+ }
AdminUserRespDTO user = userMap.get(batch.getOwnerUserId());
if (user != null) {
keyValues.put("璐d换浜�", user.getNickname());
--
Gitblit v1.9.3