15 Commits be9e03ec2e ... 7d3a96d696

Auteur SHA1 Bericht Datum
  jiakai 7d3a96d696 Merge remote-tracking branch 'origin/master' 2 weken geleden
  jiakai ee45e9a20f Merge remote-tracking branch 'origin/dev_jzg_lipf_v20260831' 2 weken geleden
  liub b42c4fa0b7 fix 费用规则出现 两个晋c问题 2 weken geleden
  Qchen 6af3f0f093 Merge remote-tracking branch 'origin/master' 2 weken geleden
  Qchen 5694e76f53 处理其他分销未改的的逻辑 2 weken geleden
  xuqiang d6bc05e458 合伙人添加业务员 app内也添加一条信息 2 weken geleden
  liub 7b89d33037 fix 费用规则出现 两个晋c问题 2 weken geleden
  wanghao c29e39bccb Merge remote-tracking branch 'origin/master' 2 weken geleden
  wanghao 4aa0b20738 费用修改的时区问题修复 2 weken geleden
  lixiaolong 632229a2c5 Merge remote-tracking branch 'origin/master' 2 weken geleden
  lixiaolong 17185f969e 修复费用规则描述中车牌号和车辆用途显示编码的问题 2 weken geleden
  wanghao 5aeeb597a5 费用管理排序按时间倒序 2 weken geleden
  liub cc10445e74 Merge remote-tracking branch 'origin/master' 2 weken geleden
  liub f1111455dd fix 新车规则维护不保存时间问题 2 weken geleden
  lixiaolong 3a85ca35ed 重构承保规则、费用规则匹配校验 2 weken geleden

+ 1 - 1
authentication/src/main/java/com/jzg/mapper/SysUserJzgInfoMapper.java

@@ -19,7 +19,7 @@ public interface SysUserJzgInfoMapper extends BaseMapper<SysUserJzgInfo> {
      * 一个用户可能存在多个身份,用逗号分隔返回
      *
      * @param userId sys_user_jzg_info 表中的 userid(即 sys_user.id)
-     * @author lipf
+     * @author liub
      * @date 2026/8/29
      */
     @Select("SELECT GROUP_CONCAT(DISTINCT s.type_attr SEPARATOR ',') FROM sys_user_jzg_info_salesman s " +

+ 3 - 2
commons/src/main/java/com/jzg/commons/entity/dto/PtlAgreementCostAdd.java

@@ -9,6 +9,7 @@ import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
 
@@ -31,12 +32,12 @@ public class PtlAgreementCostAdd {
     @Schema(description = "生效时间")
     @NotNull(message = "生效时间不能为空")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date effectiveTime;
+    private LocalDateTime effectiveTime;
 
     @Schema(description = "失效时间")
     @NotNull(message = "失效时间不能为空")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    private Date failureTime;
+    private LocalDateTime failureTime;
 
     @Schema(description = "审核方式0-自动审核;1-手动审核")
     @NotBlank(message = "审核方式不能为空")

+ 4 - 3
commons/src/main/java/com/jzg/commons/entity/po/PtlNewCarJudgeRules.java

@@ -3,12 +3,11 @@ package com.jzg.commons.entity.po;
 
 import com.alibaba.excel.annotation.ExcelIgnore;
 import com.baomidou.mybatisplus.annotation.*;
-import com.jzg.commons.core.base.BaseModel;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.time.LocalDateTime;
-import java.util.Date;
 
 
 /**
@@ -38,7 +37,9 @@ public class PtlNewCarJudgeRules{
 
     private String isEffective;
 
-    private Date saveDate;
+    @Schema(description = "插入时间")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime saveDate;
 
     @ExcelIgnore
     @Schema(description = "是否删除")

+ 311 - 514
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/FactorMatch.java

@@ -15,7 +15,6 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
 /**
@@ -25,157 +24,99 @@ public class FactorMatch {
 
     private static final Logger log = LoggerFactory.getLogger(FactorMatch.class);
 
-    private static final Map<String, String> plateFourCodeMap = new HashMap<>();
+    private static final Map<String, String> PLATE_FOUR_CODE_MAP = new HashMap<>();
 
     static {
-        plateFourCodeMap.put("1404", "晋D");     plateFourCodeMap.put("1408", "晋M");
-        plateFourCodeMap.put("1411", "晋J");     plateFourCodeMap.put("1403", "晋C");
-        plateFourCodeMap.put("1407", "晋K");     plateFourCodeMap.put("1410", "晋L");
-        plateFourCodeMap.put("1402", "晋B");     plateFourCodeMap.put("1406", "晋F");
-        plateFourCodeMap.put("1401", "晋A");     plateFourCodeMap.put("1405", "晋E");
-        plateFourCodeMap.put("1409", "晋H");     plateFourCodeMap.put("14", "晋");
-        plateFourCodeMap.put("31", "沪");        plateFourCodeMap.put("53", "云");
-        plateFourCodeMap.put("15", "蒙");        plateFourCodeMap.put("11", "京");
-        plateFourCodeMap.put("22", "吉");        plateFourCodeMap.put("51", "川");
-        plateFourCodeMap.put("12", "津");        plateFourCodeMap.put("64", "宁");
-        plateFourCodeMap.put("34", "皖");        plateFourCodeMap.put("37", "鲁");
-        plateFourCodeMap.put("44", "粤");        plateFourCodeMap.put("45", "桂");
-        plateFourCodeMap.put("65", "新");        plateFourCodeMap.put("32", "苏");
-        plateFourCodeMap.put("36", "赣");        plateFourCodeMap.put("13", "冀");
-        plateFourCodeMap.put("41", "豫");        plateFourCodeMap.put("33", "浙");
-        plateFourCodeMap.put("46", "琼");        plateFourCodeMap.put("42", "鄂");
-        plateFourCodeMap.put("43", "湘");        plateFourCodeMap.put("62", "甘");
-        plateFourCodeMap.put("35", "闽");        plateFourCodeMap.put("54", "藏");
-        plateFourCodeMap.put("52", "贵");        plateFourCodeMap.put("21", "辽");
-        plateFourCodeMap.put("50", "渝");        plateFourCodeMap.put("61", "陕");
-        plateFourCodeMap.put("63", "青");        plateFourCodeMap.put("23", "黑");
+        PLATE_FOUR_CODE_MAP.put("1404", "晋D");  PLATE_FOUR_CODE_MAP.put("1408", "晋M");
+        PLATE_FOUR_CODE_MAP.put("1411", "晋J");  PLATE_FOUR_CODE_MAP.put("1403", "晋C");
+        PLATE_FOUR_CODE_MAP.put("1407", "晋K");  PLATE_FOUR_CODE_MAP.put("1410", "晋L");
+        PLATE_FOUR_CODE_MAP.put("1402", "晋B");  PLATE_FOUR_CODE_MAP.put("1406", "晋F");
+        PLATE_FOUR_CODE_MAP.put("1401", "晋A");  PLATE_FOUR_CODE_MAP.put("1405", "晋E");
+        PLATE_FOUR_CODE_MAP.put("1409", "晋H");  PLATE_FOUR_CODE_MAP.put("14",   "晋");
+        PLATE_FOUR_CODE_MAP.put("31",   "沪");   PLATE_FOUR_CODE_MAP.put("53",   "云");
+        PLATE_FOUR_CODE_MAP.put("15",   "蒙");   PLATE_FOUR_CODE_MAP.put("11",   "京");
+        PLATE_FOUR_CODE_MAP.put("22",   "吉");   PLATE_FOUR_CODE_MAP.put("51",   "川");
+        PLATE_FOUR_CODE_MAP.put("12",   "津");   PLATE_FOUR_CODE_MAP.put("64",   "宁");
+        PLATE_FOUR_CODE_MAP.put("34",   "皖");   PLATE_FOUR_CODE_MAP.put("37",   "鲁");
+        PLATE_FOUR_CODE_MAP.put("44",   "粤");   PLATE_FOUR_CODE_MAP.put("45",   "桂");
+        PLATE_FOUR_CODE_MAP.put("65",   "新");   PLATE_FOUR_CODE_MAP.put("32",   "苏");
+        PLATE_FOUR_CODE_MAP.put("36",   "赣");   PLATE_FOUR_CODE_MAP.put("13",   "冀");
+        PLATE_FOUR_CODE_MAP.put("41",   "豫");   PLATE_FOUR_CODE_MAP.put("33",   "浙");
+        PLATE_FOUR_CODE_MAP.put("46",   "琼");   PLATE_FOUR_CODE_MAP.put("42",   "鄂");
+        PLATE_FOUR_CODE_MAP.put("43",   "湘");   PLATE_FOUR_CODE_MAP.put("62",   "甘");
+        PLATE_FOUR_CODE_MAP.put("35",   "闽");   PLATE_FOUR_CODE_MAP.put("54",   "藏");
+        PLATE_FOUR_CODE_MAP.put("52",   "贵");   PLATE_FOUR_CODE_MAP.put("21",   "辽");
+        PLATE_FOUR_CODE_MAP.put("50",   "渝");   PLATE_FOUR_CODE_MAP.put("61",   "陕");
+        PLATE_FOUR_CODE_MAP.put("63",   "青");   PLATE_FOUR_CODE_MAP.put("23",   "黑");
     }
 
+    // ============================================================
+    // 主入口
+    // ============================================================
     /**
-     * 因子比对
-     * @param ptlAgreementCostRuleList
-     * @param ruleAttrMappingVoList
-     * @param undwrtRulesAttrList
-     * @param logs
-     * @return
+     * 判断费用因子是否匹配
+     * @param ptlAgreementCostRuleList 协议规则列表
+     * @param ruleAttrMappingVoList 需要校验的规则属性映射列表
+     * @param undwrtRulesAttrList 协议费用因子元数据列表
+     * @param logs 日志
+     * @param undwrtRulesDictList 协议费用因子元数据字典列表
+     * @return 是否匹配
      */
-    public static boolean judgements(List<PtlAgreementCostRule> ptlAgreementCostRuleList, List<RuleAttrMappingVo> ruleAttrMappingVoList,
-                                     List<PtlAgreementUndwrtRulesAttr> undwrtRulesAttrList, StringBuilder logs,  List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-        if (ptlAgreementCostRuleList == null || ptlAgreementCostRuleList.isEmpty()) {
+    public static boolean judgements(List<PtlAgreementCostRule> ptlAgreementCostRuleList,
+                                     List<RuleAttrMappingVo> ruleAttrMappingVoList,
+                                     List<PtlAgreementUndwrtRulesAttr> undwrtRulesAttrList,
+                                     StringBuilder logs,
+                                     List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
+        if (CollUtil.isEmpty(ptlAgreementCostRuleList)) {
             return false;
         }
-        // 按batch分组:不同batch之间为OR关系,同batch内为AND关系
+        // 预建索引:避免内层循环反复 stream().filter() 造成 O(R*A) 扫描
+        Map<String, String> mappingIndex = buildMappingIndex(ruleAttrMappingVoList);
+        Map<String, PtlAgreementUndwrtRulesAttr> attrIndex = buildAttrIndex(undwrtRulesAttrList);
+        Map<Integer, Map<String, String>> dictIndex = buildDictIndex(undwrtRulesDictList);
+        Map<Integer, Map<String, String>> dictNameIndex = buildDictNameIndex(undwrtRulesDictList);
+
+        // 按 batch 分组:不同 batch 之间 OR,同 batch 内 AND
         Map<String, List<PtlAgreementCostRule>> batchMap = ptlAgreementCostRuleList.stream()
                 .collect(Collectors.groupingBy(rule -> rule.getBatch() != null ? rule.getBatch() : "default",
                         LinkedHashMap::new, Collectors.toList()));
 
         StringBuilder errorLogs = new StringBuilder();
         for (Map.Entry<String, List<PtlAgreementCostRule>> entry : batchMap.entrySet()) {
-            List<PtlAgreementCostRule> batchRules = entry.getValue();
             StringBuilder batchLogs = new StringBuilder();
-            boolean batchMatched = doJudgementsMatch(batchRules, ruleAttrMappingVoList, undwrtRulesAttrList,
-                    batchLogs, undwrtRulesDictList);
-            if (batchMatched) {
-                // OR关系:只要任一个batch匹配即通过
-                return true;
+            if (doJudgementsMatch(entry.getValue(), mappingIndex, attrIndex, dictIndex, dictNameIndex, batchLogs)) {
+                return true; // OR:任一 batch 匹配即通过
             }
             errorLogs.append(batchLogs);
         }
-        // 所有batch都未匹配,输出错误日志
         logs.append(errorLogs);
         return false;
     }
 
-    /**
-     * 判断一个batch内的规则是否全部匹配(AND关系)
-     */
-    private static boolean doJudgementsMatch(List<PtlAgreementCostRule> batchRules, List<RuleAttrMappingVo> ruleAttrMappingVoList,
-                                             List<PtlAgreementUndwrtRulesAttr> undwrtRulesAttrList, StringBuilder logs,
-                                             List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-        for (PtlAgreementCostRule ptlAgreementProductCostsAttrLink : batchRules) {
-            //查找规则中的 传值属性
-            RuleAttrMappingVo ruleAttrMappingVo = ruleAttrMappingVoList.stream()
-                    .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                    .findFirst()
-                    .orElse(null);
-            //如果查找不到 传值属性 直接费用对比失败
-            if (ruleAttrMappingVo == null) {
-                List<PtlAgreementUndwrtRulesAttr> collect = undwrtRulesAttrList.stream()
-                        .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                        .toList();
-                if (!collect.isEmpty()) {
-                    logs.append("规则匹配失败:" + collect.get(0).getAttrName() + "\n");
-                }
-                return false;
-            }
-
-            //查找 费用因子规则
-            PtlAgreementUndwrtRulesAttr ptlAgreementUndwrtRulesAttr = undwrtRulesAttrList.stream()
-                    .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                    .findFirst()
-                    .get();
+    // ============================================================
+    // 判断一个batch内的规则是否全部匹配(AND关系)
+    // ============================================================
 
-            boolean useFlag;
-            if(!Objects.isNull(ruleAttrMappingVo.getValue())) {
-                useFlag = attrEqual(ptlAgreementProductCostsAttrLink, ptlAgreementUndwrtRulesAttr, ruleAttrMappingVo.getValue(),
-                        false, undwrtRulesDictList);
-            }else{
-                useFlag = false;
+    private static boolean doJudgementsMatch(List<PtlAgreementCostRule> batchRules,
+                                             Map<String, String> mappingIndex,
+                                             Map<String, PtlAgreementUndwrtRulesAttr> attrIndex,
+                                             Map<Integer, Map<String, String>> dictIndex,
+                                             Map<Integer, Map<String, String>> dictNameIndex,
+                                             StringBuilder logs) {
+        for (PtlAgreementCostRule rule : batchRules) {
+            String value = mappingIndex.get(rule.getAttrCode());
+            if (value == null) {
+                // 找不到传值属性时的日志
+                appendMissingAttrLog(logs, attrIndex, rule.getAttrCode(), false);
+                return false;
             }
+            // 协议费用因子元数据
+            PtlAgreementUndwrtRulesAttr meta = attrIndex.get(rule.getAttrCode());
+            boolean useFlag = attrEqual(rule, meta, value, false, dictIndex, dictNameIndex);
 
             if (!useFlag) {
-                List<PtlAgreementUndwrtRulesAttr> collect = undwrtRulesAttrList.stream()
-                        .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                        .toList();
-
-                boolean isPlateAttr = "LicenseNo".equals(ptlAgreementProductCostsAttrLink.getAttrCode())
-                        || "LicenseArea".equals(ptlAgreementProductCostsAttrLink.getAttrCode());
-
-                // 检验的值
-                String ruleVal = ptlAgreementProductCostsAttrLink.getMin() != null
-                        ? ptlAgreementProductCostsAttrLink.getMin()
-                        : ptlAgreementProductCostsAttrLink.getMax();
-                if (isPlateAttr) {
-                    StringBuilder str = new StringBuilder();
-                    for (String s : ruleVal.split(",")) {
-                        str.append(plateFourCodeMap.getOrDefault(s, s)).append(",");
-                    }
-                    logs.append("检验的值:").append(str.toString()).append("\n");
-                } else {
-                    Integer dictId = collect.get(0).getDictId();
-                    Map<String, String> codeToNameMap = new HashMap<>();
-                    if (dictId != null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                        for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                            if (Objects.equals(label.getDictId(), dictId)) {
-                                codeToNameMap.put(label.getCode(), label.getName());
-                            }
-                        }
-                    }
-                    logs.append("检验的值:").append(displayRuleValue(ruleVal, codeToNameMap)).append("\n");
-                }
-
-                // 传入的值
-                String inVal = ruleAttrMappingVo.getValue();
-                if (isPlateAttr) {
-                    logs.append("传入的值:" + plateFourCodeMap.getOrDefault(inVal, inVal) + "\n");
-                } else {
-                    Integer dictId = collect.get(0).getDictId();
-                    Map<String, String> codeToNameMap = new HashMap<>();
-                    if (dictId != null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                        for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                            if (Objects.equals(label.getDictId(), dictId)) {
-                                codeToNameMap.put(label.getCode(), label.getName());
-                            }
-                        }
-                    }
-                    String name = codeToNameMap.getOrDefault(inVal, inVal);
-                    logs.append("传入的值:" + (codeToNameMap.isEmpty() ? inVal : name) + "\n");
-                }
-
-                if (CollUtil.isNotEmpty(collect)) {
-                    logs.append("规则匹配失败:" + collect.get(0).getAttrName() + "\n");
-                }
-
+                appendMismatchLog(logs, attrIndex, dictIndex, rule.getAttrCode(),
+                        rule, value, false);
                 return false;
             }
         }
@@ -183,22 +124,122 @@ public class FactorMatch {
     }
 
     // ============================================================
-    // 字典映射
+    // 索引预构建:把 stream().filter() 的 O(A) 一次性摊成 O(1) 查找
     // ============================================================
 
-    /**
-     * 展示"检验的值":规则里存的是 code(如 04),翻成 name(如 家庭自用)方便对账。
-     * 支持多选逗号分隔,逐个翻译;翻译不到的保留原 code。
-     */
+    /** attrCode -> value 预建索引 */
+    private static Map<String, String> buildMappingIndex(List<RuleAttrMappingVo> list) {
+        Map<String, String> map = new HashMap<>();
+        if (CollUtil.isNotEmpty(list)) {
+            for (RuleAttrMappingVo v : list) map.put(v.getAttrCode(), v.getValue());
+        }
+        return map;
+    }
+
+    /** attrCode -> meta 预建索引 */
+    private static Map<String, PtlAgreementUndwrtRulesAttr> buildAttrIndex(List<PtlAgreementUndwrtRulesAttr> list) {
+        Map<String, PtlAgreementUndwrtRulesAttr> map = new HashMap<>();
+        if (CollUtil.isNotEmpty(list)) {
+            for (PtlAgreementUndwrtRulesAttr a : list) map.put(a.getAttrCode(), a);
+        }
+        return map;
+    }
+
+    /** dictId -> (code -> name) 预建索引,供日志展示使用 */
+    private static Map<Integer, Map<String, String>> buildDictIndex(List<PtlAgreementUndwrtRulesDictLabal> dictList) {
+        Map<Integer, Map<String, String>> map = new HashMap<>();
+        if (CollUtil.isNotEmpty(dictList)) {
+            for (PtlAgreementUndwrtRulesDictLabal l : dictList) {
+                Integer dictId = l.getDictId();
+                if (dictId == null) continue;
+                map.computeIfAbsent(dictId, k -> new HashMap<>()).put(l.getCode(), l.getName());
+            }
+        }
+        return map;
+    }
+
+    /** dictId -> (name -> code) 预建索引,供 normalizeToCode 使用 */
+    private static Map<Integer, Map<String, String>> buildDictNameIndex(List<PtlAgreementUndwrtRulesDictLabal> dictList) {
+        Map<Integer, Map<String, String>> map = new HashMap<>();
+        if (CollUtil.isNotEmpty(dictList)) {
+            for (PtlAgreementUndwrtRulesDictLabal l : dictList) {
+                Integer dictId = l.getDictId();
+                if (dictId == null) continue;
+                map.computeIfAbsent(dictId, k -> new HashMap<>()).put(l.getName(), l.getCode());
+            }
+        }
+        return map;
+    }
+
+    // ============================================================
+    // 工具方法
+    // ============================================================
+
+    private static PtlAgreementCostRule toCostRule(PtlAgreementUndwrtRulesAttrLink link) {
+        PtlAgreementCostRule r = new PtlAgreementCostRule();
+        r.setMin(link.getMin());
+        r.setMax(link.getMax());
+        r.setOperator(link.getOperator());
+        r.setAttrCode(link.getAttrCode());
+        return r;
+    }
+
+    /** 找不到传值属性时的日志(基于预建索引) */
+    private static void appendMissingAttrLog(StringBuilder logs,
+                                             Map<String, PtlAgreementUndwrtRulesAttr> attrIndex,
+                                             String attrCode, boolean html) {
+        PtlAgreementUndwrtRulesAttr a = attrIndex.get(attrCode);
+        if (a != null) {
+            logs.append((html ? "<span style=\"color:red;\">" : ""))
+                    .append("规则匹配失败:").append(a.getAttrName())
+                    .append(html ? "</span>" : "").append("\n");
+        }
+    }
+
+    /** 匹配失败时的"检验的值 / 传入的值"日志(基于预建索引) */
+    private static void appendMismatchLog(StringBuilder logs,
+                                          Map<String, PtlAgreementUndwrtRulesAttr> attrIndex,
+                                          Map<Integer, Map<String, String>> dictIndex,
+                                          String attrCode,
+                                          PtlAgreementCostRule rule,
+                                          String inVal,
+                                          boolean html) {
+        PtlAgreementUndwrtRulesAttr meta = attrIndex.get(attrCode);
+        if (meta == null) return;
+
+        boolean isPlate = "LicenseNo".equals(attrCode) || "LicenseArea".equals(attrCode);
+        String ruleVal = rule.getMin() != null ? rule.getMin() : rule.getMax();
+        Map<String, String> codeToNameMap = meta.getDictId() == null ? null : dictIndex.get(meta.getDictId());
+
+        // 检验的值
+        if (isPlate) {
+            StringBuilder sb = new StringBuilder();
+            for (String s : ruleVal.split(",")) sb.append(PLATE_FOUR_CODE_MAP.getOrDefault(s, s)).append(",");
+            logs.append("检验的值:").append(sb).append("\n");
+        } else {
+            logs.append("检验的值:").append(displayRuleValue(ruleVal, codeToNameMap)).append("\n");
+        }
+
+        // 传入的值
+        if (isPlate) {
+            logs.append("传入的值:").append(PLATE_FOUR_CODE_MAP.getOrDefault(inVal, inVal)).append("\n");
+        } else {
+            logs.append("传入的值:").append(codeToNameMap == null || codeToNameMap.isEmpty() ? inVal : codeToNameMap.getOrDefault(inVal, inVal)).append("\n");
+        }
+
+        logs.append((html ? "<span style=\"color:red;\">" : "") + "规则匹配失败:" + meta.getAttrName()
+                + (html ? "</span>" : "") + "\n");
+    }
+
+    /** 规则值 code -> name 展示(如 04 -> 家庭自用(04)) */
     private static String displayRuleValue(String ruleVal, Map<String, String> codeToNameMap) {
         if (ruleVal == null) return "";
-        if (CollUtil.isEmpty(codeToNameMap)) return ruleVal;
-        String[] codes = Arrays.stream(ruleVal.split(","))
-                .map(String::trim).filter(s -> !s.isEmpty()).toArray(String[]::new);
-        if (codes.length == 0) return ruleVal;
+        if (codeToNameMap == null || codeToNameMap.isEmpty()) return ruleVal;
+        String[] codes = ruleVal.split(",");
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < codes.length; i++) {
-            String code = codes[i];
+            String code = codes[i].trim();
+            if (code.isEmpty()) continue;
             String name = codeToNameMap.getOrDefault(code, code);
             sb.append(name).append("(").append(code).append(")");
             if (i < codes.length - 1) sb.append(",");
@@ -206,422 +247,178 @@ public class FactorMatch {
         return sb.toString();
     }
 
-    public static boolean judgementsUnderwrite(List<PtlAgreementUndwrtRulesAttrLink> ptlAgreementCostRuleList, List<RuleAttrMappingVo> ruleAttrMappingVoList,
-                                     List<PtlAgreementUndwrtRulesAttr> undwrtRulesAttrList, StringBuilder logs, List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-        boolean useFlag = true;
+    public static boolean judgementsUnderwrite(List<PtlAgreementUndwrtRulesAttrLink> ptlAgreementCostRuleList,
+                                               List<RuleAttrMappingVo> ruleAttrMappingVoList,
+                                               List<PtlAgreementUndwrtRulesAttr> undwrtRulesAttrList,
+                                               StringBuilder logs,
+                                               List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
+        // 预建索引:避免内层循环反复 stream().filter() 造成 O(R*A) 扫描
+        Map<String, String> mappingIndex = buildMappingIndex(ruleAttrMappingVoList);
+        Map<String, PtlAgreementUndwrtRulesAttr> attrIndex = buildAttrIndex(undwrtRulesAttrList);
+        Map<Integer, Map<String, String>> dictIndex = buildDictIndex(undwrtRulesDictList);
+        Map<Integer, Map<String, String>> dictNameIndex = buildDictNameIndex(undwrtRulesDictList);
+
         boolean groupUseFlag = false;
-        for (PtlAgreementUndwrtRulesAttrLink ptlAgreementProductCostsAttrLink : ptlAgreementCostRuleList) {
-            //查找规则中的 传值属性
-            RuleAttrMappingVo ruleAttrMappingVo = ruleAttrMappingVoList.stream()
-                    .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                    .findFirst()
-                    .orElse(null);
-            //如果查找不到 传值属性 直接费用对比失败
-            if (ruleAttrMappingVo == null) {
-                log.info("承保规则校验-属性未找到: attrCode={}", ptlAgreementProductCostsAttrLink.getAttrCode());
-                log.info("承保规则校验-规则匹配失败: attrCode={}", ptlAgreementProductCostsAttrLink.getAttrCode());
-
-                List<PtlAgreementUndwrtRulesAttr> collect = undwrtRulesAttrList.stream()
-                        .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                        .toList();
-                if (!collect.isEmpty()) {
-                    logs.append("规则匹配失败:" + collect.get(0).getAttrName() + "\n");
-                }
+        for (PtlAgreementUndwrtRulesAttrLink link : ptlAgreementCostRuleList) {
+            String value = mappingIndex.get(link.getAttrCode());
+            if (value == null) {
+                log.info("承保规则校验-属性未找到: attrCode={}", link.getAttrCode());
+                appendMissingAttrLog(logs, attrIndex, link.getAttrCode(), true);
                 return false;
             }
 
+            PtlAgreementUndwrtRulesAttr meta = attrIndex.get(link.getAttrCode());
+            PtlAgreementCostRule costRule = toCostRule(link);
 
-            //查找 费用因子规则
-            PtlAgreementUndwrtRulesAttr ptlAgreementUndwrtRulesAttr = undwrtRulesAttrList.stream()
-                    .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                    .findFirst()
-                    .get();
-
-            if(!Objects.isNull(ruleAttrMappingVo.getValue())) {
-                PtlAgreementCostRule ptlAgreementCostRule = new PtlAgreementCostRule();
-                ptlAgreementCostRule.setMin(ptlAgreementProductCostsAttrLink.getMin());
-                ptlAgreementCostRule.setMax(ptlAgreementProductCostsAttrLink.getMax());
-                ptlAgreementCostRule.setOperator(ptlAgreementProductCostsAttrLink.getOperator());
-                ptlAgreementCostRule.setAttrCode(ptlAgreementProductCostsAttrLink.getAttrCode());
-                useFlag = attrEqual(ptlAgreementCostRule, ptlAgreementUndwrtRulesAttr, ruleAttrMappingVo.getValue(),
-                        true, undwrtRulesDictList);
+            boolean useFlag;
+            if (StrUtil.isNotBlank(value)) {
+                useFlag = attrEqual(costRule, meta, value, true, dictIndex, dictNameIndex);
                 log.info("承保规则校验-单属性匹配: attrCode={}, attrType={}, 规则值(min={}, max={}, operator={}), 传入值={}, useFlag={}",
-                        ptlAgreementProductCostsAttrLink.getAttrCode(), ptlAgreementUndwrtRulesAttr.getAttrType(),
-                        ptlAgreementProductCostsAttrLink.getMin(), ptlAgreementProductCostsAttrLink.getMax(),
-                        ptlAgreementProductCostsAttrLink.getOperator(), ruleAttrMappingVo.getValue(), useFlag);
-            }else{
+                        link.getAttrCode(), meta == null ? null : meta.getAttrType(), link.getMin(), link.getMax(),
+                        link.getOperator(), value, useFlag);
+            } else {
                 useFlag = false;
-                log.info("承保规则校验-传入值为null: attrCode={}, useFlag=false", ptlAgreementProductCostsAttrLink.getAttrCode());
-            }
-
-            if(useFlag){
-                groupUseFlag = useFlag;
+                log.info("承保规则校验-传入值为null: attrCode={}, useFlag=false", link.getAttrCode());
             }
 
-            if (!useFlag) {
+            if (useFlag) {
+                groupUseFlag = true;
+            } else {
                 log.info("承保规则校验-条件命中! attrCode={}, 传入值={}, 规则min={}, max={}, operator={}",
-                        ptlAgreementProductCostsAttrLink.getAttrCode(), ruleAttrMappingVo.getValue(),
-                        ptlAgreementProductCostsAttrLink.getMin(), ptlAgreementProductCostsAttrLink.getMax(),
-                        ptlAgreementProductCostsAttrLink.getOperator());
-
-                List<PtlAgreementUndwrtRulesAttr> collect = undwrtRulesAttrList.stream()
-                        .filter(x -> x.getAttrCode().equals(ptlAgreementProductCostsAttrLink.getAttrCode()))
-                        .toList();
-                boolean isPlateAttr = "LicenseNo".equals(ptlAgreementProductCostsAttrLink.getAttrCode())
-                        || "LicenseArea".equals(ptlAgreementProductCostsAttrLink.getAttrCode());
-
-                // 检验的值
-                String ruleVal = ptlAgreementProductCostsAttrLink.getMin() != null
-                        ? ptlAgreementProductCostsAttrLink.getMin()
-                        : ptlAgreementProductCostsAttrLink.getMax();
-                if (isPlateAttr) {
-                    StringBuilder str = new StringBuilder();
-                    for (String s : ruleVal.split(",")) {
-                        str.append(plateFourCodeMap.getOrDefault(s, s)).append(",");
-                    }
-                    logs.append("检验的值:").append(str.toString()).append("\n");
-                } else {
-                    Integer dictId = collect.get(0).getDictId();
-                    Map<String, String> codeToNameMap = new HashMap<>();
-                    if (dictId != null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                        for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                            if (Objects.equals(label.getDictId(), dictId)) {
-                                codeToNameMap.put(label.getCode(), label.getName());
-                            }
-                        }
-                    }
-                    logs.append("检验的值:").append(displayRuleValue(ruleVal, codeToNameMap)).append("\n");
-                }
-
-                // 传入的值
-                String inVal = ruleAttrMappingVo.getValue();
-                if (isPlateAttr) {
-                    logs.append("传入的值:" + plateFourCodeMap.getOrDefault(inVal, inVal) + "\n");
-                } else {
-                    Integer dictId = collect.get(0).getDictId();
-                    Map<String, String> codeToNameMap = new HashMap<>();
-                    if (dictId != null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                        for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                            if (Objects.equals(label.getDictId(), dictId)) {
-                                codeToNameMap.put(label.getCode(), label.getName());
-                            }
-                        }
-                    }
-                    String name = codeToNameMap.getOrDefault(inVal, inVal);
-                    logs.append("传入的值:" + (codeToNameMap.isEmpty() ? inVal : name) + "\n");
-                }
-
-                if (CollUtil.isNotEmpty(collect)) {
-                    logs.append("<span style=\"color:red;\">规则匹配失败:" + collect.get(0).getAttrName() + "</span>\n");
-                }
+                        link.getAttrCode(), value, link.getMin(), link.getMax(), link.getOperator());
+                appendMismatchLog(logs, attrIndex, dictIndex, link.getAttrCode(),
+                        costRule, value, true);
             }
         }
-        log.info("承保规则校验-所有条件均未命中, 规则组通过, useFlag={}", useFlag);
+        log.info("承保规则校验-所有条件均未命中, 规则组通过, useFlag={}", groupUseFlag);
         return groupUseFlag;
     }
 
-    private static boolean attrEqual(PtlAgreementCostRule ptlAgreementCostRule,
-                              PtlAgreementUndwrtRulesAttr ptlAgreementUndwrtRulesAttr, String value, boolean isUnderwrite,
-                              List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-
-        if (ptlAgreementUndwrtRulesAttr == null || ptlAgreementUndwrtRulesAttr.getAttrType() == null) {
-            // 没有元数据:无法得知 attrType,按"包含"语义做纯文本兜底比较
-            // (BrandandModel 等 inputTag 大多是 contains 语义,与原逻辑 inputTextEqual 默认分支一致)
-            log.warn("attrEqual 因子元数据缺失,按纯文本兜底比较, attrCode={}", ptlAgreementCostRule.getAttrCode());
-            if (ptlAgreementCostRule.getMin() == null || value == null) return false;
-            String finalNormalizedValue = value;
-            boolean contains = Arrays.stream(ptlAgreementCostRule.getMin().split(","))
-                    .anyMatch(o -> finalNormalizedValue.contains(o.trim()));
-            return isUnderwrite ? !contains : contains;
-        }
+    // ============================================================
+    // 比较分发(统一把传入 name 还原成 code)
+    // ============================================================
 
-        // 字典还原依据:参与比较的这条因子元数据 ptlAgreementUndwrtRulesAttr 自身挂的 dictId,
-        // 再到 undwrtRulesDictList 中按 name 找 code(如 "家庭自用" -> "04")。
-        Integer dictId = ptlAgreementUndwrtRulesAttr.getDictId();
-        // ===== 新增:把传入的 name 还原成 code 再参与比较 =====
-        // 只对依赖字典的 select/radio/checkbox 做还原;input/inputNumber/date 等保留原值
-        if (CollUtil.isNotEmpty(undwrtRulesDictList)
-                && dictId != null
-                && !ptlAgreementCostRule.getAttrCode().equals("LicenseArea") // 车牌归属地无字典,纯文本
-                && !ptlAgreementCostRule.getAttrCode().equals("LicenseNo")) {
-            String normalized = value;
-            for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                if (Objects.equals(label.getDictId(), dictId) && label.getName().equals(value)) {
-                    normalized = label.getCode();
-                    break;
-                }
-            }
-            value = normalized;
-        }
-        // ====================================================
-        boolean result = false;
-        if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("checkbox")) {
-            result = checkBoxEqual(ptlAgreementCostRule, value, dictId, undwrtRulesDictList);
-        } else if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("inputNumber")) {
-            result = inputNumberEqual(ptlAgreementCostRule, value);
-        } else if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("input") || ptlAgreementUndwrtRulesAttr.getAttrType().equals("inputTag")) {
-            //截取身份证号码
-            if (ptlAgreementCostRule.getAttrCode().equals("CarOwnersIDNumber") || ptlAgreementCostRule.getAttrCode().equals("ApplicantIDNumber") ||
-                    ptlAgreementCostRule.getAttrCode().equals("InsuredIDNumber")) {
-                value = value.substring(0, ptlAgreementCostRule.getMin().length());
-            }
-            result = inputTextEqual(ptlAgreementCostRule, value);
-        } else if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("select")) {
-            //截取车牌
-            if (ptlAgreementUndwrtRulesAttr.getAttrCode().equals("LicenseNo")) {
-                value = value.substring(0, 4);
-            }
-            //车龄走数值比较,不走字典
-            if (ptlAgreementUndwrtRulesAttr.getAttrCode().equals("VehicleAge")) {
-                result = inputNumberEqual(ptlAgreementCostRule, value);
-            // LicenseArea 是 select 但无 dictId,按 input 纯文本比较(不走字典还原)
-            } else if (ptlAgreementUndwrtRulesAttr.getAttrCode().equals("LicenseArea")) {
-                result = inputTextEqual(ptlAgreementCostRule, value);
-            } else {
-                result = selectEqual(ptlAgreementCostRule, value, dictId, undwrtRulesDictList);
-            }
-        } else if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("radio")) {
-            result = radioEqual(ptlAgreementCostRule, value, dictId, undwrtRulesDictList);
-        } else if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("datetime")){ // 时间
-            result = dateTimeEqual(ptlAgreementCostRule, value);
-        } else if (ptlAgreementUndwrtRulesAttr.getAttrType().equals("date")){
-            result = dateEqual(ptlAgreementCostRule, value);
+    private static boolean attrEqual(PtlAgreementCostRule rule,
+                                     PtlAgreementUndwrtRulesAttr meta,
+                                     String value,
+                                     boolean isUnderwrite,
+                                     Map<Integer, Map<String, String>> dictIndex,
+                                     Map<Integer, Map<String, String>> dictNameIndex) {
+        if (meta == null || meta.getAttrType() == null) {
+            log.warn("attrEqual 因子元数据缺失,按纯文本兜底比较, attrCode={}", rule.getAttrCode());
+            if ((rule.getMin() == null && rule.getMax() == null) || value == null) return false;
+            return Arrays.stream(rule.getMin().split(","))
+                    .anyMatch(o -> value.contains(o.trim())) == !isUnderwrite;
         }
-        // 判断是否是承保规则
-        if(isUnderwrite){
-            return !result;
-        }else {
-            return result;
+
+        // 统一还原:传入的是 name 就翻成 code(排除无字典的纯文本字段),O(1) 查表
+        final String cmpValue = normalizeToCode(value, meta, dictNameIndex);
+
+        boolean result;
+        switch (meta.getAttrType()) {
+            case "checkbox":    result = checkBoxEqual(rule, cmpValue); break;
+            case "inputNumber": result = inputNumberEqual(rule, cmpValue); break;
+            case "input":
+            case "inputTag":    result = inputTextEqual(rule, cmpValue); break;
+            case "select":      result = selectEqual(rule, cmpValue, meta); break;
+            case "radio":       result = radioEqual(rule, cmpValue); break;
+            case "datetime":    result = dateTimeEqual(rule, cmpValue); break;
+            case "date":        result = dateEqual(rule, cmpValue); break;
+            default:            result = false;
         }
+        return isUnderwrite ? !result : result;
     }
 
-
-    private static boolean checkBoxEqual(PtlAgreementCostRule ptlAgreementCostRule, String value, Integer dictId,
-                                  List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-        if (ptlAgreementCostRule.getMin() == null || value == null) {
-            return false;
-        }
-        // dictId 为空时(无字典):把 min 里的 code 翻成 name,再用实际 value(汉字)与 name 比较
-        String[] split = ptlAgreementCostRule.getMin().split(",");
-        for (String sp : split) {
-            String spTrim = sp.trim();
-            if (dictId == null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                    if (label.getCode().equals(spTrim) && value.trim().equals(label.getName())) {
-                        return true;
-                    }
-                }
-            }
-            if (spTrim.equals(value.trim())) {
-                return true;
-            }
-        }
-        return false;
+    /** 把传入值统一还原成 code(name -> code),基于预建索引 O(1) */
+    private static String normalizeToCode(String value,
+                                          PtlAgreementUndwrtRulesAttr meta,
+                                          Map<Integer, Map<String, String>> dictNameIndex) {
+        if (value == null || dictNameIndex.isEmpty()) return value;
+        Integer dictId = meta.getDictId();
+        if (dictId == null) return value;
+        String code = meta.getAttrCode();
+        if ("LicenseNo".equals(code) || "LicenseArea".equals(code)) return value; // 无字典从PLATE_FOUR_CODE_MAP获取还原
+        Map<String, String> nameToCode = dictNameIndex.get(dictId);
+        if (nameToCode == null || nameToCode.isEmpty()) return value;
+        return nameToCode.getOrDefault(value, value);
     }
 
-    private static boolean inputNumberEqual(PtlAgreementCostRule ptlAgreementCostRule, String value) {
-        double v = Double.parseDouble(value);
-        //统一处理数值
-        if ("1".equals(ptlAgreementCostRule.getOperator())) {
-            if (Double.parseDouble(ptlAgreementCostRule.getMin()) <= v &&
-                    Double.parseDouble(ptlAgreementCostRule.getMax()) >= v) {
-                return true;
-            }
-        } else if ("2".equals(ptlAgreementCostRule.getOperator())) {
-            if (Double.parseDouble(ptlAgreementCostRule.getMin()) > v) {
-                return true;
-            }
-        } else if ("3".equals(ptlAgreementCostRule.getOperator())) {
-            if (Double.parseDouble(ptlAgreementCostRule.getMin()) >= v) {
-                return true;
-            }
-        } else if ("4".equals(ptlAgreementCostRule.getOperator())) {
-            if (Double.parseDouble(ptlAgreementCostRule.getMax()) < v) {
-                return true;
-            }
-        } else if ("5".equals(ptlAgreementCostRule.getOperator())) {
-            if (Double.parseDouble(ptlAgreementCostRule.getMax()) <= v) {
-                return true;
-            }
-        }
-        return false;
+    private static boolean checkBoxEqual(PtlAgreementCostRule rule, String value) {
+        if (rule.getMin() == null || value == null) return false;
+        return Arrays.stream(rule.getMin().split(",")).anyMatch(o -> o.trim().equals(value.trim()));
     }
 
-    private static boolean inputTextEqual(PtlAgreementCostRule ptlAgreementCostRule, String value) {
-        //将值进行分割
-        String[] split = ptlAgreementCostRule.getMin().split(",");
-        AtomicBoolean returnBool = new AtomicBoolean(false);
-
-        List<String> equalsMap = new ArrayList<>();
-        //字符型评分
-        equalsMap.add("CharacterBasedRating");
-        //交强字符型评分
-        equalsMap.add("JqCharacterBasedRating");
-        //商业字符型评分
-        equalsMap.add("SyCharacterBasedRating");
-
-
-
-        //equest 等于判断
-        if(equalsMap.contains(ptlAgreementCostRule.getAttrCode())){
-            boolean b = Arrays.stream(split).anyMatch(value::equals);
-            returnBool.set(b);
-        }else if((ptlAgreementCostRule.getAttrCode().equals("BrandandModel") || ptlAgreementCostRule.getAttrCode().equals("CarOwnerName")
-                || ptlAgreementCostRule.getAttrCode().equals("CarOwnersAddress") || ptlAgreementCostRule.getAttrCode().equals("ApplicantAddress")
-                || ptlAgreementCostRule.getAttrCode().equals("InsuredAddress"))
-                && ptlAgreementCostRule.getOperator().equals("2")){
-            //处理品牌型号  不包含的情况
-            boolean anyMatch = Arrays.stream(split)
-                    .anyMatch(value::contains);
-            returnBool.set(!anyMatch);
-        }else {
-            boolean anyMatch = Arrays.stream(split)
-                    .anyMatch(value::contains);
-            returnBool.set(anyMatch);
-        }
-        return returnBool.get();
+    private static boolean selectEqual(PtlAgreementCostRule rule, String value, PtlAgreementUndwrtRulesAttr meta) {
+        if (rule.getMin() == null || value == null) return false;
+        if ("LicenseArea".equals(meta.getAttrCode()) || "LicenseNo".equals(meta.getAttrCode())) return inputTextEqual(rule, value);
+        if ("VehicleAge".equals(meta.getAttrCode())) return inputNumberEqual(rule, value);
+        return rule.getMin().contains(value);
     }
 
-    private static boolean selectEqual(PtlAgreementCostRule ptlAgreementCostRule, String value, Integer dictId,
-                                List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-        if (ptlAgreementCostRule.getMin() == null || value == null) {
-            return false;
-        }
-        // dictId 为空时(无字典):把 min 里的 code 翻成 name,再用实际 value(汉字)与 name 比较
-        if (ptlAgreementCostRule.getOperator().equals("2")) {
-            String [] options = ptlAgreementCostRule.getMin().split(",");
-            for (String opt : options) {
-                String optTrim = opt.trim();
-                if (optTrim.equals(value.trim())) {
-                    return true;
-                }
-                if (dictId == null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                    for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                        if (label.getCode().equals(optTrim) && value.trim().equals(label.getName())) {
-                            return true;
-                        }
-                    }
-                }
-            }
+    private static boolean radioEqual(PtlAgreementCostRule rule, String value) {
+        if ("NewEnergyMark".equals(rule.getAttrCode())) {
+            boolean newEnergy = EnergyTypeCode.isNewEnergy(value);
+            if (newEnergy && "1".equals(rule.getMin())) return true;
+            if (!newEnergy && "0".equals(rule.getMin())) return true;
             return false;
-        } else if (ptlAgreementCostRule.getMin() != null) {
-            if (ptlAgreementCostRule.getMin().contains(value)) {
-                return true;
-            }
-            if (dictId == null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                    if (label.getCode().equals(ptlAgreementCostRule.getMin()) && value.equals(label.getName())) {
-                        return true;
-                    }
-                }
-            }
         }
-
-        return false;
+        return rule.getMin().contains(value);
     }
 
-    private static boolean radioEqual(PtlAgreementCostRule ptlAgreementCostRule, String value, Integer dictId,
-                               List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList) {
-        //新能源判断
-        if ("NewEnergyMark".equals(ptlAgreementCostRule.getAttrCode())) {
-            // 是否是新能源车
-            boolean newEnergy = EnergyTypeCode.isNewEnergy(value);
-            if (newEnergy && ptlAgreementCostRule.getMin().equals("1")) {
-                return true;
-            } else if (!newEnergy && ptlAgreementCostRule.getMin().equals("0")) {
-                return true;
-            }
-        } else {
-            // dictId 为空时(无字典):把 min 里的 code 翻成 name,再用实际 value(汉字)与 name 比较
-            if (dictId == null && CollUtil.isNotEmpty(undwrtRulesDictList)) {
-                for (PtlAgreementUndwrtRulesDictLabal label : undwrtRulesDictList) {
-                    if (label.getCode().equals(ptlAgreementCostRule.getMin()) && value.equals(label.getName())) {
-                        return true;
-                    }
-                }
-            }
-            if (ptlAgreementCostRule.getMin().contains(value)) {
-                return true;
-            }
+    private static boolean inputNumberEqual(PtlAgreementCostRule rule, String value) {
+        if ((rule.getMin() == null && rule.getMax() == null) || value == null) return false;
+        double v = Double.parseDouble(value);
+        double min = rule.getMin() != null ? Double.parseDouble(rule.getMin()) : Double.MIN_VALUE;
+        double max = rule.getMax() != null ? Double.parseDouble(rule.getMax()) : Double.MAX_VALUE;
+        switch (rule.getOperator()) {
+            case "1": return min <= v && v <= max;
+            case "2": return min > v;
+            case "3": return min >= v;
+            case "4": return max < v;
+            case "5": return max <= v;
+            default:  return false;
         }
-        return false;
     }
 
-    public static boolean dateTimeEqual(PtlAgreementCostRule ptlAgreementCostRule, String value){
-        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-        if(Objects.isNull(value) || value.equals("")){
-            return false;
-        }
-        LocalDateTime v = LocalDateTime.parse(value,formatter);
-        LocalDateTime min = null,max = null;
-        if(!Objects.isNull(ptlAgreementCostRule.getMin())){
-            min = LocalDateTime.parse(ptlAgreementCostRule.getMin(),formatter);
-        }
-        if(!Objects.isNull(ptlAgreementCostRule.getMax())){
-            max = LocalDateTime.parse(ptlAgreementCostRule.getMax(),formatter);
+    private static boolean inputTextEqual(PtlAgreementCostRule rule, String value) {
+        if (rule.getMin() == null || value == null) return false;
+        String[] split = rule.getMin().split(",");
+        List<String> equalsMap = Arrays.asList("CharacterBasedRating", "JqCharacterBasedRating", "SyCharacterBasedRating");
+        if (equalsMap.contains(rule.getAttrCode())) {
+            return Arrays.stream(split).anyMatch(value::equals);
         }
+        boolean contains = Arrays.stream(split).anyMatch(value::contains);
+        boolean notOp = ("BrandandModel".equals(rule.getAttrCode()) || "CarOwnerName".equals(rule.getAttrCode())
+                || "CarOwnersAddress".equals(rule.getAttrCode()) || "ApplicantAddress".equals(rule.getAttrCode())
+                || "InsuredAddress".equals(rule.getAttrCode())) && "2".equals(rule.getOperator());
+        return notOp ? !contains : contains;
+    }
 
-        //统一处理数值
-        if ("1".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isAfter(min) && v.isBefore(max)) {
-                return true;
-            }
-        } else if ("2".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isBefore(min)) {
-                return true;
-            }
-        } else if ("3".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isBefore(min) || v.isEqual(min)) {
-                return true;
-            }
-        } else if ("4".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isAfter(max)) {
-                return true;
-            }
-        } else if ("5".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isAfter(max) || v.isEqual(max)) {
-                return true;
-            }
-        }
-        return false;
+    public static boolean dateTimeEqual(PtlAgreementCostRule rule, String value) {
+        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        if (StrUtil.isBlank(value)) return false;
+        LocalDateTime v = LocalDateTime.parse(value, f);
+        LocalDateTime min = rule.getMin() != null ? LocalDateTime.parse(rule.getMin(), f) : null;
+        LocalDateTime max = rule.getMax() != null ? LocalDateTime.parse(rule.getMax(), f) : null;
+        return compareDateTime(v, min, max, rule.getOperator());
     }
 
-    public static boolean dateEqual(PtlAgreementCostRule ptlAgreementCostRule, String value){
-//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-        if(Objects.isNull(value) || value.equals("")){
-            return false;
-        }
+    public static boolean dateEqual(PtlAgreementCostRule rule, String value) {
+        if (StrUtil.isBlank(value)) return false;
         LocalDateTime v = LocalDate.parse(value).atStartOfDay();
-        LocalDateTime min = null,max = null;
-        if(!Objects.isNull(ptlAgreementCostRule.getMin())){
-            min = LocalDate.parse(ptlAgreementCostRule.getMin()).atStartOfDay();
-        }
-        if(!Objects.isNull(ptlAgreementCostRule.getMax())){
-            max = LocalDate.parse(ptlAgreementCostRule.getMax()).atStartOfDay();
-        }
+        LocalDateTime min = rule.getMin() != null ? LocalDate.parse(rule.getMin()).atStartOfDay() : null;
+        LocalDateTime max = rule.getMax() != null ? LocalDate.parse(rule.getMax()).atStartOfDay() : null;
+        return compareDateTime(v, min, max, rule.getOperator());
+    }
 
-        //统一处理数值
-        if ("1".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isAfter(min) && v.isBefore(max)) {
-                return true;
-            }
-        } else if ("2".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isBefore(min)) {
-                return true;
-            }
-        } else if ("3".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isBefore(min) || v.isEqual(min)) {
-                return true;
-            }
-        } else if ("4".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isAfter(max)) {
-                return true;
-            }
-        } else if ("5".equals(ptlAgreementCostRule.getOperator())) {
-            if (v.isAfter(max) || v.isEqual(max)) {
-                return true;
-            }
+    private static boolean compareDateTime(LocalDateTime v, LocalDateTime min, LocalDateTime max, String op) {
+        switch (op) {
+            case "1": return v.isAfter(min) && v.isBefore(max);
+            case "2": return v.isBefore(min);
+            case "3": return !v.isAfter(min);
+            case "4": return v.isAfter(max);
+            case "5": return !v.isBefore(max);
+            default:  return false;
         }
-        return false;
     }
-}
+}

+ 27 - 16
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/aspect/AuditVerificationAspect.java

@@ -64,20 +64,29 @@ public class AuditVerificationAspect {
 
     private final PtlNewAgreementClient ptlNewAgreementClient;
 
-    private static final Map<String, String> plateFourCodeMap = new HashMap<>();
-
+    private static final Map<String, String> PLATE_FOUR_CODE_MAP = new HashMap<>();
     static {
-        plateFourCodeMap.put("晋D", "1404");
-        plateFourCodeMap.put("晋M", "1408");
-        plateFourCodeMap.put("晋J", "1411");
-        plateFourCodeMap.put("晋C", "1403");
-        plateFourCodeMap.put("晋K", "1407");
-        plateFourCodeMap.put("晋L", "1410");
-        plateFourCodeMap.put("晋B", "1402");
-        plateFourCodeMap.put("晋F", "1406");
-        plateFourCodeMap.put("晋A", "1401");
-        plateFourCodeMap.put("晋E", "1405");
-        plateFourCodeMap.put("晋H", "1409");
+        PLATE_FOUR_CODE_MAP.put("晋D", "1404");  PLATE_FOUR_CODE_MAP.put("晋M", "1408");
+        PLATE_FOUR_CODE_MAP.put("晋J", "1411");  PLATE_FOUR_CODE_MAP.put("晋C", "1403");
+        PLATE_FOUR_CODE_MAP.put("晋K", "1407");  PLATE_FOUR_CODE_MAP.put("晋L", "1410");
+        PLATE_FOUR_CODE_MAP.put("晋B", "1402");  PLATE_FOUR_CODE_MAP.put("晋F", "1406");
+        PLATE_FOUR_CODE_MAP.put("晋A", "1401");  PLATE_FOUR_CODE_MAP.put("晋E", "1405");
+        PLATE_FOUR_CODE_MAP.put("晋H", "1409");  PLATE_FOUR_CODE_MAP.put("晋",   "14");
+        PLATE_FOUR_CODE_MAP.put("沪",   "31");   PLATE_FOUR_CODE_MAP.put("云",   "53");
+        PLATE_FOUR_CODE_MAP.put("蒙",   "15");   PLATE_FOUR_CODE_MAP.put("京",   "11");
+        PLATE_FOUR_CODE_MAP.put("吉",   "22");   PLATE_FOUR_CODE_MAP.put("川",   "51");
+        PLATE_FOUR_CODE_MAP.put("津",   "12");   PLATE_FOUR_CODE_MAP.put("宁",   "64");
+        PLATE_FOUR_CODE_MAP.put("皖",   "34");   PLATE_FOUR_CODE_MAP.put("鲁",   "37");
+        PLATE_FOUR_CODE_MAP.put("粤",   "44");   PLATE_FOUR_CODE_MAP.put("桂",   "45");
+        PLATE_FOUR_CODE_MAP.put("新",   "65");   PLATE_FOUR_CODE_MAP.put("苏",   "32");
+        PLATE_FOUR_CODE_MAP.put("赣",   "36");   PLATE_FOUR_CODE_MAP.put("冀",   "13");
+        PLATE_FOUR_CODE_MAP.put("豫",   "41");   PLATE_FOUR_CODE_MAP.put("浙",   "33");
+        PLATE_FOUR_CODE_MAP.put("琼",   "46");   PLATE_FOUR_CODE_MAP.put("鄂",   "42");
+        PLATE_FOUR_CODE_MAP.put("湘",   "43");   PLATE_FOUR_CODE_MAP.put("甘",   "62");
+        PLATE_FOUR_CODE_MAP.put("闽",   "35");   PLATE_FOUR_CODE_MAP.put("藏",   "54");
+        PLATE_FOUR_CODE_MAP.put("贵",   "52");   PLATE_FOUR_CODE_MAP.put("辽",   "21");
+        PLATE_FOUR_CODE_MAP.put("渝",   "50");   PLATE_FOUR_CODE_MAP.put("陕",   "61");
+        PLATE_FOUR_CODE_MAP.put("青",   "63");   PLATE_FOUR_CODE_MAP.put("黑",   "23");
     }
 
 
@@ -222,8 +231,11 @@ public class AuditVerificationAspect {
         log.info("=== 承保规则校验开始, 规则组数={}, 传入属性数={} ===", ruleGroups == null ? 0 : ruleGroups.size(), ruleAttrMappingVoList.size());
 
         ruleAttrMappingVoList.forEach(ruleAttrMappingVo -> {
-            if ("LicenseNo".equals(ruleAttrMappingVo.getAttrCode()) && ruleAttrMappingVo.getValue().startsWith("晋")) {
-                ruleAttrMappingVo.setValue(plateFourCodeMap.getOrDefault(ruleAttrMappingVo.getValue().substring(0, 2), ruleAttrMappingVo.getValue()));
+            if ("LicenseNo".equals(ruleAttrMappingVo.getAttrCode())) {
+                ruleAttrMappingVo.setValue(PLATE_FOUR_CODE_MAP.getOrDefault(ruleAttrMappingVo.getValue().substring(0, 2), ruleAttrMappingVo.getValue()));
+            }
+            if ("LicenseArea".equals(ruleAttrMappingVo.getAttrCode())) {
+                ruleAttrMappingVo.setValue(PLATE_FOUR_CODE_MAP.getOrDefault(ruleAttrMappingVo.getValue().substring(0, 1), ruleAttrMappingVo.getValue()));
             }
         });
 
@@ -247,7 +259,6 @@ public class AuditVerificationAspect {
             }
 
             // 直接判断该规则组是否匹配,无需循环调用
-            // 有一个匹配上  或者都没匹配上 都返回true
             boolean ruleMatched = FactorMatch.judgementsUnderwrite(ptlAgreementUndwrtRulesNews, ruleAttrMappingVoList, undwrtRulesAttrList, ruleLogs, undwrtRulesDictList);
 
             log.info("规则组[{}]匹配结果: ruleMatched={}, 错误日志=[{}]", groupIndex, ruleMatched, ruleLogs);

+ 34 - 9
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/aspect/QuoteVerificationAspect.java

@@ -73,6 +73,31 @@ public class QuoteVerificationAspect {
     private final BaseController baseController;
     private final PtlNewAgreementClient ptlNewAgreementClient;
 
+    private static final Map<String, String> PLATE_FOUR_CODE_MAP = new HashMap<>();
+    static {
+        PLATE_FOUR_CODE_MAP.put("晋D", "1404");  PLATE_FOUR_CODE_MAP.put("晋M", "1408");
+        PLATE_FOUR_CODE_MAP.put("晋J", "1411");  PLATE_FOUR_CODE_MAP.put("晋C", "1403");
+        PLATE_FOUR_CODE_MAP.put("晋K", "1407");  PLATE_FOUR_CODE_MAP.put("晋L", "1410");
+        PLATE_FOUR_CODE_MAP.put("晋B", "1402");  PLATE_FOUR_CODE_MAP.put("晋F", "1406");
+        PLATE_FOUR_CODE_MAP.put("晋A", "1401");  PLATE_FOUR_CODE_MAP.put("晋E", "1405");
+        PLATE_FOUR_CODE_MAP.put("晋H", "1409");  PLATE_FOUR_CODE_MAP.put("晋",   "14");
+        PLATE_FOUR_CODE_MAP.put("沪",   "31");   PLATE_FOUR_CODE_MAP.put("云",   "53");
+        PLATE_FOUR_CODE_MAP.put("蒙",   "15");   PLATE_FOUR_CODE_MAP.put("京",   "11");
+        PLATE_FOUR_CODE_MAP.put("吉",   "22");   PLATE_FOUR_CODE_MAP.put("川",   "51");
+        PLATE_FOUR_CODE_MAP.put("津",   "12");   PLATE_FOUR_CODE_MAP.put("宁",   "64");
+        PLATE_FOUR_CODE_MAP.put("皖",   "34");   PLATE_FOUR_CODE_MAP.put("鲁",   "37");
+        PLATE_FOUR_CODE_MAP.put("粤",   "44");   PLATE_FOUR_CODE_MAP.put("桂",   "45");
+        PLATE_FOUR_CODE_MAP.put("新",   "65");   PLATE_FOUR_CODE_MAP.put("苏",   "32");
+        PLATE_FOUR_CODE_MAP.put("赣",   "36");   PLATE_FOUR_CODE_MAP.put("冀",   "13");
+        PLATE_FOUR_CODE_MAP.put("豫",   "41");   PLATE_FOUR_CODE_MAP.put("浙",   "33");
+        PLATE_FOUR_CODE_MAP.put("琼",   "46");   PLATE_FOUR_CODE_MAP.put("鄂",   "42");
+        PLATE_FOUR_CODE_MAP.put("湘",   "43");   PLATE_FOUR_CODE_MAP.put("甘",   "62");
+        PLATE_FOUR_CODE_MAP.put("闽",   "35");   PLATE_FOUR_CODE_MAP.put("藏",   "54");
+        PLATE_FOUR_CODE_MAP.put("贵",   "52");   PLATE_FOUR_CODE_MAP.put("辽",   "21");
+        PLATE_FOUR_CODE_MAP.put("渝",   "50");   PLATE_FOUR_CODE_MAP.put("陕",   "61");
+        PLATE_FOUR_CODE_MAP.put("青",   "63");   PLATE_FOUR_CODE_MAP.put("黑",   "23");
+    }
+
     @AfterReturning(pointcut = "@annotation(com.jzg.quotation.summary.aop.QuoteVerification)", returning = "result")
     public void doAfter(HttpResult<QuoteResultsVo> result) {
         String loginUserId = baseController.getUserId();
@@ -130,10 +155,6 @@ public class QuoteVerificationAspect {
             log.info("过滤的费用列表:{}",JSONObject.toJSONString(agreementProductCosts));
             if (CollUtil.isNotEmpty(agreementProductCosts)) {
                 //遍历费用因子
-                HttpResult<String> convertLicense2AreaNumber = orgClient.convertLicense2AreaNumber(insOrdersCarInfo.getLicenseNo().substring(0, 2));
-                if(convertLicense2AreaNumber.isSuccess()){
-                    insOrdersCarInfo.setLicenseNo(convertLicense2AreaNumber.getData());//车牌转code
-                }
                 String costId = verificationCosts(agreementProductCosts, logs, insOrdersOther, insOrdersCarInfo, insOrdersRisks,
                         insOrdersCarUserInfos, kindList, insOrdersCosts, insOrdersAccidentalDriving, insOrders);
                 if (costId != null) {
@@ -249,16 +270,20 @@ public class QuoteVerificationAspect {
                                      InsOrdersAccidentalDriving insOrdersAccidentalDriving, InsOrders insOrders) {
         //获取所有费用属性
         List<PtlAgreementUndwrtRulesAttr> undwrtRulesAttrList = orgClient.list().getData();
-//        HttpResult comparenew = orgClient.compareNewCar(insOrdersCarInfo.getRegisterDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), insOrders.getCompanyId(), insOrdersCarInfo.getVehicleUseCode());
         boolean isNewCar = false;
-//        if(comparenew.getCode()== 200) {
-//            // 新旧车判断
-//             isNewCar = comparenew.getData().equals("true") ? true : false;
-//        }
         //获取所有费用属性关联
         List<RuleAttrMappingVo> ruleAttrMappingVoList = RuleAttrMappingVo.getRuleAttrMappingVoList(insOrdersOther,insOrdersCarInfo,
                 riskList, insOrdersCarUserInfos, kindList, insOrdersCosts, insOrdersAccidentalDriving, isNewCar, insOrders.getCompanyId());
 
+        ruleAttrMappingVoList.forEach(ruleAttrMappingVo -> {
+            if ("LicenseNo".equals(ruleAttrMappingVo.getAttrCode())) {
+                ruleAttrMappingVo.setValue(PLATE_FOUR_CODE_MAP.getOrDefault(ruleAttrMappingVo.getValue().substring(0, 2), ruleAttrMappingVo.getValue()));
+            }
+            if ("LicenseArea".equals(ruleAttrMappingVo.getAttrCode())) {
+                ruleAttrMappingVo.setValue(PLATE_FOUR_CODE_MAP.getOrDefault(ruleAttrMappingVo.getValue().substring(0, 1), ruleAttrMappingVo.getValue()));
+            }
+        });
+
         // 字典数据在一次报价内是只读不变的,提到循环外避免N+1远程调用
         // 修复批量报价时该方法被 organization 服务打爆的问题
         List<PtlAgreementUndwrtRulesDictLabal> undwrtRulesDictList = ptlNewAgreementClient.getUndwrtRulesDictList();

+ 12 - 9
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsOrdersServiceImpl.java

@@ -2194,10 +2194,11 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
             o.setFirstDistributionRatio(BigDecimal.ZERO);
             return null;
         }
+        BigDecimal commissionRatio1 = setting.getCommissionRatioLevel1().divide(new BigDecimal(100)).setScale(5, RoundingMode.DOWN);
         o.setFirstDistributorId(referrer.getReferrerId());
-        BigDecimal fee5 = totalPremium.multiply(setting.getCommissionRatioLevel1()).setScale(5, RoundingMode.DOWN);
-        o.setFirstDistributionFee(totalPremium.multiply(setting.getCommissionRatioLevel1()).setScale(2, RoundingMode.DOWN));
-        o.setFirstDistributionRatio(setting.getCommissionRatioLevel1());
+        BigDecimal fee5 = totalPremium.multiply(commissionRatio1.setScale(5, RoundingMode.DOWN));
+        o.setFirstDistributionFee(totalPremium.multiply(commissionRatio1.setScale(2, RoundingMode.DOWN)));
+        o.setFirstDistributionRatio(commissionRatio1);
         Map<String, Object> map = new HashMap<>();
         map.put("id", referrer.getReferrerId());
         map.put("diffAmount", fee5.subtract(o.getFirstDistributionFee()));
@@ -2214,10 +2215,11 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
             o.setSecondDistributionRatio(BigDecimal.ZERO);
             return null;
         }
+        BigDecimal commissionRatio2 = setting.getCommissionRatioLevel2().divide(new BigDecimal(100)).setScale(5, RoundingMode.DOWN);
         o.setSecondDistributorId(referrer.getReferrerId());
-        BigDecimal fee5 = totalPremium.multiply(setting.getCommissionRatioLevel2()).setScale(5, RoundingMode.DOWN);
-        o.setSecondDistributionFee(totalPremium.multiply(setting.getCommissionRatioLevel2()).setScale(2, RoundingMode.DOWN));
-        o.setSecondDistributionRatio(setting.getCommissionRatioLevel2());
+        BigDecimal fee5 = totalPremium.multiply(commissionRatio2).setScale(5, RoundingMode.DOWN);
+        o.setSecondDistributionFee(totalPremium.multiply(commissionRatio2).setScale(2, RoundingMode.DOWN));
+        o.setSecondDistributionRatio(commissionRatio2);
         Map<String, Object> map = new HashMap<>();
         map.put("id", referrer.getReferrerId());
         map.put("diffAmount", fee5.subtract(o.getSecondDistributionFee()));
@@ -2234,10 +2236,11 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
             o.setThirdDistributionRatio(BigDecimal.ZERO);
             return BigDecimal.ZERO;
         }
+        BigDecimal commissionRatio3 = setting.getCommissionRatioLevel3().divide(new BigDecimal(100)).setScale(5, RoundingMode.DOWN);
         o.setThirdDistributorId(referrer.getReferrerId());
-        BigDecimal fee5 = totalPremium.multiply(setting.getCommissionRatioLevel3()).setScale(5, RoundingMode.DOWN);
-        o.setThirdDistributionFee(totalPremium.multiply(setting.getCommissionRatioLevel3()).setScale(2, RoundingMode.DOWN));
-        o.setThirdDistributionRatio(setting.getCommissionRatioLevel3());
+        BigDecimal fee5 = totalPremium.multiply(commissionRatio3).setScale(5, RoundingMode.DOWN);
+        o.setThirdDistributionFee(totalPremium.multiply(commissionRatio3).setScale(2, RoundingMode.DOWN));
+        o.setThirdDistributionRatio(commissionRatio3);
         return fee5.subtract(o.getThirdDistributionFee());
     }
 

+ 8 - 29
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/build/ZhongAnCrawlerQuoteResultsVoBuild.java

@@ -119,37 +119,16 @@ public class ZhongAnCrawlerQuoteResultsVoBuild {
         QuoteResultsVo.ScoreVo scoreVo = new QuoteResultsVo.ScoreVo();
         scoreVo.setJqAdjustRate(dataDTO.getCompelDiscount());
         scoreVo.setSyAdjustRate(dataDTO.getBusinessDiscount());
-        String forceRenewalFlag = dataDTO.getForceRenewalFlag();
-        String bizRenewalFlag = dataDTO.getBizRenewalFlag();
-        if (forceRenewalFlag == null) {
+        Integer renewalFlag = dataDTO.getInsureFlag();
+        if (renewalFlag != null && renewalFlag == 2) {
+            scoreVo.setJqRenewal(String.valueOf(RenewalEnum.Renewal.getCode()));
+            scoreVo.setSyRenewal(String.valueOf(RenewalEnum.Renewal.getCode()));
+        } else if (renewalFlag != null && renewalFlag == 3) {
             scoreVo.setJqRenewal(String.valueOf(RenewalEnum.Transfer.getCode()));
-        } else {
-            switch (forceRenewalFlag) {
-                case "PA":
-                    scoreVo.setJqRenewal(String.valueOf(RenewalEnum.Transfer.getCode()));
-                    break;
-                case "ZA":
-                    scoreVo.setJqRenewal(String.valueOf(RenewalEnum.Renewal.getCode()));
-                    break;
-                default:
-                    scoreVo.setJqRenewal(String.valueOf(RenewalEnum.New.getCode()));
-                    break;
-            }
-        }
-        if (bizRenewalFlag == null) {
             scoreVo.setSyRenewal(String.valueOf(RenewalEnum.Transfer.getCode()));
-        } else {
-            switch (bizRenewalFlag) {
-                case "PA":
-                    scoreVo.setSyRenewal(String.valueOf(RenewalEnum.Transfer.getCode()));
-                    break;
-                case "ZA":
-                    scoreVo.setSyRenewal(String.valueOf(RenewalEnum.Renewal.getCode()));
-                    break;
-                default:
-                    scoreVo.setSyRenewal(String.valueOf(RenewalEnum.New.getCode()));
-                    break;
-            }
+        } else if (renewalFlag != null && renewalFlag == 1) {
+            scoreVo.setJqRenewal(String.valueOf(RenewalEnum.New.getCode()));
+            scoreVo.setSyRenewal(String.valueOf(RenewalEnum.New.getCode()));
         }
         JSONArray scoreJson = new JSONArray();
         scoreJson.add(new JSONObject()

+ 3 - 3
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerQuoteRequest.java

@@ -132,13 +132,13 @@ public class ZhongAnCrawlerQuoteRequest{
                 nonAutoInfoDtos.add(nonAutoInfoDto);
             });
             boolean hasKpNhjcb = nonAutoInfoDtos.stream()
-                    .anyMatch(dto -> "kp_nhjcb_v1".equals(dto.getProductCode()));
+                    .anyMatch(dto -> "kp_nhjcb_v2".equals(dto.getProductCode()));
             if (!hasKpNhjcb) {
-                NonAutoInfoDto jtywxV24 = new NonAutoInfoDto("kp_nhjcb_v1", "0", null);
+                NonAutoInfoDto jtywxV24 = new NonAutoInfoDto("kp_nhjcb_v2", "0", null);
                 nonAutoInfoDtos.add(jtywxV24);
             }
         } else {
-            NonAutoInfoDto jtywxV24 = new NonAutoInfoDto("kp_nhjcb_v1", "0", null);
+            NonAutoInfoDto jtywxV24 = new NonAutoInfoDto("kp_nhjcb_v2", "0", null);
             NonAutoInfoDto wjsGabV6 = new NonAutoInfoDto("wjs_gab_v10", "0", null);
             NonAutoInfoDto wjs_cwyjtywx_v1 = new NonAutoInfoDto("wjs_cwyjtywx_v1", "0", null);
             NonAutoInfoDto kp_czwyjcx_v1 = new NonAutoInfoDto("kp_czwyjcx_v1", "0", null);

+ 23 - 30
tenant/organization/src/main/java/com/jzg/organization/component/BuildDescUtils.java

@@ -40,22 +40,15 @@ public class BuildDescUtils {
             } else if ("radio".equals(attrType)) {
                 desc.append(radioIdentifying(ptlAgreementUndwrtRulesAttr, link)).append(";\t\t");
             } else if ("checkbox".equals(attrType) || "select".equals(attrType)) {
-                if(link.getMinArray() != null && link.getMinArray().length > 0){
-                    desc.append(ptlAgreementUndwrtRulesAttr.getAttrName()).append("包含");
-                    for (int k=0 ; k<link.getMinArray().length; k++){
-                        PtlAgreementUndwrtRulesDictLabal ptlAgreementUndwrtRulesDictLabal = null;
-                        for (PtlAgreementUndwrtRulesDictLabal x : link.getDictLabal()) {
-                            if (Arrays.asList(link.getMinArray()).contains(x.getCode())) {
-                                ptlAgreementUndwrtRulesDictLabal = x;
-                                link.getMinArray()[k] = null;
-                                break;
-                            }
-                        }
-                        desc.append(null != ptlAgreementUndwrtRulesDictLabal ? ptlAgreementUndwrtRulesDictLabal.getName() : "").append(",");
-                    }
-                    // 条件描述后补充一个分号
-                    desc.append(",");
-                }else {
+                if (link.getMinArray() != null && link.getMinArray().length > 0) {
+                    // minArray 转 Set,避免循环内反复创建 List 做 contains 查找
+                    Set<String> minCodes = Arrays.stream(link.getMinArray()).collect(Collectors.toSet());
+                    String names = Optional.ofNullable(link.getDictLabal()).orElse(Collections.emptyList()).stream()
+                            .filter(labal -> minCodes.contains(labal.getCode()))
+                            .map(PtlAgreementUndwrtRulesDictLabal::getName)
+                            .collect(Collectors.joining(","));
+                    desc.append(ptlAgreementUndwrtRulesAttr.getAttrName()).append("包含").append(names).append(";\t\t");
+                } else {
                     desc.append(ptlAgreementUndwrtRulesAttr.getAttrName()).append("包含").append(link.getMin()).append(";\t\t");
                 }
             } else if ("inputTag".equals(attrType)) {
@@ -148,29 +141,29 @@ public class BuildDescUtils {
         return ptlAgreementUndwrtRulesAttr.getAttrName() + "为" + ptlAgreementUndwrtRulesDictLabal.getName();
     }
 
-    public static String selectIdentifying(PtlAgreementUndwrtRulesAttr ptlAgreementUndwrtRulesAttr, PtlAgreementUndwrtRulesAttrLink ptlAgreementProductCostsAttrLink) {
+    public static String selectIdentifying(PtlAgreementUndwrtRulesAttr undwrtRulesAttr, PtlAgreementUndwrtRulesAttrLink link) {
         StringBuilder returnMsg = new StringBuilder();
-        returnMsg.append(ptlAgreementUndwrtRulesAttr.getAttrName()).append("为");
         // 兼容 min 逗号分隔存储,保证 minArray 有值
-        if (ptlAgreementProductCostsAttrLink.getMinArray() == null) {
-            String minStr = ptlAgreementProductCostsAttrLink.getMin();
+        if (link.getMinArray() == null) {
+            String minStr = link.getMin();
             if (minStr != null && !minStr.isEmpty()) {
-                ptlAgreementProductCostsAttrLink.setMinArray(minStr.split(","));
+                link.setMinArray(minStr.split(","));
             }
         }
 
         // 优先取 link 上的字典标签列表(JSONArray -> List),为空时回退到属性自带字典
-        List<PtlAgreementUndwrtRulesDictLabal> dictLabalList = getDictLabalList(ptlAgreementUndwrtRulesAttr, ptlAgreementProductCostsAttrLink);
+        List<PtlAgreementUndwrtRulesDictLabal> dictLabalList = getDictLabalList(undwrtRulesAttr, link);
 
         // 用字典标签的 code 匹配 minArray 中的每一项
-        if (ptlAgreementProductCostsAttrLink.getMinArray() != null) {
-            for (String item : ptlAgreementProductCostsAttrLink.getMinArray()) {
-                PtlAgreementUndwrtRulesDictLabal ptlAgreementUndwrtRulesDictLabal = dictLabalList.stream()
-                        .filter(x -> x.getCode() != null && x.getCode().equals(item)).findAny().orElse(null);
-                if (ptlAgreementUndwrtRulesDictLabal != null) {
-                    returnMsg.append(ptlAgreementUndwrtRulesDictLabal.getName()).append(",");
-                }
-            }
+        if (link.getMinArray() != null && link.getMinArray().length > 0) {
+            // minArray 转 Set,避免循环内反复创建 List 做 contains 查找
+            Set<String> minCodes = Arrays.stream(link.getMinArray()).collect(Collectors.toSet());
+            String names = Optional.ofNullable(dictLabalList).orElse(Collections.emptyList()).stream()
+                    .filter(labal -> minCodes.contains(labal.getCode()))
+                    .map(PtlAgreementUndwrtRulesDictLabal::getName)
+                    .collect(Collectors.joining(","));
+            returnMsg.append(undwrtRulesAttr.getAttrName()).append("包含").append(names).append(",");
+
         }
         return returnMsg.toString();
     }

+ 2 - 18
tenant/organization/src/main/java/com/jzg/organization/controller/NewCarJudgeRulesController.java

@@ -1,34 +1,16 @@
 package com.jzg.organization.controller;
 
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.jzg.commons.constants.OperationTypeEnum;
 import com.jzg.commons.core.base.BaseController;
 import com.jzg.commons.core.page.HttpResult;
-import com.jzg.commons.entity.dto.*;
-import com.jzg.commons.entity.enums.YesNoEnum;
-import com.jzg.commons.entity.po.OperatorTrajectory;
-import com.jzg.commons.entity.po.PtlAgreement;
 import com.jzg.commons.entity.po.PtlNewCarJudgeRules;
-import com.jzg.commons.entity.vo.AgreementVo;
 import com.jzg.commons.entity.vo.NewCarQuery;
-import com.jzg.commons.entity.vo.UpAndDownVo;
-import com.jzg.commons.service.OperatorTrajectoryService;
-import com.jzg.commons.util.AssertionUtils;
-import com.jzg.commons.util.spring.SpringUtils;
-import com.jzg.organization.mapper.PtlAgreementMapper;
 import com.jzg.organization.service.NewCarJudgeRulesService;
-import com.jzg.organization.service.PtlAgreementDeptService;
-import com.jzg.organization.service.PtlAgreementService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDateTime;
-import java.util.List;
-import java.util.Objects;
 
 /**
  * 协议管理接口
@@ -60,12 +42,14 @@ public class NewCarJudgeRulesController extends BaseController {
     @PostMapping("addNewCar")
     public HttpResult addNewCar(@RequestBody PtlNewCarJudgeRules newCarJudgeRules){
         newCarJudgeRules.setSystemCode(getUserSystemCode());
+        newCarJudgeRules.setSaveDate(LocalDateTime.now());
         return newCarJudgeRulesService.addNewCar(newCarJudgeRules) ? HttpResult.ok("添加新旧车规则成功") : HttpResult.error("添加新旧车规则失败");
     }
 
     @Operation(summary = "修改新旧车规则")
     @PostMapping("updateNewCar")
     public HttpResult updateNewCar(@RequestBody PtlNewCarJudgeRules newCarJudgeRules){
+        newCarJudgeRules.setSaveDate(LocalDateTime.now());
         return newCarJudgeRulesService.updateNewCar(newCarJudgeRules) ? HttpResult.ok("修改新旧车规则成功") : HttpResult.error("修改新旧车规则失败");
     }
 

+ 18 - 0
tenant/organization/src/main/java/com/jzg/organization/service/impl/SysUserServiceImpl.java

@@ -1533,6 +1533,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
            }
            // 关联用户角色
            saveRole(userByUserId);
+            // 合伙人添加业务员    app内也要新增一条数据
+           saveUserApp(userByUserId, userByUserId.getSystemCode());
            return HttpResult.ok("添加业务员成功");
        }catch (Exception e){
            log.error("添加业务员异常",e);
@@ -1540,6 +1542,16 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
        }
     }
 
+    private void saveUserApp(SysUserJzgInfo userByUserId, String systemCode) {
+        boolean exists = sysUserJzgAppMapper.exists(new LambdaQueryWrapper<>(SysUserJzgApp.class).eq(SysUserJzgApp::getUserId, userByUserId.getUserId()));
+        if (!exists){
+            SysUserJzgApp sysUserJzgApp = BeanUtil.copyProperties(userByUserId, SysUserJzgApp.class);
+            sysUserJzgApp.setId(IdGenerate.nextId());
+            sysUserJzgApp.setSystemCode(systemCode);
+            sysUserJzgAppMapper.insert(sysUserJzgApp);
+        }
+    }
+
     @Override
     public HttpResult<SysUserJzgInfo> getUserInfoUserId(String userId) {
         return HttpResult.ok(sysUserJzgInfoMapper.getUserJzgInfoByUserId(userId));
@@ -1569,6 +1581,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 
     public void addPartner(SysUserVo sysUserVo){
         String referrerId = sysUserVo.getReferrerId();
+        if (StringUtils.isEmpty(referrerId)){
+            throw new SystemException("推荐人不能为空");
+        }
         SysUser sysUser = baseMapper.getUserByMobile(sysUserVo.getMobile());
         if (sysUserVo.isCodeInvitation()){
             SysUserJzgInfo userJzgInfo = sysUserJzgInfoMapper.selectByUserIdInfo(sysUserVo.getReferrerId());
@@ -1613,6 +1628,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
             }
             sysUserVo.setUserId(sysUserJzgInfo.getId());
         }
+        if (sysUserVo.getGrade() > 3){
+            saveUserApp(sysUserJzgInfo, baseController.getSystemCode());
+        }
         partnerAddsSalespersonIdentity(sysUserJzgInfo.getId(),"3");
         if ((!Objects.isNull(sysUserVo.getGrade()) && 4 == sysUserVo.getGrade())){
             SysOrganizationAdd organizationAdd = new SysOrganizationAdd();

+ 1 - 0
tenant/organization/src/main/resources/mapper/PtlAgreementCostMapper.xml

@@ -205,6 +205,7 @@
             t.is_delete = 0
             AND t.id IN (${costId})
         </where>
+        order by t.create_time desc
     </select>