From 158f73961b138f527cb2bb2ad71b3d7dd944d7f6 Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Fri, 9 Oct 2026 13:40:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=83=E7=B4=A0=E7=BB=84=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Impl/LabelDataProcessorServiceImpl.java | 189 ++++++++++-------- 1 file changed, 108 insertions(+), 81 deletions(-) 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 6031af0b..4cf968a7 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 @@ -167,9 +167,23 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService } } - // 第二轮处理:处理元素组合引用 + // 用原始模板定位元素,用第一轮的结果提供值;加工后内容不能再作为引用标识。 + Map referenceElements = new LinkedHashMap<>(); + Map resolvedElements = new IdentityHashMap<>(); + Set resolvingElements = Collections.newSetFromMap(new IdentityHashMap<>()); + for (int i = 0; i < elements.size(); i++) { + ReportLabelList original = elements.get(i); + ReportLabelList processed = firstPassElements.get(i); + referenceElements.put(getElementDisplayName(original), processed); + if (!containsElementReferences(original.getData())) { + resolvedElements.put(processed, processed); + } + } + + // 第二轮处理:组合只读取已经加工的值,不再次截取、替换或生成流水号。 for (ReportLabelList element : firstPassElements) { - ReportLabelList finalElement = processElementCombinations(element, enhancedDataMap, firstPassElements, printFlag); + ReportLabelList finalElement = processElementCombinations(element, enhancedDataMap, + firstPassElements, referenceElements, resolvedElements, resolvingElements, printFlag); // 如果元素被设置为不显示,则跳过该元素 if (("onecode".equals(element.getType()) || "qrcode".equals(element.getType()) @@ -195,6 +209,12 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService log.debug("处理条码元素: type={}, originalData={}", element.getType(), originalData); + // 保留组合引用中的原始字段模板,待所有来源元素完成加工后再解析。 + // 否则 {文本(#{FIELD})} 会提前变成 {文本(原始值)},无法匹配加工后的元素。 + if (containsElementReferences(originalData)) { + return originalData; + } + // 检查是否包含流水号引用(各种可能的格式) if (containsSerialNumberReference(originalData)) { log.debug("检测到流水号引用,开始处理"); @@ -316,35 +336,45 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService * 处理元素组合引用 */ private ReportLabelList processElementCombinations(ReportLabelList element, Map dataMap, - List allElements,Boolean printFlag) { + List allElements, + Map referenceElements, + Map resolvedElements, + Set resolvingElements, Boolean printFlag) { + if (resolvedElements.containsKey(element)) { + return resolvedElements.get(element); + } if (element == null || element.getData() == null || element.getData().isEmpty()) { return element; } + if (!resolvingElements.add(element)) { + log.warn("检测到循环元素组合引用: type={}, data={}", element.getType(), element.getData()); + return element; + } - String originalData = element.getData(); - - // 检查是否包含元素引用 - if (containsElementReferences(originalData)) { + try { ReportLabelList processedElement = copyElement(element); - String combinedData = processElementCombination(originalData, dataMap, allElements, element, printFlag); + String combinedData = processElementCombination(element.getData(), dataMap, allElements, + referenceElements, resolvedElements, resolvingElements, printFlag); + // 文本自身的加工规则在组合完成后执行一次;引用值不再做字段替换。 + if ("text".equals(element.getType())) { + combinedData = formatTextValue(combinedData, element, printFlag); + } processedElement.setData(combinedData); - log.debug("处理元素组合: 原始数据={}, 组合后数据={}", originalData, combinedData); + resolvedElements.put(element, processedElement); return processedElement; + } finally { + resolvingElements.remove(element); } - - return element; } /** - * 检查数据中是否包含元素引用 + * 只识别元素引用,不能把普通的 #{字段名} 当成元素组合。 */ private boolean containsElementReferences(String data) { if (data == null || data.isEmpty()) { return false; } - - // 检查是否包含 {元素类型} 格式的引用(排除 #{字段名} 格式) - Pattern pattern = Pattern.compile("\\{(?!#)[^}]+\\}"); + Pattern pattern = Pattern.compile("(? dataMap, - List allElements, ReportLabelList currentElement,Boolean printFlag) { - if (originalData == null || originalData.isEmpty()) { - return originalData; - } - - // 检查是否是自定义表达式模式 + List allElements, + Map referenceElements, + Map resolvedElements, + Set resolvingElements, Boolean printFlag) { if (originalData.startsWith("CUSTOM:")) { return processCustomCombination(originalData.substring(7), dataMap, allElements); } - // 处理模板模式的元素引用 {元素类型} 或 {元素类型(内容)} - String processedData = originalData; - - // 创建元素映射,便于查找 - Map elementMap = new HashMap<>(); - for (ReportLabelList element : allElements) { - if (element != currentElement) { // 排除自身 - String elementKey = getElementDisplayName(element); - elementMap.put(elementKey, element); + StringBuilder result = new StringBuilder(); + int literalStart = 0; + for (int i = 0; i < originalData.length(); i++) { + if (originalData.charAt(i) != '{') { + continue; + } + int end = findReferenceEnd(originalData, i); + if (end < 0) { + break; + } + if (i > 0 && originalData.charAt(i - 1) == '#') { + // 普通字段由后续的片段替换处理,不进入元素匹配。 + i = end; + continue; } - } - - // 替换元素引用 - Pattern elementPattern = Pattern.compile("\\{([^}]+)\\}"); - Matcher matcher = elementPattern.matcher(processedData); - StringBuffer result = new StringBuffer(); - while (matcher.find()) { - String reference = matcher.group(1); - String replacement = ""; - - // 检查是否是数据源字段引用 #{fieldName} - if (reference.startsWith("#{") && reference.endsWith("}")) { - String fieldName = reference.substring(2, reference.length() - 1); - - // 特殊处理流水号引用 - if ("SERIAL_NUMBER".equals(fieldName)) { - Object serialValue = getMapValueIgnoreCase(dataMap, "SERIAL_NUMBER"); - replacement = serialValue != null ? serialValue.toString() : ""; - log.debug("元素组合中使用流水号引用: SERIAL_NUMBER={}", replacement); - } - // 首先检查是否是系统变量 - else if (isSystemVariable(fieldName)) { - replacement = getSystemVariableValue(fieldName); - log.debug("元素组合中使用系统变量: {}={}", fieldName, replacement); - } else { - // 普通数据源字段 - Object value = getMapValueIgnoreCase(dataMap, fieldName); - replacement = value != null ? value.toString() : ""; - log.debug("元素组合中使用数据源字段: {}={}", fieldName, replacement); - } + result.append(replaceDataSourceFields(originalData.substring(literalStart, i), dataMap)); + String reference = originalData.substring(i + 1, end); + ReportLabelList referencedElement = findElementByReference(reference, referenceElements); + if (referencedElement == null) { + result.append(replaceDataSourceFields(originalData.substring(i, end + 1), dataMap)); } else { - // 查找匹配的元素 - ReportLabelList referencedElement = findElementByReference(reference, elementMap); - if (referencedElement != null) { - // 递归处理引用的元素数据 - replacement = processElementData(referencedElement, dataMap,false, printFlag).getData(); - if (replacement == null) { - replacement = ""; - } - } else { - // 如果找不到匹配的元素,保持原样 - replacement = "{" + reference + "}"; - } + ReportLabelList resolved = processElementCombinations(referencedElement, dataMap, allElements, + referenceElements, resolvedElements, resolvingElements, printFlag); + // 直接使用已加工的值,避免二次加工或把结果中的花括号再解释为模板。 + result.append(resolved.getData() != null ? resolved.getData() : ""); } - - matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); + i = end; + literalStart = end + 1; } - matcher.appendTail(result); - + result.append(replaceDataSourceFields(originalData.substring(literalStart), dataMap)); return result.toString(); } + /** + * 引用内容可能包含 #{字段} 或嵌套的条码组合,必须按配对花括号读取完整引用。 + */ + private int findReferenceEnd(String data, int start) { + int depth = 0; + for (int i = start; i < data.length(); i++) { + if (data.charAt(i) == '{') { + depth++; + } else if (data.charAt(i) == '}' && --depth == 0) { + return i; + } + } + return -1; + } + /** * 处理自定义组合表达式 */ @@ -678,9 +695,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService String typeName = typeNames.getOrDefault(element.getType(), element.getType()); String content = element.getData() != null && !element.getData().isEmpty() - ? "(" + (element.getData().length() > 10 - ? element.getData().substring(0, 10) + "..." - : element.getData()) + ")" + ? "(" + element.getData() + ")" : ""; return typeName + content; @@ -692,7 +707,18 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService private String processTextElement(String originalData, Map dataMap, ReportLabelList element, Boolean printFlag) { // 首先替换数据源字段 String replacedData = replaceDataSourceFields(originalData, dataMap); + if ("date".equals(element.getDataType())) { + // 普通日期模板保留原有的占位符及固定前后缀处理。 + return appendDateSerialSuffixIfEnabled( + processDateText(originalData, replacedData, dataMap, element), element, printFlag); + } + return formatTextValue(replacedData, element, printFlag); + } + /** + * 格式化已解析的文本值,不再解释其中的数据源占位符或元素引用。 + */ + private String formatTextValue(String replacedData, ReportLabelList element, Boolean printFlag) { // 根据数据类型进行不同的处理 String dataType = element.getDataType(); if (dataType == null) { @@ -707,7 +733,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService break; case "date": return appendDateSerialSuffixIfEnabled( - processDateText(originalData, replacedData, dataMap, element), + processDateElement(replacedData, element), element, printFlag ); @@ -1632,6 +1658,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService copy.setBarcodeType(original.getBarcodeType()); copy.setShowContent(original.getShowContent()); copy.setShowElement(original.getShowElement()); + copy.setShowSerialNumber(original.getShowSerialNumber()); copy.setShowMainSeq(original.getShowMainSeq()); copy.setSeqName(original.getSeqName()); copy.setIsChecked(original.getIsChecked());