From 5f79a0c8b459cf0acba8d91c12eaee2f01292601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=8C=E5=85=88=E8=88=9C?= <2499071264@qq.com> Date: Fri, 13 Nov 2026 10:53:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BA=BA=E5=91=98=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=B2=BB=E7=90=86=E8=BF=81=E7=A7=BB=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=966?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apiConfig/model/PersonApiSyncOptions.java | 68 +++++- .../impl/PersonApiConfigServiceImpl.java | 40 +++- .../impl/PersonGovernanceSyncServiceImpl.java | 25 ++- .../personGovernance/apiConfig/form.html | 199 +++++++++++++++++- 4 files changed, 309 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/model/PersonApiSyncOptions.java b/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/model/PersonApiSyncOptions.java index 1733796..2bd7b5a 100644 --- a/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/model/PersonApiSyncOptions.java +++ b/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/model/PersonApiSyncOptions.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.Function; @Data public class PersonApiSyncOptions { @@ -13,11 +15,11 @@ public class PersonApiSyncOptions { private String unitConfigId; private List rules = new ArrayList<>(); - public Map fieldDefaults() { - Map defaults = new HashMap<>(); + public Map defaultRulesByTarget() { + Map defaults = new HashMap<>(); for (FieldRule rule : rules) { - if (rule.getDefaultValue() != null && !rule.getDefaultValue().isEmpty()) { - defaults.put(rule.getTargetField(), rule.getDefaultValue()); + if (rule.hasDefault()) { + defaults.put(rule.getTargetField(), rule); } } return defaults; @@ -30,5 +32,63 @@ public class PersonApiSyncOptions { private Integer length; private String dictCode; private String defaultValue; + private List defaultRules = new ArrayList<>(); + + public boolean hasDefault() { + return (defaultValue != null && !defaultValue.isEmpty()) + || (defaultRules != null && !defaultRules.isEmpty()); + } + + public String resolveDefault(Function readSource) { + if (defaultRules != null) { + for (DefaultRule rule : defaultRules) { + if (rule.getCondition().matches(readSource)) { + return rule.getResult(); + } + } + } + return defaultValue == null || defaultValue.isEmpty() ? null : defaultValue; + } + } + + @Data + public static class DefaultRule { + private Condition condition; + private String result; + } + + @Data + public static class Condition { + private String operator; + private String sourceField; + private String value; + private List children; + + public boolean matches(Function readSource) { + if ("AND".equals(operator)) { + return children.stream().allMatch(child -> child.matches(readSource)); + } + if ("OR".equals(operator)) { + return children.stream().anyMatch(child -> child.matches(readSource)); + } + Object actual = readSource.apply(sourceField); + String text = actual == null ? null : String.valueOf(actual); + return switch (operator) { + case "EQ" -> text != null && text.equals(value); + case "NE" -> text != null && !text.equals(value); + case "CONTAINS" -> text != null && text.contains(value); + case "EMPTY" -> text == null || text.isBlank(); + case "NOT_EMPTY" -> text != null && !text.isBlank(); + default -> throw new IllegalArgumentException("不支持的默认值条件运算符:" + operator); + }; + } + + public void collectSourceFields(Set fields) { + if (children != null) { + children.forEach(child -> child.collectSourceFields(fields)); + } else { + fields.add(sourceField); + } + } } } diff --git a/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonApiConfigServiceImpl.java b/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonApiConfigServiceImpl.java index 471d4c6..5b4e0ad 100644 --- a/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonApiConfigServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonApiConfigServiceImpl.java @@ -49,6 +49,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.regex.Pattern; /** API配置、数据库元数据和只读测试实现。 */ @@ -134,7 +135,7 @@ public class PersonApiConfigServiceImpl extends BaseServiceImpl private PersonApiConfig saveConfig(PersonApiConfig config, List mappings, List params, PersonApiSyncOptions options) { - Map defaults = options == null ? java.util.Collections.emptyMap() : options.fieldDefaults(); + Map defaults = options == null ? Map.of() : options.defaultRulesByTarget(); Assert.notNull(config, "配置不能为空"); Assert.hasText(config.getConfigName(), "请填写配置名称"); PersonApiConfig stored = Strings.isBlank(config.getId()) ? null : fetch(config.getId()); @@ -376,7 +377,7 @@ public class PersonApiConfigServiceImpl extends BaseServiceImpl return "HTTP_API".equals(config.getSourceType()) && "sys_unit".equalsIgnoreCase(config.getTargetTable()); } - private boolean hasMappingValue(PersonApiFieldMapping mapping, Map defaults) { + private boolean hasMappingValue(PersonApiFieldMapping mapping, Map defaults) { return Strings.isNotBlank(mapping.getSourceField()) || (mapping.getTargetField() != null && defaults.containsKey(mapping.getTargetField())); } @@ -390,10 +391,15 @@ public class PersonApiConfigServiceImpl extends BaseServiceImpl "请选择有效的单位API配置"); } Assert.notNull(options.getRules(), "字段配置不能为空"); + Set sourceFields = new LinkedHashSet<>(); + if (mappings != null) { + mappings.stream().map(PersonApiFieldMapping::getSourceField).filter(Strings::isNotBlank) + .map(String::trim).forEach(sourceFields::add); + } java.util.Set> ruleFields = new java.util.HashSet<>(); for (PersonApiSyncOptions.FieldRule rule : options.getRules()) { Assert.notNull(rule, "字段配置不能为空"); - boolean hasDefault = rule.getDefaultValue() != null && !rule.getDefaultValue().isEmpty(); + boolean hasDefault = rule.hasDefault(); if (rule.getLength() != null || !hasDefault) { Assert.hasText(rule.getSourceField(), "请填写配置规则的来源字段"); } @@ -410,6 +416,13 @@ public class PersonApiConfigServiceImpl extends BaseServiceImpl Assert.isTrue(!List.of("id", "pullTime").contains(rule.getTargetField()) && !Boolean.TRUE.equals(mapping.getIdentityFlag()), "主键、批次时间和唯一标识不能设置默认值"); } + if (rule.getDefaultRules() != null) { + for (PersonApiSyncOptions.DefaultRule defaultRule : rule.getDefaultRules()) { + Assert.notNull(defaultRule, "默认值规则不能为空"); + Assert.hasText(defaultRule.getResult(), "请填写默认值规则的结果:" + rule.getTargetField()); + validateDefaultCondition(defaultRule.getCondition(), sourceFields, rule.getTargetField()); + } + } if (Strings.isNotBlank(rule.getDictCode())) { Assert.hasText(rule.getTargetField(), "选择字典前请填写目标字段"); Assert.isTrue(!"pullTime".equals(rule.getTargetField()) @@ -418,12 +431,31 @@ public class PersonApiConfigServiceImpl extends BaseServiceImpl } } if (Strings.isNotBlank(options.getUnitConfigId())) { - Map defaults = options.fieldDefaults(); + Map defaults = options.defaultRulesByTarget(); Assert.isTrue(mappings != null && mappings.stream().anyMatch(mapping -> "unitId".equals(mapping.getTargetField()) && hasMappingValue(mapping, defaults)), "自动同步单位需要配置unitId映射"); } } + private void validateDefaultCondition(PersonApiSyncOptions.Condition condition, + Set sourceFields, String targetField) { + Assert.notNull(condition, "请配置默认值条件:" + targetField); + String operator = condition.getOperator(); + if ("AND".equals(operator) || "OR".equals(operator)) { + Assert.notEmpty(condition.getChildren(), "默认值条件组至少需要一项:" + targetField); + condition.getChildren().forEach(child -> validateDefaultCondition(child, sourceFields, targetField)); + return; + } + Assert.isTrue(operator != null && List.of("EQ", "NE", "CONTAINS", "EMPTY", "NOT_EMPTY").contains(operator), + "默认值条件运算符不正确:" + targetField); + Assert.isNull(condition.getChildren(), "普通条件不能包含子条件:" + targetField); + Assert.isTrue(sourceFields.contains(condition.getSourceField()), "请选择已配置的来源字段:" + targetField); + if (List.of("EQ", "NE", "CONTAINS").contains(operator)) { + Assert.isTrue(condition.getValue() != null && !condition.getValue().isEmpty(), + "请填写默认值条件的比较值:" + targetField); + } + } + @Override @Aop(TransAop.READ_COMMITTED) public void deleteConfig(String id) { diff --git a/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonGovernanceSyncServiceImpl.java b/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonGovernanceSyncServiceImpl.java index 27238b2..9daff44 100644 --- a/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonGovernanceSyncServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/personGovernance/apiConfig/service/impl/PersonGovernanceSyncServiceImpl.java @@ -101,7 +101,13 @@ public class PersonGovernanceSyncServiceImpl implements PersonGovernanceSyncServ List mappings = dao.query(PersonApiFieldMapping.class, Cnd.where("configId", "=", configId).asc("sort")); PersonApiSyncOptions options = personApiConfigService.syncOptions(configId); - Map fieldDefaults = options.fieldDefaults(); + Map fieldDefaults = options.defaultRulesByTarget(); + Set conditionSourceFields = new HashSet<>(); + for (PersonApiSyncOptions.FieldRule rule : fieldDefaults.values()) { + if (rule.getDefaultRules() != null) { + rule.getDefaultRules().forEach(item -> item.getCondition().collectSourceFields(conditionSourceFields)); + } + } boolean unitTarget = "sys_unit".equalsIgnoreCase(config.getTargetTable()); if (unitTarget) { // 单位写入可能随父批次一起提交,行锁一直持有到外层事务完成。 @@ -114,9 +120,11 @@ public class PersonGovernanceSyncServiceImpl implements PersonGovernanceSyncServ // 页面会加载整张表的列;批次字段由系统生成,未配置的非必填列交给数据库默认值。 mappings = mappings.stream() .filter(m -> !"pullTime".equals(m.getTargetField()) && (unitTarget || !"id".equals(m.getTargetField()))) - .filter(m -> Strings.isNotBlank(m.getTargetField()) || options.getRules().stream().noneMatch(rule -> - rule.getLength() != null && Strings.isBlank(rule.getTargetField()) - && Objects.equals(rule.getSourceField(), m.getSourceField()))) + .filter(m -> Strings.isNotBlank(m.getTargetField()) + || (!conditionSourceFields.contains(Strings.sNull(m.getSourceField()).trim()) + && options.getRules().stream().noneMatch(rule -> + rule.getLength() != null && Strings.isBlank(rule.getTargetField()) + && Objects.equals(rule.getSourceField(), m.getSourceField())))) .filter(m -> Boolean.TRUE.equals(m.getRequired()) || (Strings.isNotBlank(m.getTargetField()) && (Strings.isNotBlank(m.getSourceField()) || fieldDefaults.containsKey(m.getTargetField())))) @@ -376,7 +384,7 @@ public class PersonGovernanceSyncServiceImpl implements PersonGovernanceSyncServ /** 校验目标表和业务唯一标识;数据库唯一约束由批量写入检查,冲突时整批回滚。 */ private List validateTarget(PersonApiConfig config, List mappings, - Map fieldDefaults) { + Map fieldDefaults) { Assert.hasText(config.getTargetTable(), "请选择目标人员中间表"); List columns = personApiConfigService.columns(config.getTargetTable()); Map fields = new HashMap<>(); @@ -427,7 +435,7 @@ public class PersonGovernanceSyncServiceImpl implements PersonGovernanceSyncServ private void insertPage(PersonApiConfig config, List mappings, List columns, List rows, PersonSyncBatch batch, String lockKey, String owner, PersonApiSyncOptions options, Map> dictionaryValues, Set unitIds, - Map fieldDefaults) { + Map fieldDefaults) { Assert.isTrue((long) batch.getSourceCount() + rows.size() <= MAX_ROWS, "超过单批最大行数,已终止同步"); batch.setSourceCount(batch.getSourceCount() + rows.size()); Map types = new HashMap<>(); @@ -470,7 +478,10 @@ public class PersonGovernanceSyncServiceImpl implements PersonGovernanceSyncServ Object value = Strings.isBlank(mapping.getSourceField()) ? null : personApiConfigService.readResponsePath(row, mapping.getSourceField()); if (value == null) { - value = fieldDefaults.get(mapping.getTargetField()); + PersonApiSyncOptions.FieldRule defaultRule = fieldDefaults.get(mapping.getTargetField()); + if (defaultRule != null) { + value = defaultRule.resolveDefault(source -> personApiConfigService.readResponsePath(row, source)); + } } if (Boolean.TRUE.equals(mapping.getRequired()) && !(preserveUserNulls && value == null)) { Assert.isTrue(value != null && !Strings.isBlank(String.valueOf(value)), "必填来源字段为空:" + mapping.getSourceField()); diff --git a/src/main/resources/views/platform/personGovernance/apiConfig/form.html b/src/main/resources/views/platform/personGovernance/apiConfig/form.html index c2e6895..8e60a14 100644 --- a/src/main/resources/views/platform/personGovernance/apiConfig/form.html +++ b/src/main/resources/views/platform/personGovernance/apiConfig/form.html @@ -470,7 +470,10 @@ - + + 逻辑设置 + + 已配置 {{fieldRuleDraft.defaultRules.length}} 条规则 @@ -484,6 +487,62 @@ 确定 + +
+
+
+ +
+ 规则 {{index + 1}} +
+ 上移 + 下移 + 删除规则 +
+
+ + + + + + +
+
+ 新增规则 +
+ +
逻辑预览
+
+
+ 写入系统字段 {{fieldRuleRow.targetField}} +
+

+ + + 从上往下判断,命中即停止。 +

+
+
{{index === 0 ? '如果' : '否则,如果'}} {{formatDefaultCondition(rule.condition)}}
+
则写入 {{rule.result.trim() ? JSON.stringify(rule.result) : '(待填写结果)'}}
+
+
+ {{defaultLogicDraft.length ? '否则' : '固定默认值'}} + + +
+
+
+
+
+ 取消 + 确定 +
+
+