Эх сурвалжийг харах

华泰-处理报价异常信息不显示问题;报价逻辑多余重试机制去除;

lixiaolong 3 сар өмнө
parent
commit
16c110d554

+ 2 - 2
tenant/insurance/quotation-huatai/src/main/java/com/jzg/quotation/huatai/crawler/component/HtCrawlerRequestComponent.java

@@ -152,7 +152,7 @@ public class HtCrawlerRequestComponent {
      * @param headers
      * @param headers
      * @return
      * @return
      */
      */
-    public HtCrawlerCarQueryResponse.DataDTO carQuery(HtCrawlerCarQueryRequest htCrawlerCarQueryRequest, HttpHeaders headers, CarInfoVo carInfoVo) throws Exception {
+    public HtCrawlerCarQueryResponse.DataDTO carQuery(HtCrawlerCarQueryRequest htCrawlerCarQueryRequest, HttpHeaders headers, CarInfoVo carInfoVo) {
         List<String> cookie = headers.get("Cookie");
         List<String> cookie = headers.get("Cookie");
         log.info("huatai_cookie:{}", cookie);
         log.info("huatai_cookie:{}", cookie);
         ResponseEntity<HtCrawlerCarQueryResponse> carQueryResponseEntity = requestComponent.objectPostWithProxy(RequestUrl.CAR_QUERY.getRequestUrl(huaTaiCrawlerProperties.getBaseUrl()), htCrawlerCarQueryRequest, HtCrawlerCarQueryResponse.class, headers, proxyHostName, proxyPort);
         ResponseEntity<HtCrawlerCarQueryResponse> carQueryResponseEntity = requestComponent.objectPostWithProxy(RequestUrl.CAR_QUERY.getRequestUrl(huaTaiCrawlerProperties.getBaseUrl()), htCrawlerCarQueryRequest, HtCrawlerCarQueryResponse.class, headers, proxyHostName, proxyPort);
@@ -182,7 +182,7 @@ public class HtCrawlerRequestComponent {
      * @return
      * @return
      * @throws Exception
      * @throws Exception
      */
      */
-    public String quote(HtCrawlerQuoteRequest htCrawlerQuoteRequest, HttpHeaders headers) throws Exception {
+    public String quote(HtCrawlerQuoteRequest htCrawlerQuoteRequest, HttpHeaders headers) {
         headers.remove("Referer");
         headers.remove("Referer");
         headers.add("Referer", "https://cspxp.pc.ehuatai.com/htcsp/VehicleInfoEntryAction.do?cmd=saveOneStept");
         headers.add("Referer", "https://cspxp.pc.ehuatai.com/htcsp/VehicleInfoEntryAction.do?cmd=saveOneStept");
         ResponseEntity<HtCrawlerQuoteResponse> responseEntity = requestComponent.objectPostWithProxy(RequestUrl.QUOTE_PRICE.getRequestUrl(huaTaiCrawlerProperties.getBaseUrl()), htCrawlerQuoteRequest, HtCrawlerQuoteResponse.class, headers, proxyHostName, proxyPort);
         ResponseEntity<HtCrawlerQuoteResponse> responseEntity = requestComponent.objectPostWithProxy(RequestUrl.QUOTE_PRICE.getRequestUrl(huaTaiCrawlerProperties.getBaseUrl()), htCrawlerQuoteRequest, HtCrawlerQuoteResponse.class, headers, proxyHostName, proxyPort);

+ 63 - 89
tenant/insurance/quotation-huatai/src/main/java/com/jzg/quotation/huatai/crawler/service/Impl/HuaTaiCrawlerRequestImpl.java

@@ -107,6 +107,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     private static final Pattern PAT_MEAL_ID = Pattern.compile("\"mealid\":\"(.*?)\"");
     private static final Pattern PAT_MEAL_ID = Pattern.compile("\"mealid\":\"(.*?)\"");
     private static final Pattern LIMIT_AMOUNT = Pattern.compile("value=\"(.*?)\" id=\"js_actualvalue\"");
     private static final Pattern LIMIT_AMOUNT = Pattern.compile("value=\"(.*?)\" id=\"js_actualvalue\"");
     private static final Pattern PAT_END_DATE = Pattern.compile("终保日期\\s*([^;]+)");
     private static final Pattern PAT_END_DATE = Pattern.compile("终保日期\\s*([^;]+)");
+    private static final Pattern RESPONSE_ERR = Pattern.compile("(\"infoName\"\\s*:\\s*\"([^\"]*)\",\\s*\"infomsg\"\\s*:\\s*\"([^\"]*)\"|\"erroeInfo\"\\s*:\\s*\"([^\"]*)\")",Pattern.DOTALL);
 
 
     private static final Set<String> SPECIAL_USERS = Set.of(
     private static final Set<String> SPECIAL_USERS = Set.of(
             "EA27000180", "EA27000401", "EA27000098", "EA27000076",
             "EA27000180", "EA27000401", "EA27000098", "EA27000076",
@@ -167,22 +168,6 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         return req.authenticate(dto, HtRequestConstant.REQUEST_NUMBER);
         return req.authenticate(dto, HtRequestConstant.REQUEST_NUMBER);
     }
     }
 
 
-    // ====================== 重试工具 ======================
-    @FunctionalInterface
-    public interface RetryableTask<T> { T execute() throws Exception; }
-
-    private <T> T retry(RetryableTask<T> task, int max, long delay, String name) {
-        for (int i = 0; i < max; i++) {
-            try { return task.execute(); }
-            catch (Exception e) {
-                log.warn("{} 失败,第 {} 次重试", name, i + 1);
-                if (i + 1 >= max) throw new SystemException(name + " 失败,已重试 " + max + " 次", e.getMessage());
-                sleep(delay);
-            }
-        }
-        throw new SystemException(name + " 失败,已达到最大重试次数");
-    }
-
     private void sleep(long ms) {
     private void sleep(long ms) {
         try { Thread.sleep(ms); }
         try { Thread.sleep(ms); }
         catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException("重试被中断", ie); }
         catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException("重试被中断", ie); }
@@ -215,7 +200,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
 
 
         Map<String, Object> res = decrypt(MAPPER.readValue(
         Map<String, Object> res = decrypt(MAPPER.readValue(
                 post(props.getBaseUrl() + "/htcsp/VehicleInfoEntryAction.do?cmd=xbquery", buildJsonHeaders(cookie), postData),
                 post(props.getBaseUrl() + "/htcsp/VehicleInfoEntryAction.do?cmd=xbquery", buildJsonHeaders(cookie), postData),
-                HashMap.class));
+                Map.class));
         log.info("xbQuery result: {}", JSONObject.toJSONString(res));
         log.info("xbQuery result: {}", JSONObject.toJSONString(res));
 
 
         Map<String, Object> carmodel = (Map<String, Object>) res.get("carmodeldtojson");
         Map<String, Object> carmodel = (Map<String, Object>) res.get("carmodeldtojson");
@@ -262,17 +247,16 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         //带重试的获取报价编号、车型型号
         //带重试的获取报价编号、车型型号
         Map<String, Object> xbResult = retry(() -> {
         Map<String, Object> xbResult = retry(() -> {
             try { return xbQuery(dto.getUsername(), cookie, car); }
             try { return xbQuery(dto.getUsername(), cookie, car); }
-            catch (Exception e) { refreshLogin(dto); throw e; }
+            catch (Exception e) { refreshLogin(dto); throw new SystemException(e.getMessage()); }
         }, MAX_RETRIES, RETRY_DELAY_MS, "预报价获取登录信息");
         }, MAX_RETRIES, RETRY_DELAY_MS, "预报价获取登录信息");
 
 
         String quotationNo = str(xbResult, "quotationNo");
         String quotationNo = str(xbResult, "quotationNo");
         String modelcodexh = str(xbResult, "modelcodexh");
         String modelcodexh = str(xbResult, "modelcodexh");
         //报价前预处理-保存车辆信息、过滤车型等处理
         //报价前预处理-保存车辆信息、过滤车型等处理
         PreResult pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo);
         PreResult pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo);
-        //带重试的报价
-        CoreResult core = executeQuoteWithRetry(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
-
-        if (!core.success()) throw new RuntimeException("报价失败,已达到最大重试次数");
+        //报价
+        CoreResult core = executeQuote(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
+        if (!core.success()) throw new SystemException("报价失败");
         //保存订单到MongoDB
         //保存订单到MongoDB
         saveOrder(quoteVo, core);
         saveOrder(quoteVo, core);
         //组装费用
         //组装费用
@@ -400,41 +384,23 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     }
     }
 
 
     // ====================== 报价核心 ======================
     // ====================== 报价核心 ======================
-    private CoreResult executeQuoteWithRetry(QuoteVo quoteVo, String quotationNo, LoginDTO dto,
+    private CoreResult executeQuote(QuoteVo quoteVo, String quotationNo, LoginDTO dto,
                                              String cookie, PreResult pre,
                                              String cookie, PreResult pre,
                                              Map<String, Object> gsInfo, AttributionInformationVo attr) {
                                              Map<String, Object> gsInfo, AttributionInformationVo attr) {
-        int retry = 0;
         String fcPrice = "";
         String fcPrice = "";
         HtCrawlerQuoteResponse.DataDTO data = null;
         HtCrawlerQuoteResponse.DataDTO data = null;
 
 
-        while (retry < MAX_RETRIES) {
-            try {
-                if (retry > 0) { log.info("第 {} 次重试,重新开始报价流程...", retry + 1); sleep(SHORT_DELAY_MS); }
-
-                StepResult step = executeQuoteSteps(quoteVo, quotationNo, dto, cookie, pre, gsInfo);
-                data = step.data();
-
-                if (data.getApplicationdto() != null) {
-                    if (StringUtils.isNotBlank(step.personalInsuredJSON())) {
-                        fcPrice = fetchNoCarPremium(cookie, quotationNo, attr, step.personalInsuredJSON());
-                    }
-                    return new CoreResult(fcPrice, data, true);
-                }
-                log.warn("applicationdto 为 null,第 {} 次重试...", ++retry);
-            } catch (Exception e) {
-                if (e.getMessage() != null && e.getMessage().contains("重试次数已达上限")) throw wrap(e);
-                log.warn("报价异常,第 {} 次重试... 异常: {}", ++retry, e.getMessage());
-                if (retry >= MAX_RETRIES) throw new RuntimeException("报价重试次数已达上限: " + e.getMessage());
-                sleep(RETRY_DELAY_MS);
+        StepResult step = executeQuoteSteps(quoteVo, quotationNo, dto, cookie, pre, gsInfo);
+        data = step.data();
+        if (data.getApplicationdto() != null) {
+            if (StringUtils.isNotBlank(step.personalInsuredJSON())) {
+                fcPrice = fetchNoCarPremium(cookie, quotationNo, attr, step.personalInsuredJSON());
             }
             }
+            return new CoreResult(fcPrice, data, true);
         }
         }
         return new CoreResult(fcPrice, data, false);
         return new CoreResult(fcPrice, data, false);
     }
     }
 
 
-    private RuntimeException wrap(Exception e) {
-        return e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
-    }
-
     private String fetchNoCarPremium(String cookie, String quotationNo,
     private String fetchNoCarPremium(String cookie, String quotationNo,
                                      AttributionInformationVo attr, String personalInsuredJSON) {
                                      AttributionInformationVo attr, String personalInsuredJSON) {
         try {
         try {
@@ -456,7 +422,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     }
     }
 
 
     private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
     private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
-                                         String cookie, PreResult pre, Map<String, Object> gsInfo) throws Exception {
+                                         String cookie, PreResult pre, Map<String, Object> gsInfo) {
         HttpHeaders h = buildQuoteStep1Headers(cookie);
         HttpHeaders h = buildQuoteStep1Headers(cookie);
         HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, pre.carDTO(), pre.params(), quotationNo, pre.dataDTO(), dto, gsInfo);
         HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, pre.carDTO(), pre.params(), quotationNo, pre.dataDTO(), dto, gsInfo);
         String body = req.saveOneStept(r, h).getBody().toString();
         String body = req.saveOneStept(r, h).getBody().toString();
@@ -555,25 +521,8 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     private QuoteVo handleQuoteErrors(String decryptData, QuoteVo q) {
     private QuoteVo handleQuoteErrors(String decryptData, QuoteVo q) {
         boolean hasError = decryptData.contains("erroeInfo") || decryptData.contains("errrorFlag");
         boolean hasError = decryptData.contains("erroeInfo") || decryptData.contains("errrorFlag");
         if (!hasError) return q;
         if (!hasError) return q;
-        if (decryptData.contains("本机构并未配置此险种") || decryptData.contains("重复投保的其它公司") ||
-                (decryptData.contains("发生重复投保") && !decryptData.contains("终保日期"))) {
-            try {
-                throw new SystemException(MAPPER.readValue(decryptData, Map.class).get("erroeInfo").toString());
-            } catch (JsonProcessingException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        if (decryptData.contains("发生重复投保") && decryptData.contains("终保日期")) {
-            q = handleDuplicateInsurance(decryptData, q);
-            return q;
-        }
-        if (decryptData.contains("erroeInfo") || decryptData.contains("errrorFlag")) {
-            try {
-                throw new SystemException(MAPPER.readValue(decryptData, Map.class).get("erroeInfo").toString());
-            } catch (JsonProcessingException e) {
-                throw new RuntimeException(e);
-            }
+        if (decryptData.contains("发生重复投保") && decryptData.contains("终保日期") && !decryptData.contains("重复投保的其它公司")) {
+            return handleDuplicateInsurance(decryptData, q);
         }
         }
         return q;
         return q;
     }
     }
@@ -598,15 +547,17 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     }
     }
 
 
     private HtCrawlerQuoteResponse.DataDTO resolveQuoteResponse(QuoteVo q, String decryptData, String mealid, String limitAmount,
     private HtCrawlerQuoteResponse.DataDTO resolveQuoteResponse(QuoteVo q, String decryptData, String mealid, String limitAmount,
-                                                              HttpHeaders h, String personalInsuredJSON) throws Exception {
-        //单交不能重复投
-        if (decryptData.contains("存在有效交强险保单") || decryptData.contains("重复投保的其它公司")) throw new Exception(decryptData);
+                                                                HttpHeaders h, String personalInsuredJSON) {
+        if (!decryptData.contains("录入的校验码有误") && decryptData.contains("erroeInfo")) {
+            log.error("报价失败: {}", decryptData);
+            throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
+        }
         HtCrawlerQuoteResponse.DataDTO data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
         HtCrawlerQuoteResponse.DataDTO data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
         if (data.getApplicationdto() != null) return data;
         if (data.getApplicationdto() != null) return data;
 
 
         List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> list =
         List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> list =
                 data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
                 data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
-        if (list == null || list.isEmpty() || list.size() > 3) return data;
+        if (list == null || list.isEmpty()) return data;
 
 
         for (int i = 0; i < MAX_RETRIES; i++) {
         for (int i = 0; i < MAX_RETRIES; i++) {
             String basePartJSON = buildBasePartJSON(list);
             String basePartJSON = buildBasePartJSON(list);
@@ -630,15 +581,11 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
                 // 用新的 basePart 列表更新 list,下一轮循环会自动重新 buildBasePartJSON
                 // 用新的 basePart 列表更新 list,下一轮循环会自动重新 buildBasePartJSON
                 list = result != null && result.getBasepartdtolist() != null
                 list = result != null && result.getBasepartdtolist() != null
                         ? result.getBasepartdtolist().getBasepartdto() : null;
                         ? result.getBasepartdtolist().getBasepartdto() : null;
-                if (list == null || list.isEmpty() || list.size() > 3) {
+                if (list == null || list.isEmpty()) {
                     return result != null ? result : data;
                     return result != null ? result : data;
                 }
                 }
                 continue;
                 continue;
             }
             }
-
-            if (response.contains("erroeInfo")) {
-                throw new Exception(ERR_PREFIX + JSONObject.parseObject(response, HtCrawlerQuoteResponse.DataErrDTO.class).getErroeInfo());
-            }
             return result != null ? result : data;
             return result != null ? result : data;
         }
         }
         return data;
         return data;
@@ -649,7 +596,6 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         String basePartJSON = "";
         String basePartJSON = "";
         if (size == 1) {
         if (size == 1) {
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
-            log.info("buildBasePartJSON0: {}, {}", size, JSONObject.toJSONString(basePartDTO));
             String querrysequenceno = basePartDTO.getQuerrysequenceno();
             String querrysequenceno = basePartDTO.getQuerrysequenceno();
             String autocheckcode = basePartDTO.getAutocheckcode();
             String autocheckcode = basePartDTO.getAutocheckcode();
             String riskfalg = "0".equals(querrysequenceno.substring(0, 1)) ? "0" : "1";
             String riskfalg = "0".equals(querrysequenceno.substring(0, 1)) ? "0" : "1";
@@ -657,11 +603,9 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         }
         }
         if (size == 2) {
         if (size == 2) {
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
-            log.info("buildBasePartJSON0: {}, {}", size, JSONObject.toJSONString(basePartDTO));
             String querrysequenceno = basePartDTO.getQuerrysequenceno();
             String querrysequenceno = basePartDTO.getQuerrysequenceno();
             String autocheckcode = basePartDTO.getAutocheckcode();
             String autocheckcode = basePartDTO.getAutocheckcode();
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO1 = list.get(1);
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO1 = list.get(1);
-            log.info("buildBasePartJSON1: {}, {}", size, JSONObject.toJSONString(basePartDTO1));
             String querrysequenceno1 = basePartDTO1.getQuerrysequenceno();
             String querrysequenceno1 = basePartDTO1.getQuerrysequenceno();
             String autocheckcode1 = basePartDTO1.getAutocheckcode();
             String autocheckcode1 = basePartDTO1.getAutocheckcode();
             basePartJSON = "[{'riskfalg':'0','checktype':2,'querysequenceno':'"+querrysequenceno1+"','checkcode':'"+autocheckcode1+"','answer':''}," +
             basePartJSON = "[{'riskfalg':'0','checktype':2,'querysequenceno':'"+querrysequenceno1+"','checkcode':'"+autocheckcode1+"','answer':''}," +
@@ -669,15 +613,12 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         }
         }
         if (size == 3) {
         if (size == 3) {
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
-            log.info("buildBasePartJSON0: {}, {}", size, JSONObject.toJSONString(basePartDTO));
             String querrysequenceno = basePartDTO.getQuerrysequenceno();
             String querrysequenceno = basePartDTO.getQuerrysequenceno();
             String autocheckcode = basePartDTO.getAutocheckcode();
             String autocheckcode = basePartDTO.getAutocheckcode();
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO1 = list.get(1);
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO1 = list.get(1);
-            log.info("buildBasePartJSON1: {}, {}", size, JSONObject.toJSONString(basePartDTO1));
             String querrysequenceno1 = basePartDTO1.getQuerrysequenceno();
             String querrysequenceno1 = basePartDTO1.getQuerrysequenceno();
             String autocheckcode1 = basePartDTO1.getAutocheckcode();
             String autocheckcode1 = basePartDTO1.getAutocheckcode();
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO2 = list.get(2);
             HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO2 = list.get(2);
-            log.info("buildBasePartJSON2: {}, {}", size, JSONObject.toJSONString(basePartDTO2));
             String querrysequenceno2 = basePartDTO2.getQuerrysequenceno();
             String querrysequenceno2 = basePartDTO2.getQuerrysequenceno();
             String autocheckcode2 = basePartDTO2.getAutocheckcode();
             String autocheckcode2 = basePartDTO2.getAutocheckcode();
             basePartJSON = "[{'riskfalg':'0','checktype':2,'querysequenceno':'"+querrysequenceno1+"','checkcode':'"+autocheckcode1+"','answer':''}," +
             basePartJSON = "[{'riskfalg':'0','checktype':2,'querysequenceno':'"+querrysequenceno1+"','checkcode':'"+autocheckcode1+"','answer':''}," +
@@ -704,7 +645,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         Map<String, Object> map = MAPPER.readValue(res, Map.class);
         Map<String, Object> map = MAPPER.readValue(res, Map.class);
 
 
         if (isUnderwritingFailed(order.getCiCategory(), map, res)) {
         if (isUnderwritingFailed(order.getCiCategory(), map, res)) {
-            throw new SystemException("核保失败-------" + map.get("MSG"));
+            throw new SystemException("核保失败-------" + convertResponseMsg(map.get("MSG").toString()));
         }
         }
         if (res.contains("起保时间不正确")) {
         if (res.contains("起保时间不正确")) {
             throw new SystemException("起保时间不正确-------即时起保分钟数必须为00/15/30/45\n请重新选择起保时间!");
             throw new SystemException("起保时间不正确-------即时起保分钟数必须为00/15/30/45\n请重新选择起保时间!");
@@ -755,10 +696,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
             }
             }
             int s = html.indexOf("原因"), e = html.lastIndexOf("。");
             int s = html.indexOf("原因"), e = html.lastIndexOf("。");
             throw new SystemException("审核未通过:" + (s >= 0 && e > s ? html.substring(s, e) : "审核未通过"));
             throw new SystemException("审核未通过:" + (s >= 0 && e > s ? html.substring(s, e) : "审核未通过"));
-        } catch (SystemException se) { throw se; }
-        catch (Exception e) {
-            throw new SystemException(e.getMessage());
-        }
+        } catch (Exception e) { throw new SystemException(e.getMessage()); }
     }
     }
 
 
     private UnderwritingResultsVo handlePassedUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters params, UnderwritingVo vo) {
     private UnderwritingResultsVo handlePassedUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters params, UnderwritingVo vo) {
@@ -846,7 +784,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         } catch (Exception e) { throw new RuntimeException(e); }
         } catch (Exception e) { throw new RuntimeException(e); }
     }
     }
 
 
-    private Map fetchUploadInitParam(String token) {
+    private Map<String, Object> fetchUploadInitParam(String token) {
         HttpHeaders h = new HttpHeaders();
         HttpHeaders h = new HttpHeaders();
         h.set(HtRequestConstant.COOKIE, req.getCookie());
         h.set(HtRequestConstant.COOKIE, req.getCookie());
         h.set("Accept", "application/json, text/plain, */*");
         h.set("Accept", "application/json, text/plain, */*");
@@ -1074,6 +1012,22 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         });
         });
     }
     }
 
 
+    // ====================== 重试工具 ======================
+    @FunctionalInterface
+    public interface RetryableTask<T> { T execute() throws Exception; }
+
+    private <T> T retry(RetryableTask<T> task, int max, long delay, String name) {
+        for (int i = 0; i < max; i++) {
+            try { return task.execute(); }
+            catch (Exception e) {
+                log.warn("{} 失败,第 {} 次重试", name, i + 1);
+                if (i + 1 >= max) throw new SystemException(name + " 失败,已重试 " + max + " 次", e.getMessage());
+                sleep(delay);
+            }
+        }
+        throw new SystemException(name + " 失败,已达到最大重试次数");
+    }
+
     // ====================== HTTP 通用工具 ======================
     // ====================== HTTP 通用工具 ======================
     private String get(String url, HttpHeaders headers, MultiValueMap<String, String> params) {
     private String get(String url, HttpHeaders headers, MultiValueMap<String, String> params) {
         UriComponentsBuilder b = UriComponentsBuilder.fromHttpUrl(url);
         UriComponentsBuilder b = UriComponentsBuilder.fromHttpUrl(url);
@@ -1087,7 +1041,7 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
 
 
     @SuppressWarnings("unchecked")
     @SuppressWarnings("unchecked")
     private Map<String, Object> exchangeForm(String url, Map<String, String> queryParams,
     private Map<String, Object> exchangeForm(String url, Map<String, String> queryParams,
-                                               MultiValueMap<String, String> data, HttpHeaders headers) throws JsonProcessingException {
+                                             MultiValueMap<String, String> data, HttpHeaders headers) throws JsonProcessingException {
         UriComponentsBuilder b = UriComponentsBuilder.fromHttpUrl(url);
         UriComponentsBuilder b = UriComponentsBuilder.fromHttpUrl(url);
         if (queryParams != null) queryParams.forEach(b::queryParam);
         if (queryParams != null) queryParams.forEach(b::queryParam);
         String body = RT.exchange(b.toUriString(), HttpMethod.POST, new HttpEntity<>(data, headers), String.class).getBody();
         String body = RT.exchange(b.toUriString(), HttpMethod.POST, new HttpEntity<>(data, headers), String.class).getBody();
@@ -1153,4 +1107,24 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         }
         }
         return m;
         return m;
     }
     }
+    /**
+     * 提取 (infoName + infomsg) 或者 erroeInfo 拼接字符串
+     */
+    public static String convertResponseMsg(String responseStr) {
+        Matcher matcher = RESPONSE_ERR.matcher(responseStr);
+        StringBuilder sb = new StringBuilder();
+        while (matcher.find()) {
+            if (matcher.group(2) != null && matcher.group(3) != null) {
+                // 场景1:infoName + infomsg
+                String infoName = matcher.group(2).trim();
+                String infomsg = matcher.group(3).trim();
+                sb.append(infoName).append(":").append(infomsg).append("\n");
+            } else if (matcher.group(4) != null) {
+                // 场景2:erroeInfo 单独错误
+                sb.append(matcher.group(4).trim()).append("\n");
+            }
+        }
+        if (StringUtils.isBlank(sb)) sb.append(responseStr);
+        return sb.toString().trim();
+    }
 }
 }

+ 4 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/controller/UnifyOrderManager.java

@@ -391,6 +391,10 @@ public class UnifyOrderManager {
             log.error("车险报价异常", e);
             log.error("车险报价异常", e);
             Throwable root = e.getCause() != null ? e.getCause() : e;
             Throwable root = e.getCause() != null ? e.getCause() : e;
             String errMsg = root.getMessage() != null ? root.getMessage() : "系统异常,报价失败";
             String errMsg = root.getMessage() != null ? root.getMessage() : "系统异常,报价失败";
+            // 去除异常类名前缀
+            if (errMsg.matches("^[a-zA-Z0-9.]+Exception:.*")) {
+                errMsg = errMsg.substring(errMsg.indexOf(":") + 1).trim();
+            }
             try {
             try {
                 insOrdersService.orderAfterUpdateFailedQuote(ordersNo, errMsg);
                 insOrdersService.orderAfterUpdateFailedQuote(ordersNo, errMsg);
             } catch (Exception ex) {
             } catch (Exception ex) {