Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

lixiaolong 1 месяц назад
Родитель
Сommit
0372775625

+ 1 - 1
tenant/insurance/quotation-huanong/src/main/java/com/jzg/quotation/huanong/crawler/service/impl/HuaNongCrawlerRequestImpl.java

@@ -1067,7 +1067,7 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
         Optional<HuaNongCrawlerQueryReviveOpinionResponse.OpinionDTO> manualOpinion =
                 findOpinion(opinionResponse, "0");
         if (manualOpinion.isPresent()) {
-            setOrderStatus(result, InsOrderStatusEnum.STAFF_PROCESS);
+            setOrderStatus(result, InsOrderStatusEnum.AUDIT_FAIL);
             result.setErrorMsg(formatOpinion(manualOpinion.get(), false));
             return result;
         }

+ 61 - 5
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementDispatchServiceImpl.java

@@ -30,6 +30,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -181,6 +182,56 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
                     ));
             Map<String, PtlAreaLicense> areaLicenseMap = ptlAreaLicenseService.queryAllAreaLicenseMap();
 
+            // ===== 消除 N+1:提前批量查询所有依赖数据并构建索引 =====
+            // N+1-A:规则属性 attrCode → Attr(直接复用 L146 已查到的 undwrtRulesAttrList,不再逐条单查)
+            Map<String, PtlAgreementUndwrtRulesAttr> attrCode2RuleAttr = undwrtRulesAttrList.stream()
+                    .collect(Collectors.toMap(
+                            PtlAgreementUndwrtRulesAttr::getAttrCode,
+                            Function.identity(),
+                            (o1, o2) -> o1
+                    ));
+
+            // N+1-B:字典标签 dictId → List<DictLabal>(从 attrCode2RuleAttr 取所有非空 dictId,一次批量查)
+            Set<Integer> dictIdSet = attrCode2RuleAttr.values().stream()
+                    .map(PtlAgreementUndwrtRulesAttr::getDictId)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toSet());
+            Map<Integer, List<PtlAgreementUndwrtRulesDictLabal>> dictId2Labels = new HashMap<>();
+            if (!dictIdSet.isEmpty()) {
+                List<PtlAgreementUndwrtRulesDictLabal> allLabels = ptlAgreementUndwrtRulesDictLabalService.list(
+                        new LambdaQueryWrapper<PtlAgreementUndwrtRulesDictLabal>()
+                                .in(PtlAgreementUndwrtRulesDictLabal::getDictId, dictIdSet));
+                dictId2Labels = allLabels.stream()
+                        .collect(Collectors.groupingBy(PtlAgreementUndwrtRulesDictLabal::getDictId));
+            }
+
+            // N+1-C:协议 agreementId → PtlAgreement(收集所有 specify_agreement 动作的 agreementId,一次批量查)
+            Set<String> agreementIdSet = new HashSet<>();
+            for (PtlAgreementDispatchAction action : ptlAgreementDispatchActions) {
+                if ("specify_agreement".equals(action.getActionCode()) && action.getActionJson() != null) {
+                    String agreementId = action.getActionJson().getString("agreementId");
+                    if (StrUtil.isNotBlank(agreementId)) {
+                        agreementIdSet.add(agreementId);
+                    }
+                }
+            }
+            // after_action 中的 specify_agreement 也要收集
+            afterActionsByCompany.values().stream().flatMap(List::stream).forEach(afterAction -> {
+                if ("specify_agreement".equals(afterAction.getActionCode()) && afterAction.getActionJson() != null) {
+                    String agreementId = afterAction.getActionJson().getString("agreementId");
+                    if (StrUtil.isNotBlank(agreementId)) {
+                        agreementIdSet.add(agreementId);
+                    }
+                }
+            });
+            Map<String, PtlAgreement> agreementById = new HashMap<>();
+            if (!agreementIdSet.isEmpty()) {
+                List<PtlAgreement> agreements = ptlAgreementService.listByIds(agreementIdSet);
+                agreementById = agreements.stream()
+                        .collect(Collectors.toMap(PtlAgreement::getId, Function.identity(), (a, b) -> a));
+            }
+            // ============================================================
+
             // ===== 收集所有 change_bs_account 动作的 accountId,批量查询一次(消除串行 RPC) =====
             List<String> accountIds = new ArrayList<>();
             for (PtlAgreementDispatchAction action : ptlAgreementDispatchActions) {
@@ -247,13 +298,14 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
 
                         attrlink.setMaxName(maxName);
                     }
-                    System.out.printf(attrlink.getAttrCode()+"\n");
-                    PtlAgreementUndwrtRulesAttr undwrtRuleAttrByAttrCode = ptlAgreementUndwrtRulesAttrService.getUndwrtRuleAttrByAttrCode(attrlink.getAttrCode());
+                    // 从索引中取规则属性(N+1-A 消除:原逐条 DB 查询改为 Map get)
+                    PtlAgreementUndwrtRulesAttr undwrtRuleAttrByAttrCode = attrCode2RuleAttr.get(attrlink.getAttrCode());
                     if(undwrtRuleAttrByAttrCode != null){
                         attrlink.setAttrCodeName(undwrtRuleAttrByAttrCode.getAttrName());
                         if(undwrtRuleAttrByAttrCode.getDictId() != null){
                             attrlink.setAttrCodeName(undwrtRuleAttrByAttrCode.getAttrName());
-                            List<PtlAgreementUndwrtRulesDictLabal> dictLabelsByTypeCode = ptlAgreementUndwrtRulesDictLabalService.getDictLabelsByTypeCode(undwrtRuleAttrByAttrCode.getDictId());
+                            // 从索引中取字典标签(N+1-B 消除:原逐条 DB 查询改为 Map get)
+                            List<PtlAgreementUndwrtRulesDictLabal> dictLabelsByTypeCode = dictId2Labels.getOrDefault(undwrtRuleAttrByAttrCode.getDictId(), Collections.emptyList());
 
                             PtlAgreementUndwrtRulesDictLabal ptlAgreementUndwrtRulesDictLabal = dictLabelsByTypeCode.stream().filter(x -> x.getCode().equals(attrlink.getMin())).findFirst().orElse(null);
                             if(ptlAgreementUndwrtRulesDictLabal != null){
@@ -275,7 +327,9 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
                         action.setActionName(sysDict.getLabel());
                         if("specify_agreement".equals(action.getActionCode())){
                             if(action.getActionJson() != null && !action.getActionJson().isEmpty()) {
-                                PtlAgreement byId = ptlAgreementService.getById(action.getActionJson().get("agreementId").toString());
+                                // N+1-C 消除:从批量查询的索引中取协议(原逐条 getById 改为 Map get)
+                                String agreementId = action.getActionJson().getString("agreementId");
+                                PtlAgreement byId = agreementById.get(agreementId);
                                 if(byId != null) {
                                     action.getActionJson().put("agreementName", byId.getAgreementName());
                                 }
@@ -321,7 +375,9 @@ public class PtlAgreementDispatchServiceImpl extends ServiceImpl<PtlAgreementDis
                     if("specify_agreement".equals(afterAction.getActionCode())){
                         //specify_agreement 指定协议
                         if(afterAction.getActionJson() != null) {
-                            PtlAgreement byId = ptlAgreementService.getById(afterAction.getActionJson().get("agreementId").toString());
+                            // N+1-C 消除:从批量查询的索引中取协议(原逐条 getById 改为 Map get)
+                            String agreementId = afterAction.getActionJson().getString("agreementId");
+                            PtlAgreement byId = agreementById.get(agreementId);
                             if(byId != null) {
                                 afterAction.getActionJson().put("agreementName", byId.getAgreementName());
                             }

+ 120 - 23
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlSchemeServiceImpl.java

@@ -363,7 +363,13 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
 
     @Override
     public boolean deleteScheme(String schemeId) {
-        return ptlSchemeInfoMapper.deleteById(schemeId) > 0;
+        PtlSchemeInfo ptlSchemeInfo = ptlSchemeInfoMapper.selectById(schemeId);
+        if(ptlSchemeInfo != null){
+            ptlSchemeMapper.deleteById(ptlSchemeInfo.getSchemeId());
+            ptlSchemeInfoMapper.deleteById(schemeId);
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -414,6 +420,14 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
 
     /**
      * 规则过滤保险公司
+     * <p>
+     * 主流程编排方法,按以下步骤执行:
+     * Step1: 根据权限获取所有保司
+     * Step2: 协议和账号状态过滤
+     * Step3: 业务员归属权限过滤
+     * Step4: 方案匹配 + 费用规则校验 + 过滤不匹配方案的保司
+     * Step5: 构建保司结果 VO + 调度规则校验
+     * Step6: 国任车主与投保人不一致时,返回车主约定T0028特约
      *
      * @param schemeRuleFilterVo 过滤保险公司的条件
      * @return List<PtlAgreementInsCompanyVo> 满足报价要求的保险公司以及其下的协议
@@ -425,18 +439,83 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
         String userSystemCode = baseController.getUserSystemCode();
         String systemCode = baseController.getSystemCode();
         log.info("租户匹配保司以及保司下的协议等信息。 schemeRuleFilterVo=[{}],userSystemCode=[{}],systemCode=[{}]", JSONUtil.toJsonStr(schemeRuleFilterVo), userSystemCode, systemCode);
+
+        long totalStart = System.currentTimeMillis();
+
+        // Step1: 根据权限获取所有保司
+        long step1Start = System.currentTimeMillis();
+        log.info("【性能监控】Step1: 根据权限获取所有保司 - 开始");
+        List<EsmInsCompany> companyList = getAuthorizedInsCompanies(systemCode);
+        log.info("【性能监控】Step1: 根据权限获取所有保司 - 结束,耗时[{}]ms", System.currentTimeMillis() - step1Start);
+
+        // Step2: 协议和账号状态过滤
+        long step2Start = System.currentTimeMillis();
+        log.info("【性能监控】Step2: 协议和账号状态过滤 - 开始");
+        filterByAgreementAndAccountStatus(companyList);
+        log.info("【性能监控】Step2: 协议和账号状态过滤 - 结束,耗时[{}]ms", System.currentTimeMillis() - step2Start);
+        log.info("协议/账号状态过滤完成,开始后续业务匹配");
+
+        // Step3: 业务员的归属权限是可选参数,不选的话不进行过滤
+        long step3Start = System.currentTimeMillis();
+        log.info("【性能监控】Step3: 业务员归属权限过滤 - 开始");
+        companyList = salespersonFilterCompanyList(schemeRuleFilterVo, companyList);
+        log.info("【性能监控】Step3: 业务员归属权限过滤 - 结束,耗时[{}]ms", System.currentTimeMillis() - step3Start);
+
+        log.info("根据权限获取到的保司个数是[{}].systemCode=[{}]", CollUtil.size(companyList), systemCode);
+        if (CollUtil.isEmpty(companyList)) {
+            log.info("租户[{}]没有可报价的保险公司,请到平台系统的【租户管理】-【功能配置】页面进行配置并且查看对应公司的协议,费用是否维护好", systemCode);
+            AssertionUtils.isFail(companyList.isEmpty(), "没有可报价的保险公司");
+        }
+
+        // Step4: 根据基本规则匹配方案 + 费用规则校验 + 过滤不匹配方案的保司
+        long step4Start = System.currentTimeMillis();
+        log.info("【性能监控】Step4: 方案匹配+费用规则校验+保司过滤 - 开始");
+        ValidateSchemeRuleVo validateSchemeRuleVo = matchSchemeAndFilterCompany(schemeRuleFilterVo, companyList);
+        log.info("【性能监控】Step4: 方案匹配+费用规则校验+保司过滤 - 结束,耗时[{}]ms", System.currentTimeMillis() - step4Start);
+
+        // Step5: 构建保司结果 VO + 调度规则校验
+        long step5Start = System.currentTimeMillis();
+        log.info("【性能监控】Step5: 构建保司结果VO+调度规则校验 - 开始");
+        List<PtlAgreementInsCompanyVo> resVo = buildResultVoAndApplyDispatch(companyList, validateSchemeRuleVo);
+        log.info("【性能监控】Step5: 构建保司结果VO+调度规则校验 - 结束,耗时[{}]ms", System.currentTimeMillis() - step5Start);
+
+        // Step6: 国任车主与投保人不一致时,返回车主约定T0028特约
+        long step6Start = System.currentTimeMillis();
+        log.info("【性能监控】Step6: 国任T0028特约处理 - 开始");
+        applyOwnerClauseForXDCX(resVo, schemeRuleFilterVo);
+        log.info("【性能监控】Step6: 国任T0028特约处理 - 结束,耗时[{}]ms", System.currentTimeMillis() - step6Start);
+
+        log.info("【性能监控】ruleFilterCompany 全流程结束,总耗时[{}]ms", System.currentTimeMillis() - totalStart);
+        return resVo;
+    }
+
+    /**
+     * Step1: 根据权限获取所有保司
+     *
+     * @param systemCode 系统编码
+     * @return 有权限的保司列表
+     */
+    private List<EsmInsCompany> getAuthorizedInsCompanies(String systemCode) {
         //根据权限获取所有保司
         HttpResult<List<EsmInsCompany>> companyListResult = esmInsCompanyClient.getUserCompany(systemCode);
         log.info("租户[{}]有权限的保司有[{}]个", systemCode, CollUtil.size(companyListResult.getData()));
         AssertionUtils.isFail(companyListResult.getCode() != 200, companyListResult.getMsg());
-        List<EsmInsCompany> companyList = companyListResult.getData();
+        return companyListResult.getData();
+    }
 
+    /**
+     * Step2: 协议和账号状态过滤
+     * <p>
+     * 过滤条件:
+     *   1. 协议必须启用    (isEnable == 0)
+     *   2. 协议必须生效中  (validStatus == "0")
+     *   3. 关联账号必须可用 (useStatus == "0") 且可报价 (quoteStatus == "0")
+     * 过滤后如果某保司没有任何有效协议,会被后续 removeIf 自动排除
+     *
+     * @param companyList 保司列表(原地修改)
+     */
+    private void filterByAgreementAndAccountStatus(List<EsmInsCompany> companyList) {
         // ========================= 协议和账号状态过滤 =========================
-        // 过滤条件:
-        //   1. 协议必须启用    (isEnable == 0)
-        //   2. 协议必须生效中  (validStatus == "0")
-        //   3. 关联账号必须可用 (useStatus == "0") 且可报价 (quoteStatus == "0")
-        // 过滤后如果某保司没有任何有效协议,会被下面的 removeIf 自动排除
         if (CollUtil.isNotEmpty(companyList)) {
             // 1. 收集所有需要校验的归属账号 id
             List<String> attributionIds = companyList.stream()
@@ -485,18 +564,17 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
                 company.setAgreements(validAgreements);
             }
         }
-        log.info("协议/账号状态过滤完成,开始后续业务匹配");
         // ====================================================================
+    }
 
-        // 业务员的归属权限是可选参数,不选的话不进行过滤
-        companyList = salespersonFilterCompanyList(schemeRuleFilterVo, companyList);
-
-        log.info("根据权限获取到的保司个数是[{}].systemCode=[{}]", CollUtil.size(companyList), systemCode);
-        if (CollUtil.isEmpty(companyList)) {
-            log.info("租户[{}]没有可报价的保险公司,请到平台系统的【租户管理】-【功能配置】页面进行配置并且查看对应公司的协议,费用是否维护好", systemCode);
-            AssertionUtils.isFail(companyList.isEmpty(), "没有可报价的保险公司");
-        }
-
+    /**
+     * Step4: 根据基本规则匹配方案 + 费用规则校验 + 过滤不匹配方案的保司
+     *
+     * @param schemeRuleFilterVo 过滤条件
+     * @param companyList 保司列表(原地修改,移除不匹配方案的保司及空协议保司)
+     * @return 方案规则校验 VO(含 quoteVo,供调度规则校验使用)
+     */
+    private ValidateSchemeRuleVo matchSchemeAndFilterCompany(SchemeRuleFilterVo schemeRuleFilterVo, List<EsmInsCompany> companyList) {
         //根据基本规则 能源、车辆类型、使用性质获取方案
         List<PtlScheme> ptlSchemes = ptlSchemeMapper.selectList(new LambdaQueryWrapper<PtlScheme>()
                 .eq(PtlScheme::getEnergyType, schemeRuleFilterVo.getCarInfo().getEnergyTypeCode().equals("0") ? "0" : "1")
@@ -529,6 +607,17 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
         Set<String> companyIdSet = ptlSchemes.stream().map(PtlScheme::getCompanyId).collect(Collectors.toSet());
         // 移除不匹配方案的保司,以及空协议的保司
         companyList.removeIf(company -> !companyIdSet.contains(company.getId()) || CollUtil.isEmpty(company.getAgreements()));
+        return validateSchemeRuleVo;
+    }
+
+    /**
+     * Step5: 构建保司结果 VO + 调度规则校验
+     *
+     * @param companyList 过滤后的保司列表
+     * @param validateSchemeRuleVo 方案规则校验 VO(提供 quoteVo)
+     * @return 保司结果 VO 列表
+     */
+    private List<PtlAgreementInsCompanyVo> buildResultVoAndApplyDispatch(List<EsmInsCompany> companyList, ValidateSchemeRuleVo validateSchemeRuleVo) {
         List<PtlAgreementInsCompanyVo> resVo = new ArrayList<>();
         companyList.forEach(company -> {
             PtlAgreementInsCompanyVo vo = new PtlAgreementInsCompanyVo();
@@ -540,12 +629,11 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
 
         ValidateDispatchRuleVo dispatchRuleVos = new ValidateDispatchRuleVo();
         dispatchRuleVos.setQuoteVo(validateSchemeRuleVo.getQuoteVo());
-        //2.协议调度规则数据拼接(一次批量查询所有保司,避免逐保司重复的全表/字典查询与串行 RPC)
+        //2.协议调度规则数据拼接(同项目内直接走 Service 调用,避免 Feign 自调用的 HTTP 往返与序列化开销)
         List<String> allCompanyIds = companyList.stream().map(EsmInsCompany::getId).collect(Collectors.toList());
         try {
-            HttpResult agreementDispatch = orgClient.getAgreementDispatchByCompanyIds(allCompanyIds);
-            if (agreementDispatch != null && agreementDispatch.getCode() == 200 && agreementDispatch.getData() != null) {
-                PtlAgreementDispatchVo dispatchVoResult = new ObjectMapper().convertValue(agreementDispatch.getData(), PtlAgreementDispatchVo.class);
+            PtlAgreementDispatchVo dispatchVoResult = ptlAgreementDispatchService.getAgreementDispatchByCompanyIds(allCompanyIds);
+            if (dispatchVoResult != null && CollUtil.isNotEmpty(dispatchVoResult.getDispatchVos())) {
                 List<ValidateDispatchRuleVo.DispatchAttrVo> dispatchAttrVos = new ArrayList<>();
                 for (PtlAgreementDispatchVo.DispatchVo vo : dispatchVoResult.getDispatchVos()) {
                     List<PtlAgreementDispatchRulesAttrLink> attrLinks = vo.getAttrLinks();
@@ -556,8 +644,8 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
                     dispatchAttrVo.setCompanyId(vo.getCompanyId());
                     dispatchAttrVo.setSectionGroups(grouped);
                     dispatchAttrVos.add(dispatchAttrVo);
-                    dispatchRuleVos.getDispatchAttrVos().addAll(dispatchAttrVos);
                 }
+                dispatchRuleVos.getDispatchAttrVos().addAll(dispatchAttrVos);
             }
         } catch (Exception e) {
             log.warn("批量查询协议调度异常", e);
@@ -599,6 +687,16 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
                 }
             });
         }
+        return resVo;
+    }
+
+    /**
+     * Step6: 国任车主与投保人不一致时,返回车主约定T0028特约
+     *
+     * @param resVo 保司结果 VO 列表
+     * @param schemeRuleFilterVo 过滤条件(含车主、投保人信息)
+     */
+    private void applyOwnerClauseForXDCX(List<PtlAgreementInsCompanyVo> resVo, SchemeRuleFilterVo schemeRuleFilterVo) {
         // 国任车主与投保人不一致时,返回车主约定T0028特约
         for (PtlAgreementInsCompanyVo company : resVo) {
             if ("XDCX".equals(company.getCode())) {
@@ -624,7 +722,6 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
                 break;
             }
         }
-        return resVo;
     }
     /**
      *  报价公司过滤入参统一校验