Browse Source

元素组合

clodop
han\hanst 1 month ago
parent
commit
158f73961b
  1. 189
      src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java

189
src/main/java/com/gaotao/modules/base/service/Impl/LabelDataProcessorServiceImpl.java

@ -167,9 +167,23 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
} }
} }
// 第二轮处理:处理元素组合引用
// 用原始模板定位元素,用第一轮的结果提供值;加工后内容不能再作为引用标识。
Map<String, ReportLabelList> referenceElements = new LinkedHashMap<>();
Map<ReportLabelList, ReportLabelList> resolvedElements = new IdentityHashMap<>();
Set<ReportLabelList> 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) { 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()) 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); log.debug("处理条码元素: type={}, originalData={}", element.getType(), originalData);
// 保留组合引用中的原始字段模板,待所有来源元素完成加工后再解析。
// 否则 {文本(#{FIELD})} 会提前变成 {文本(原始值)},无法匹配加工后的元素。
if (containsElementReferences(originalData)) {
return originalData;
}
// 检查是否包含流水号引用(各种可能的格式) // 检查是否包含流水号引用(各种可能的格式)
if (containsSerialNumberReference(originalData)) { if (containsSerialNumberReference(originalData)) {
log.debug("检测到流水号引用,开始处理"); log.debug("检测到流水号引用,开始处理");
@ -316,35 +336,45 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
* 处理元素组合引用 * 处理元素组合引用
*/ */
private ReportLabelList processElementCombinations(ReportLabelList element, Map<String, Object> dataMap, private ReportLabelList processElementCombinations(ReportLabelList element, Map<String, Object> dataMap,
List<ReportLabelList> allElements,Boolean printFlag) {
List<ReportLabelList> allElements,
Map<String, ReportLabelList> referenceElements,
Map<ReportLabelList, ReportLabelList> resolvedElements,
Set<ReportLabelList> resolvingElements, Boolean printFlag) {
if (resolvedElements.containsKey(element)) {
return resolvedElements.get(element);
}
if (element == null || element.getData() == null || element.getData().isEmpty()) { if (element == null || element.getData() == null || element.getData().isEmpty()) {
return element; 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); 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); processedElement.setData(combinedData);
log.debug("处理元素组合: 原始数据={}, 组合后数据={}", originalData, combinedData);
resolvedElements.put(element, processedElement);
return processedElement; return processedElement;
} finally {
resolvingElements.remove(element);
} }
return element;
} }
/** /**
* 检查数据中是否包含元素引用
* 只识别元素引用,不能把普通的 #{字段名} 当成元素组合。
*/ */
private boolean containsElementReferences(String data) { private boolean containsElementReferences(String data) {
if (data == null || data.isEmpty()) { if (data == null || data.isEmpty()) {
return false; return false;
} }
// 检查是否包含 {元素类型} 格式的引用(排除 #{字段名} 格式)
Pattern pattern = Pattern.compile("\\{(?!#)[^}]+\\}");
Pattern pattern = Pattern.compile("(?<!#)\\{(?:文本|一维码|二维码|图片|流水号)(?:\\(|\\})");
return pattern.matcher(data).find() || data.startsWith("CUSTOM:"); return pattern.matcher(data).find() || data.startsWith("CUSTOM:");
} }
@ -376,7 +406,10 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
// 处理不同类型的元素 // 处理不同类型的元素
switch (element.getType()) { switch (element.getType()) {
case "text": case "text":
processedElement.setData(processTextElement(originalData, dataMap, element, printFlag));
// 和条码一样,保留组合模板,避免提前替换字段或截取引用表达式。
if (!containsElementReferences(originalData)) {
processedElement.setData(processTextElement(originalData, dataMap, element, printFlag));
}
break; break;
case "onecode": case "onecode":
case "qrcode": case "qrcode":
@ -445,79 +478,63 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
* 支持将多个元素的内容按特定格式组合 * 支持将多个元素的内容按特定格式组合
*/ */
private String processElementCombination(String originalData, Map<String, Object> dataMap, private String processElementCombination(String originalData, Map<String, Object> dataMap,
List<ReportLabelList> allElements, ReportLabelList currentElement,Boolean printFlag) {
if (originalData == null || originalData.isEmpty()) {
return originalData;
}
// 检查是否是自定义表达式模式
List<ReportLabelList> allElements,
Map<String, ReportLabelList> referenceElements,
Map<ReportLabelList, ReportLabelList> resolvedElements,
Set<ReportLabelList> resolvingElements, Boolean printFlag) {
if (originalData.startsWith("CUSTOM:")) { if (originalData.startsWith("CUSTOM:")) {
return processCustomCombination(originalData.substring(7), dataMap, allElements); return processCustomCombination(originalData.substring(7), dataMap, allElements);
} }
// 处理模板模式的元素引用 {元素类型} 或 {元素类型(内容)}
String processedData = originalData;
// 创建元素映射,便于查找
Map<String, ReportLabelList> 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 { } 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(); 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 typeName = typeNames.getOrDefault(element.getType(), element.getType());
String content = element.getData() != null && !element.getData().isEmpty() String content = element.getData() != null && !element.getData().isEmpty()
? "(" + (element.getData().length() > 10
? element.getData().substring(0, 10) + "..."
: element.getData()) + ")"
? "(" + element.getData() + ")"
: ""; : "";
return typeName + content; return typeName + content;
@ -692,7 +707,18 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
private String processTextElement(String originalData, Map<String, Object> dataMap, ReportLabelList element, Boolean printFlag) { private String processTextElement(String originalData, Map<String, Object> dataMap, ReportLabelList element, Boolean printFlag) {
// 首先替换数据源字段 // 首先替换数据源字段
String replacedData = replaceDataSourceFields(originalData, dataMap); 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(); String dataType = element.getDataType();
if (dataType == null) { if (dataType == null) {
@ -707,7 +733,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
break; break;
case "date": case "date":
return appendDateSerialSuffixIfEnabled( return appendDateSerialSuffixIfEnabled(
processDateText(originalData, replacedData, dataMap, element),
processDateElement(replacedData, element),
element, element,
printFlag printFlag
); );
@ -1632,6 +1658,7 @@ public class LabelDataProcessorServiceImpl implements LabelDataProcessorService
copy.setBarcodeType(original.getBarcodeType()); copy.setBarcodeType(original.getBarcodeType());
copy.setShowContent(original.getShowContent()); copy.setShowContent(original.getShowContent());
copy.setShowElement(original.getShowElement()); copy.setShowElement(original.getShowElement());
copy.setShowSerialNumber(original.getShowSerialNumber());
copy.setShowMainSeq(original.getShowMainSeq()); copy.setShowMainSeq(original.getShowMainSeq());
copy.setSeqName(original.getSeqName()); copy.setSeqName(original.getSeqName());
copy.setIsChecked(original.getIsChecked()); copy.setIsChecked(original.getIsChecked());

Loading…
Cancel
Save