Selaa lähdekoodia

车辆查询参数

helixiao 1 vuosi sitten
vanhempi
commit
d1f8e5a1de
18 muutettua tiedostoa jossa 1543 lisäystä ja 55 poistoa
  1. 75 0
      tenant/insurance/quotation-commons/src/main/java/com/jzg/quotation/commons/utils/HttpUtil.java
  2. 5 0
      tenant/insurance/quotation-summary/pom.xml
  3. 4 0
      tenant/insurance/quotation-summary/src/main/resources/application-dev.yaml
  4. 52 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/component/ZhongAnCrawlerCacheComponent.java
  5. 44 15
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/component/ZhongAnCrawlerRequestComponent.java
  6. 5 2
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/constant/ZhongAnRequestConstant.java
  7. 3 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/constant/enums/RequestUrl.java
  8. 1 1
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/ZhongAnCrawlerConfigureParameters.java
  9. 8 1
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerBaseRequest.java
  10. 24 4
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerCarQueryRequest.java
  11. 34 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerLoginRequest.java
  12. 35 28
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerQuoteRequest.java
  13. 4 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/response/ZhongAnCrawlerBaseResponse.java
  14. 1 1
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/repository/ZhongAnCrawlerOrderRepository.java
  15. 1 1
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/Impl/ZhongAnCrawlerOrderServiceImpl.java
  16. 91 2
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/Impl/ZhongAnCrawlerRequestImpl.java
  17. 653 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/baojia.java
  18. 503 0
      tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/test.java

+ 75 - 0
tenant/insurance/quotation-commons/src/main/java/com/jzg/quotation/commons/utils/HttpUtil.java

@@ -10,8 +10,11 @@ import org.apache.commons.httpclient.methods.multipart.Part;
 import java.io.*;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * http 工具类
@@ -109,4 +112,76 @@ public class HttpUtil {
 
         return response;
     }
+
+    // 发送GET请求的工具方法
+    public static HttpURLConnection sendGetRequest(String url, Map<String, String> params,
+                                                    Map<String, String> headers, boolean followRedirects)
+            throws IOException {
+        // 如果有参数,构建带参数的URL
+        if (params != null && !params.isEmpty()) {
+            StringBuilder urlBuilder = new StringBuilder(url);
+            urlBuilder.append("?");
+            for (Map.Entry<String, String> entry : params.entrySet()) {
+                urlBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8"))
+                        .append("=")
+                        .append(URLEncoder.encode(entry.getValue(), "UTF-8"))
+                        .append("&");
+            }
+            // 移除最后一个&
+            url = urlBuilder.substring(0, urlBuilder.length() - 1);
+        }
+
+        URL requestUrl = new URL(url);
+        HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
+
+        // 设置不跟随重定向
+        connection.setInstanceFollowRedirects(followRedirects);
+
+        // 设置请求方法
+        connection.setRequestMethod("GET");
+
+        // 设置请求头
+        if (headers != null) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                connection.setRequestProperty(entry.getKey(), entry.getValue());
+            }
+        }
+
+        // 连接
+        connection.connect();
+
+        return connection;
+    }
+
+    // 从响应头中提取zaLoginCookieKey
+    public static String extractZaLoginCookieKey(Map<String, List<String>> headers) {
+        Pattern pattern = Pattern.compile("zaLoginCookieKey=(.*?);");
+
+        // 遍历所有响应头寻找Set-Cookie
+        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+            if (entry.getKey() != null && entry.getKey().equalsIgnoreCase("Set-Cookie")) {
+                for (String cookie : entry.getValue()) {
+                    Matcher matcher = pattern.matcher(cookie);
+                    if (matcher.find()) {
+                        return matcher.group(1);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    // 从URL中提取flowId
+    public static String extractFlowId(String url) {
+        if (url == null) return null;
+
+        Pattern pattern = Pattern.compile("flowId=(.*?)&");
+        Matcher matcher = pattern.matcher(url);
+        if (matcher.find()) {
+            return matcher.group(1);
+        }
+        return null;
+    }
+
+
 }

+ 5 - 0
tenant/insurance/quotation-summary/pom.xml

@@ -111,6 +111,11 @@
             <artifactId>quotation-ansheng</artifactId>
             <version>1.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>com.jzg</groupId>
+            <artifactId>quotation-zhongan</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
 
         <!-- thymeleaf 模版类 -->
         <dependency>

+ 4 - 0
tenant/insurance/quotation-summary/src/main/resources/application-dev.yaml

@@ -184,3 +184,7 @@ zijin:
     downLoadDocument: http://test-open.zking.com/temp/api/v1/insurance/nonAutoMobile/queryPolicy/downLoadDocument
     # 对接三方渠道验车链接接口
     sendCheckCarLink: http://open.zking.com/api/v1/open/open-aggregate/auth/wanJiaYun/sendCheckCarLink
+
+
+zhongAn:
+  id: "975113"

+ 52 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/component/ZhongAnCrawlerCacheComponent.java

@@ -0,0 +1,52 @@
+package com.jzg.quotation.zhongan.crawler.component;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RMap;
+import org.redisson.api.RedissonClient;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ZhongAnCrawlerCacheComponent {
+
+    private final RedissonClient redissonClient;
+
+    /**
+     * 众安财险授权cookie
+     */
+    public static final String COOKIE = "cookie:";
+    public static final String ZHONGAN_COOKIE = "zhoangan:cookie:";
+    /**
+     * 众安财险登录后Id
+     */
+    public static final String FLOWID = "flowId:";
+
+
+
+    public void cacheCookie(String zaLoginCookieKey, String flowId, String userName) {
+        Map<String, String> authorizationMap = new HashMap<>();
+
+        authorizationMap.put(COOKIE, zaLoginCookieKey);
+        authorizationMap.put(FLOWID, flowId);
+        RMap<Object, Object> map = redissonClient.getMap(ZHONGAN_COOKIE + userName);
+        map.putAll(authorizationMap);
+        map.expire(Duration.ofHours(1L));
+    }
+
+    public String getCookie(String username) {
+        return (String) redissonClient.getMap(ZHONGAN_COOKIE + username).get(COOKIE);
+    }
+
+    public String getFlowId(String username) {
+        return (String) redissonClient.getMap(ZHONGAN_COOKIE + username).get(FLOWID);
+    }
+
+
+
+}

+ 44 - 15
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/component/ZhongAnCrawlerRequestComponent.java

@@ -1,7 +1,10 @@
 package com.jzg.quotation.zhongan.crawler.component;
 
+import com.jzg.commons.exception.SystemException;
+import com.jzg.commons.util.StringUtils;
 import com.jzg.quotation.commons.component.RequestComponent;
 import com.jzg.quotation.commons.constant.CacheConstant;
+import com.jzg.quotation.commons.utils.RequestObjectConversion;
 import com.jzg.quotation.zhongan.crawler.constant.ZhongAnRequestConstant;
 import com.jzg.quotation.zhongan.crawler.constant.enums.RequestUrl;
 import com.jzg.quotation.zhongan.crawler.entity.request.*;
@@ -10,9 +13,14 @@ import com.jzg.quotation.zhongan.crawler.properties.ZhongAnCrawlerProperties;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
+import org.springframework.util.MultiValueMap;
+import reactor.core.publisher.Mono;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -31,8 +39,14 @@ public class ZhongAnCrawlerRequestComponent {
 
     private final ZhongAnCrawlerProperties zhongAnCrawlerProperties;
 
+    private final ZhongAnCrawlerCacheComponent zhongAnCrawlerCacheComponent;
+
+    @Value("${zhongAn.id}")
+    private String zhongAnId;
+
     /**
      * 登录
+     *
      * @return
      */
     public List<String> authenticate() {
@@ -41,39 +55,46 @@ public class ZhongAnCrawlerRequestComponent {
 
     /**
      * 获取cookie
+     *
      * @param username
      * @return
      */
-    public List<String> getCookie(String username) {
-        return (List<String>) redissonClient.getMap(CacheConstant.HUATAI_AUTHORIZATION + username).get(ZhongAnRequestConstant.COOKIE);
+    public String getCookie(String username) {
+        return (String) redissonClient.getMap(zhongAnCrawlerCacheComponent.ZHONGAN_COOKIE + username).get(zhongAnCrawlerCacheComponent.COOKIE);
     }
 
     /**
      * 获取请求头
+     *
      * @return
      */
     public HttpHeaders getHeaders(String username) {
-        List<String> cookie = getCookie(username);
+        String cookie = getCookie(username);
         if (cookie == null || cookie.isEmpty()) {
-            cookie = authenticate();
+            throw new SystemException("缓存中未获取到cookie!");
         }
         HttpHeaders headers = new HttpHeaders();
-        headers.add(ZhongAnRequestConstant.COOKIE, cookie.stream().collect(Collectors.joining(";")));
+        headers.add(ZhongAnRequestConstant.COOKIE, cookie);
+        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36");
+        headers.add("Accept", "application/json, text/plain, */*");
+//        headers.add("Content-Type", "application/json");
         return headers;
     }
 
     /**
      * 车辆查询
+     *
      * @param carQueryRequest
      * @param headers
      * @return
      */
     public List<ZhongAnCrawlerCarQueryResponse.ValueDTO.DataDTO.ResultDTO.VehicleDTO> carQuery(ZhongAnCrawlerCarQueryRequest carQueryRequest, HttpHeaders headers) {
-        List<ZhongAnCrawlerCarQueryResponse.ValueDTO.DataDTO.ResultDTO.VehicleDTO> vehicleDTOList = null;
+
+        List<ZhongAnCrawlerCarQueryResponse.ValueDTO.DataDTO.ResultDTO.VehicleDTO> vehicleDTOList = new ArrayList<>();
         Integer start = 0;
         Integer pageTotal = 0;
         do {
-            ZhongAnCrawlerCarQueryResponse carQueryResponse = requestComponent.objectPost(RequestUrl.CAR_QUERY.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), carQueryRequest, ZhongAnCrawlerCarQueryResponse.class, headers).getBody();
+            ZhongAnCrawlerCarQueryResponse carQueryResponse = requestComponent.formData(RequestUrl.CAR_QUERY.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), carQueryRequest, ZhongAnCrawlerCarQueryResponse.class, headers).getBody();
             List<ZhongAnCrawlerCarQueryResponse.ValueDTO.DataDTO.ResultDTO.VehicleDTO> vehicleList = carQueryResponse.getValue().getDatas().getResult().getVehicleList();
             vehicleDTOList.addAll(vehicleList);
             pageTotal = carQueryResponse.getValue().getDatas().getResult().getPageTotal();
@@ -85,80 +106,88 @@ public class ZhongAnCrawlerRequestComponent {
 
     /**
      * 报价
+     *
      * @param quoteRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerQuoteResponse quote(ZhongAnCrawlerQuoteRequest quoteRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.QUOTE.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), quoteRequest, ZhongAnCrawlerQuoteResponse.class, headers ).getBody();
+        return requestComponent.formData(RequestUrl.QUOTE.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), quoteRequest, ZhongAnCrawlerQuoteResponse.class, headers).getBody();
     }
 
     /**
      * 确认报价
+     *
      * @param confirmQuoteRequest
      * @param headers
      */
     public void confirmQuote(ZhongAnCrawlerConfirmQuoteRequest confirmQuoteRequest, HttpHeaders headers) {
-        requestComponent.objectPost(RequestUrl.CONFIRM_QUOTE.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), confirmQuoteRequest, ZhongAnCrawlerQuoteResponse.class, headers );
+        requestComponent.objectPost(RequestUrl.CONFIRM_QUOTE.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), confirmQuoteRequest, ZhongAnCrawlerQuoteResponse.class, headers);
     }
 
     /**
      * 获取订单信息
+     *
      * @param getOrderRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerGetOrderResponse getOrder(ZhongAnCrawlerGetOrderRequest getOrderRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.GET_ORDER.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), getOrderRequest, ZhongAnCrawlerGetOrderResponse.class, headers ).getBody();
+        return requestComponent.objectPost(RequestUrl.GET_ORDER.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), getOrderRequest, ZhongAnCrawlerGetOrderResponse.class, headers).getBody();
     }
 
     /**
      * 确认订单
+     *
      * @param confirmOrderRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerConfirmOrderResponse confirmOrder(ZhongAnCrawlerConfirmOrderRequest confirmOrderRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.CONFIRM_ORDER.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), confirmOrderRequest, ZhongAnCrawlerConfirmOrderResponse.class, headers ).getBody();
+        return requestComponent.objectPost(RequestUrl.CONFIRM_ORDER.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), confirmOrderRequest, ZhongAnCrawlerConfirmOrderResponse.class, headers).getBody();
     }
 
     /**
      * 非车险提交核保
+     *
      * @param jyxUnderwritingRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerJyxUnderwritingResponse jyxUnderwriting(ZhongAnCrawlerJyxUnderwritingRequest jyxUnderwritingRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.JYX_UNDERWRITING.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), jyxUnderwritingRequest, ZhongAnCrawlerJyxUnderwritingResponse.class, headers ).getBody();
+        return requestComponent.objectPost(RequestUrl.JYX_UNDERWRITING.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), jyxUnderwritingRequest, ZhongAnCrawlerJyxUnderwritingResponse.class, headers).getBody();
     }
 
     /**
      * 上传影像
+     *
      * @param imageRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerUploadImageResponse uploadImage(ZhongAnCrawlerUploadImageRequest imageRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.UPLOAD_IMAGE.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), imageRequest, ZhongAnCrawlerUploadImageResponse.class, headers ).getBody();
+        return requestComponent.objectPost(RequestUrl.UPLOAD_IMAGE.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), imageRequest, ZhongAnCrawlerUploadImageResponse.class, headers).getBody();
     }
 
     /**
      * 获取支付链接
+     *
      * @param paymentRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerPaymentResponse payment(ZhongAnCrawlerPaymentRequest paymentRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.PAYMENT_LINK.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), paymentRequest, ZhongAnCrawlerPaymentResponse.class, headers ).getBody();
+        return requestComponent.objectPost(RequestUrl.PAYMENT_LINK.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), paymentRequest, ZhongAnCrawlerPaymentResponse.class, headers).getBody();
     }
 
     /**
      * 获取保单下载参数
+     *
      * @param downloadPolicyRequest
      * @param headers
      * @return
      */
     public ZhongAnCrawlerDownloadPolicyResponse downloadPolicy(ZhongAnCrawlerDownloadPolicyRequest downloadPolicyRequest, HttpHeaders headers) {
-        return requestComponent.objectPost(RequestUrl.DOWNLOAD_POLICY.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), downloadPolicyRequest, ZhongAnCrawlerDownloadPolicyResponse.class, headers ).getBody();
+        return requestComponent.objectPost(RequestUrl.DOWNLOAD_POLICY.getRequestUrl(zhongAnCrawlerProperties.getBaseUrl()), downloadPolicyRequest, ZhongAnCrawlerDownloadPolicyResponse.class, headers).getBody();
     }
 }

+ 5 - 2
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/constant/ZhongAnRequestConstant.java

@@ -6,14 +6,17 @@ package com.jzg.quotation.zhongan.crawler.constant;
  * @date: 2025/5/12 10:15
  **/
 public class ZhongAnRequestConstant {
-    public static final String COOKIE = "Cookie";
+    public static final String COOKIE = "cookie";
 
     public static final String I_PARAM = "e";
 
     /**
      * 车型查询page参数
      */
-    public static final String CAR_QUERY_PAGE = "/vehicleModel/index";
+    public static final String CAR_QUERY_PAGE = "%2FbaseInfo";
+    public static final String CAR_vehicle_PAGE = "%2FvehicleModel%2Fvehicles";
+
+
 
     /**
      * 报价page参数

+ 3 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/constant/enums/RequestUrl.java

@@ -12,6 +12,9 @@ import lombok.Getter;
 @AllArgsConstructor
 @Getter
 public enum RequestUrl implements CrawlerRequestUrlStandard {
+
+    CAR_VIN("/open/bmw/car_controller/query_car_info.json","车架号查询"),
+
     CAR_QUERY("/open/bmw/car_controller/query_vehicle_model.json", "车型查询"),
 
     QUOTE("/open/bmw/n/quote_controller/premium_trial.json", "报价"),

+ 1 - 1
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/ZhongAnCrawlerConfigureParameters.java

@@ -20,5 +20,5 @@ public class ZhongAnCrawlerConfigureParameters implements ConfigureParameters {
      */
     private String flowId;
 
-    private String flag;
+    private String flag = "0";
 }

+ 8 - 1
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerBaseRequest.java

@@ -1,5 +1,6 @@
 package com.jzg.quotation.zhongan.crawler.entity.request;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 
 import java.io.Serial;
@@ -14,9 +15,15 @@ import java.io.Serializable;
 public class ZhongAnCrawlerBaseRequest implements Serializable {
     @Serial
     private static final long serialVersionUID = 4225445134500846763L;
-
+    @JsonProperty("flowId")
     private String flowId;
+
+    @JsonProperty("page")
     private String page;
+
+    @JsonProperty("flag")
     private String flag;
+
+    @JsonProperty("i")
     private String i;
 }

+ 24 - 4
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerCarQueryRequest.java

@@ -1,5 +1,7 @@
 package com.jzg.quotation.zhongan.crawler.entity.request;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.jzg.commons.entity.quote.vo.CarInfoVo;
 import com.jzg.quotation.zhongan.crawler.constant.ZhongAnRequestConstant;
 import com.jzg.quotation.zhongan.crawler.entity.ZhongAnCrawlerConfigureParameters;
 import lombok.Data;
@@ -12,13 +14,14 @@ import java.io.Serial;
  * @date: 2025/5/12 10:41
  **/
 @Data
-public class ZhongAnCrawlerCarQueryRequest extends ZhongAnCrawlerBaseRequest {
+public class
+ZhongAnCrawlerCarQueryRequest extends ZhongAnCrawlerBaseRequest {
     @Serial
     private static final long serialVersionUID = -8564194443790815627L;
 
     public ZhongAnCrawlerCarQueryRequest(String vehicleBrand, ZhongAnCrawlerConfigureParameters parameters) {
         super.setFlowId(parameters.getFlowId());
-        super.setPage(ZhongAnRequestConstant.CAR_QUERY_PAGE);
+        super.setPage(ZhongAnRequestConstant.CAR_vehicle_PAGE);
         super.setFlag(parameters.getFlag());
         super.setI(ZhongAnRequestConstant.I_PARAM);
         this.vehicleBrand = vehicleBrand;
@@ -28,14 +31,31 @@ public class ZhongAnCrawlerCarQueryRequest extends ZhongAnCrawlerBaseRequest {
     /**
      * 品牌型号
      */
+    @JsonProperty("vehicleBrand")
     private String vehicleBrand;
+    @JsonProperty("brandName")
     private String brandName;
+    @JsonProperty("familyName")
     private String familyName;
+    @JsonProperty("familyCode")
     private String familyCode;
+    @JsonProperty("engine")
     private String engine;
+    @JsonProperty("start")
     private Integer start = 0;
-    private Integer limit = 12;
-    private String callVehicleModelLibraryFlag = "0";
+    @JsonProperty("limit")
+    private Integer limit = 30;
+    @JsonProperty("callVehicleModelLibraryFlag")
+    private String callVehicleModelLibraryFlag = "1";
+
+//    @JsonProperty("vehicleFrameNo")
+//    private String vehicleFrameNo;
+//
+//    @JsonProperty("passCheck")
+//    private String passCheck;
+
+
+
 
     /**
      * flowId				FJ14358876876b6b9550a

+ 34 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/request/ZhongAnCrawlerLoginRequest.java

@@ -0,0 +1,34 @@
+package com.jzg.quotation.zhongan.crawler.entity.request;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+@Data
+public class ZhongAnCrawlerLoginRequest implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -1L;
+
+    private String partnerChannelCode;
+
+    private String partnerUserAccount;
+
+    private String partnerChildChannelCode;
+
+    private String promotionNo;
+
+    private String productId;
+
+    private String policySource;
+
+    private String subaoBizContent;
+
+    private String insurerCode;
+
+
+
+
+}

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

@@ -1,6 +1,7 @@
 package com.jzg.quotation.zhongan.crawler.entity.request;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.jzg.commons.entity.quote.vo.KindInfoVo;
 import com.jzg.commons.entity.quote.vo.RiskInfoVo;
 import com.jzg.commons.entity.quote.vo.QuoteVo;
@@ -8,6 +9,7 @@ import com.jzg.quotation.zhongan.crawler.constant.ZhongAnRequestConstant;
 import com.jzg.quotation.zhongan.crawler.entity.ZhongAnCrawlerConfigureParameters;
 import com.jzg.quotation.zhongan.crawler.entity.dto.CoverageInfoDTO;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
 
 import java.io.Serial;
 import java.util.ArrayList;
@@ -23,6 +25,39 @@ public class ZhongAnCrawlerQuoteRequest extends ZhongAnCrawlerBaseRequest {
     @Serial
     private static final long serialVersionUID = -5514389426425862446L;
 
+    /**
+     * 是否选择商业险(1,是;0,否)
+     */
+    @JsonProperty("addBusi")
+    private String addBusi;
+
+    @JsonProperty("coverageInfo")
+    private String coverageInfo;
+    /**
+     * 是否选择交强险(1,是;0,否)
+     */
+    @JsonProperty("addCompel")
+    private String addCompel;
+    @JsonProperty("addTax")
+    private String addTax = "0";
+    /**
+     * 商业险生效日期
+     */
+    @JsonProperty("effectiveDate")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private String effectiveDate;
+    /**
+     * 交强险生效日期
+     */
+    @JsonProperty("compelInsEffectiveDate")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private String compelInsEffectiveDate;
+    /**
+     * 非车信息
+     */
+    @JsonProperty("nonAutoInfo")
+    private String nonAutoInfo;
+
     public ZhongAnCrawlerQuoteRequest(QuoteVo quoteVo, ZhongAnCrawlerConfigureParameters parameters) {
         super.setFlowId(parameters.getFlowId());
         super.setPage(ZhongAnRequestConstant.QUOTE_PAGE);
@@ -54,34 +89,6 @@ public class ZhongAnCrawlerQuoteRequest extends ZhongAnCrawlerBaseRequest {
         this.coverageInfo = JSONObject.toJSONString(coverageInfoDTOS);
     }
 
-    /**
-     * 是否选择商业险(1,是;0,否)
-     */
-    private String addBusi;
-    private String coverageInfo;
-    /**
-     * 是否选择交强险(1,是;0,否)
-     */
-    private String addCompel;
-    private String addTax = "0";
-    /**
-     * 商业险生效日期
-     */
-    private String effectiveDate;
-    /**
-     *
-     * 
-     *
-     *
-     *
-     * 交强险生效日期
-     */
-    private String compelInsEffectiveDate;
-    /**
-     * 非车信息
-     */
-    private String nonAutoInfo;
-
     /**
      * flowId								FJ14358876876b6b9550a
      * page								/insureProgram

+ 4 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/entity/response/ZhongAnCrawlerBaseResponse.java

@@ -1,5 +1,6 @@
 package com.jzg.quotation.zhongan.crawler.entity.response;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 
 import java.io.Serial;
@@ -15,10 +16,13 @@ public class ZhongAnCrawlerBaseResponse implements Serializable {
     @Serial
     private static final long serialVersionUID = 2513263996059644680L;
 
+    @JsonProperty("errorMsg")
     private String errorMsg;
 
+    @JsonProperty("errorCode")
     private String errorCode;
 
+    @JsonProperty("success")
     private Boolean success;
 
 }

+ 1 - 1
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/Repository/ZhongAnCrawlerOrderRepository.java → tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/repository/ZhongAnCrawlerOrderRepository.java

@@ -1,4 +1,4 @@
-package com.jzg.quotation.zhongan.crawler.Repository;
+package com.jzg.quotation.zhongan.crawler.repository;
 
 import com.jzg.quotation.zhongan.crawler.entity.po.ZhongAnCrawlerOrder;
 import org.springframework.data.mongodb.repository.MongoRepository;

+ 1 - 1
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/Impl/ZhongAnCrawlerOrderServiceImpl.java

@@ -1,6 +1,6 @@
 package com.jzg.quotation.zhongan.crawler.service.Impl;
 
-import com.jzg.quotation.zhongan.crawler.Repository.ZhongAnCrawlerOrderRepository;
+import com.jzg.quotation.zhongan.crawler.repository.ZhongAnCrawlerOrderRepository;
 import com.jzg.quotation.zhongan.crawler.entity.po.ZhongAnCrawlerOrder;
 import com.jzg.quotation.zhongan.crawler.service.ZhongAnCrawlerOrderService;
 import lombok.RequiredArgsConstructor;

+ 91 - 2
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/Impl/ZhongAnCrawlerRequestImpl.java

@@ -5,6 +5,8 @@ import com.jzg.commons.entity.quote.vo.AttributionInformationVo;
 import com.jzg.commons.entity.quote.vo.CarInfoVo;
 import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.commons.entity.quote.vo.aggregated.*;
+import com.jzg.commons.exception.SystemException;
+import com.jzg.commons.util.StringUtils;
 import com.jzg.quotation.commons.annotation.QuoteCrawlerService;
 import com.jzg.quotation.commons.constant.InsuranceCode;
 import com.jzg.commons.entity.quote.vo.base.LoginBase;
@@ -12,7 +14,9 @@ import com.jzg.commons.entity.quote.vo.base.OrderBase;
 import com.jzg.commons.entity.quote.vo.image.InsuranceImageVo;
 import com.jzg.quotation.commons.filter.CarModelsFilterUtils;
 import com.jzg.quotation.commons.standard.conversion.ConfigureParametersConversion;
+import com.jzg.quotation.commons.utils.HttpUtil;
 import com.jzg.quotation.zhongan.crawler.build.ZhongAnCrawlerQuoteResultsVoBuild;
+import com.jzg.quotation.zhongan.crawler.component.ZhongAnCrawlerCacheComponent;
 import com.jzg.quotation.zhongan.crawler.component.ZhongAnCrawlerRequestComponent;
 import com.jzg.quotation.zhongan.crawler.constant.ZhongAnRequestConstant;
 import com.jzg.quotation.zhongan.crawler.entity.ZhongAnCrawlerConfigureParameters;
@@ -22,13 +26,18 @@ import com.jzg.quotation.zhongan.crawler.entity.response.*;
 import com.jzg.quotation.zhongan.crawler.service.ZhongAnCrawlerOrderService;
 import com.jzg.quotation.zhongan.crawler.service.ZhongAnCrawlerRequest;
 import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpHeaders;
+import org.springframework.web.reactive.function.client.WebClient;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
 import java.util.Base64;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -45,6 +54,11 @@ public class ZhongAnCrawlerRequestImpl implements ZhongAnCrawlerRequest {
 
     private final ZhongAnCrawlerOrderService zhongAnCrawlerOrderService;
 
+    private final ZhongAnCrawlerCacheComponent zhongAnCrawlerCacheComponent;
+
+    @Value("${zhongAn.id}")
+    private String zhongAnId;
+
     /**
      * 登录
      * @param loginBase 登录信息
@@ -62,12 +76,16 @@ public class ZhongAnCrawlerRequestImpl implements ZhongAnCrawlerRequest {
      */
     @Override
     public QuoteResultsVo quote(QuoteVo quoteVo) {
+        loginCookieCache(zhongAnId);
         CarInfoVo carInfoVo = quoteVo.getCarInfoVo();
         AttributionInformationVo attributionInformationVo = quoteVo.getOrder().getAttributionInformationVo();
         //获取配置信息
         ZhongAnCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(ZhongAnCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
-        HttpHeaders headers = zhongAnCrawlerRequestComponent.getHeaders(attributionInformationVo.getUsername());
-
+        HttpHeaders headers = zhongAnCrawlerRequestComponent.getHeaders(zhongAnId);
+        String flowId = parameters.getFlowId();
+        if (StringUtils.isEmpty(flowId)) {
+            parameters.setFlowId(zhongAnCrawlerCacheComponent.getFlowId(zhongAnId));
+        }
         //车型查询
         ZhongAnCrawlerCarQueryRequest carQueryRequest = new ZhongAnCrawlerCarQueryRequest(carInfoVo.getBrandName(), parameters);
         List<ZhongAnCrawlerCarQueryResponse.ValueDTO.DataDTO.ResultDTO.VehicleDTO> vehicleDTOList = zhongAnCrawlerRequestComponent.carQuery(carQueryRequest, headers);
@@ -76,6 +94,9 @@ public class ZhongAnCrawlerRequestImpl implements ZhongAnCrawlerRequest {
         //报价
         ZhongAnCrawlerQuoteRequest quoteRequest = new ZhongAnCrawlerQuoteRequest(quoteVo, parameters);
         ZhongAnCrawlerQuoteResponse quoteResponse = zhongAnCrawlerRequestComponent.quote(quoteRequest, headers);
+        if (quoteResponse != null && StringUtils.isNotEmpty(quoteResponse.getErrorMsg())) {
+            throw new SystemException("众安财险登录失效,报价失败,联系管理员!");
+        }
 
         //确认报价
         ZhongAnCrawlerConfirmQuoteRequest confirmQuoteRequest = new ZhongAnCrawlerConfirmQuoteRequest(parameters);
@@ -101,6 +122,74 @@ public class ZhongAnCrawlerRequestImpl implements ZhongAnCrawlerRequest {
         zhongAnCrawlerOrderService.save(zhongAnCrawlerOrder);
         return ZhongAnCrawlerQuoteResultsVoBuild.buildQuoteResultsVo(quoteVo, quoteResponse.getValue().getDatas());
     }
+    //登录
+    private void loginCookieCache(String zhongAnId) {
+        try {
+//            ZhongAnCrawlerLoginRequest params = new ZhongAnCrawlerLoginRequest();
+//            params.setPartnerChannelCode("m18x462r");
+//            params.setPartnerUserAccount("975113");
+//            params.setPartnerChildChannelCode("");
+//            params.setPromotionNo("0c033ab79c6847c0878342480aef76a1");
+//            params.setProductId("10676");
+//            params.setPolicySource("40");
+//            params.setSubaoBizContent("");
+//            params.setInsurerCode("ZHONGANCAR");
+
+            Map<String, String> params = new HashMap<>();
+            params.put("partnerChannelCode", "m18x462r");
+            params.put("partnerUserAccount", zhongAnId);
+            params.put("partnerChildChannelCode", "");
+            params.put("promotionNo", "0c033ab79c6847c0878342480aef76a1");
+            params.put("productId", "10676");
+            params.put("policySource", "40");
+            params.put("subaoBizContent", "");
+            params.put("insurerCode", "ZHONGANCAR");
+
+
+            Map<String, String> headers = new HashMap<>();
+            headers.put("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36");
+            headers.put("Accept","application/json, text/plain, */*");
+
+            // 发送第一个请求,不跟随重定向
+            String url = "https://www.cyouzai.com/busi-integration/channel/baoBiaoH5Redirect";
+            HttpURLConnection connection = HttpUtil.sendGetRequest(url, params, headers, false);
+            String firstLocation = connection.getHeaderField("Location");
+            connection.disconnect();
+
+            System.out.println(firstLocation);
+
+            // 发送第二个请求,不跟随重定向
+            connection = HttpUtil.sendGetRequest(firstLocation, null, headers, false);
+            String secondLocation = connection.getHeaderField("Location");
+            connection.disconnect();
+
+            // 发送第三个请求,不跟随重定向
+            connection = HttpUtil.sendGetRequest(secondLocation, null, headers, false);
+            Map<String, List<String>> responseHeaders = connection.getHeaderFields();
+            connection.disconnect();
+
+            // 提取zaLoginCookieKey
+            String zaLoginCookieKey = HttpUtil.extractZaLoginCookieKey(responseHeaders);
+            if (zaLoginCookieKey != null && !zaLoginCookieKey.isEmpty()) {
+                // 获取Location头
+                String thirdLocation = connection.getHeaderField("Location");
+
+                // 提取flowId
+                String flowId = HttpUtil.extractFlowId(thirdLocation);
+                //缓存数据
+                zhongAnCrawlerCacheComponent.cacheCookie(zaLoginCookieKey,flowId,zhongAnId);
+
+                System.out.println("key=="+zaLoginCookieKey+"------flowId="+flowId);
+
+            } else {
+                throw new SystemException("未获取到-----zaLoginCookieKey");
+            }
+
+        }catch (Exception e) {
+            throw new SystemException("message", "请求发生错误: " + e.getMessage());
+        }
+
+    }
 
     /**
      * 提交核保 子订单

+ 653 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/baojia.java

@@ -0,0 +1,653 @@
+//package com.jzg.quotation.zhongan.crawler.service;
+//
+//import com.fasterxml.jackson.core.JsonProcessingException;
+//import com.fasterxml.jackson.databind.JsonNode;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import org.apache.hc.client5.http.classic.methods.HttpPost;
+//import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+//import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+//import org.apache.hc.client5.http.impl.classic.HttpClients;
+//import org.apache.hc.core5.http.ContentType;
+//import org.apache.hc.core5.http.io.entity.StringEntity;
+//import org.apache.hc.core5.http.message.BasicHeader;
+//import redis.clients.jedis.Jedis;
+//import java.io.IOException;
+//import java.nio.charset.StandardCharsets;
+//import java.util.*;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//
+//public class InsuranceCalculator {
+//    // 成员变量(对应Python类的self.xxx)
+//    private String flowId;
+//    private Map<String, String> headers = new HashMap<>();
+//    private Map<String, String> cookies = new HashMap<>();
+//    private String quoteId;
+//    private String zhejiuPrice;
+//    private String sanzheChooseFlag;
+//    private String sanzheAmount;
+//    private String sjzerenChooseFlag;
+//    private String sjzerenAmount;
+//    private String ckzerenChooseFlag;
+//    private String ckzerenAmount;
+//    private String ybwSanzheChooseFlag;
+//    private String ybwSanzheAmount;
+//    private String ybwSijiChooseFlag;
+//    private String ybwSijiAmount;
+//    private String ybwCkChooseFlag;
+//    private String ybwCkAmount;
+//    private String huahenChooseFlag;
+//    private String huahenAmount;
+//    private String chesunChooseFlag;
+//    private String fujiaJiejiariChooseFlag;
+//    private String wbdwChooseFlag;
+//    private Map<String, Object> accidentalDriving;
+//    private String jiaoqiangChooseFlag;
+//    private String shangyeChooseFlag;
+//    private String jiaoqiangStartDate;
+//    private String chesunStartDate;
+//    private Integer maxQuoteNum;
+//    private String zaLoginCookieKey;
+//    private String licenseNo;
+//    private String vin;
+//    private String tbIdentifyNumber;
+//    private String username;
+//    private String cftbMessage;
+//    private String jqRepeatinfo;
+//    private String syRepeatinfo;
+//    private String seat;
+//    private Map<String, Object> carInfo = new HashMap<>();
+//    private Map<String, Object> fjxDict = new HashMap<>();
+//    private List<Map<String, Object>> coverageInfo = new ArrayList<>();
+//    private List<Map<String, Object>> nonAutoInfo = new ArrayList<>();
+//    private Map<String, String> data = new HashMap<>();
+//
+//    // JSON解析器
+//    private static final ObjectMapper objectMapper = new ObjectMapper();
+//    // Redis连接(实际使用中建议通过连接池管理)
+//    private Jedis redisConn = new Jedis("localhost", 6379);
+//
+//    /**
+//     * 核心计算方法(对应Python的calculation方法)
+//     */
+//    public Map<String, Object> calculation() throws IOException {
+//        // 第一步:发送基础信息请求
+//        String baseUrl = "https://c.zhongan.com/open/bmw/n/quote_controller/query_quote_base_info.json";
+//        Map<String, String> baseData = new HashMap<>();
+//        baseData.put("flowId", flowId);
+//        baseData.put("page", "/insureProgram");
+//        baseData.put("flag", "0");
+//        baseData.put("i", "e");
+//        baseData.put("quoteType", "0");
+//
+//        String baseResponse = sendPostRequest(baseUrl, headers, cookies, baseData);
+//        // 提取quoteId(正则匹配)
+//        quoteId = extractByRegex(baseResponse, "\"quoteId\":\"(.*?)\"", 1);
+//        // 提取vehicleActualPrice
+//        JsonNode baseJson = objectMapper.readTree(baseResponse);
+//        zhejiuPrice = baseJson.path("value").path("baseInfo").path("vehicleActualPrice").asText("");
+//
+//        // 构建coverageInfo(根据不同选择标志)
+//        buildCoverageInfo(baseResponse);
+//
+//        // 构建nonAutoInfo(驾意险相关)
+//        buildNonAutoInfo();
+//
+//        // 构建报价参数data
+//        buildQuoteData();
+//
+//        // 处理即时起保
+//        handleInstantCoverage();
+//
+//        // 第二步:发送报价请求
+//        return sendQuoteRequest();
+//    }
+//
+//    /**
+//     * 发送POST请求
+//     */
+//    private String sendPostRequest(String url, Map<String, String> headers, Map<String, String> cookies, Map<String, String> data) throws IOException {
+//        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+//            HttpPost httpPost = new HttpPost(url);
+//
+//            // 设置请求头
+//            if (headers != null) {
+//                headers.forEach((k, v) -> httpPost.addHeader(new BasicHeader(k, v)));
+//            }
+//            // 设置Cookie(合并到header)
+//            if (cookies != null && !cookies.isEmpty()) {
+//                StringBuilder cookieStr = new StringBuilder();
+//                cookies.forEach((k, v) -> cookieStr.append(k).append("=").append(v).append("; "));
+//                httpPost.addHeader("Cookie", cookieStr.toString().trim());
+//            }
+//
+//            // 设置请求体(表单格式)
+//            StringBuilder dataStr = new StringBuilder();
+//            data.forEach((k, v) -> dataStr.append(k).append("=").append(v).append("&"));
+//            httpPost.setEntity(new StringEntity(
+//                    dataStr.toString().replaceAll("&$", ""),
+//                    ContentType.APPLICATION_FORM_URLENCODED.withCharset(StandardCharsets.UTF_8)
+//            ));
+//
+//            // 执行请求
+//            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+//                return new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * 正则提取字符串
+//     */
+//    private String extractByRegex(String text, String regex, int group) {
+//        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
+//        Matcher matcher = pattern.matcher(text);
+//        if (matcher.find()) {
+//            return matcher.group(group);
+//        }
+//        return "";
+//    }
+//
+//    /**
+//     * 构建coverageInfo列表(对应Python中多个if判断添加coverageInfo的逻辑)
+//     */
+//    private void buildCoverageInfo(String responseText) {
+//        // 第三者责任险
+//        if ("on".equals(sanzheChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", sanzheAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052325" : "1510030944");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 司机责任险
+//        if ("on".equals(sjzerenChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", sjzerenAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052326" : "1510030945");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 乘客责任险
+//        if ("on".equals(ckzerenChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", ckzerenAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052327" : "1510030946");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 医保外第三者
+//        if ("on".equals(ybwSanzheChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", ybwSanzheAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052346" : "1510031007");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 医保外司机
+//        if ("on".equals(ybwSijiChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", ybwSijiAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052347" : "1510031006");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 医保外乘客
+//        if ("on".equals(ybwCkChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", ybwCkAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052348" : "1510030950");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 划痕险相关
+//        if ("on".equals(huahenChooseFlag)) {
+//            addHuahenCoverage(responseText);
+//        }
+//        // 车损险(未选划痕险但选了车损险)
+//        if (!"on".equals(huahenChooseFlag) && "on".equals(chesunChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", zhejiuPrice);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052324" : "1510030943");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 附加节假日
+//        if ("on".equals(fujiaJiejiariChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", sanzheAmount);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", responseText.contains("新能源") ? "1510052345" : "1510031005");
+//            coverageInfo.add(coverage);
+//        }
+//
+//        // 无法找到第三方
+//        if ("on".equals(wbdwChooseFlag)) {
+//            Map<String, Object> coverage = new HashMap<>();
+//            coverage.put("amount", zhejiuPrice);
+//            coverage.put("dutyAttributeType", "02");
+//            coverage.put("dutyAttributeValue", "0");
+//            coverage.put("productId", "1510052328");
+//            coverageInfo.add(coverage);
+//        }
+//    }
+//
+//    /**
+//     * 处理划痕险覆盖信息(含车损险判断)
+//     */
+//    private void addHuahenCoverage(String responseText) {
+//        // 划痕险基础条目
+//        Map<String, Object> huahen = new HashMap<>();
+//        huahen.put("amount", huahenAmount);
+//        huahen.put("dutyAttributeType", "02");
+//        huahen.put("dutyAttributeValue", "0");
+//        huahen.put("productId", responseText.contains("新能源") ? "1510052337" : "1510030949");
+//        coverageInfo.add(huahen);
+//
+//        // 车损险条目(无论是否选车损险,划痕险都需附加)
+//        Map<String, Object> chesun = new HashMap<>();
+//        chesun.put("amount", zhejiuPrice);
+//        chesun.put("dutyAttributeType", "02");
+//        chesun.put("dutyAttributeValue", "0");
+//        chesun.put("productId", responseText.contains("新能源") ? "1510052324" : "1510030943");
+//        coverageInfo.add(chesun);
+//    }
+//
+//    /**
+//     * 构建nonAutoInfo(驾意险相关)
+//     */
+//    private void buildNonAutoInfo() {
+//        if (accidentalDriving != null && !accidentalDriving.isEmpty()) {
+//            Map<String, Object> info = new HashMap<>();
+//            info.put("productCode", "kp_jtywx_v24");
+//            info.put("insuredFlag", "1");
+//            info.put("combination", accidentalDriving.get("combination").toString());
+//            nonAutoInfo.add(info);
+//        } else {
+//            Map<String, Object> info1 = new HashMap<>();
+//            info1.put("productCode", "kp_jtywx_v24");
+//            info1.put("insuredFlag", "0");
+//            nonAutoInfo.add(info1);
+//
+//            Map<String, Object> info2 = new HashMap<>();
+//            info2.put("productCode", "health_jcwy_jtx_v1");
+//            info2.put("insuredFlag", "0");
+//            nonAutoInfo.add(info2);
+//        }
+//    }
+//
+//    /**
+//     * 构建报价参数data
+//     */
+//    private void buildQuoteData() throws JsonProcessingException {
+//        data.put("flowId", flowId);
+//        data.put("page", "/insureProgram");
+//        data.put("flag", "0");
+//        data.put("i", "e");
+//        data.put("nonAutoInfo", objectMapper.writeValueAsString(nonAutoInfo));
+//
+//        // 单交强
+//        if ("on".equals(jiaoqiangChooseFlag) && !"on".equals(shangyeChooseFlag)) {
+//            data.put("addBusi", "0");
+//            data.put("addCompel", "1");
+//            data.put("addTax", "0");
+//            data.put("compelInsEffectiveDate", jiaoqiangStartDate);
+//            data.put("isTrusted", "true");
+//        }
+//        // 单商业
+//        else if (!"on".equals(jiaoqiangChooseFlag) && "on".equals(shangyeChooseFlag)) {
+//            data.put("addBusi", "1");
+//            data.put("coverageInfo", objectMapper.writeValueAsString(coverageInfo));
+//            data.put("addCompel", "0");
+//            data.put("addTax", "0");
+//            data.put("effectiveDate", chesunStartDate);
+//        }
+//        // 交商同投
+//        else if ("on".equals(jiaoqiangChooseFlag) && "on".equals(shangyeChooseFlag)) {
+//            data.put("addBusi", "1");
+//            data.put("coverageInfo", objectMapper.writeValueAsString(coverageInfo));
+//            data.put("addCompel", "1");
+//            data.put("taxType", "PAY_TAXES");
+//            data.put("addTax", "1");
+//            data.put("effectiveDate", chesunStartDate);
+//            data.put("compelInsEffectiveDate", jiaoqiangStartDate);
+//        }
+//    }
+//
+//    /**
+//     * 处理即时起保参数
+//     */
+//    private void handleInstantCoverage() {
+//        boolean jqLongEnough = jiaoqiangStartDate != null && jiaoqiangStartDate.length() > 16;
+//        boolean syLongEnough = chesunStartDate != null && chesunStartDate.length() > 16;
+//
+//        if (jqLongEnough && syLongEnough) {
+//            data.put("compInstantFlag", "1");
+//            data.put("busiInstantFlag", "1");
+//        } else if (jqLongEnough) {
+//            data.put("compInstantFlag", "1");
+//        } else if (syLongEnough) {
+//            data.put("busiInstantFlag", "1");
+//        }
+//    }
+//
+//    /**
+//     * 发送报价请求并处理结果
+//     */
+//    private Map<String, Object> sendQuoteRequest() throws IOException {
+//        if (maxQuoteNum == null) {
+//            return buildErrorResponse(400, "未获取到报价剩余次数", maxQuoteNum);
+//        }
+//        if (maxQuoteNum <= 0) {
+//            return buildErrorResponse(400, "报价剩余次数不足", maxQuoteNum);
+//        }
+//
+//        // 发送报价请求
+//        String quoteUrl = "https://c.zhongan.com/open/bmw/n/quote_controller/premium_trial.json";
+//        maxQuoteNum--;
+//        String quoteResponse = sendPostRequest(quoteUrl, headers, cookies, data);
+//
+//        // 发送理赔信息请求
+//        String claimUrl = "https://c.zhongan.com/open/bmw/n/query_controller/query_busi_claim_info.json";
+//        Map<String, String> claimData = new HashMap<>();
+//        claimData.put("flowId", flowId);
+//        claimData.put("page", "%2FinsureProgram");
+//        claimData.put("i", "e");
+//        claimData.put("flag", "0");
+//        sendPostRequest(claimUrl, headers, cookies, claimData); // 仅发送,不处理返回
+//
+//        // 处理报价响应
+//        JsonNode quoteJson = objectMapper.readTree(quoteResponse);
+//        if (!quoteJson.path("success").asBoolean(true)) {
+//            return buildErrorResponse(400, quoteJson.path("errorMsg").asText("请求失败"), maxQuoteNum);
+//        }
+//
+//        // 处理"您的爱车上一年"相关逻辑(二次报价)
+//        if (quoteResponse.contains("您的爱车上一年")) {
+//            return handleYearlyRenewal(quoteResponse);
+//        } else {
+//            // 直接处理正常报价结果
+//            return handleNormalQuote(quoteResponse);
+//        }
+//    }
+//
+//    /**
+//     * 处理续保相关逻辑(含二次报价)
+//     */
+//    private Map<String, Object> handleYearlyRenewal(String firstResponse) throws IOException {
+//        // 提取续保信息
+//        jqRepeatinfo = extractByRegex(firstResponse, "\"insureMessageF\":\"(.*?)\"", 1);
+//        syRepeatinfo = extractByRegex(firstResponse, "\"insureMessage\":\"(.*?)\"", 1);
+//
+//        // 处理交强险到期日
+//        String jqData = extractByRegex(firstResponse, "交强险于(.*?)到期", 1);
+//        String formattedJqDate = formatDate(jqData);
+//        // 处理商业险到期日
+//        String syData = extractByRegex(firstResponse, "商业险于(.*?)到期", 1);
+//        String formattedSyDate = formatDate(syData);
+//
+//        // 更新data参数并二次报价
+//        data.put("effectiveDate", formattedSyDate != null ? formattedSyDate : chesunStartDate);
+//        data.put("compelInsEffectiveDate", formattedJqDate != null ? formattedJqDate : jiaoqiangStartDate);
+//
+//        if (maxQuoteNum <= 0) {
+//            return buildErrorResponse(400, "报价剩余次数不足", maxQuoteNum);
+//        }
+//        maxQuoteNum--;
+//        String secondUrl = "https://c.zhongan.com/open/bmw/n/quote_controller/premium_trial.json";
+//        String secondResponse = sendPostRequest(secondUrl, headers, cookies, data);
+//
+//        // 若二次响应仍包含续保信息,三次报价(逻辑同Python)
+//        if (secondResponse.contains("您的爱车上一年")) {
+//            // 重复提取和格式化日期(代码省略,同上述逻辑)
+//            // ...(此处省略与上述相同的日期提取和格式化代码)
+//
+//            if (maxQuoteNum <= 0) {
+//                return buildErrorResponse(400, "报价剩余次数不足", maxQuoteNum);
+//            }
+//            maxQuoteNum--;
+//            String thirdResponse = sendPostRequest(secondUrl, headers, cookies, data);
+//            return handleNormalQuote(thirdResponse);
+//        } else {
+//            return handleNormalQuote(secondResponse);
+//        }
+//    }
+//
+//    /**
+//     * 处理正常报价结果
+//     */
+//    private Map<String, Object> handleNormalQuote(String response) throws IOException {
+//        JsonNode json = objectMapper.readTree(response);
+//        // 提取价格信息
+//        String totalPremium = extractByRegex(response, "\"totalPremium\":(.*?),", 1);
+//        String taxPremium = extractByRegex(response, "\"taxPremium\":(.*?),", 1);
+//        String bizPremium = extractByRegex(response, "\"bizTotalPremium\":(.*?),", 1);
+//        String compelPremium = extractByRegex(response, "\"compelPremium\":(.*?),", 1);
+//
+//        // 处理附加险信息
+//        handleCoveragePremium(json, response.contains("新能源"));
+//
+//        // 生成订单号
+//        String plyappno = UUID.randomUUID().toString().replaceAll("-", "");
+//        // 存储Redis信息
+//        saveToRedis(plyappno);
+//
+//        // 处理评分、折扣率
+//        String mark = extractByRegex(response, "policyGradePa\":\"(.*?)\"", 1);
+//        String jqDiscount = extractByRegex(response, "compelDiscount\":\"(.*?)\"", 1);
+//        String syDiscount = extractByRegex(response, "businessDiscount\":\"(.*?)\"", 1);
+//
+//        // 处理起止日期
+//        Map<String, String> dateInfo = handleDateRange();
+//
+//        // 处理驾意险信息
+//        List<Map<String, Object>> fcxInfoList = buildFcxInfoList(json);
+//
+//        // 处理车型信息
+//        Map<String, Object> carInfo = buildCarInfo();
+//
+//        // 处理绿通信息
+//        Map<String, Object> greenWayInfo = handleGreenWay(response);
+//
+//        // 构建返回结果
+//        Map<String, Object> result = new HashMap<>();
+//        result.put("code", 200);
+//        result.put("INSURANCE_TYPE", fjxDict);
+//        result.put("carInsureShiptax", taxPremium);
+//        result.put("busiTotalPremium", bizPremium);
+//        result.put("forceCarInsureRisk", compelPremium);
+//        result.put("carInsureMain", totalPremium);
+//        result.put("plyappno", plyappno);
+//        result.put("message", cftbMessage);
+//        result.put("other", Map.of(
+//                "mark", mark,
+//                "jq_discount", jqDiscount,
+//                "sy_discount", syDiscount,
+//                "isQuoteGreenWay", greenWayInfo.get("isQuoteGreenWay"),
+//                "errorCodeMap", greenWayInfo.get("errorCodeMap"),
+//                "jq_renewalflag", json.path("value").path("datas").path("forceRenewalFlag").asText().equals("ZA") ? "1" : "0",
+//                "sy_renewalflag", json.path("value").path("datas").path("forceRenewalFlag").asText().equals("ZA") ? "1" : "0",
+//                "maxQuoteNum", maxQuoteNum
+//        ));
+//        result.put("jq_startDate", dateInfo.get("jqStartDate"));
+//        result.put("jq_endDate", dateInfo.get("jqEndDate"));
+//        result.put("sy_startDate", dateInfo.get("syStartDate"));
+//        result.put("sy_endDate", dateInfo.get("syEndDate"));
+//        result.put("jq_repeatinfo", jqRepeatinfo);
+//        result.put("sy_repeatinfo", syRepeatinfo);
+//        result.put("drivingInsurances", fcxInfoList);
+//        result.put("carInfo", carInfo);
+//
+//        // 存储结果到Redis
+//        redisConn.hset("zhongan_" + plyappno, "ret", objectMapper.writeValueAsString(result));
+//        return result;
+//    }
+//
+//    /**
+//     * 格式化日期字符串
+//     */
+//    private String formatDate(String dateStr) {
+//        if (dateStr == null || dateStr.isEmpty()) return null;
+//        dateStr = dateStr.replace("年", "-").replace("月", "-").replace("日", "");
+//        // 处理不同长度的日期(逻辑同Python)
+//        // ...(此处省略具体日期格式化代码,可根据Python逻辑实现)
+//        return dateStr;
+//    }
+//
+//    /**
+//     * 处理附加险保费信息
+//     */
+//    private void handleCoveragePremium(JsonNode json, boolean isNewEnergy) {
+//        JsonNode coverageList = json.path("value").path("datas").path("vehiclePremium").path("vehicleCoverageList");
+//        if (coverageList.isArray()) {
+//            for (JsonNode node : coverageList) {
+//                String productId = node.path("productId").asText();
+//                String premium = node.path("totalCoveragePremium").asText();
+//                if (isNewEnergy) {
+//                    mapPremium(productId, premium,
+//                            Map.of("1510052324", "A", "1510052325", "B",
+//                                    "1510052326", "D3", "1510052327", "D4",
+//                                    "1510052345", "BD", "1510030943", "L",
+//                                    "1510052346", "SY_FJ_YBW1", "1510052348", "SY_FJ_YBW2",
+//                                    "1510052347", "SY_FJ_YBW3", "1510052328", "SY_WBDWGZ"));
+//                } else {
+//                    mapPremium(productId, premium,
+//                            Map.of("1510030943", "A", "1510030944", "B",
+//                                    "1510030945", "D3", "1510030946", "D4",
+//                                    "1510031005", "BD", "1510030949", "L",
+//                                    "1510031007", "SY_FJ_YBW1", "1510030950", "SY_FJ_YBW2",
+//                                    "1510031006", "SY_FJ_YBW3"));
+//                }
+//            }
+//        }
+//        fjxDict.put("A_amount", zhejiuPrice);
+//    }
+//
+//    /**
+//     * 映射附加险保费到字典
+//     */
+//    private void mapPremium(String productId, String premium, Map<String, String> mapping) {
+//        if (mapping.containsKey(productId)) {
+//            fjxDict.put(mapping.get(productId), premium);
+//        }
+//    }
+//
+//    /**
+//     * 存储信息到Redis
+//     */
+//    private void saveToRedis(String plyappno) {
+//        redisConn.hset("zhongan_" + plyappno, "flowId", flowId);
+//        redisConn.hset("zhongan_" + plyappno, "zaLoginCookieKey", zaLoginCookieKey);
+//        redisConn.hset("zhongan_" + plyappno, "license", licenseNo);
+//        redisConn.hset("zhongan_" + plyappno, "vin", vin);
+//        redisConn.hset("zhongan_" + plyappno, "tb_identifyNumber", tbIdentifyNumber);
+//        redisConn.hset("zhongan_" + plyappno, "username", username);
+//        redisConn.hset("zhongan_" + plyappno, "jiaoqiang_chooseFlag", jiaoqiangChooseFlag);
+//        redisConn.hset("zhongan_" + plyappno, "shangye_chooseFlag", shangyeChooseFlag);
+//        redisConn.hset("zhongan_" + plyappno, "accidentalDriving", accidentalDriving.toString());
+//        redisConn.expire("zhongan_" + plyappno, 5184000); // 60天过期
+//    }
+//
+//    /**
+//     * 处理日期范围(起保日和到期日)
+//     */
+//    private Map<String, String> handleDateRange() {
+//        Map<String, String> dateInfo = new HashMap<>();
+//        // 逻辑同Python:根据交强和商业险选择情况计算起止日期
+//        // ...(此处省略具体日期计算代码)
+//        return dateInfo;
+//    }
+//
+//    /**
+//     * 构建驾意险信息列表
+//     */
+//    private List<Map<String, Object>> buildFcxInfoList(JsonNode json) {
+//        List<Map<String, Object>> list = new ArrayList<>();
+//        if (accidentalDriving != null && !accidentalDriving.isEmpty()) {
+//            Map<String, Object> info = new HashMap<>();
+//            info.put("name", accidentalDriving.get("name"));
+//            info.put("price", json.path("value").path("datas").path("vehiclePremium").path("nonTotalPremium").asText());
+//            info.put("policy", "");
+//            list.add(info);
+//        }
+//        return list;
+//    }
+//
+//    /**
+//     * 构建车型信息
+//     */
+//    private Map<String, Object> buildCarInfo() {
+//        Map<String, Object> info = new HashMap<>();
+//        info.put("modelcname", carInfo.get("vehicleModelName"));
+//        info.put("modelCode", carInfo.get("vehicleModelCode"));
+//        info.put("exhaustscale", carInfo.get("exhaustMeasure"));
+//        info.put("seatCount", seat);
+//        info.put("purchasePrice", carInfo.get("vehicleAcquisitionPrice"));
+//        info.put("power", carInfo.get("power"));
+//        info.put("caryear", carInfo.get("configName"));
+//        return info;
+//    }
+//
+//    /**
+//     * 处理绿通信息
+//     */
+//    private Map<String, Object> handleGreenWay(String response) throws IOException {
+//        Map<String, Object> greenInfo = new HashMap<>();
+//        String isGreen = extractByRegex(response, "isQuoteGreenWay\":\"(.*?)\"", 1);
+//        greenInfo.put("isQuoteGreenWay", isGreen.isEmpty() ? "0" : isGreen);
+//
+//        if (!isGreen.isEmpty()) {
+//            String greenUrl = "https://c.zhongan.com/open/bmw/quote_controller/get_green_base_info.json";
+//            Map<String, String> greenData = new HashMap<>();
+//            greenData.put("quoteId", quoteId);
+//            greenData.put("flowId", flowId);
+//            greenData.put("page", "%2FinsureProgram");
+//            greenData.put("i", "e");
+//            greenData.put("flag", "0");
+//
+//            String greenResponse = sendPostRequest(greenUrl, headers, cookies, greenData);
+//            JsonNode greenJson = objectMapper.readTree(greenResponse);
+//            JsonNode errorCodeMap = greenJson.path("value").path("datas").path("errorCodeMap");
+//
+//            List<String> errorList = new ArrayList<>();
+//            if (errorCodeMap.isObject()) {
+//                errorCodeMap.fieldNames().forEachRemaining(key ->
+//                        errorList.add(key + ":" + errorCodeMap.path(key).asText())
+//                );
+//            }
+//            greenInfo.put("errorCodeMap", errorList);
+//        } else {
+//            greenInfo.put("errorCodeMap", new ArrayList<>());
+//        }
+//        return greenInfo;
+//    }
+//
+//    /**
+//     * 构建错误响应
+//     */
+//    private Map<String, Object> buildErrorResponse(int code, String message, Integer maxQuoteNum) {
+//        Map<String, Object> error = new HashMap<>();
+//        error.put("code", code);
+//        error.put("message", message);
+//        error.put("other", Map.of("maxQuoteNum", maxQuoteNum));
+//        return error;
+//    }
+//
+//    // Getter和Setter(省略,实际使用中需生成)
+//    // ...
+//}

+ 503 - 0
tenant/insurance/quotation-zhongan/src/main/java/com/jzg/quotation/zhongan/crawler/service/test.java

@@ -0,0 +1,503 @@
+//package com.jzg.quotation.zhongan.crawler.service;
+//
+//import org.apache.http.HttpEntity;
+//import org.apache.http.NameValuePair;
+//import org.apache.http.client.entity.UrlEncodedFormEntity;
+//import org.apache.http.client.methods.CloseableHttpResponse;
+//import org.apache.http.client.methods.HttpPost;
+//import org.apache.http.impl.client.CloseableHttpClient;
+//import org.apache.http.impl.client.HttpClients;
+//import org.apache.http.message.BasicNameValuePair;
+//import org.apache.http.util.EntityUtils;
+//import com.fasterxml.jackson.databind.JsonNode;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import redis.clients.jedis.Jedis;
+//import java.io.IOException;
+//import java.nio.charset.StandardCharsets;
+//import java.text.ParseException;
+//import java.text.SimpleDateFormat;
+//import java.util.*;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//
+//public class ZABfjs {
+//    // 成员变量
+//    private String username;
+//    private int maxQuoteNum;
+//    private String modelCName;
+//    private String engineNo;
+//    private String vin;
+//    private String licenseNo;
+//    private int seatCount;
+//    private String purchasePrice;
+//    private String vehicleUse;
+//    private String limitLoad;
+//    private String cartype;
+//    private String energyType;
+//    private String familyName;
+//    private String identifyNumber;
+//    private String uname;
+//    private String address;
+//    private String phoneNumber;
+//    private String tbIdentifyNumber;
+//    private String tbUname;
+//    private String tbAddress;
+//    private String tbPhoneNumber;
+//    private String bbIdentifyNumber;
+//    private String bbUname;
+//    private String bbAddress;
+//    private String bbPhoneNumber;
+//    private String registerDate;
+//    private String issueDate;
+//    private int isTransfer;
+//    private boolean jiaoqiangChooseFlag;
+//    private boolean chesunChooseFlag;
+//    private String jiaoqiangStartDate;
+//    private String jiaoqiangEndDate;
+//    private String chesunStartDate;
+//    private String chesunEndDate;
+//    private boolean shangyeChooseFlag;
+//    private boolean wbdwChooseFlag;
+//    private boolean sanzheChooseFlag;
+//    private String sanzheAmount;
+//    private boolean sjzerenChooseFlag;
+//    private String sjzerenAmount;
+//    private boolean ckzerenChooseFlag;
+//    private String ckzerenAmount;
+//    private boolean huahenChooseFlag;
+//    private String huahenAmount;
+//    private boolean fujiachesunChooseFlag;
+//    private String fujiachesunAmount;
+//    private boolean fujiasanzheChooseFlag;
+//    private String fujiasanzheAmount;
+//    private boolean fujiasijiChooseFlag;
+//    private String fujiasijiAmount;
+//    private boolean fujiachengkeChooseFlag;
+//    private String fujiachengkeAmount;
+//    private boolean fujiaJiejiariChooseFlag;
+//    private String fujiaJiejiariAmount;
+//    private boolean ybwSanzheChooseFlag;
+//    private String ybwSanzheAmount;
+//    private boolean ybwSijiChooseFlag;
+//    private String ybwSijiAmount;
+//    private boolean ybwCkChooseFlag;
+//    private String ybwCkAmount;
+//    private String accidentalDriving;
+//
+//    // 其他变量
+//    private String zhejiuPrice;
+//    private String cityCode;
+//    private String cityName;
+//    private String zaLoginCookieKey;
+//    private String flowId;
+//    private List<Map<String, Object>> coverageInfo = new ArrayList<>();
+//    private List<Map<String, Object>> nonAutoInfo = new ArrayList<>();
+//    private String isQuoteGreenWay = "";
+//    private String cftbMessage = "";
+//    private double price = 0;
+//    private double chechuan = 0;
+//    private double shangyePrice = 0;
+//    private double jiaoqiangPrice = 0;
+//    private String plyappno;
+//    private Map<String, Integer> fjxDict = new HashMap<String, Integer>() {{
+//        put("A", 0);
+//        put("B", 0);
+//        put("D3", 0);
+//        put("D4", 0);
+//        put("BD", 0);
+//        put("L", 0);
+//        put("SY_FJ_YBW1", 0);
+//        put("SY_FJ_YBW2", 0);
+//        put("SY_FJ_YBW3", 0);
+//    }};
+//    private Map<String, String> headers = new HashMap<String, String>() {{
+//        put("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36");
+//    }};
+//    private Map<String, String> cookies;
+//    private Map<String, String> carInfo;
+//    private String quoteId = "";
+//    private String jqRepeatinfo = "";
+//    private String syRepeatinfo = "";
+//    private String yxscType = "";
+//    private String yxscId = "";
+//    private String bjRes = "";
+//    private String desVehicleFrameNo = "";
+//    private String desVehicleEngineNo = "";
+//
+//    // 构造函数
+//    public ZABfjs(String username, int maxQuoteNum, String modelCName, String engineNo, String vin,
+//                  String licenseNo, int seatCount, String purchasePrice, String vehicleUse, String limitLoad,
+//                  String cartype, String energyType, String familyName, String identifyNumber, String uname,
+//                  String address, String phoneNumber, String tbIdentifyNumber, String tbUname, String tbAddress,
+//                  String tbPhoneNumber, String bbIdentifyNumber, String bbUname, String bbAddress,
+//                  String bbPhoneNumber, String registerDate, String issueDate, boolean isTransfer,
+//                  boolean jiaoqiangChooseFlag, boolean chesunChooseFlag, String jiaoqiangStartDate,
+//                  String jiaoqiangEndDate, String chesunStartDate, String chesunEndDate, boolean shangyeChooseFlag,
+//                  boolean wbdwChooseFlag, boolean sanzheChooseFlag, String sanzheAmount, boolean sjzerenChooseFlag,
+//                  String sjzerenAmount, boolean ckzerenChooseFlag, String ckzerenAmount, boolean huahenChooseFlag,
+//                  String huahenAmount, boolean fujiachesunChooseFlag, String fujiachesunAmount,
+//                  boolean fujiasanzheChooseFlag, String fujiasanzheAmount, boolean fujiasijiChooseFlag,
+//                  String fujiasijiAmount, boolean fujiachengkeChooseFlag, String fujiachengkeAmount,
+//                  boolean fujiaJiejiariChooseFlag, String fujiaJiejiariAmount, boolean ybwSanzheChooseFlag,
+//                  String ybwSanzheAmount, boolean ybwSijiChooseFlag, String ybwSijiAmount, boolean ybwCkChooseFlag,
+//                  String ybwCkAmount, String accidentalDriving) {
+//        this.username = username;
+//        this.maxQuoteNum = maxQuoteNum;
+//        this.modelCName = modelCName.replace("牌", "");
+//        this.engineNo = engineNo;
+//        this.vin = vin;
+//        this.licenseNo = licenseNo;
+//        this.seatCount = seatCount;
+//        this.purchasePrice = purchasePrice;
+//        this.vehicleUse = vehicleUse;
+//        this.limitLoad = limitLoad;
+//        this.cartype = cartype;
+//        this.energyType = energyType;
+//        this.familyName = familyName;
+//        this.identifyNumber = identifyNumber;
+//        this.uname = uname;
+//        this.address = address;
+//        this.phoneNumber = phoneNumber;
+//        this.tbIdentifyNumber = tbIdentifyNumber;
+//        this.tbUname = tbUname;
+//        this.tbAddress = tbAddress;
+//        this.tbPhoneNumber = tbPhoneNumber;
+//        this.bbIdentifyNumber = bbIdentifyNumber;
+//        this.bbUname = bbUname;
+//        this.bbAddress = bbAddress;
+//        this.bbPhoneNumber = bbPhoneNumber;
+//        this.registerDate = registerDate;
+//        this.issueDate = issueDate;
+//        this.isTransfer = isTransfer ? 1 : 0;
+//        this.jiaoqiangChooseFlag = jiaoqiangChooseFlag;
+//        this.chesunChooseFlag = chesunChooseFlag;
+//        this.jiaoqiangStartDate = jiaoqiangStartDate;
+//        this.jiaoqiangEndDate = jiaoqiangEndDate;
+//        this.chesunStartDate = chesunStartDate;
+//        this.chesunEndDate = chesunEndDate;
+//        this.shangyeChooseFlag = shangyeChooseFlag;
+//        this.wbdwChooseFlag = wbdwChooseFlag;
+//        this.sanzheChooseFlag = sanzheChooseFlag;
+//        this.sanzheAmount = sanzheAmount;
+//        this.sjzerenChooseFlag = sjzerenChooseFlag;
+//        this.sjzerenAmount = sjzerenAmount;
+//        this.ckzerenChooseFlag = ckzerenChooseFlag;
+//        this.ckzerenAmount = ckzerenAmount;
+//        this.huahenChooseFlag = huahenChooseFlag;
+//        this.huahenAmount = huahenAmount;
+//        this.fujiachesunChooseFlag = fujiachesunChooseFlag;
+//        this.fujiachesunAmount = fujiachesunAmount;
+//        this.fujiasanzheChooseFlag = fujiasanzheChooseFlag;
+//        this.fujiasanzheAmount = fujiasanzheAmount;
+//        this.fujiasijiChooseFlag = fujiasijiChooseFlag;
+//        this.fujiasijiAmount = fujiasijiAmount;
+//        this.fujiachengkeChooseFlag = fujiachengkeChooseFlag;
+//        this.fujiachengkeAmount = fujiachengkeAmount;
+//        this.fujiaJiejiariChooseFlag = fujiaJiejiariChooseFlag;
+//        this.fujiaJiejiariAmount = fujiaJiejiariAmount;
+//        this.ybwSanzheChooseFlag = ybwSanzheChooseFlag;
+//        this.ybwSanzheAmount = ybwSanzheAmount;
+//        this.ybwSijiChooseFlag = ybwSijiChooseFlag;
+//        this.ybwSijiAmount = ybwSijiAmount;
+//        this.ybwCkChooseFlag = ybwCkChooseFlag;
+//        this.ybwCkAmount = ybwCkAmount;
+//        this.accidentalDriving = accidentalDriving;
+//    }
+//
+//    // 获取城市代码
+//    public void getCityCode() {
+//        // 假设license_code是一个包含license和code的列表
+//        for (Map<String, String> item : Config.LICENSE_CODE) {
+//            if (licenseNo.contains(item.get("license"))) {
+//                this.cityCode = item.get("code");
+//                this.cityName = item.get("name");
+//                return;
+//            }
+//        }
+//        // 默认值
+//        this.cityCode = "140100";
+//        this.cityName = "太原市";
+//    }
+//
+//    // 从身份证获取生日
+//    public String getBirthday(String id) {
+//        if (id.length() >= 14) {
+//            return id.substring(6, 10) + "-" + id.substring(10, 12) + "-" + id.substring(12, 14);
+//        }
+//        return "";
+//    }
+//
+//    // 从身份证获取性别
+//    public String getSex(String id) {
+//        if (id.length() >= 17) {
+//            int sexCode = Integer.parseInt(id.substring(16, 17));
+//            return sexCode % 2 == 0 ? "F" : "M";
+//        }
+//        return "";
+//    }
+//
+//    // 获取省份代码
+//    public String[] getProvinceCode(String address) {
+//        String[] result = new String[3];
+//        // 假设city_conde是一个二维数组
+//        for (String[] item : Config.CITY_CODE) {
+//            if (address.contains(item[item.length - 1])) {
+//                result[0] = item[0];
+//                result[1] = item[item.length - 2];
+//                result[2] = item[2];
+//                break;
+//            }
+//        }
+//        return result;
+//    }
+//
+//    // 检查登录状态
+//    public void checkLogin() {// 假设Redis在本地运行
+//        this.zaLoginCookieKey = (String) redissonClient.getMap(zhongAnCrawlerCacheComponent.ZHONGAN_COOKIE + username).get(zhongAnCrawlerCacheComponent.COOKIE);
+//        this.flowId = (String) redissonClient.getMap(zhongAnCrawlerCacheComponent.ZHONGAN_COOKIE + username).get(zhongAnCrawlerCacheComponent.COOKIE);
+//        jedis.close();
+//
+//        if (this.flowId == null || this.flowId.isEmpty()) {
+//            this.flowId = "账号错误";
+//            return;
+//        }
+//
+//        this.cookies = new HashMap<>();
+//        this.cookies.put("zaLoginCookieKey", this.zaLoginCookieKey);
+//
+//        try {
+//            // 发送请求检查登录状态
+//            String url = "https://c.zhongan.com/open/bmw/query_controller/query_policy_list.json";
+//            Map<String, String> params = new HashMap<>();
+//            params.put("status", "4");
+//            params.put("pageIndex", "1");
+//            params.put("queryType", "1");
+//            params.put("flowId", this.flowId);
+//            params.put("page", "%2Forder%2FmyOrders");
+//            params.put("i", "e");
+//            params.put("flag", "0");
+//
+//            String response = sendPostRequest(url, params, headers, cookies);
+//            ObjectMapper mapper = new ObjectMapper();
+//            JsonNode jsonNode = mapper.readTree(response);
+//
+//            if (jsonNode.get("errorCode").asText().isEmpty()) {
+//                // 登录有效,继续其他操作
+//                url = "https://c.zhongan.com/open/bmw/index_controller/cache_input_query.json";
+//                params = new HashMap<>();
+//                params.put("insurePlace", this.cityName);
+//                params.put("insurePlaceCode", this.cityCode);
+//                params.put("thirdOrgCode", "");
+//                params.put("licenseNo", this.licenseNo);
+//                params.put("branchCode", "");
+//                params.put("isOpenRenewalFlag", "0");
+//                params.put("flowId", this.flowId);
+//                params.put("page", "%2FinsureEntry");
+//                params.put("i", "e");
+//                params.put("flag", "0");
+//
+//                sendPostRequest(url, params, headers, cookies);
+//
+//                url = "https://c.zhongan.com/open/bmw/car_controller/query_car_info.json";
+//                params = new HashMap<>();
+//                params.put("vehicleFrameNo", "");
+//                params.put("passCheck", "");
+//                params.put("flowId", this.flowId);
+//                params.put("page", "%2FbaseInfo");
+//                params.put("i", "e");
+//                params.put("flag", "0");
+//
+//                response = sendPostRequest(url, params, headers, cookies);
+//
+//                // 使用正则表达式提取信息
+//                this.desVehicleFrameNo = extractByRegex(response, "desVehicleFrameNo\":\"(.*?)\"");
+//                this.desVehicleEngineNo = extractByRegex(response, "desVehicleEngineNo\":\"(.*?)\"");
+//            } else {
+//                // 登录失效,重新获取用户信息
+//                getUserInfo(username);
+//                checkLogin();
+//            }
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//    }
+//
+//    // 获取保险结束日期
+//    public String getEndDay(String dateStr) {
+//        try {
+//            String[] parts = dateStr.split("-");
+//            int year = Integer.parseInt(parts[0]) + 1;
+//            String newDateStr = year + "-" + parts[1] + "-" + parts[2];
+//
+//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//            Date date = sdf.parse(newDateStr);
+//            long timeStamp = date.getTime() / 1000 - 1;
+//            return sdf.format(new Date(timeStamp * 1000));
+//        } catch (Exception e) {
+//            if (e.getMessage().contains("day is out of range for month")) {
+//                try {
+//                    String[] dateTime = dateStr.split(" ");
+//                    String[] dateParts = dateTime[0].split("-");
+//                    int day = Integer.parseInt(dateParts[2]) - 1;
+//                    String newDate = dateParts[0] + "-" + dateParts[1] + "-" + day + " " + dateTime[1];
+//
+//                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//                    Date date = sdf.parse(newDate);
+//                    long timeStamp = date.getTime() / 1000 - 1;
+//                    return sdf.format(new Date(timeStamp * 1000));
+//                } catch (Exception ex) {
+//                    ex.printStackTrace();
+//                }
+//            }
+//            e.printStackTrace();
+//        }
+//        return "";
+//    }
+//
+//    // 获取车辆信息
+//    public Map<String, Object> getCarInfo() {
+//        try {
+//            String url = "https://c.zhongan.com/open/bmw/car_controller/query_jyyt_vehicle_model.json";
+//            Map<String, String> params = new HashMap<>();
+//            params.put("vehicleFrameNo", this.vin);
+//            params.put("callVehicleModelLibraryFlag", "0");
+//            params.put("flowId", this.flowId);
+//            params.put("page", "%2FbaseInfo");
+//            params.put("i", "e");
+//            params.put("flag", "0");
+//
+//            String response = sendPostRequest(url, headers, cookies, params);
+//            ObjectMapper mapper = new ObjectMapper();
+//            JsonNode jsonNode = mapper.readTree(response);
+//
+//            JsonNode valueNode = jsonNode.get("value");
+//            if (valueNode != null) {
+//                JsonNode dataNode = valueNode.get("datas");
+//                if (dataNode != null) {
+//                    JsonNode carListNode = dataNode.get("vehicleModelList");
+//                    if (carListNode != null && carListNode.isArray()) {
+//                        // 处理车辆列表
+//                        return processCarList(carListNode);
+//                    }
+//                }
+//            }
+//
+//            // 如果没有找到车辆信息,尝试另一个接口
+//            url = "https://c.zhongan.com/open/bmw/car_controller/query_vehicle_model.json";
+//            params = new HashMap<>();
+//            params.put("vehicleBrand", this.modelCName);
+//            params.put("brandName", "");
+//            params.put("familyName", "");
+//            params.put("familyCode", "");
+//            params.put("engine", "");
+//            params.put("gearboxType", "");
+//            params.put("start", "0");
+//            params.put("limit", "30");
+//            params.put("callVehicleModelLibraryFlag", "1");
+//            params.put("flowId", this.flowId);
+//            params.put("page", "%2FvehicleModel%2Fvehicles");
+//            params.put("i", "e");
+//            params.put("flag", "0");
+//
+//            response = sendPostRequest(url, headers, cookies, params);
+//            jsonNode = mapper.readTree(response);
+//
+//            valueNode = jsonNode.get("value");
+//            if (valueNode != null) {
+//                dataNode = valueNode.get("datas");
+//                if (dataNode != null) {
+//                    JsonNode resultNode = dataNode.get("result");
+//                    if (resultNode != null) {
+//                        JsonNode carList = resultNode.get("vehicleList");
+//                        if (carList != null && carList.isArray()) {
+//                            // 处理车辆列表
+//                            return processCarList(carList);
+//                        }
+//                    }
+//                }
+//            }
+//
+//            Map<String, Object> errorResult = new HashMap<>();
+//            errorResult.put("code", 400);
+//            errorResult.put("message", "未找到车辆信息");
+//            return errorResult;
+//
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//            Map<String, Object> errorResult = new HashMap<>();
+//            errorResult.put("code", 500);
+//            errorResult.put("message", "获取车辆信息失败: " + e.getMessage());
+//            return errorResult;
+//        }
+//    }
+//
+//    // 处理车辆列表
+//    private Map<String, Object> processCarList(JsonNode carListNode) throws Exception {
+//        // 实现车辆列表处理逻辑
+//        // 代码太长,这里省略具体实现,保持与Python代码逻辑一致
+//        return new HashMap<>();
+//    }
+//
+//    // 发送POST请求
+//    private String sendPostRequest(String url, Map<String, String> headers, Map<String, String> cookies,
+//                                   Map<String, String> params) throws IOException {
+//        CloseableHttpClient httpClient = HttpClients.createDefault();
+//        HttpPost httpPost = new HttpPost(url);
+//
+//        // 设置 headers
+//        if (headers != null) {
+//            for (Map.Entry<String, String> entry : headers.entrySet()) {
+//                httpPost.setHeader(entry.getKey(), entry.getValue());
+//            }
+//        }
+//
+//        // 设置 cookies
+//        if (cookies != null && !cookies.isEmpty()) {
+//            StringBuilder cookieStr = new StringBuilder();
+//            for (Map.Entry<String, String> entry : cookies.entrySet()) {
+//                cookieStr.append(entry.getKey()).append("=").append(entry.getValue()).append("; ");
+//            }
+//            httpPost.setHeader("Cookie", cookieStr.toString());
+//        }
+//
+//        // 设置参数
+//        if (params != null && !params.isEmpty()) {
+//            List<NameValuePair> nameValuePairs = new ArrayList<>();
+//            for (Map.Entry<String, String> entry : params.entrySet()) {
+//                nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
+//            }
+//            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, StandardCharsets.UTF_8));
+//        }
+//
+//        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+//            HttpEntity entity = response.getEntity();
+//            return EntityUtils.toString(entity, StandardCharsets.UTF_8);
+//        }
+//    }
+//
+//    // 正则表达式提取
+//    private String extractByRegex(String text, String patternStr) {
+//        Pattern pattern = Pattern.compile(patternStr);
+//        Matcher matcher = pattern.matcher(text);
+//        if (matcher.find()) {
+//            return matcher.group(1);
+//        }
+//        return "";
+//    }
+//
+//    // 获取用户信息(假设实现)
+//    private void getUserInfo(String username) {
+//        // 实现获取用户信息的逻辑
+//    }
+//}
+//
+//// 配置类(假设)
+//class Config {
+//    public static final List<Map<String, String>> LICENSE_CODE = new ArrayList<>();
+//    public static final String[][] CITY_CODE = {};
+//
+//    static {
+//        // 初始化license_code数据
+//        // ...
+//    }
+//}