From 185de1fc8e15432a5202405b154aebc694754c6f Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Thu, 30 Jul 2026 14:03:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=96=E7=AE=B1=E6=A0=87=E7=AD=BE=E5=8F=AF?= =?UTF-8?q?=E8=BF=9E=E5=B8=A6=E6=89=93=E5=8D=B0=E5=86=85=E7=AE=B1=E6=A0=87?= =?UTF-8?q?=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/entity/PrintLabelRequest.java | 1 + .../Impl/LabelDataProcessorServiceImpl.java | 44 ++- .../Impl/ReportLabelListServiceImpl.java | 334 ++++++++++++++---- 3 files changed, 309 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/gaotao/modules/base/entity/PrintLabelRequest.java b/src/main/java/com/gaotao/modules/base/entity/PrintLabelRequest.java index 48fc6ff..804c0e8 100644 --- a/src/main/java/com/gaotao/modules/base/entity/PrintLabelRequest.java +++ b/src/main/java/com/gaotao/modules/base/entity/PrintLabelRequest.java @@ -29,5 +29,6 @@ public class PrintLabelRequest { private String lineNo; // 行号 private String relNo; // 关联号 private Integer lineItemNo; // 行项目号 + private List innerBox; // 内箱标签数量列表(每个元素对应一份内箱标签的qty) private Map customFields; // 前端补充字段(视图无字段时用于标签替换) } diff --git a/src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java b/src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java index fd62914..f95e33f 100644 --- a/src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java +++ b/src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java @@ -42,6 +42,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService private static final Pattern DATA_SOURCE_PATTERN = Pattern.compile("#\\{([^}]+)\\}"); private static final String CUSTOM_FIELDS_CONTEXT_KEY = "__CUSTOM_FIELDS_CONTEXT__"; private static final String RESOLVED_LABEL_DATA_LIST_KEY = "__RESOLVED_LABEL_DATA_LIST__"; + private static final String CACHED_IFS_VIEW_DATA_LIST_KEY = "__CACHED_IFS_VIEW_DATA_LIST__"; /** * 从数据映射中取值:保持原有精确匹配逻辑,未命中时再从前端补充字段中按大小写不敏感匹配 @@ -1962,11 +1963,19 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService log.info("获取到主视图数据记录数: {}", mainViewDataList.size()); } - // 3.2 查询IFS视图数据(从IFS API获取) + // 3.2 查询IFS视图数据(优先复用缓存,避免同一次请求重复调用IFS API) List> ifsViewDataList = new ArrayList<>(); if (ifsViewSql != null && !ifsViewSql.trim().isEmpty()) { - ifsViewDataList = getIfsDataFromApi(queryParams); - log.info("从IFS API获取到数据记录数: {}", ifsViewDataList.size()); + ifsViewDataList = getCachedIfsDataFromQueryParams(queryParams); + if (ifsViewDataList.isEmpty()) { + ifsViewDataList = getIfsDataFromApi(queryParams); + if (queryParams != null) { + queryParams.put(CACHED_IFS_VIEW_DATA_LIST_KEY, ifsViewDataList); + } + log.info("从IFS API获取到数据记录数: {}", ifsViewDataList.size()); + } else { + log.info("复用缓存IFS数据记录数: {}", ifsViewDataList.size()); + } if (ifsViewDataList.isEmpty()) { throw new RuntimeException("ifs视图数据获取失败"); } @@ -2077,6 +2086,35 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService return Collections.emptyMap(); } + /** + * 从queryParams提取缓存的IFS数据 + */ + private List> getCachedIfsDataFromQueryParams(Map queryParams) { + if (queryParams == null) { + return Collections.emptyList(); + } + Object cachedIfsDataObj = queryParams.get(CACHED_IFS_VIEW_DATA_LIST_KEY); + if (!(cachedIfsDataObj instanceof List cachedIfsDataList) || cachedIfsDataList.isEmpty()) { + return Collections.emptyList(); + } + List> normalizedResult = new ArrayList<>(); + for (Object rowObj : cachedIfsDataList) { + if (!(rowObj instanceof Map rowMap)) { + continue; + } + Map normalizedRow = new HashMap<>(); + for (Map.Entry entry : rowMap.entrySet()) { + if (entry.getKey() != null) { + normalizedRow.put(entry.getKey().toString(), entry.getValue()); + } + } + if (!normalizedRow.isEmpty()) { + normalizedResult.add(normalizedRow); + } + } + return normalizedResult; + } + /** * 判断是否为系统变量 * diff --git a/src/main/java/com/gaotao/modules/base/service/Impl/ReportLabelListServiceImpl.java b/src/main/java/com/gaotao/modules/base/service/Impl/ReportLabelListServiceImpl.java index 1089bab..79764ef 100644 --- a/src/main/java/com/gaotao/modules/base/service/Impl/ReportLabelListServiceImpl.java +++ b/src/main/java/com/gaotao/modules/base/service/Impl/ReportLabelListServiceImpl.java @@ -692,32 +692,13 @@ public class ReportLabelListServiceImpl extends ServiceImpl labelSettingDataList = baseService.getLabelSettingList(labelSettingData); - LabelSettingData labelSetting; - if (labelSettingDataList.isEmpty()) { - throw new RuntimeException("未找到对应的标签"); - } else { - labelSetting = labelSettingDataList.getFirst(); - rfidFlag = labelSetting.getRfidFlag(); - } + LabelSettingData outerLabelSetting = getRequiredLabelSetting(resolvedReportId, printRequest.getLabelType()); + String outerRfidFlag = outerLabelSetting.getRfidFlag(); try { // 1. 构建查询参数Map - Map queryParams = new HashMap<>(); - queryParams.put("site", printRequest.getSite()); - List unitIds = printRequest.getUnitIds(); - queryParams.put("unitIds", unitIds); - // ifs外箱标签视图 - queryParams.put("consignmentId", printRequest.getConsignmentId()); - queryParams.put("jobNo", printRequest.getJobNo()); - queryParams.put("lineNo", printRequest.getLineNo()); - queryParams.put("relNo", printRequest.getRelNo()); - queryParams.put("lineItemNo", printRequest.getLineItemNo()); + Map queryParams = buildCommonQueryParams(printRequest); /* 添加自定义字段 前端补充字段(视图无字段时用于标签替换)比如标签有一个元素是#{qty},是视图里不存在的,前端传入 { "reportId": "xxx", @@ -725,6 +706,7 @@ public class ReportLabelListServiceImpl extends ServiceImpl zplCodeList = previewLabelWithRealData(labelSetting.getLabelNo(), true, queryParams); + // 2. 生成外箱标签:带真实数据的ZPL代码和对应数据 + List zplCodeList = previewLabelWithRealData(outerLabelSetting.getLabelNo(), true, queryParams); // 同时获取原始数据用于保存WMS标签记录 - List> labelDataList = getLabelDataForPrint(labelSetting.getLabelNo(), queryParams); - // 2. 验证ZPL代码 + List> labelDataList = getLabelDataForPrint(outerLabelSetting.getLabelNo(), queryParams); + // 3. 验证ZPL代码 if (zplCodeList == null || zplCodeList.isEmpty()) { throw new RuntimeException("ZPL代码获取失败"); } - log.info("生成了 {} 个ZPL代码,准备打印", zplCodeList.size()); - // 3. 获取用户的打印机配置 - UserLabelPrinterData printerQuery = new UserLabelPrinterData(); - printerQuery.setUserId(printRequest.getUserId()); - printerQuery.setLabelNo(labelSetting.getLabelNo()); - List printers = baseService.getUserLabelPrinters(printerQuery); - if (printers.isEmpty()) { - throw new RuntimeException("未找到指定的打印机配置"); - } - UserLabelPrinterData printer = printers.getFirst(); - String printerIP = printer.getIpAddress(); - if (printerIP == null || printerIP.trim().isEmpty()) { - throw new RuntimeException("打印机IP地址未配置"); - } - // 4. 处理打印份数 - int requestedCopies = 1; + log.info("生成了 {} 个外箱标签ZPL代码,准备打印", zplCodeList.size()); - // 5. 将所有打印任务添加到队列中(不直接打印) + // 4. 获取外箱标签打印机配置 + UserLabelPrinterData outerPrinter = getRequiredLabelPrinter(printRequest.getUserId(), outerLabelSetting.getLabelNo()); + + // 5. 将外箱打印任务加入队列(不直接打印) int totalLabels = zplCodeList.size(); List taskIds = new ArrayList<>(); - for (int i = 0; i < totalLabels; i++) { String zplCode = zplCodeList.get(i); Map labelData = i < labelDataList.size() ? labelDataList.get(i) : new HashMap<>(); - - // 如果是RFID标签,在这里组装完整的RFID ZPL(包含写EPC指令) - if ("Y".equals(rfidFlag)) { - zplCode = buildRfidZpl(zplCode, labelData); - log.info("已组装RFID ZPL(通用),unit_id={}", labelData.get("unit_id")); - } - - // 添加到打印任务队列 - Long taskId = printTaskService.addPrintTask( - printerIP, - zplCode, - rfidFlag, - requestedCopies, - labelData, - printRequest.getSite() != null ? printRequest.getSite() : "DEFAULT", - printRequest.getUserId() != null ? printRequest.getUserId().toString() : "SYSTEM" - ); + Long taskId = enqueueSingleTask(outerPrinter.getIpAddress(), zplCode, outerRfidFlag, labelData, printRequest); taskIds.add(taskId); - log.info("打印任务已加入队列 {} / {}, taskId={}", i + 1, totalLabels, taskId); } - // 6. 记录日志 - log.info("✓ 所有打印任务已加入队列,共 {} 个任务,任务ID: {}", totalLabels, taskIds); + // 6. customerId + innerBox 场景:在外箱任务后自动补打对应内箱子标签 + enqueueInnerBoxTasksIfNeeded(printRequest, resolvedReportId, queryParams, outerPrinter, taskIds); + + // 7. 记录日志 + log.info("✓ 所有打印任务已加入队列,共 {} 个任务,任务ID: {}", taskIds.size(), taskIds); } catch (Exception e) { System.err.println("RFID标签打印失败: " + e.getMessage()); throw new RuntimeException("RFID标签打印失败: " + e.getMessage()); } } + /** + * 构建通用打印查询参数 + */ + private Map buildCommonQueryParams(PrintLabelRequest printRequest) { + Map queryParams = new HashMap<>(); + queryParams.put("site", printRequest.getSite()); + queryParams.put("unitIds", printRequest.getUnitIds()); + // ifs外箱标签视图 + queryParams.put("consignmentId", printRequest.getConsignmentId()); + queryParams.put("jobNo", printRequest.getJobNo()); + queryParams.put("lineNo", printRequest.getLineNo()); + queryParams.put("relNo", printRequest.getRelNo()); + queryParams.put("lineItemNo", printRequest.getLineItemNo()); + return queryParams; + } + + /** + * 获取标签设置(labelType为空时仅按labelNo匹配) + */ + private LabelSettingData getRequiredLabelSetting(String labelNo, String labelType) { + LabelSettingData query = new LabelSettingData(); + query.setLabelNo(labelNo); + if (StringUtils.isNotBlank(labelType)) { + query.setLabelType(labelType); + } + List labelSettingList = baseService.getLabelSettingList(query); + if (labelSettingList == null || labelSettingList.isEmpty()) { + throw new RuntimeException("未找到对应的标签: " + labelNo); + } + return labelSettingList.getFirst(); + } + + /** + * 获取用户对应标签的打印机配置 + */ + private UserLabelPrinterData getRequiredLabelPrinter(String userId, String labelNo) { + UserLabelPrinterData printerQuery = new UserLabelPrinterData(); + printerQuery.setUserId(userId); + printerQuery.setLabelNo(labelNo); + List printers = baseService.getUserLabelPrinters(printerQuery); + if (printers == null || printers.isEmpty()) { + throw new RuntimeException("未找到指定的打印机配置: labelNo=" + labelNo); + } + UserLabelPrinterData printer = printers.getFirst(); + if (StringUtils.isBlank(printer.getIpAddress())) { + throw new RuntimeException("打印机IP地址未配置: labelNo=" + labelNo); + } + return printer; + } + + /** + * 添加单个打印任务到队列(内部统一处理RFID逻辑) + */ + private Long enqueueSingleTask(String printerIP, String zplCode, String rfidFlag, + Map labelData, PrintLabelRequest printRequest) { + String resolvedZpl = zplCode; + if ("Y".equals(rfidFlag)) { + resolvedZpl = buildRfidZpl(zplCode, labelData); + log.info("已组装RFID ZPL(通用),unit_id={}", labelData.get("unit_id")); + } + return printTaskService.addPrintTask( + printerIP, + resolvedZpl, + rfidFlag, + 1, + labelData, + printRequest.getSite() != null ? printRequest.getSite() : "DEFAULT", + printRequest.getUserId() != null ? printRequest.getUserId() : "SYSTEM" + ); + } + + /** + * customerId + innerBox 场景:打印外箱标签对应的内箱子标签 + */ + private void enqueueInnerBoxTasksIfNeeded(PrintLabelRequest printRequest, + String outerLabelNo, + Map baseQueryParams, + UserLabelPrinterData outerPrinter, + List taskIds) { + if (StringUtils.isBlank(printRequest.getCustomerId())) { + return; + } + List innerBoxList = printRequest.getInnerBox(); + if (innerBoxList == null || innerBoxList.isEmpty()) { + return; + } + + String innerLabelNo = resolveInnerLabelByCustomer(printRequest, outerLabelNo); + if (StringUtils.isBlank(innerLabelNo)) { + throw new RuntimeException("未找到外箱标签对应的内箱标签配置,outerLabelNo=" + outerLabelNo); + } + + LabelSettingData innerLabelSetting = getRequiredLabelSetting(innerLabelNo, null); + UserLabelPrinterData innerPrinter = resolveInnerPrinter(printRequest.getUserId(), innerLabelNo, outerPrinter); + + Map innerQueryParams = new HashMap<>(baseQueryParams); + int innerIndex = 1; + for (String innerQty : innerBoxList) { + if (StringUtils.isBlank(innerQty)) { + continue; + } + Map innerCustomFields = buildInnerCustomFields(printRequest.getCustomFields(), innerQty.trim()); + innerQueryParams.put("customFields", innerCustomFields); + + // innerBox 的每个元素代表一份内箱标签,qty由当前元素覆盖 + List innerZplList = previewLabelWithRealData(innerLabelNo, true, innerQueryParams); + if (innerZplList == null || innerZplList.isEmpty()) { + throw new RuntimeException("内箱标签ZPL代码获取失败,innerQty=" + innerQty); + } + List> innerLabelDataList = getLabelDataForPrint(innerLabelNo, innerQueryParams); + Map innerLabelData = innerLabelDataList != null && !innerLabelDataList.isEmpty() + ? new HashMap<>(innerLabelDataList.getFirst()) : new HashMap<>(); + + if (innerZplList.size() > 1) { + log.warn("内箱标签生成了多条数据,本次按第一条打印。innerQty={}, count={}", innerQty, innerZplList.size()); + } + Long taskId = enqueueSingleTask( + innerPrinter.getIpAddress(), + innerZplList.getFirst(), + innerLabelSetting.getRfidFlag(), + innerLabelData, + printRequest + ); + taskIds.add(taskId); + log.info("内箱标签任务已加入队列 {} / {}, qty={}, taskId={}", + innerIndex, innerBoxList.size(), innerQty, taskId); + innerIndex++; + } + } + + /** + * 解析内箱标签打印机:优先取内箱标签专属打印机,未配置则沿用外箱打印机 + */ + private UserLabelPrinterData resolveInnerPrinter(String userId, String innerLabelNo, UserLabelPrinterData outerPrinter) { + try { + return getRequiredLabelPrinter(userId, innerLabelNo); + } catch (Exception ex) { + log.warn("内箱标签未配置独立打印机,沿用外箱打印机。innerLabelNo={}, reason={}", innerLabelNo, ex.getMessage()); + return outerPrinter; + } + } + + /** + * 构建内箱标签 customFields:保留原字段并覆盖 qty + */ + private Map buildInnerCustomFields(Map sourceCustomFields, String innerQty) { + Map innerCustomFields = new HashMap<>(); + if (sourceCustomFields != null && !sourceCustomFields.isEmpty()) { + innerCustomFields.putAll(sourceCustomFields); + } + boolean qtyUpdated = false; + for (String key : new ArrayList<>(innerCustomFields.keySet())) { + if (StringUtils.equalsIgnoreCase(StringUtils.trimToEmpty(key), "qty")) { + innerCustomFields.put(key, innerQty); + qtyUpdated = true; + } + } + if (!qtyUpdated) { + innerCustomFields.put("qty", innerQty); + } + return innerCustomFields; + } + + /** + * 根据外箱标签解析对应内箱标签 + */ + private String resolveInnerLabelByCustomer(PrintLabelRequest printRequest, String outerLabelNo) { + String customerId = StringUtils.trimToNull(printRequest.getCustomerId()); + if (StringUtils.isBlank(customerId) || StringUtils.isBlank(outerLabelNo)) { + return null; + } + String addressNo = StringUtils.trimToNull(printRequest.getAddressNo()); + try { + CustomerLabelSettingData query = new CustomerLabelSettingData(); + query.setSearchFlag("Y"); + query.setCustomerId(customerId.trim()); + // 不在SQL层限定addressNo,保留“地址精确匹配 -> 客户通用地址回退”的业务顺序 + List customerLabelList = baseService.getCustomerLabelSettingList(query); + if (customerLabelList == null || customerLabelList.isEmpty()) { + return null; + } + + CustomerLabelSettingData exactInnerLabel = null; + CustomerLabelSettingData exactAnyLabel = null; + CustomerLabelSettingData fallbackInnerLabel = null; + CustomerLabelSettingData fallbackAnyLabel = null; + + for (CustomerLabelSettingData item : customerLabelList) { + if (item == null || StringUtils.isBlank(item.getLabelNo())) { + continue; + } + if (StringUtils.isNotBlank(printRequest.getSite()) + && !StringUtils.equalsIgnoreCase(printRequest.getSite(), item.getSite())) { + continue; + } + if (!"Y".equalsIgnoreCase(StringUtils.trimToEmpty(item.getSubLabelFlag()))) { + continue; + } + if (!StringUtils.equalsIgnoreCase(StringUtils.trimToEmpty(item.getParentLabelNo()), outerLabelNo)) { + continue; + } + + boolean isInnerLabelType = "内箱标签".equals(StringUtils.trimToEmpty(item.getLabelType())); + String itemAddressNo = StringUtils.trimToNull(item.getAddressNo()); + + if (StringUtils.isNotBlank(addressNo)) { + if (StringUtils.equalsIgnoreCase(addressNo, itemAddressNo)) { + if (isInnerLabelType) { + exactInnerLabel = item; + break; + } + if (exactAnyLabel == null) { + exactAnyLabel = item; + } + continue; + } + if (StringUtils.isBlank(itemAddressNo)) { + if (isInnerLabelType && fallbackInnerLabel == null) { + fallbackInnerLabel = item; + } + if (fallbackAnyLabel == null) { + fallbackAnyLabel = item; + } + } + continue; + } + + if (isInnerLabelType) { + exactInnerLabel = item; + break; + } + if (exactAnyLabel == null) { + exactAnyLabel = item; + } + } + + CustomerLabelSettingData targetLabel = exactInnerLabel != null ? exactInnerLabel + : (exactAnyLabel != null ? exactAnyLabel + : (fallbackInnerLabel != null ? fallbackInnerLabel : fallbackAnyLabel)); + return targetLabel != null ? targetLabel.getLabelNo() : null; + } catch (Exception e) { + log.warn("根据外箱标签解析内箱标签失败,customerId={}, outerLabelNo={}, error={}", + customerId, outerLabelNo, e.getMessage()); + return null; + } + } + /** * 文本日期元素是否启用流水号后缀 */ @@ -905,9 +1107,7 @@ public class ReportLabelListServiceImpl extends ServiceImpl 客户通用地址回退”的业务顺序 List customerLabelList = baseService.getCustomerLabelSettingList(query); if (customerLabelList == null || customerLabelList.isEmpty()) { log.warn("客户标签映射未找到,回退前端reportId。customerId={}, addressNo={}, labelType={}, reportId={}",