Kaynağa Gözat

大地保险对接至车辆信息获取

liub 4 ay önce
ebeveyn
işleme
54c95dc815
28 değiştirilmiş dosya ile 3470 ekleme ve 79 silme
  1. 42 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/component/DaDiCrawlerCacheComponent.java
  2. 370 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/component/DaDiCrawlerRequestComponent.java
  3. 4 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/constant/InsuranceMap.java
  4. 62 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/constant/enums/RequestUrl.java
  5. 39 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/DaDiCrawlerConfigureParameters.java
  6. 56 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiAgencyAgreementInfoRequest.java
  7. 20 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiAgentListRequest.java
  8. 33 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiBaseRequest.java
  9. 416 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiCarModelRequest.java
  10. 75 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiCrawlerAuthenticateRequest.java
  11. 111 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiVehicleChannelRequest.java
  12. 289 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiAgencyAgreementInfoResponse.java
  13. 107 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiAgentInfoResponse.java
  14. 37 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiBaseResponse.java
  15. 457 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiCrawlerAuthenticateResponse.java
  16. 33 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiCrawlerCaptchaResponse.java
  17. 273 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiVehicleChannelInfoResponse.java
  18. 488 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/network/NetworkRequest.java
  19. 21 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/properties/DaDiCrawlerProperties.java
  20. 1 3
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/DaDiCrawlerOrderService.java
  21. 3 2
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/DaDiCrawlerQuoteProcessService.java
  22. 1 1
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/DaDiCrawlerRequest.java
  23. 54 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/impl/DaDiCrawlerQuoteProcessServiceImpl.java
  24. 109 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/impl/DaDiCrawlerRequestImpl.java
  25. 0 73
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/service/impl/DaDiCrawlerRequestImpl.java
  26. 303 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/utils/CaptchaUtils.java
  27. 60 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/utils/DaDiAESUtil.java
  28. 6 0
      tenant/insurance/quotation-summary/pom.xml

+ 42 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/component/DaDiCrawlerCacheComponent.java

@@ -0,0 +1,42 @@
+package com.jzg.quotation.dadi.crawler.component;
+
+import lombok.RequiredArgsConstructor;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+
+@Component
+@RequiredArgsConstructor
+public class DaDiCrawlerCacheComponent {
+
+    private final RedissonClient redissonClient;
+
+    public static final String DADI_TOKEN = "dadi:token:";
+
+    public static final Duration DADI_TOKEN_TIME = Duration.ofHours(6L);
+
+    /**
+     * 缓存 token 信息
+     *
+     * @param username 用户名
+     * @param token    token
+     */
+    public void cacheToken(String username, String token) {
+        RBucket<String> bucket = redissonClient.getBucket(DADI_TOKEN + username);
+        bucket.set(token, DADI_TOKEN_TIME);
+    }
+
+    /**
+     * 获取token
+     *
+     * @param username 用户名
+     * @return 用户名
+     */
+    public String getToken(String username) {
+        RBucket<String> bucket = redissonClient.getBucket(DADI_TOKEN + username);
+        return bucket.get();
+    }
+
+}

+ 370 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/component/DaDiCrawlerRequestComponent.java

@@ -0,0 +1,370 @@
+package com.jzg.quotation.dadi.crawler.component;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson2.JSON;
+import com.jzg.commons.entity.quote.vo.CarInfoVo;
+import com.jzg.quotation.commons.service.ExteriorUtilsRequest;
+import com.jzg.quotation.dadi.crawler.constant.enums.RequestUrl;
+import com.jzg.quotation.dadi.crawler.entity.DaDiCrawlerConfigureParameters;
+import com.jzg.quotation.dadi.crawler.entity.request.*;
+import com.jzg.quotation.dadi.crawler.entity.response.*;
+import com.jzg.quotation.dadi.crawler.network.NetworkRequest;
+import com.jzg.quotation.dadi.crawler.properties.DaDiCrawlerProperties;
+import com.jzg.quotation.dadi.utils.CaptchaUtils;
+import com.jzg.quotation.dadi.utils.DaDiAESUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 爬虫请求组件
+ * @date 2026/05/21 14:41
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class DaDiCrawlerRequestComponent {
+
+    private final NetworkRequest networkRequest;
+
+    private final ExteriorUtilsRequest exteriorUtilsRequest;
+
+    private final DaDiCrawlerProperties daDiCrawlerProperties;
+
+    private final DaDiCrawlerCacheComponent daDiCrawlerCacheComponent;
+
+
+    /**
+     * 获取请求头
+     *
+     * @return
+     */
+    public HttpHeaders getHeaders(String username, String password) {
+//        String authorization = getAuthorization(username);
+//        if (!StringUtils.hasLength(authorization)) {
+//            authorization = authenticate(username, password, RequestConstant.REQUEST_NUMBER);
+//        }
+        HttpHeaders headers = new HttpHeaders();
+        headers.set(HttpHeaders.AUTHORIZATION, "");
+        headers.set(HttpHeaders.AUTHORIZATION, "");
+        headers.set(HttpHeaders.AUTHORIZATION, "");
+        headers.set(HttpHeaders.AUTHORIZATION, "");
+        return headers;
+    }
+
+    /**
+     * 验证码
+     *
+     * @return
+     */
+    public DaDiCrawlerCaptchaResponse captcha() {
+        try {
+            // 请求 - 使用Hutool网络工具类
+            String url = RequestUrl.IDENTIFY_CODE.getRequestUrl(daDiCrawlerProperties.getBaseUrl());
+            String responseBody = networkRequest.doPost(url);
+            DaDiCrawlerCaptchaResponse daDiCrawlerCaptcha = JSONObject.parseObject(responseBody, DaDiCrawlerCaptchaResponse.class);
+
+            String resJson = DaDiAESUtil.decryptStr(daDiCrawlerCaptcha.getData());
+            DaDiCrawlerCaptchaResponse recordResponse = JSONObject.parseObject(resJson, DaDiCrawlerCaptchaResponse.class);
+
+            // 识别验证码
+            String systemCode = exteriorUtilsRequest.captchaIdentify(recordResponse.getSrc());
+            daDiCrawlerCaptcha.setSrc(systemCode);
+            daDiCrawlerCaptcha.setRandomNum(recordResponse.getRandomNum());
+            daDiCrawlerCaptcha.setSolve(CaptchaUtils.solveToString(systemCode));
+            log.info("识别的验证码[{}],验证码编号[{}],验证码计算结果[{}]", systemCode, recordResponse.getRandomNum(), CaptchaUtils.solveToString(systemCode));
+            return daDiCrawlerCaptcha;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    /**
+     * 登录
+     *
+     * @param username  用户名称
+     * @param password  密码
+     * @param captcha   验证码
+     * @param randomNum 验证码编号
+     * @return 成功返回Token和用户信息
+     */
+    public DaDiCrawlerAuthenticateResponse daDiLogin(String username, String password, String captcha, String randomNum) {
+        try {
+            String url = RequestUrl.LOGIN.getRequestUrl(daDiCrawlerProperties.getBaseUrl());
+            DaDiCrawlerAuthenticateRequest authenticateRequest = new DaDiCrawlerAuthenticateRequest(password, username, captcha, randomNum);
+            String requestBody = DaDiAESUtil.encryptStr(JSON.toJSONString(authenticateRequest));
+            String responseBody = networkRequest.doPost(url, requestBody);
+            log.info("\n----------------------> 登录请求成功, \n----------------------> 响应结果:[{}],", responseBody);
+            DaDiBaseResponse daDiCrawlerCaptcha = JSONObject.parseObject(responseBody, DaDiBaseResponse.class);
+            if (!daDiCrawlerCaptcha.isSuccess()) {
+                throw new RuntimeException(daDiCrawlerCaptcha.getMsg());
+            }
+            String resJson = DaDiAESUtil.decryptStr(daDiCrawlerCaptcha.getData());
+            log.info("\n----------------------> 响应结果解析成功, \n----------------------> 解析结果:[{}],", resJson);
+            DaDiCrawlerAuthenticateResponse daDiCrawlerAuthenticateResponse = JSONObject.parseObject(resJson, DaDiCrawlerAuthenticateResponse.class);
+            return daDiCrawlerAuthenticateResponse;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 获取Token
+     */
+    public String getToken(String username, String password) {
+        String token = daDiCrawlerCacheComponent.getToken(username);
+        if (!StringUtils.hasLength(token)) {
+            // 登录验证码获取
+            DaDiCrawlerCaptchaResponse captchaResponse = captcha();
+            log.info("获取到的验证码[{}],验证码编号[{}]", captchaResponse.getSrc(), captchaResponse.getRandomNum());
+            DaDiCrawlerAuthenticateResponse daDiCrawlerAuthenticateResponse = daDiLogin(username, password, captchaResponse.getSolve(), captchaResponse.getRandomNum());
+            daDiCrawlerCacheComponent.cacheToken(username, daDiCrawlerAuthenticateResponse.getToken());
+            return daDiCrawlerAuthenticateResponse.getToken();
+        }
+        return token;
+    }
+
+    /**
+     * 获取代理信息
+     *
+     * @param headers
+     * @param parameters
+     * @return
+     */
+    public DaDiAgentInfoResponse getAgentInfo(HttpHeaders headers, DaDiCrawlerConfigureParameters parameters, String username) throws Exception {
+        String url = RequestUrl.GET_LOGIN_COM_INFO.getRequestUrl(daDiCrawlerProperties.getBaseUrl());
+        DaDiAgentListRequest authenticateRequest = new DaDiAgentListRequest(parameters.getAgentName(), username);
+        String requestBody = DaDiAESUtil.encryptStr(JSON.toJSONString(authenticateRequest));
+        String responseBody = networkRequest.doPost(url, requestBody, headers);
+        log.info("\n----------------------> 获取代理信息列表请求成功, \n----------------------> 响应结果:[{}],", responseBody);
+        DaDiBaseResponse daDiCrawlerCaptcha = JSONObject.parseObject(responseBody, DaDiBaseResponse.class);
+        if (!daDiCrawlerCaptcha.isSuccess()) {
+            throw new RuntimeException(daDiCrawlerCaptcha.getMsg());
+        }
+        String resJson = DaDiAESUtil.decryptStr(daDiCrawlerCaptcha.getData());
+        List<DaDiAgentInfoResponse> daDiAgentInfoResponseList = JSONObject.parseArray(resJson, DaDiAgentInfoResponse.class);
+        log.info("\n----------------------> 获取代理信息列表结果解析成功, \n----------------------> 解析结果:[{}],", resJson);
+        DaDiAgentInfoResponse daDiAgentInfoResponse =
+                daDiAgentInfoResponseList
+                        .stream()
+                        .filter(agentInfo ->
+                                agentInfo.getAgentCode().equals(parameters.getAgentName())).findFirst().orElse(null);
+        return daDiAgentInfoResponse;
+    }
+
+    /**
+     * 获取代理协议信息
+     *
+     * @param headers
+     * @param agentInfo
+     * @return
+     */
+    public DaDiAgencyAgreementInfoResponse getAgencyAgreementInfo(HttpHeaders headers, DaDiAgentInfoResponse agentInfo) throws Exception {
+        String url = RequestUrl.GET_AGENCY_AGREEMENT_INFO.getRequestUrl(daDiCrawlerProperties.getBaseUrl());
+        DaDiAgencyAgreementInfoRequest authenticateRequest = new DaDiAgencyAgreementInfoRequest(agentInfo.getAgentCode(), "DEJ", agentInfo.getBusinessSource(), agentInfo.getAgentCode(), agentInfo.getUserCode());
+        String requestBody = DaDiAESUtil.encryptStr(JSON.toJSONString(authenticateRequest));
+        String responseBody = networkRequest.doPost(url, requestBody, headers);
+        log.info("\n----------------------> 获取代理协议信息请求成功, \n----------------------> 响应结果:[{}],", responseBody);
+        DaDiBaseResponse daDiCrawlerCaptcha = JSONObject.parseObject(responseBody, DaDiBaseResponse.class);
+        if (!daDiCrawlerCaptcha.isSuccess()) {
+            throw new RuntimeException(daDiCrawlerCaptcha.getMsg());
+        }
+        String resJson = DaDiAESUtil.decryptStr(daDiCrawlerCaptcha.getData());
+        log.info("\n----------------------> 获取代理协议信息结果解析成功, \n----------------------> 解析结果:[{}],", resJson);
+        DaDiAgencyAgreementInfoResponse daDiAgencyAgreementInfoResponse = JSONObject.parseObject(resJson, DaDiAgencyAgreementInfoResponse.class);
+        return daDiAgencyAgreementInfoResponse;
+    }
+
+    /**
+     * 获取车辆渠道信息
+     *
+     * @param headers
+     * @param carInfo 车辆信息
+     * @return
+     */
+    public DaDiVehicleChannelInfoResponse getDaDiVehicleChannelInfo(HttpHeaders headers, CarInfoVo carInfo, DaDiAgentInfoResponse agentInfo) throws Exception {
+        String url = RequestUrl.QUERY_BY_VIN_NO.getRequestUrl(daDiCrawlerProperties.getBaseUrl());
+        DaDiCarModelRequest carModelRequest = new DaDiCarModelRequest();
+        // === 车辆基础信息 ===
+        carModelRequest.setFrameNo(carInfo.getVinNo());
+        carModelRequest.setEngineNo(carInfo.getEngineNo());
+        carModelRequest.setLicenseNo(carInfo.getLicenseNo());
+        carModelRequest.setLicenseColorCode(carInfo.getLicenseColorCode());
+        carModelRequest.setLicenseType(carInfo.getLicenseKindCode());
+        carModelRequest.setEnrollDate(carInfo.getRegisterDate() + " 00:00:00");
+        carModelRequest.setVehicleBrand(carInfo.getBrandName());
+        carModelRequest.setBrandName(carInfo.getBrandName());
+        // === 使用信息 ===
+        carModelRequest.setUserYear(String.valueOf(calcUseYears(carInfo)[0]));
+        carModelRequest.setUseMonth(String.valueOf(calcUseYears(carInfo)[1]));
+        carModelRequest.setUseNatureCode(getCarNatureCode(carInfo));
+        // === 车辆类别 ===
+        carModelRequest.setVehicleCategory(carInfo.getCarTypeCode());
+        carModelRequest.setCarKindCode(getCarKindCode(carInfo));
+        // === 过户信息 ===
+        String[] transferInfo = getTransferInfo(carInfo);
+        carModelRequest.setChgOwnerFlag(transferInfo[0]);
+        carModelRequest.setTransferVehicleType(transferInfo[2]);
+        carModelRequest.setTransferDate(transferInfo[1]);
+        // === 车辆配置 ===
+        carModelRequest.setSeatCount(carInfo.getSeatCount());
+        carModelRequest.setTonCount(carInfo.getTonCount());
+        carModelRequest.setHaulage(carInfo.getLimitLoad());
+        carModelRequest.setPowerScale(carInfo.getPowerScale());
+        carModelRequest.setPurchasePrice(carInfo.getPurchasePrice());
+        carModelRequest.setExhaustScale(carInfo.getDisplacement());
+        carModelRequest.setEnergyType(carInfo.getModelEnergyType());
+        carModelRequest.setColorCode(carInfo.getColorCode());
+        // === 证件信息 ===
+        carModelRequest.setTravelIssueDate(carInfo.getIssueDate());
+        carModelRequest.setModelCode(carInfo.getCarModelNo());
+        // === 业务标志 ===
+        carModelRequest.setLoanVehicleFlag(carInfo.isLoanStatus() ? "1" : "0");
+        carModelRequest.setNoLicenseFlag(carInfo.getIsRegistered());
+        carModelRequest.setRenewalFlag("0");
+        carModelRequest.setActualValue("0");
+        // === 默认值(与大地接口对齐) ===
+        carModelRequest.setArgueSolution("01");
+        carModelRequest.setCarCheckStatus("0");
+        carModelRequest.setCarRegiste("0");
+        carModelRequest.setEcdemicVehicle("0");
+        carModelRequest.setIsAboutAgri("0");
+        // === 代理信息 ===
+        carModelRequest.setComCode(agentInfo.getAgentCode());
+        carModelRequest.setUserCode(agentInfo.getUserCode());
+
+        String requestBody = DaDiAESUtil.encryptStr(JSON.toJSONString(carModelRequest));
+        String responseBody = networkRequest.doPost(url, requestBody, headers);
+        log.info("\n----------------------> 获取车辆渠道信息请求成功, \n----------------------> 响应结果:[{}],", responseBody);
+        DaDiBaseResponse daDiCrawlerCaptcha = JSONObject.parseObject(responseBody, DaDiBaseResponse.class);
+        if (!daDiCrawlerCaptcha.isSuccess()) {
+            throw new RuntimeException(daDiCrawlerCaptcha.getMsg());
+        }
+        String resJson = DaDiAESUtil.decryptStr(daDiCrawlerCaptcha.getData());
+        log.info("\n----------------------> 获取车辆渠道信息结果解析成功, \n----------------------> 解析结果:[{}],", resJson);
+        DaDiVehicleChannelInfoResponse daDiVehicleChannelInfo = new DaDiVehicleChannelInfoResponse();
+        return daDiVehicleChannelInfo;
+    }
+
+    /**
+     * 获取过户信息
+     *
+     * @param carInfo 车辆信息
+     * @return [0]chgOwnerFlag 过户标识, [1]transferDate 过户日期, [2]transferVehicleType 过户车辆类型
+     */
+    private String[] getTransferInfo(CarInfoVo carInfo) {
+        String chgOwnerFlag = "0";
+        String transferDate = "";
+        String transferVehicleType = "";
+        boolean transferFlagBi = Boolean.TRUE.equals(carInfo.isTransferBi());
+        boolean transferFlag = Boolean.TRUE.equals(carInfo.isTransfer());
+
+        if (transferFlagBi || transferFlag) {
+            chgOwnerFlag = "1";
+            transferDate = carInfo.getIssueDate();
+            if (transferFlagBi && transferFlag) {
+                transferVehicleType = "TBI";
+            } else if (transferFlagBi) {
+                transferVehicleType = "BI";
+            } else {
+                transferVehicleType = "TI";
+            }
+        }
+        return new String[]{chgOwnerFlag, transferDate, transferVehicleType};
+    }
+
+    /**
+     * 计算车辆使用年限和月份
+     * 对应 Python calc_use_years()
+     */
+    public int[] calcUseYears(CarInfoVo carInfo) {
+        // 使用年限
+        Map<String, Object> car = new HashMap<>();
+        car.put("firstyearDate", carInfo.getRegisterDate());
+        car.put("enrollDate", carInfo.getIssueDate());
+        LocalDate firstDate;
+        Object firstyearDate = car.get("firstyearDate");
+        Object enrollDate = car.get("enrollDate");
+
+        if (firstyearDate != null) {
+            firstDate = LocalDate.parse(firstyearDate.toString().replace("-", "/"), DateTimeFormatter.ofPattern("yyyy/M/d"));
+        } else if (enrollDate != null) {
+            firstDate = LocalDate.parse(enrollDate.toString().replace("-", "/"), DateTimeFormatter.ofPattern("yyyy/M/d"));
+        } else {
+            firstDate = LocalDate.now();
+        }
+
+        LocalDate effectDate = LocalDate.now().plusDays(1);
+
+        long yearsBetween = ChronoUnit.YEARS.between(firstDate, effectDate);
+        long monthsBetween = ChronoUnit.MONTHS.between(firstDate, effectDate);
+        long daysBetween = ChronoUnit.DAYS.between(firstDate.withDayOfYear(effectDate.getDayOfYear()), effectDate);
+
+        int useYears = (int) Math.max(yearsBetween, 0);
+        int useMonths = (int) monthsBetween;
+
+        return new int[]{useYears, useMonths};
+    }
+
+    /**
+     * 获取车辆种类代码
+     * 对应 Python get_car_kind_code()
+     */
+    public String getCarKindCode(CarInfoVo carInfo) {
+        if (carInfo.getCarKindCode().equals("A0")) {
+            carInfo.setCarKindCode("11");
+        } else {
+            carInfo.setCarKindCode("21");
+        }
+        return carInfo.getCarKindCode();
+    }
+
+    /**
+     * 营业车辆性质映射(vehicleUseCode → useNatureCode)
+     */
+    private static final Map<String, String> YY_CAR_NATURE_MAP = Map.of(
+            "01", "101",  // 营业出租租赁
+            "02", "102",  // 营业城市公交
+            "03", "103",  // 营业公路客运
+            "04", "104"   // 营业货运
+    );
+
+    /**
+     * 非营业车辆性质映射(vehicleUseCode → useNatureCode)
+     */
+    private static final Map<String, String> FYY_CAR_NATURE_MAP = Map.of(
+            "05", "85",   // 家庭自用
+            "06", "230",  // 非营业机关
+            "07", "220",  // 非营业企业
+            "08", "240"   // 非营业货运
+    );
+
+    /**
+     * 获取车辆性质代码(大地useNatureCode)
+     * 对应 Python get_car_nature_code()
+     */
+    public String getCarNatureCode(CarInfoVo carInfo) {
+        String carNatureCode = carInfo.getCarNatureCode();
+        String vehicleUseCode = carInfo.getVehicleUseCode();
+
+        if ("01".equals(carNatureCode)) {
+            return YY_CAR_NATURE_MAP.getOrDefault(vehicleUseCode, carNatureCode);
+        } else if ("02".equals(carNatureCode)) {
+            return FYY_CAR_NATURE_MAP.getOrDefault(vehicleUseCode, carNatureCode);
+        }
+        return carNatureCode;
+    }
+}
+

+ 4 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/constant/InsuranceMap.java

@@ -0,0 +1,4 @@
+package com.jzg.quotation.dadi.crawler.constant;
+
+public final class InsuranceMap {
+}

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

@@ -0,0 +1,62 @@
+package com.jzg.quotation.dadi.crawler.constant.enums;
+
+import com.jzg.quotation.commons.standard.CrawlerRequestUrlStandard;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author wks
+ * @version 1.0
+ * @description: 请求链接
+ * @date 2025/11/11 15:09
+ */
+@Getter
+@AllArgsConstructor
+public enum RequestUrl implements CrawlerRequestUrlStandard {
+
+    IDENTIFY_CODE("/csu/user/captcha", "获取验证码"),
+    LOGIN("/csu/user/login", "登录"),
+
+    GET_LOGIN_COM_INFO("/csv/commonAgent/searchAgentList", "获取代理人列表"),
+    GET_AGENCY_AGREEMENT_INFO("/csv/channel/agentQuery", "获取代理协议信息"),
+    QUERY_BY_VIN_NO("/csv/vehicleModel/getCarModel", "车架号查询车型"),
+
+
+    GET_AGENT_AGREEMENT("/api/offerprpall/initSelectClaim/getAgentAgreement", "合同协议号查询"),
+
+    QUERY_CAR_MODEL("/api/grecar/ecar/queryCarModel", "车型查询"),
+    GET_CAR_PRICE("/api/grecar/ecar/getCarPrice", "车价查询"),
+
+    CALCULATION_PREMIUM("/api/grecar/ecar/calculationPremium", "保费计算"),
+    WRITE_BACK_ADDRESS("/api/grecar/areas/writeBackAddress", "回写地址"),
+    PROPOSAL_NO_SAVE("/api/grecar/ecar/proposalNoSave", "保存投保单号"),
+    UPLOAD("/api/grecar/photo/upload", "上传影像"),
+    SUBMIT_UNDERWRITE("/api/grecar/ecar/submitUnderwrite", "提交核保"),
+
+    CHECK_NOTICE("/api/grepolicycenter/epolicy/checkNotice", "查询电子投保单"),
+    GET_ELE_PROPOSAL_QR_CORE("/api/grsavecarcore/savecarcore/getEleProposalQRCore", "获取二维码"),
+
+    QUERY_PRPALL_PROPOSAL_INFO("/api/grecar/proposalSearch/queryPrpallProposalInfo", "订单状态查询"),
+
+    TRANS_CODE_ELE_POLICY_NO("/api/grecar/print/transCodeElePolicyNo", "查询下载电子保单的编码"),
+    GET_ELE_POLICY_FOR_GRECAR("/api/grsavecarcore/savecarcore/getElePolicyForGrecar?certiNo=%s&activityplan=jsb&operatorCode=%s&comCode=%s&token=%s", "下载保单"),
+    GET_ELE_POLICY_FLAG_FOR_GRECAR("/api/grsavecarcore/savecarcore/getElePolicyFlagForGrecar?certiNo=%s&activityplan=jsb&operatorCode=%s&comCode=%s&token=%s", "下载电子标志"),
+
+    ;
+
+
+    private final String uri;
+
+    private final String description;
+
+
+    @Override
+    public String getRequestDescription() {
+        return this.description;
+    }
+
+    @Override
+    public String uri() {
+        return this.uri;
+    }
+}

+ 39 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/DaDiCrawlerConfigureParameters.java

@@ -0,0 +1,39 @@
+package com.jzg.quotation.dadi.crawler.entity;
+
+import com.jzg.quotation.commons.standard.ConfigureParameters;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 直连 配置信息
+ * @date 2026/5/21 14:50
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class DaDiCrawlerConfigureParameters implements ConfigureParameters {
+
+    @Serial
+    private static final long serialVersionUID = -7015043171384687216L;
+
+    /**
+     * 协议名称
+     */
+    private String agreementName;
+
+    /**
+     * 代理人名称
+     */
+    private String agentName;
+
+    /**
+     * 代理/经纪/渠道代码
+     */
+    private String shadowAgent;
+
+}

+ 56 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiAgencyAgreementInfoRequest.java

@@ -0,0 +1,56 @@
+package com.jzg.quotation.dadi.crawler.entity.request;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【】
+ * @date 2026/5/22 16:59
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DaDiAgencyAgreementInfoRequest extends DaDiBaseRequest {
+
+    /**
+     * 请求类型,默认01
+     */
+    private String requestType;
+
+    /**
+     * 险种代码
+     */
+    private String riskCode;
+
+    /**
+     * 业务来源
+     */
+    private String businessSource;
+
+    /**
+     * 代理人代码
+     */
+    private String agentCode;
+
+    /**
+     * 协议号,默认空
+     */
+    private String agreementNo;
+
+    /**
+     * 协议名称,默认空
+     */
+    private String agreementName;
+
+    public DaDiAgencyAgreementInfoRequest(String comCode,  String riskCode, String businessSource, String agentCode, String userCode) {
+        this.comCode = comCode;
+        this.requestType = "01";
+        this.riskCode = riskCode;
+        this.businessSource = businessSource;
+        this.agentCode = agentCode;
+        this.agreementNo = "";
+        this.agreementName = "";
+        this.userCode = userCode;
+    }
+}

+ 20 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiAgentListRequest.java

@@ -0,0 +1,20 @@
+package com.jzg.quotation.dadi.crawler.entity.request;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【】
+ * @date 2026/5/22 15:46
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DaDiAgentListRequest extends DaDiBaseRequest {
+
+    public DaDiAgentListRequest(String comCode, String userCode) {
+        this.comCode = comCode;
+        this.userCode = userCode;
+    }
+}

+ 33 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiBaseRequest.java

@@ -0,0 +1,33 @@
+package com.jzg.quotation.dadi.crawler.entity.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【】
+ * @date 2026/5/22 09:49
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DaDiBaseRequest implements Serializable {
+    /**
+     * 公司代码
+     */
+    public String comCode;
+
+    /**
+     * 用户代码
+     */
+    public String userCode;
+
+    /**
+     * 代理人代码
+     */
+    public String agentCode;
+}

+ 416 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiCarModelRequest.java

@@ -0,0 +1,416 @@
+package com.jzg.quotation.dadi.crawler.entity.request;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【车型查询请求】
+ * @date 2026/5/22 17:49
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DaDiCarModelRequest extends DaDiBaseRequest {
+
+    /**
+     * 简易报价标识,默认K01
+     */
+    private String simpleQuoteFlag = "K01";
+
+    /**
+     * 车辆类型标识(通过浏览器URL正则匹配)
+     */
+    private String vehicleTypeFlag;
+
+    /**
+     * 实际价值,默认0
+     */
+    private String actualValue = "0";
+
+    /**
+     * 争议解决方式代码
+     */
+    private String argueSolution;
+
+    /**
+     * 仲裁委员会代码
+     */
+    private String arbitBoardcode;
+
+    /**
+     * 仲裁委员会名称
+     */
+    private String arbitBoardname;
+
+    /**
+     * 验车状态
+     */
+    private String carCheckStatus;
+
+    /**
+     * 验车时间
+     */
+    private String carCheckTime;
+
+    /**
+     * 验车人
+     */
+    private String carChecker;
+
+    /**
+     * 补录时间
+     */
+    private String complementTime;
+
+    /**
+     * 购车发票日期
+     */
+    private String carInvoiceDate;
+
+    /**
+     * 车辆注册标识
+     */
+    private String carRegiste;
+
+    /**
+     * 证件日期
+     */
+    private String certificateDate;
+
+    /**
+     * 证件号码
+     */
+    private String certificateNo;
+
+    /**
+     * 证件类型
+     */
+    private String certificateType;
+
+    /**
+     * 颜色代码
+     */
+    private String colorCode;
+
+    /**
+     * 异地车辆标识
+     */
+    private String ecdemicVehicle;
+
+    /**
+     * 能源类型
+     */
+    private String energyType;
+
+    /**
+     * 燃料类型
+     */
+    private String fuelType;
+
+    /**
+     * 其他燃气类型描述
+     */
+    private String otherGasTypeDesc;
+
+    /**
+     * 纯电续航里程
+     */
+    private String pureElectricRange;
+
+    /**
+     * 发动机号
+     */
+    private String engineNo;
+
+    /**
+     * 初登日期(格式:yyyy-MM-dd HH:mm:ss)
+     */
+    private String enrollDate;
+
+    /**
+     * 排量
+     */
+    private String exhaustScale;
+
+    /**
+     * 首年日期
+     */
+    private String firstyearDate;
+
+    /**
+     * 车架号
+     */
+    private String frameNo;
+
+    /**
+     * 是否涉农标识
+     */
+    private String isAboutAgri;
+
+    /**
+     * 车牌颜色代码
+     */
+    private String licenseColorCode;
+
+    /**
+     * 车牌号
+     */
+    private String licenseNo;
+
+    /**
+     * 车牌类型
+     */
+    private String licenseType;
+
+    /**
+     * 打印使用性质代码
+     */
+    private String printUseNatureCode;
+
+    /**
+     * 贷款购车标识
+     */
+    private String loanVehicleFlag;
+
+    /**
+     * 制造厂
+     */
+    private String madeFactory;
+
+    /**
+     * 车型代码
+     */
+    private String modelCode;
+
+    /**
+     * 车型名称
+     */
+    private String modelName;
+
+    /**
+     * 网约车标识
+     */
+    private String net;
+
+    /**
+     * 新车标识
+     */
+    private String newVehicle;
+
+    /**
+     * 无牌标识
+     */
+    private String noLicenseFlag;
+
+    /**
+     * 告知类型
+     */
+    private String noticeType;
+
+    /**
+     * 功率
+     */
+    private String powerScale;
+
+    /**
+     * 最高车速
+     */
+    private String maxSpeed;
+
+    /**
+     * 拖挂车保单号
+     */
+    private String tractorTrailerPolicyNo;
+
+    /**
+     * 地区系数
+     */
+    private String areaFactor;
+
+    /**
+     * 购买价格
+     */
+    private String purchasePrice;
+
+    /**
+     * 行驶区域代码
+     */
+    private String runAreaCode;
+
+    /**
+     * 行驶里程
+     */
+    private String runMiles;
+
+    /**
+     * 销售渠道
+     */
+    private String salesChannel;
+
+    /**
+     * 核定座位数
+     */
+    private String seatCount;
+
+    /**
+     * 限行标识
+     */
+    private String restricFlag;
+
+    /**
+     * 特殊车辆标识
+     */
+    private String specialCarFlag;
+
+    /**
+     * 吨位
+     */
+    private String tonCount;
+
+    /**
+     * 载质量/牵引质量
+     */
+    private String haulage;
+
+    /**
+     * 费率分级
+     */
+    private String rateClassification;
+
+    /**
+     * 过户标识
+     */
+    private String chgOwnerFlag;
+
+    /**
+     * 过户车辆类型
+     */
+    private String transferVehicleType;
+
+    /**
+     * 过户日期
+     */
+    private String transferDate;
+
+    /**
+     * 行驶证发证日期
+     */
+    private String travelIssueDate;
+
+    /**
+     * 行驶证车型号
+     */
+    private String travelVehicleModel;
+
+    /**
+     * 车辆类型别名
+     */
+    private String carTypeAlias;
+
+    /**
+     * 使用性质代码(如:家庭自用)
+     */
+    private String useNatureCode;
+
+    /**
+     * 使用年数
+     */
+    private String userYear;
+
+    /**
+     * 使用月数
+     */
+    private String useMonth;
+
+    /**
+     * 车辆品牌
+     */
+    private String vehicleBrand;
+
+    /**
+     * 车辆类别
+     */
+    private String vehicleCategory;
+
+    /**
+     * 续保标识,默认0
+     */
+    private String renewalFlag = "0";
+
+    /**
+     * 车辆种类代码(如:11 客车)
+     */
+    private String carKindCode;
+
+    /**
+     * 车辆混合动力代码
+     */
+    private String vehicleHyCode;
+
+    /**
+     * 进口标识
+     */
+    private String importFlag;
+
+    /**
+     * 品牌代码
+     */
+    private String brandCode;
+
+    /**
+     * 品牌名称
+     */
+    private String brandName;
+
+    /**
+     * 销售公司
+     */
+    private String saleCompany;
+
+    /**
+     * 销售区域代码
+     */
+    private String saleAreaCode;
+
+    /**
+     * 4S店标识
+     */
+    private String sale4SFlag;
+
+    /**
+     * 车辆精油信息
+     */
+    private Object vehicleJingyou;
+
+    /**
+     * 新车分类
+     */
+    private String newVehicleClass;
+
+    /**
+     * 家族名称
+     */
+    private String familyName;
+
+    /**
+     * 特殊车辆标识
+     */
+    private String specialVehicleFlag;
+
+    /**
+     * 海外车辆标识
+     */
+    private String overseasVehicleFlag;
+
+    /**
+     * 生效日期
+     */
+    private String effectiveDate;
+
+    /**
+     * 代理人代码
+     */
+    private String producerCode;
+
+}

+ 75 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiCrawlerAuthenticateRequest.java

@@ -0,0 +1,75 @@
+package com.jzg.quotation.dadi.crawler.entity.request;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】登录认证请求体
+ * @date 2026/5/22 09:49
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DaDiCrawlerAuthenticateRequest extends DaDiBaseRequest {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 登录标识
+     */
+    private String loginFlag;
+
+    /**
+     * 手机号
+     */
+    private String mobile;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 系统类型
+     */
+    private String system;
+
+    /**
+     * 终端类型
+     */
+    private String terminalType;
+
+    /**
+     * 版本号
+     */
+    private String version;
+
+    /**
+     * 身份证号
+     */
+    private String sinNo;
+
+    /**
+     * 验证码
+     */
+    private String captcha;
+
+    /**
+     * 随机数
+     */
+    private String randomNum;
+
+    public DaDiCrawlerAuthenticateRequest(String password,  String userCode, String captcha, String randomNum) {
+        this.loginFlag = "2";
+        this.mobile = "";
+        this.password = password;
+        this.system =  "0";
+        this.terminalType = "ios_h5";
+        this.userCode = userCode;
+        this.version = "";
+        this.sinNo = "";
+        this.captcha = captcha;
+        this.randomNum = randomNum;
+    }
+}

+ 111 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/request/DaDiVehicleChannelRequest.java

@@ -0,0 +1,111 @@
+package com.jzg.quotation.dadi.crawler.entity.request;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description:  【大地财险】 渠道信息
+ * @date 2026/5/22 17:20
+ */
+@Data
+@NoArgsConstructor
+public class DaDiVehicleChannelRequest extends DaDiBaseRequest{
+
+    /**
+     * 代理协议代码
+     */
+    private String agentAgreementCode;
+
+    /**
+     * 代理协议名称
+     */
+    private String agentAgreementName;
+
+    /**
+     * 代理人名称
+     */
+    private String agentName;
+
+    /**
+     * 业务性质(业务来源)
+     */
+    private String businessNature;
+
+    /**
+     * 是否代理,默认1
+     */
+    private String isProxy;
+
+    /**
+     * 操作员/用户代码
+     */
+    private String operator;
+
+    /**
+     * 机构代码
+     */
+    private String orgCode;
+
+    /**
+     * 代理机构代码
+     */
+    private String agencyOrgCode;
+
+    /**
+     * 许可证号
+     */
+    private String permitNo;
+
+    /**
+     * 展业编号
+     */
+    private String exhibitionNo;
+
+    /**
+     * 协议号
+     */
+    private String agreementNo;
+
+    /**
+     * 协议名称
+     */
+    private String agreementName;
+
+    /**
+     * 公司名称
+     */
+    private String comName;
+
+    /**
+     * 业务来源
+     */
+    private String businessSource;
+
+    /**
+     * 业务来源代码
+     */
+    private String businessSourceCode;
+
+    public DaDiVehicleChannelRequest(String agentAgreementCode, String agentAgreementName, String agentCode, String agentName, String businessNature, String isProxy, String operator, String orgCode, String agencyOrgCode, String permitNo, String exhibitionNo, String agreementNo, String agreementName, String comCode, String comName, String userCode, String businessSource, String businessSourceCode) {
+        this.agentAgreementCode = agentAgreementCode;
+        this.agentAgreementName = agentAgreementName;
+        this.agentCode = agentCode;
+        this.agentName = agentName;
+        this.businessNature = businessNature;
+        this.isProxy = isProxy;
+        this.operator = operator;
+        this.orgCode = orgCode;
+        this.agencyOrgCode = agencyOrgCode;
+        this.permitNo = permitNo;
+        this.exhibitionNo = exhibitionNo;
+        this.agreementNo = agreementNo;
+        this.agreementName = agreementName;
+        this.comCode = comCode;
+        this.comName = comName;
+        this.userCode = userCode;
+        this.businessSource = businessSource;
+        this.businessSourceCode = businessSourceCode;
+    }
+}

+ 289 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiAgencyAgreementInfoResponse.java

@@ -0,0 +1,289 @@
+package com.jzg.quotation.dadi.crawler.entity.response;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 代理协议查询结果
+ * @date 2026/5/22 16:56
+ */
+@Data
+@NoArgsConstructor
+public class DaDiAgencyAgreementInfoResponse extends DaDiBaseResponse{
+
+    @SerializedName("salesMainMsgDto")
+    private SalesMainMsgDtoDTO salesMainMsgDto;
+    @SerializedName("lifeInsFlag")
+    private String lifeInsFlag;
+
+    public SalesMainMsgDtoDTO getSalesMainMsgDto() {
+        return salesMainMsgDto;
+    }
+
+    public void setSalesMainMsgDto(SalesMainMsgDtoDTO salesMainMsgDto) {
+        this.salesMainMsgDto = salesMainMsgDto;
+    }
+
+    public String getLifeInsFlag() {
+        return lifeInsFlag;
+    }
+
+    public void setLifeInsFlag(String lifeInsFlag) {
+        this.lifeInsFlag = lifeInsFlag;
+    }
+
+    public static class SalesMainMsgDtoDTO {
+
+        @SerializedName("salesAgentMsgDto")
+        private SalesAgentMsgDtoDTO salesAgentMsgDto;
+        @SerializedName("salesAgreementMsgList")
+        private List<SalesAgreementMsgListDTO> salesAgreementMsgList;
+
+        public SalesAgentMsgDtoDTO getSalesAgentMsgDto() {
+            return salesAgentMsgDto;
+        }
+
+        public void setSalesAgentMsgDto(SalesAgentMsgDtoDTO salesAgentMsgDto) {
+            this.salesAgentMsgDto = salesAgentMsgDto;
+        }
+
+        public List<SalesAgreementMsgListDTO> getSalesAgreementMsgList() {
+            return salesAgreementMsgList;
+        }
+
+        public void setSalesAgreementMsgList(List<SalesAgreementMsgListDTO> salesAgreementMsgList) {
+            this.salesAgreementMsgList = salesAgreementMsgList;
+        }
+
+        public static class SalesAgentMsgDtoDTO {
+            @SerializedName("inputDate")
+            private String inputDate;
+            @SerializedName("agentCode")
+            private String agentCode;
+            @SerializedName("agentName")
+            private String agentName;
+            @SerializedName("addressName")
+            private String addressName;
+            @SerializedName("businessNature")
+            private String businessNature;
+            @SerializedName("comCode")
+            private String comCode;
+            @SerializedName("exhibitionNo")
+            private String exhibitionNo;
+            @SerializedName("permitNo")
+            private String permitNo;
+            @SerializedName("phoneNumber")
+            private String phoneNumber;
+            @SerializedName("riskCode")
+            private String riskCode;
+            @SerializedName("orgCode")
+            private String orgCode;
+            @SerializedName("comName")
+            private String comName;
+
+            public String getInputDate() {
+                return inputDate;
+            }
+
+            public void setInputDate(String inputDate) {
+                this.inputDate = inputDate;
+            }
+
+            public String getAgentCode() {
+                return agentCode;
+            }
+
+            public void setAgentCode(String agentCode) {
+                this.agentCode = agentCode;
+            }
+
+            public String getAgentName() {
+                return agentName;
+            }
+
+            public void setAgentName(String agentName) {
+                this.agentName = agentName;
+            }
+
+            public String getAddressName() {
+                return addressName;
+            }
+
+            public void setAddressName(String addressName) {
+                this.addressName = addressName;
+            }
+
+            public String getBusinessNature() {
+                return businessNature;
+            }
+
+            public void setBusinessNature(String businessNature) {
+                this.businessNature = businessNature;
+            }
+
+            public String getComCode() {
+                return comCode;
+            }
+
+            public void setComCode(String comCode) {
+                this.comCode = comCode;
+            }
+
+            public String getExhibitionNo() {
+                return exhibitionNo;
+            }
+
+            public void setExhibitionNo(String exhibitionNo) {
+                this.exhibitionNo = exhibitionNo;
+            }
+
+            public String getPermitNo() {
+                return permitNo;
+            }
+
+            public void setPermitNo(String permitNo) {
+                this.permitNo = permitNo;
+            }
+
+            public String getPhoneNumber() {
+                return phoneNumber;
+            }
+
+            public void setPhoneNumber(String phoneNumber) {
+                this.phoneNumber = phoneNumber;
+            }
+
+            public String getRiskCode() {
+                return riskCode;
+            }
+
+            public void setRiskCode(String riskCode) {
+                this.riskCode = riskCode;
+            }
+
+            public String getOrgCode() {
+                return orgCode;
+            }
+
+            public void setOrgCode(String orgCode) {
+                this.orgCode = orgCode;
+            }
+
+            public String getComName() {
+                return comName;
+            }
+
+            public void setComName(String comName) {
+                this.comName = comName;
+            }
+        }
+
+        public static class SalesAgreementMsgListDTO {
+            @SerializedName("TCIDefaultTopcommission")
+            private int tCIDefaultTopcommission;
+            @SerializedName("TCITopcommission")
+            private int tCITopcommission;
+            @SerializedName("agreementName")
+            private String agreementName;
+            @SerializedName("agreementNo")
+            private String agreementNo;
+            @SerializedName("comCode")
+            private String comCode;
+            @SerializedName("defaultTopcommission")
+            private int defaultTopcommission;
+            @SerializedName("endDate")
+            private String endDate;
+            @SerializedName("startDate")
+            private String startDate;
+            @SerializedName("topcommission")
+            private int topcommission;
+            @SerializedName("riskCode")
+            private String riskCode;
+
+            public int getTCIDefaultTopcommission() {
+                return tCIDefaultTopcommission;
+            }
+
+            public void setTCIDefaultTopcommission(int tCIDefaultTopcommission) {
+                this.tCIDefaultTopcommission = tCIDefaultTopcommission;
+            }
+
+            public int getTCITopcommission() {
+                return tCITopcommission;
+            }
+
+            public void setTCITopcommission(int tCITopcommission) {
+                this.tCITopcommission = tCITopcommission;
+            }
+
+            public String getAgreementName() {
+                return agreementName;
+            }
+
+            public void setAgreementName(String agreementName) {
+                this.agreementName = agreementName;
+            }
+
+            public String getAgreementNo() {
+                return agreementNo;
+            }
+
+            public void setAgreementNo(String agreementNo) {
+                this.agreementNo = agreementNo;
+            }
+
+            public String getComCode() {
+                return comCode;
+            }
+
+            public void setComCode(String comCode) {
+                this.comCode = comCode;
+            }
+
+            public int getDefaultTopcommission() {
+                return defaultTopcommission;
+            }
+
+            public void setDefaultTopcommission(int defaultTopcommission) {
+                this.defaultTopcommission = defaultTopcommission;
+            }
+
+            public String getEndDate() {
+                return endDate;
+            }
+
+            public void setEndDate(String endDate) {
+                this.endDate = endDate;
+            }
+
+            public String getStartDate() {
+                return startDate;
+            }
+
+            public void setStartDate(String startDate) {
+                this.startDate = startDate;
+            }
+
+            public int getTopcommission() {
+                return topcommission;
+            }
+
+            public void setTopcommission(int topcommission) {
+                this.topcommission = topcommission;
+            }
+
+            public String getRiskCode() {
+                return riskCode;
+            }
+
+            public void setRiskCode(String riskCode) {
+                this.riskCode = riskCode;
+            }
+        }
+    }
+}

+ 107 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiAgentInfoResponse.java

@@ -0,0 +1,107 @@
+package com.jzg.quotation.dadi.crawler.entity.response;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 代理人查询结果
+ * @date 2026/5/22 16:05
+ */
+@Data
+@NoArgsConstructor
+public class DaDiAgentInfoResponse extends DaDiBaseResponse{
+
+    @SerializedName("id")
+    private String id;
+    @SerializedName("userCode")
+    private String userCode;
+    @SerializedName("businessSource")
+    private String businessSource;
+    @SerializedName("agentCode")
+    private String agentCode;
+    @SerializedName("agentName")
+    private String agentName;
+    @SerializedName("permitNo")
+    private String permitNo;
+    @SerializedName("exhibitionNo")
+    private String exhibitionNo;
+    @SerializedName("agencyOrgCode")
+    private String agencyOrgCode;
+    @SerializedName("isDefault")
+    private String isDefault;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUserCode() {
+        return userCode;
+    }
+
+    public void setUserCode(String userCode) {
+        this.userCode = userCode;
+    }
+
+    public String getBusinessSource() {
+        return businessSource;
+    }
+
+    public void setBusinessSource(String businessSource) {
+        this.businessSource = businessSource;
+    }
+
+    public String getAgentCode() {
+        return agentCode;
+    }
+
+    public void setAgentCode(String agentCode) {
+        this.agentCode = agentCode;
+    }
+
+    public String getAgentName() {
+        return agentName;
+    }
+
+    public void setAgentName(String agentName) {
+        this.agentName = agentName;
+    }
+
+    public String getPermitNo() {
+        return permitNo;
+    }
+
+    public void setPermitNo(String permitNo) {
+        this.permitNo = permitNo;
+    }
+
+    public String getExhibitionNo() {
+        return exhibitionNo;
+    }
+
+    public void setExhibitionNo(String exhibitionNo) {
+        this.exhibitionNo = exhibitionNo;
+    }
+
+    public String getAgencyOrgCode() {
+        return agencyOrgCode;
+    }
+
+    public void setAgencyOrgCode(String agencyOrgCode) {
+        this.agencyOrgCode = agencyOrgCode;
+    }
+
+    public String getIsDefault() {
+        return isDefault;
+    }
+
+    public void setIsDefault(String isDefault) {
+        this.isDefault = isDefault;
+    }
+}

+ 37 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiBaseResponse.java

@@ -0,0 +1,37 @@
+package com.jzg.quotation.dadi.crawler.entity.response;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @description:
+ * @author: shenwd
+ * @date: 2025/4/7 15:45
+ **/
+@Data
+public class DaDiBaseResponse implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 8468085174218499877L;
+
+    /**
+     * 响应码
+     */
+    private String code;
+
+    /**
+     * 加密数据
+     */
+    private String data;
+
+    /**
+     * 响应消息
+     */
+    private String msg;
+
+
+    public boolean isSuccess(){
+        return "SUCCESS".equals(msg);
+    }
+}

+ 457 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiCrawlerAuthenticateResponse.java

@@ -0,0 +1,457 @@
+package com.jzg.quotation.dadi.crawler.entity.response;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 登录认证结果
+ * @date 2026/5/22 11:41
+ */
+@Data
+@NoArgsConstructor
+public class DaDiCrawlerAuthenticateResponse extends DaDiBaseResponse {
+
+    @SerializedName("userCode")
+    private String userCode;
+    @SerializedName("userName")
+    private String userName;
+    @SerializedName("company")
+    private String company;
+    @SerializedName("comCName")
+    private String comCName;
+    @SerializedName("makeCompany")
+    private String makeCompany;
+    @SerializedName("makeCompanyCName")
+    private String makeCompanyCName;
+    @SerializedName("mobile")
+    private String mobile;
+    @SerializedName("address")
+    private String address;
+    @SerializedName("email")
+    private String email;
+    @SerializedName("valid")
+    private String valid;
+    @SerializedName("password")
+    private String password;
+    @SerializedName("comRole")
+    private String comRole;
+    @SerializedName("loginFlag")
+    private String loginFlag;
+    @SerializedName("token")
+    private String token;
+    @SerializedName("storeCode")
+    private String storeCode;
+    @SerializedName("handlerCode")
+    private String handlerCode;
+    @SerializedName("handlerName")
+    private String handlerName;
+    @SerializedName("comCode")
+    private String comCode;
+    @SerializedName("comName")
+    private String comName;
+    @SerializedName("channelCode")
+    private String channelCode;
+    @SerializedName("isSaleMan")
+    private String isSaleMan;
+    @SerializedName("recommendCode")
+    private String recommendCode;
+    @SerializedName("rankname")
+    private String rankname;
+    @SerializedName("homePermissionInfo")
+    private String homePermissionInfo;
+    @SerializedName("teamcode")
+    private String teamcode;
+    @SerializedName("comLevel")
+    private String comLevel;
+    @SerializedName("branchCode")
+    private String branchCode;
+    @SerializedName("branchName")
+    private String branchName;
+    @SerializedName("userPhone")
+    private String userPhone;
+    @SerializedName("isTeamLeader")
+    private String isTeamLeader;
+    @SerializedName("openid")
+    private String openid;
+    @SerializedName("unionid")
+    private String unionid;
+    @SerializedName("isTeamAccQuotOpen")
+    private String isTeamAccQuotOpen;
+    @SerializedName("isGroupAccQuotOpen")
+    private String isGroupAccQuotOpen;
+    @SerializedName("isBuildAccQuotOpen")
+    private String isBuildAccQuotOpen;
+    @SerializedName("isEmployerLiabilityQuotOpen")
+    private String isEmployerLiabilityQuotOpen;
+    @SerializedName("thirdComeCode")
+    private String thirdComeCode;
+    @SerializedName("thirdComeName")
+    private String thirdComeName;
+    @SerializedName("areaCode")
+    private String areaCode;
+    @SerializedName("userType")
+    private String userType;
+    @SerializedName("asmtStatus")
+    private String asmtStatus;
+    @SerializedName("idCard")
+    private String idCard;
+    @SerializedName("creditOrgFlag")
+    private String creditOrgFlag;
+    @SerializedName("headPortraitFileName")
+    private String headPortraitFileName;
+
+    public String getUserCode() {
+        return userCode;
+    }
+
+    public void setUserCode(String userCode) {
+        this.userCode = userCode;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getCompany() {
+        return company;
+    }
+
+    public void setCompany(String company) {
+        this.company = company;
+    }
+
+    public String getComCName() {
+        return comCName;
+    }
+
+    public void setComCName(String comCName) {
+        this.comCName = comCName;
+    }
+
+    public String getMakeCompany() {
+        return makeCompany;
+    }
+
+    public void setMakeCompany(String makeCompany) {
+        this.makeCompany = makeCompany;
+    }
+
+    public String getMakeCompanyCName() {
+        return makeCompanyCName;
+    }
+
+    public void setMakeCompanyCName(String makeCompanyCName) {
+        this.makeCompanyCName = makeCompanyCName;
+    }
+
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getValid() {
+        return valid;
+    }
+
+    public void setValid(String valid) {
+        this.valid = valid;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getComRole() {
+        return comRole;
+    }
+
+    public void setComRole(String comRole) {
+        this.comRole = comRole;
+    }
+
+    public String getLoginFlag() {
+        return loginFlag;
+    }
+
+    public void setLoginFlag(String loginFlag) {
+        this.loginFlag = loginFlag;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getStoreCode() {
+        return storeCode;
+    }
+
+    public void setStoreCode(String storeCode) {
+        this.storeCode = storeCode;
+    }
+
+    public String getHandlerCode() {
+        return handlerCode;
+    }
+
+    public void setHandlerCode(String handlerCode) {
+        this.handlerCode = handlerCode;
+    }
+
+    public String getHandlerName() {
+        return handlerName;
+    }
+
+    public void setHandlerName(String handlerName) {
+        this.handlerName = handlerName;
+    }
+
+    public String getComCode() {
+        return comCode;
+    }
+
+    public void setComCode(String comCode) {
+        this.comCode = comCode;
+    }
+
+    public String getComName() {
+        return comName;
+    }
+
+    public void setComName(String comName) {
+        this.comName = comName;
+    }
+
+    public String getChannelCode() {
+        return channelCode;
+    }
+
+    public void setChannelCode(String channelCode) {
+        this.channelCode = channelCode;
+    }
+
+    public String getIsSaleMan() {
+        return isSaleMan;
+    }
+
+    public void setIsSaleMan(String isSaleMan) {
+        this.isSaleMan = isSaleMan;
+    }
+
+    public String getRecommendCode() {
+        return recommendCode;
+    }
+
+    public void setRecommendCode(String recommendCode) {
+        this.recommendCode = recommendCode;
+    }
+
+    public String getRankname() {
+        return rankname;
+    }
+
+    public void setRankname(String rankname) {
+        this.rankname = rankname;
+    }
+
+    public String getHomePermissionInfo() {
+        return homePermissionInfo;
+    }
+
+    public void setHomePermissionInfo(String homePermissionInfo) {
+        this.homePermissionInfo = homePermissionInfo;
+    }
+
+    public String getTeamcode() {
+        return teamcode;
+    }
+
+    public void setTeamcode(String teamcode) {
+        this.teamcode = teamcode;
+    }
+
+    public String getComLevel() {
+        return comLevel;
+    }
+
+    public void setComLevel(String comLevel) {
+        this.comLevel = comLevel;
+    }
+
+    public String getBranchCode() {
+        return branchCode;
+    }
+
+    public void setBranchCode(String branchCode) {
+        this.branchCode = branchCode;
+    }
+
+    public String getBranchName() {
+        return branchName;
+    }
+
+    public void setBranchName(String branchName) {
+        this.branchName = branchName;
+    }
+
+    public String getUserPhone() {
+        return userPhone;
+    }
+
+    public void setUserPhone(String userPhone) {
+        this.userPhone = userPhone;
+    }
+
+    public String getIsTeamLeader() {
+        return isTeamLeader;
+    }
+
+    public void setIsTeamLeader(String isTeamLeader) {
+        this.isTeamLeader = isTeamLeader;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getUnionid() {
+        return unionid;
+    }
+
+    public void setUnionid(String unionid) {
+        this.unionid = unionid;
+    }
+
+    public String getIsTeamAccQuotOpen() {
+        return isTeamAccQuotOpen;
+    }
+
+    public void setIsTeamAccQuotOpen(String isTeamAccQuotOpen) {
+        this.isTeamAccQuotOpen = isTeamAccQuotOpen;
+    }
+
+    public String getIsGroupAccQuotOpen() {
+        return isGroupAccQuotOpen;
+    }
+
+    public void setIsGroupAccQuotOpen(String isGroupAccQuotOpen) {
+        this.isGroupAccQuotOpen = isGroupAccQuotOpen;
+    }
+
+    public String getIsBuildAccQuotOpen() {
+        return isBuildAccQuotOpen;
+    }
+
+    public void setIsBuildAccQuotOpen(String isBuildAccQuotOpen) {
+        this.isBuildAccQuotOpen = isBuildAccQuotOpen;
+    }
+
+    public String getIsEmployerLiabilityQuotOpen() {
+        return isEmployerLiabilityQuotOpen;
+    }
+
+    public void setIsEmployerLiabilityQuotOpen(String isEmployerLiabilityQuotOpen) {
+        this.isEmployerLiabilityQuotOpen = isEmployerLiabilityQuotOpen;
+    }
+
+    public String getThirdComeCode() {
+        return thirdComeCode;
+    }
+
+    public void setThirdComeCode(String thirdComeCode) {
+        this.thirdComeCode = thirdComeCode;
+    }
+
+    public String getThirdComeName() {
+        return thirdComeName;
+    }
+
+    public void setThirdComeName(String thirdComeName) {
+        this.thirdComeName = thirdComeName;
+    }
+
+    public String getAreaCode() {
+        return areaCode;
+    }
+
+    public void setAreaCode(String areaCode) {
+        this.areaCode = areaCode;
+    }
+
+    public String getUserType() {
+        return userType;
+    }
+
+    public void setUserType(String userType) {
+        this.userType = userType;
+    }
+
+    public String getAsmtStatus() {
+        return asmtStatus;
+    }
+
+    public void setAsmtStatus(String asmtStatus) {
+        this.asmtStatus = asmtStatus;
+    }
+
+    public String getIdCard() {
+        return idCard;
+    }
+
+    public void setIdCard(String idCard) {
+        this.idCard = idCard;
+    }
+
+    public String getCreditOrgFlag() {
+        return creditOrgFlag;
+    }
+
+    public void setCreditOrgFlag(String creditOrgFlag) {
+        this.creditOrgFlag = creditOrgFlag;
+    }
+
+    public String getHeadPortraitFileName() {
+        return headPortraitFileName;
+    }
+
+    public void setHeadPortraitFileName(String headPortraitFileName) {
+        this.headPortraitFileName = headPortraitFileName;
+    }
+}

+ 33 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiCrawlerCaptchaResponse.java

@@ -0,0 +1,33 @@
+package com.jzg.quotation.dadi.crawler.entity.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 获取登录验证码 返回参数
+ * @date 2026/5/21 15:58
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class DaDiCrawlerCaptchaResponse extends DaDiBaseResponse{
+
+    /**
+     * 验证码图片
+     */
+    private String src;
+
+    /**
+     * 验证码编号
+     */
+    private String randomNum;
+
+    /**
+     * 验证码解析结果
+     */
+    private String solve;
+
+}

+ 273 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/entity/response/DaDiVehicleChannelInfoResponse.java

@@ -0,0 +1,273 @@
+package com.jzg.quotation.dadi.crawler.entity.response;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】 汽车车型查询结果
+ * @date 2026/5/22 17:42
+ */
+@Data
+@NoArgsConstructor
+public class DaDiVehicleChannelInfoResponse extends DaDiBaseResponse {
+
+    @SerializedName("carModels")
+    private List<CarModel> carModels;
+
+    /**
+     * 车型信息
+     */
+    @Data
+    @NoArgsConstructor
+    public static class CarModel {
+
+        /** 车辆品牌 */
+        @SerializedName("vehicleBrand")
+        private String vehicleBrand;
+
+        /** 核定座位数 */
+        @SerializedName("seatCount")
+        private int seatCount;
+
+        /** 吨位 */
+        @SerializedName("tonCount")
+        private int tonCount;
+
+        /** 整备质量 */
+        @SerializedName("net")
+        private int net;
+
+        /** 排量 */
+        @SerializedName("exhaustScale")
+        private int exhaustScale;
+
+        /** 购买价格 */
+        @SerializedName("purchasePrice")
+        private int purchasePrice;
+
+        /** 车型代码 */
+        @SerializedName("modelCode")
+        private String modelCode;
+
+        /** 车型名称 */
+        @SerializedName("modelName")
+        private String modelName;
+
+        /** 车辆精油(精友)信息 */
+        @SerializedName("vehicleJingyou")
+        private VehicleJingyou vehicleJingyou;
+
+        /** 防盗标志 */
+        @SerializedName("alarmFlag")
+        private String alarmFlag;
+
+        /** 气囊数量 */
+        @SerializedName("airbagNum")
+        private int airbagNum;
+
+        /** 变速器类型 */
+        @SerializedName("derailleurType")
+        private String derailleurType;
+
+        /** 进口标识 */
+        @SerializedName("importFlag")
+        private String importFlag;
+
+        /** 上市年份 */
+        @SerializedName("marketYear")
+        private String marketYear;
+
+        /** 风险标志 */
+        @SerializedName("riskFlag")
+        private String riskFlag;
+
+        /** 新车分类 */
+        @SerializedName("newVehicleClass")
+        private String newVehicleClass;
+
+        /** 家族名称 */
+        @SerializedName("familyName")
+        private String familyName;
+    }
+
+    /**
+     * 车辆精油(精友)详细信息
+     */
+    @Data
+    @NoArgsConstructor
+    public static class VehicleJingyou {
+
+        /** 行业车型代码 */
+        @SerializedName("industryModelCode")
+        private String industryModelCode;
+
+        /** 行业车辆代码 */
+        @SerializedName("industryVehicleCode")
+        private String industryVehicleCode;
+
+        /** 行业车辆名称 */
+        @SerializedName("industryVehicleName")
+        private String industryVehicleName;
+
+        /** 车辆代码 */
+        @SerializedName("vehicleCode")
+        private String vehicleCode;
+
+        /** 车辆名称 */
+        @SerializedName("vehicleName")
+        private String vehicleName;
+
+        /** 厂商代码 */
+        @SerializedName("factoryCode")
+        private String factoryCode;
+
+        /** 厂商名称 */
+        @SerializedName("factoryName")
+        private String factoryName;
+
+        /** 品牌代码 */
+        @SerializedName("brandCode")
+        private String brandCode;
+
+        /** 品牌名称 */
+        @SerializedName("brandName")
+        private String brandName;
+
+        /** 家族代码 */
+        @SerializedName("familyCode")
+        private String familyCode;
+
+        /** 家族名称 */
+        @SerializedName("familyName")
+        private String familyName;
+
+        /** 车辆类别代码 */
+        @SerializedName("vehicleClassCode")
+        private String vehicleClassCode;
+
+        /** 车辆类别名称 */
+        @SerializedName("vehicleClassName")
+        private String vehicleClassName;
+
+        /** 车辆类型 */
+        @SerializedName("vehicleType")
+        private String vehicleType;
+
+        /** 排量 */
+        @SerializedName("displacement")
+        private String displacement;
+
+        /** 座位数 */
+        @SerializedName("seat")
+        private String seat;
+
+        /** 吨位 */
+        @SerializedName("tonnage")
+        private String tonnage;
+
+        /** 变速器类型 */
+        @SerializedName("gearboxType")
+        private String gearboxType;
+
+        /** 价格 */
+        @SerializedName("price")
+        private String price;
+
+        /** 购置价(含税) */
+        @SerializedName("purchasePriceTax")
+        private String purchasePriceTax;
+
+        /** 购买价格 */
+        @SerializedName("purchasePrice")
+        private String purchasePrice;
+
+        /** 核保系数代码 */
+        @SerializedName("hfCode")
+        private String hfCode;
+
+        /** 核保系数名称 */
+        @SerializedName("hfName")
+        private String hfName;
+
+        /** 价格类型 */
+        @SerializedName("pricetype")
+        private String pricetype;
+
+        /** 防盗装置 */
+        @SerializedName("antiTheft")
+        private String antiTheft;
+
+        /** 气囊数量 */
+        @SerializedName("airbagNum")
+        private String airbagNum;
+
+        /** 上市日期 */
+        @SerializedName("marketDate")
+        private String marketDate;
+
+        /** 风险标识 */
+        @SerializedName("riskFlags")
+        private String riskFlags;
+
+        /** 停售标识 */
+        @SerializedName("stopFlag")
+        private String stopFlag;
+
+        /** 总质量 */
+        @SerializedName("fullWeight")
+        private String fullWeight;
+
+        /** 费率 */
+        @SerializedName("rate")
+        private String rate;
+
+        /** 搜索代码 */
+        @SerializedName("searchCode")
+        private String searchCode;
+
+        /** 功率 */
+        @SerializedName("power")
+        private String power;
+
+        /** 适用风险费率 */
+        @SerializedName("fitsRiskRate")
+        private String fitsRiskRate;
+
+        /** 集团适用费率 */
+        @SerializedName("groupFitsRate")
+        private String groupFitsRate;
+
+        /** 集团维修费率 */
+        @SerializedName("groupRepairRate")
+        private String groupRepairRate;
+
+        /** 车辆备注 */
+        @SerializedName("carRemark")
+        private String carRemark;
+
+        /** 集团名称 */
+        @SerializedName("groupName")
+        private String groupName;
+
+        /** 新车分类 */
+        @SerializedName("newVehicleClass")
+        private String newVehicleClass;
+
+        /** 排放标准 */
+        @SerializedName("effluentStandard")
+        private String effluentStandard;
+
+        /** 动力类型 */
+        @SerializedName("powerType")
+        private String powerType;
+
+        /** 动力类型代码 */
+        @SerializedName("powerTypeCode")
+        private String powerTypeCode;
+    }
+}

+ 488 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/network/NetworkRequest.java

@@ -0,0 +1,488 @@
+package com.jzg.quotation.dadi.crawler.network;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.Method;
+import cn.hutool.json.JSONUtil;
+import com.jzg.quotation.dadi.utils.DaDiAESUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.util.TextUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】网络请求基类 - 基于Hutool工具类封装
+ * @date 2026/5/22 08:30
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class NetworkRequest {
+
+    /**
+     * 默认超时时间(毫秒)
+     */
+    private static final int DEFAULT_TIMEOUT = 120000;
+
+    /**
+     * 公共请求头(所有请求自动携带)
+     */
+    private static final Map<String, String> COMMON_HEADERS = new LinkedHashMap<>();
+
+    static {
+        COMMON_HEADERS.put(HttpHeaders.CONNECTION, "Keep-Alive");
+        COMMON_HEADERS.put(HttpHeaders.USER_AGENT, "okhttp/3.12.0");
+    }
+
+    /**
+     * 当前登录Token(登录后通过setToken()设置)
+     */
+    private String token;
+
+    // ==================== 公共请求头 ====================
+
+    /**
+     * 设置登录Token
+     *
+     * @param token 登录返回的X-Access-Token
+     */
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    /**
+     * 获取当前Token
+     *
+     * @return 当前Token
+     */
+    public String getToken() {
+        return token;
+    }
+
+    /**
+     * 获取包含公共请求头和Token的HttpHeaders
+     *
+     * @return HttpHeaders(可变,调用方可追加自定义header)
+     */
+    public HttpHeaders getDefaultHeaders() {
+        HttpHeaders headers = new HttpHeaders();
+        COMMON_HEADERS.forEach(headers::set);
+        headers.set(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8");
+        if (getToken() != null && !getToken().isEmpty()) {
+            headers.set("X-Access-Token", getToken());
+        }
+        return headers;
+    }
+
+    // ==================== GET 请求 ====================
+
+    /**
+     * GET请求(无参)
+     */
+    public String doGet(String url) {
+        return doGet(url, null);
+    }
+
+    /**
+     * GET请求(带参数)
+     */
+    public String doGet(String url, Map<String, Object> params) {
+        return doGet(url, params, null);
+    }
+
+    /**
+     * GET请求(带参数和请求头)
+     */
+    public String doGet(String url, Map<String, Object> params, HttpHeaders headers) {
+        return execute(Method.GET, url, params, null, headers);
+    }
+
+    // ==================== POST 请求 ====================
+
+    /**
+     * POST请求(无参)
+     */
+    public String doPost(String url) {
+        return doPost(url, (String) null);
+    }
+
+    /**
+     * POST请求(JSON字符串体)
+     */
+    public String doPost(String url, String body) {
+        return doPost(url, body, null);
+    }
+
+    /**
+     * POST请求(JSON字符串体 + 请求头)
+     */
+    public String doPost(String url, String body, HttpHeaders headers) {
+        return execute(Method.POST, url, null, body, headers);
+    }
+
+    /**
+     * POST请求(对象自动转JSON)
+     */
+    public String doPost(String url, Object bodyObj) {
+        return doPost(url, bodyObj, null);
+    }
+
+    /**
+     * POST请求(对象自动转JSON + 请求头)
+     */
+    public String doPost(String url, Object bodyObj, HttpHeaders headers) {
+        String body = bodyObj instanceof String ? (String) bodyObj : JSONUtil.toJsonStr(bodyObj);
+        return doPost(url, body, headers);
+    }
+
+    // ==================== POST Form 请求 ====================
+
+    /**
+     * POST表单请求(表单参数)
+     */
+    public String doPostForm(String url, Map<String, Object> formParams) {
+        return doPostForm(url, formParams, null);
+    }
+
+    /**
+     * POST表单请求(表单参数 + 请求头)
+     */
+    public String doPostForm(String url, Map<String, Object> formParams, HttpHeaders headers) {
+        return executeForm(Method.POST, url, formParams, headers);
+    }
+
+    // ==================== PUT 请求 ====================
+
+    /**
+     * PUT请求(无参)
+     */
+    public String doPut(String url) {
+        return doPut(url, (String) null);
+    }
+
+    /**
+     * PUT请求(JSON字符串体)
+     */
+    public String doPut(String url, String body) {
+        return doPut(url, body, null);
+    }
+
+    /**
+     * PUT请求(JSON字符串体 + 请求头)
+     */
+    public String doPut(String url, String body, HttpHeaders headers) {
+        return execute(Method.PUT, url, null, body, headers);
+    }
+
+    /**
+     * PUT请求(对象自动转JSON)
+     */
+    public String doPut(String url, Object bodyObj) {
+        return doPut(url, bodyObj, null);
+    }
+
+    /**
+     * PUT请求(对象自动转JSON + 请求头)
+     */
+    public String doPut(String url, Object bodyObj, HttpHeaders headers) {
+        String body = bodyObj instanceof String ? (String) bodyObj : JSONUtil.toJsonStr(bodyObj);
+        return doPut(url, body, headers);
+    }
+
+    // ==================== DELETE 请求 ====================
+
+    /**
+     * DELETE请求(无参)
+     */
+    public String doDelete(String url) {
+        return doDelete(url, null);
+    }
+
+    /**
+     * DELETE请求(带参数)
+     */
+    public String doDelete(String url, Map<String, Object> params) {
+        return doDelete(url, params, null);
+    }
+
+    /**
+     * DELETE请求(带参数和请求头)
+     */
+    public String doDelete(String url, Map<String, Object> params, HttpHeaders headers) {
+        return execute(Method.DELETE, url, params, null, headers);
+    }
+
+    // ==================== PATCH 请求 ====================
+
+    /**
+     * PATCH请求
+     */
+    public String doPatch(String url, String body) {
+        return doPatch(url, body, null);
+    }
+
+    /**
+     * PATCH请求(带请求头)
+     */
+    public String doPatch(String url, String body, HttpHeaders headers) {
+        return execute(Method.PATCH, url, null, body, headers);
+    }
+
+    // ==================== HEAD 请求 ====================
+
+    /**
+     * HEAD请求
+     */
+    public String doHead(String url) {
+        return doHead(url, null);
+    }
+
+    /**
+     * HEAD请求(带请求头)
+     */
+    public String doHead(String url, HttpHeaders headers) {
+        return execute(Method.HEAD, url, null, null, headers);
+    }
+
+    // ==================== OPTIONS 请求 ====================
+
+    /**
+     * OPTIONS请求
+     */
+    public String doOptions(String url) {
+        return doOptions(url, null);
+    }
+
+    /**
+     * OPTIONS请求(带请求头)
+     */
+    public String doOptions(String url, HttpHeaders headers) {
+        return execute(Method.OPTIONS, url, null, null, headers);
+    }
+
+    // ==================== 通用请求方法 ====================
+
+    /**
+     * 通用请求方法(完整参数)
+     *
+     * @param method  请求方式
+     * @param url     请求地址
+     * @param params  URL查询参数
+     * @param body    请求体(JSON)
+     * @param headers 请求头
+     * @return 响应体字符串
+     */
+    public String doRequest(Method method, String url, Map<String, Object> params,
+                            String body, HttpHeaders headers) {
+        return execute(method, url, params, body, headers);
+    }
+
+    // ==================== 响应对象方法 ====================
+
+    /**
+     * GET请求(返回HttpResponse对象,可获取状态码、响应头等)
+     */
+    public HttpResponse doGetForResponse(String url, Map<String, Object> params, HttpHeaders headers) {
+        return executeForResponse(Method.GET, url, params, null, headers);
+    }
+
+    /**
+     * POST请求(返回HttpResponse对象,可获取状态码、响应头等)
+     */
+    public HttpResponse doPostForResponse(String url, String body, HttpHeaders headers) {
+        return executeForResponse(Method.POST, url, null, body, headers);
+    }
+
+    /**
+     * POST表单请求(返回HttpResponse对象)
+     */
+    public HttpResponse doPostFormForResponse(String url, Map<String, Object> formParams, HttpHeaders headers) {
+        return executeFormForResponse(Method.POST, url, formParams, headers);
+    }
+
+    // ==================== 内部执行方法 ====================
+
+    /**
+     * 执行HTTP请求(JSON体)
+     */
+    private String execute(Method method, String url, Map<String, Object> params,
+                           String body, HttpHeaders headers) {
+        long startTime = System.currentTimeMillis();
+        try {
+            HttpRequest request = buildRequest(method, url, params, body, headers);
+            HttpResponse response = request.timeout(DEFAULT_TIMEOUT).execute();
+            // 使用bodyBytes()避免Hutool根据Content-Type自动解析响应体
+            byte[] bodyBytes = response.bodyBytes();
+            String result = bodyBytes != null ? new String(bodyBytes, StandardCharsets.UTF_8) : null;
+            log.info("\n----------------------> HTTP请求成功: \n----------------------> method:{}, \n----------------------> url:{}, \n----------------------> body:{},\n----------------------> 耗时:{}ms, \n----------------------> 状态码:{}, \n----------------------> 响应长度:{}",
+                    method, url, TextUtils.isEmpty(body) ? null : DaDiAESUtil.decryptStr(body), System.currentTimeMillis() - startTime, response.getStatus(),
+                    result != null ? result.length() : 0);
+            return result;
+        } catch (Exception e) {
+            log.error("\n----------------------> HTTP请求失败, \n----------------------> method:{}, \n----------------------> url:{},\n---------------------->  耗时:{}ms",
+                    method, url, System.currentTimeMillis() - startTime, e);
+            throw new RuntimeException(StrUtil.format("\n----------------------> HTTP请求失败: {}, {}", method, url), e);
+        }
+    }
+
+    /**
+     * 执行HTTP请求(表单体)
+     */
+    private String executeForm(Method method, String url, Map<String, Object> formParams,
+                               HttpHeaders headers) {
+        long startTime = System.currentTimeMillis();
+        try {
+            HttpRequest request = createRequest(method, url);
+            setCommonFormHeaders(request);
+            setHeaders(request, headers);
+            if (formParams != null && !formParams.isEmpty()) {
+                request.form(formParams);
+            }
+            HttpResponse response = request.timeout(DEFAULT_TIMEOUT).execute();
+            // 使用bodyBytes()避免Hutool根据Content-Type自动解析响应体
+            byte[] bodyBytes = response.bodyBytes();
+            String result = bodyBytes != null ? new String(bodyBytes, StandardCharsets.UTF_8) : null;
+            log.info("\n----------------------> HTTP表单请求成功, \n----------------------> method:{},\n----------------------> url:{},\n----------------------> 耗时:{}ms, \n----------------------> 状态码:{}, \n----------------------> 响应长度:{}",
+                    method, url, System.currentTimeMillis() - startTime, response.getStatus(),
+                    result != null ? result.length() : 0);
+            return result;
+        } catch (Exception e) {
+            log.error("HTTP表单请求失败, \n----------------------> method:{}, \n----------------------> url:{}, \n---------------------->  耗时:{}ms",
+                    method, url, System.currentTimeMillis() - startTime, e);
+            throw new RuntimeException(StrUtil.format("HTTP表单请求失败: {}, {}", method, url), e);
+        }
+    }
+
+    /**
+     * 执行HTTP请求(返回完整响应对象)
+     */
+    private HttpResponse executeForResponse(Method method, String url, Map<String, Object> params,
+                                            String body, HttpHeaders headers) {
+        long startTime = System.currentTimeMillis();
+        try {
+            HttpRequest request = buildRequest(method, url, params, body, headers);
+            HttpResponse response = request.timeout(DEFAULT_TIMEOUT).execute();
+            log.info("\n----------------------> HTTP请求成功, \n----------------------> method:{}, \n----------------------> url:{}, \n----------------------> body:{},\n---------------------->  耗时:{}ms, \n----------------------> 状态码:{}",
+                    method, url, TextUtils.isEmpty(body) ? null : DaDiAESUtil.decryptStr(body), System.currentTimeMillis() - startTime, response.getStatus());
+            return response;
+        } catch (Exception e) {
+            log.error("\n----------------------> HTTP请求失败, \n----------------------> method:{}, \n----------------------> url:{}, \n---------------------->  耗时:{}ms",
+                    method, url, System.currentTimeMillis() - startTime, e);
+            throw new RuntimeException(StrUtil.format("\n----------------------> HTTP请求失败: {}, {}", method, url), e);
+        }
+    }
+
+    /**
+     * 执行HTTP表单请求(返回完整响应对象)
+     */
+    private HttpResponse executeFormForResponse(Method method, String url, Map<String, Object> formParams,
+                                                HttpHeaders headers) {
+        long startTime = System.currentTimeMillis();
+        try {
+            HttpRequest request = createRequest(method, url);
+            setCommonFormHeaders(request);
+            setHeaders(request, headers);
+            if (formParams != null && !formParams.isEmpty()) {
+                request.form(formParams);
+            }
+            HttpResponse response = request.timeout(DEFAULT_TIMEOUT).execute();
+            log.info("HTTP表单请求成功, \n----------------------> method:{}, \n----------------------> url:{}, \n---------------------->  耗时:{}ms, \n----------------------> 状态码:{}",
+                    method, url, System.currentTimeMillis() - startTime, response.getStatus());
+            return response;
+        } catch (Exception e) {
+            log.error("HTTP表单请求失败, \n----------------------> method:{}, \n----------------------> url:{}, \n---------------------->  耗时:{}ms",
+                    method, url, System.currentTimeMillis() - startTime, e);
+            throw new RuntimeException(StrUtil.format("HTTP表单请求失败: {}, {}", method, url), e);
+        }
+    }
+
+    /**
+     * 构建HttpRequest对象(JSON体)
+     */
+    private HttpRequest buildRequest(Method method, String url, Map<String, Object> params,
+                                     String body, HttpHeaders headers) {
+        HttpRequest request = createRequest(method, url);
+        setCommonHeaders(request);
+        setHeaders(request, headers);
+        setParams(request, params);
+        setBody(request, body);
+        return request;
+    }
+
+    /**
+     * 设置公共请求头(Token + 固定头)
+     */
+    private void setCommonHeaders(HttpRequest request) {
+        COMMON_HEADERS.forEach(request::header);
+        request.header("Content-Type", "application/json; charset=utf-8");
+        if (getToken() != null && !getToken().isEmpty()) {
+            request.header("X-Access-Token", getToken());
+        }
+    }
+
+    /**
+     * 设置Form请求的公共请求头(不含Content-Type,由request.form()自动设置)
+     */
+    private void setCommonFormHeaders(HttpRequest request) {
+        COMMON_HEADERS.forEach(request::header);
+        if (getToken() != null && !getToken().isEmpty()) {
+            request.header("X-Access-Token", getToken());
+        }
+    }
+
+    /**
+     * 创建基础请求对象
+     */
+    private HttpRequest createRequest(Method method, String url) {
+        return switch (method) {
+            case GET -> HttpRequest.get(url);
+            case POST -> HttpRequest.post(url);
+            case PUT -> HttpRequest.put(url);
+            case DELETE -> HttpRequest.delete(url);
+            case PATCH -> HttpRequest.patch(url);
+            case HEAD -> HttpRequest.head(url);
+            case OPTIONS -> HttpRequest.options(url);
+            case TRACE -> HttpRequest.trace(url);
+            default -> throw new IllegalStateException("Unexpected value: " + method);
+        };
+    }
+
+    /**
+     * 设置参数
+     */
+    private void setParams(HttpRequest request, Map<String, Object> params) {
+        if (params != null && !params.isEmpty()) {
+            request.form(params);
+        }
+    }
+
+    /**
+     * 设置请求体
+     */
+    private void setBody(HttpRequest request, String body) {
+        if (StrUtil.isNotBlank(body)) {
+            request.body(body);
+        }
+    }
+
+    /**
+     * 设置请求头(HttpHeaders → 取每个header的第一个值)
+     */
+    private void setHeaders(HttpRequest request, HttpHeaders headers) {
+        if (headers != null && !headers.isEmpty()) {
+            headers.forEach((key, values) -> {
+                if (values != null && !values.isEmpty()) {
+                    request.header(key, values.get(0));
+                }
+            });
+        }
+    }
+}

+ 21 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/properties/DaDiCrawlerProperties.java

@@ -0,0 +1,21 @@
+package com.jzg.quotation.dadi.crawler.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @description: 恒邦财险
+ * @author: shenwd
+ * @date: 2025/4/7 11:34
+ **/
+@Data
+@Component
+@ConfigurationProperties(prefix = "dadi.crawler")
+public class DaDiCrawlerProperties {
+    /**
+     * 恒邦财险车险系统url
+     * https://car.hbins.com.cn
+     */
+    private String baseUrl;
+}

+ 1 - 3
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/service/DaDiCrawlerOrderService.java → tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/DaDiCrawlerOrderService.java

@@ -1,8 +1,6 @@
-package com.jzg.quotation.dadi.service;
+package com.jzg.quotation.dadi.crawler.service;
 
 
 public interface DaDiCrawlerOrderService {
 
-
-
 }

+ 3 - 2
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/service/DaDiCrawlerQuoteProcessService.java → tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/DaDiCrawlerQuoteProcessService.java

@@ -1,4 +1,4 @@
-package com.jzg.quotation.dadi.service;
+package com.jzg.quotation.dadi.crawler.service;
 
 import com.jzg.commons.entity.quote.vo.base.LoginBase;
 import com.jzg.quotation.commons.entity.DetectLoginRequest;
@@ -34,8 +34,9 @@ public interface DaDiCrawlerQuoteProcessService {
      * 获取请求头信息
      *
      * @param username 用户名
+     * @param password 密码
      * @return 请求头
      */
-    HttpHeaders getHeaders(String username);
+    HttpHeaders getHeaders(String username, String password);
 
 }

+ 1 - 1
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/service/DaDiCrawlerRequest.java → tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/DaDiCrawlerRequest.java

@@ -1,4 +1,4 @@
-package com.jzg.quotation.dadi.service;
+package com.jzg.quotation.dadi.crawler.service;
 
 import com.jzg.quotation.commons.service.GetCaptchaBaseService;
 import com.jzg.quotation.commons.service.QuotationCrawlerBaseService;

+ 54 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/impl/DaDiCrawlerQuoteProcessServiceImpl.java

@@ -0,0 +1,54 @@
+package com.jzg.quotation.dadi.crawler.service.impl;
+
+import com.jzg.commons.entity.quote.vo.base.LoginBase;
+import com.jzg.quotation.commons.entity.DetectLoginRequest;
+import com.jzg.quotation.commons.entity.GetCaptchaRequest;
+import com.jzg.quotation.commons.entity.GetCaptchaResponse;
+import com.jzg.quotation.dadi.crawler.component.DaDiCrawlerCacheComponent;
+import com.jzg.quotation.dadi.crawler.component.DaDiCrawlerRequestComponent;
+import com.jzg.quotation.dadi.crawler.entity.response.DaDiCrawlerAuthenticateResponse;
+import com.jzg.quotation.dadi.crawler.entity.response.DaDiCrawlerCaptchaResponse;
+import com.jzg.quotation.dadi.crawler.service.DaDiCrawlerQuoteProcessService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+@Service
+@RequiredArgsConstructor
+public class DaDiCrawlerQuoteProcessServiceImpl implements DaDiCrawlerQuoteProcessService {
+
+    private final DaDiCrawlerCacheComponent daDiCrawlerCacheComponent;
+
+    private final DaDiCrawlerRequestComponent daDiCrawlerRequestComponent;
+
+    @Override
+    public GetCaptchaResponse getCaptcha(GetCaptchaRequest sendCaptchaRequest) {
+        DaDiCrawlerCaptchaResponse captchaResponse = daDiCrawlerRequestComponent.captcha();
+        GetCaptchaResponse getCaptchaResponse = new GetCaptchaResponse();
+        getCaptchaResponse.setCaptchaImage(captchaResponse.getSolve());
+        getCaptchaResponse.setIdentifyId(captchaResponse.getRandomNum());
+        return getCaptchaResponse;
+    }
+
+    @Override
+    public void login(LoginBase loginBase) {
+        DaDiCrawlerCaptchaResponse captchaResponse = daDiCrawlerRequestComponent.captcha();
+        DaDiCrawlerAuthenticateResponse daDiCrawlerAuthenticateResponse = daDiCrawlerRequestComponent.daDiLogin(loginBase.getUsername(), loginBase.getPassword(), captchaResponse.getSrc(), captchaResponse.getRandomNum());
+        daDiCrawlerCacheComponent.cacheToken(loginBase.getUsername(), daDiCrawlerAuthenticateResponse.getToken());
+    }
+
+    @Override
+    public boolean detectLogin(DetectLoginRequest detectLoginRequest) {
+        String token = daDiCrawlerRequestComponent.getToken(detectLoginRequest.getUsername(), detectLoginRequest.getPassword());
+        return StringUtils.hasLength(token);
+    }
+
+    @Override
+    public HttpHeaders getHeaders(String username, String password) {
+        String token = daDiCrawlerRequestComponent.getToken(username, password);
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("X-Access-Token",  token);
+        return headers;
+    }
+}

+ 109 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/service/impl/DaDiCrawlerRequestImpl.java

@@ -0,0 +1,109 @@
+package com.jzg.quotation.dadi.crawler.service.impl;
+
+import com.jzg.commons.constants.dict.InsOrderStatusEnum;
+import com.jzg.commons.entity.quote.vo.AttributionInformationVo;
+import com.jzg.commons.entity.quote.vo.QuoteVo;
+import com.jzg.commons.entity.quote.vo.aggregated.*;
+import com.jzg.commons.entity.quote.vo.base.LoginBase;
+import com.jzg.quotation.commons.annotation.QuoteCrawlerService;
+import com.jzg.quotation.commons.constant.InsuranceCode;
+import com.jzg.quotation.commons.entity.DetectLoginRequest;
+import com.jzg.quotation.commons.entity.GetCaptchaRequest;
+import com.jzg.quotation.commons.entity.GetCaptchaResponse;
+import com.jzg.quotation.commons.standard.conversion.ConfigureParametersConversion;
+import com.jzg.quotation.dadi.crawler.component.DaDiCrawlerRequestComponent;
+import com.jzg.quotation.dadi.crawler.entity.DaDiCrawlerConfigureParameters;
+import com.jzg.quotation.dadi.crawler.entity.request.DaDiVehicleChannelRequest;
+import com.jzg.quotation.dadi.crawler.entity.response.DaDiAgencyAgreementInfoResponse;
+import com.jzg.quotation.dadi.crawler.entity.response.DaDiAgentInfoResponse;
+import com.jzg.quotation.dadi.crawler.entity.response.DaDiVehicleChannelInfoResponse;
+import com.jzg.quotation.dadi.crawler.service.DaDiCrawlerQuoteProcessService;
+import com.jzg.quotation.dadi.crawler.service.DaDiCrawlerRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Slf4j
+@QuoteCrawlerService(value = InsuranceCode.INSURANCE_CCIC)
+@Service
+@RequiredArgsConstructor
+public class DaDiCrawlerRequestImpl implements DaDiCrawlerRequest {
+
+    private final DaDiCrawlerRequestComponent daDiCrawlerRequestComponent;
+
+    private final DaDiCrawlerQuoteProcessService daDiCrawlerQuoteProcessService;
+
+    @Override
+    public GetCaptchaResponse getCaptcha(GetCaptchaRequest sendCaptchaRequest) {
+        return daDiCrawlerQuoteProcessService.getCaptcha(sendCaptchaRequest);
+    }
+
+    @Override
+    public void login(LoginBase loginBase) {
+        daDiCrawlerQuoteProcessService.login(loginBase);
+    }
+
+
+    @Override
+    public boolean detectLogin(DetectLoginRequest detectLoginRequest) {
+        return daDiCrawlerQuoteProcessService.detectLogin(detectLoginRequest);
+    }
+
+    @Override
+    public QuoteResultsVo quote(QuoteVo quoteVo) throws Exception {
+        // 1.0 获取token的请求头
+        AttributionInformationVo attributionInformationVo = quoteVo.getOrder().getAttributionInformationVo();
+        HttpHeaders headers = daDiCrawlerQuoteProcessService.getHeaders(attributionInformationVo.getUsername(), attributionInformationVo.getPassword());
+        // 1.1获取配置信息
+        DaDiCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(DaDiCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
+        //1.2获取代理人信息
+        DaDiAgentInfoResponse agentInfoVo = daDiCrawlerRequestComponent.getAgentInfo(headers, parameters, attributionInformationVo.getUsername());
+        // 1.3 获取代理协议信息
+        DaDiAgencyAgreementInfoResponse agencyAgreementInfo = daDiCrawlerRequestComponent.getAgencyAgreementInfo(headers, agentInfoVo);
+        DaDiAgencyAgreementInfoResponse.SalesMainMsgDtoDTO salesMainMsgDto = agencyAgreementInfo.getSalesMainMsgDto();
+        DaDiAgencyAgreementInfoResponse.SalesMainMsgDtoDTO.SalesAgentMsgDtoDTO salesAgentMsgDto = salesMainMsgDto.getSalesAgentMsgDto();
+        List<DaDiAgencyAgreementInfoResponse.SalesMainMsgDtoDTO.SalesAgreementMsgListDTO> salesAgreementMsgList = salesMainMsgDto.getSalesAgreementMsgList();
+        DaDiAgencyAgreementInfoResponse.SalesMainMsgDtoDTO.SalesAgreementMsgListDTO SalesAgreementMsgDto = salesAgreementMsgList.get(0);
+        DaDiVehicleChannelRequest daDiVehicleChannelRequest = new DaDiVehicleChannelRequest(SalesAgreementMsgDto.getAgreementNo(), SalesAgreementMsgDto.getAgreementName(), salesAgentMsgDto.getAgentCode(), salesAgentMsgDto.getAgentName(), agentInfoVo.getBusinessSource(), "1", attributionInformationVo.getUsername(), salesAgentMsgDto.getOrgCode(), salesAgentMsgDto.getOrgCode(), salesAgentMsgDto.getPermitNo(), salesAgentMsgDto.getExhibitionNo(), SalesAgreementMsgDto.getAgreementNo(), SalesAgreementMsgDto.getAgreementName(), salesAgentMsgDto.getComCode(), salesAgentMsgDto.getComName(), attributionInformationVo.getUsername(), salesAgentMsgDto.getBusinessNature(), salesAgentMsgDto.getBusinessNature());
+        // 1.4 获取车辆信息
+        DaDiVehicleChannelInfoResponse vehicleChannelInfoVo = daDiCrawlerRequestComponent.getDaDiVehicleChannelInfo(headers, quoteVo.getCarInfoVo(), agentInfoVo);
+
+        QuoteResultsVo quoteResultsVo = new QuoteResultsVo();
+        quoteResultsVo.setErrorMessage("测试 大地 未登录");
+        quoteResultsVo.setQuoteStatusEnum(InsOrderStatusEnum.QUOTE_FAIL);
+        return quoteResultsVo;
+    }
+
+    @Override
+    public UnderwritingResultsVo underwriting(UnderwritingVo underwritingVo) throws Exception {
+        return null;
+    }
+
+    @Override
+    public PaymentLinkResultsVo getPaymentLink(PaymentLinkVo paymentLinkVo) throws Exception {
+        return null;
+    }
+
+    @Override
+    public void uploadImage(InsuranceUploadImageVo insuranceUploadImageVo) {
+
+    }
+
+    @Override
+    public void queryClauseData(ClauseDataVo clauseDataVo) {
+
+    }
+
+    @Override
+    public DownloadPolicyResultVo downloadPolicy(DownloadPolicyVo downloadPolicyVo) {
+        return null;
+    }
+
+    @Override
+    public OrderStatusResultVo queryOrderState(OrderStatusVo orderStatusVo) throws Exception {
+        return null;
+    }
+}

+ 0 - 73
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/service/impl/DaDiCrawlerRequestImpl.java

@@ -1,73 +0,0 @@
-package com.jzg.quotation.dadi.service.impl;
-
-import com.jzg.commons.entity.quote.vo.QuoteVo;
-import com.jzg.commons.entity.quote.vo.aggregated.*;
-import com.jzg.commons.entity.quote.vo.base.LoginBase;
-import com.jzg.quotation.commons.annotation.QuoteCrawlerService;
-import com.jzg.quotation.commons.constant.InsuranceCode;
-import com.jzg.quotation.commons.entity.DetectLoginRequest;
-import com.jzg.quotation.commons.entity.GetCaptchaRequest;
-import com.jzg.quotation.commons.entity.GetCaptchaResponse;
-import com.jzg.quotation.dadi.service.DaDiCrawlerRequest;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-
-@QuoteCrawlerService(value = InsuranceCode.INSURANCE_CCIC)
-@Service
-@RequiredArgsConstructor
-public class DaDiCrawlerRequestImpl implements DaDiCrawlerRequest {
-
-
-    @Override
-    public GetCaptchaResponse getCaptcha(GetCaptchaRequest sendCaptchaRequest) {
-        return null;
-    }
-
-    @Override
-    public void login(LoginBase loginBase) {
-
-    }
-
-    @Override
-    public QuoteResultsVo quote(QuoteVo quoteVo) throws Exception {
-
-        QuoteResultsVo quoteResultsVo = new QuoteResultsVo();
-        quoteResultsVo.setErrorMessage("测试 大地");
-        return quoteResultsVo;
-    }
-
-    @Override
-    public UnderwritingResultsVo underwriting(UnderwritingVo underwritingVo) throws Exception {
-        return null;
-    }
-
-    @Override
-    public PaymentLinkResultsVo getPaymentLink(PaymentLinkVo paymentLinkVo) throws Exception {
-        return null;
-    }
-
-    @Override
-    public void uploadImage(InsuranceUploadImageVo insuranceUploadImageVo) {
-
-    }
-
-    @Override
-    public void queryClauseData(ClauseDataVo clauseDataVo) {
-
-    }
-
-    @Override
-    public DownloadPolicyResultVo downloadPolicy(DownloadPolicyVo downloadPolicyVo) {
-        return null;
-    }
-
-    @Override
-    public OrderStatusResultVo queryOrderState(OrderStatusVo orderStatusVo) throws Exception {
-        return null;
-    }
-
-    @Override
-    public boolean detectLogin(DetectLoginRequest detectLoginRequest) {
-        return false;
-    }
-}

+ 303 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/utils/CaptchaUtils.java

@@ -0,0 +1,303 @@
+package com.jzg.quotation.dadi.utils;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Liub
+ * @version 1.0
+ * @description: 【大地财险】验证码识别工具类 - 中文数字等式计算
+ * @date 2026/5/22 08:49
+ */
+public class CaptchaUtils {
+
+    /**
+     * 中文个位数字映射(0-9 + 特殊数字)
+     */
+    private static final Map<Character, Integer> DIGIT_MAP = new LinkedHashMap<>();
+
+    /**
+     * 中文位值单位映射
+     */
+    private static final Map<Character, Integer> UNIT_MAP = new LinkedHashMap<>();
+
+    /**
+     * 中文运算符映射表
+     */
+    private static final Map<String, String> OPERATOR_MAP = new LinkedHashMap<>();
+
+    static {
+        // 中文个位数字(大小写兼容)
+        DIGIT_MAP.put('零', 0);
+        DIGIT_MAP.put('〇', 0);
+        DIGIT_MAP.put('○', 0);
+        DIGIT_MAP.put('一', 1);
+        DIGIT_MAP.put('壹', 1);
+        DIGIT_MAP.put('二', 2);
+        DIGIT_MAP.put('贰', 2);
+        DIGIT_MAP.put('两', 2);
+        DIGIT_MAP.put('三', 3);
+        DIGIT_MAP.put('叁', 3);
+        DIGIT_MAP.put('四', 4);
+        DIGIT_MAP.put('肆', 4);
+        DIGIT_MAP.put('五', 5);
+        DIGIT_MAP.put('伍', 5);
+        DIGIT_MAP.put('六', 6);
+        DIGIT_MAP.put('陆', 6);
+        DIGIT_MAP.put('七', 7);
+        DIGIT_MAP.put('柒', 7);
+        DIGIT_MAP.put('八', 8);
+        DIGIT_MAP.put('捌', 8);
+        DIGIT_MAP.put('九', 9);
+        DIGIT_MAP.put('玖', 9);
+
+        // 传统特殊数字(完整数值,无需单位即可表示)
+        DIGIT_MAP.put('廿', 20);
+        DIGIT_MAP.put('卅', 30);
+        DIGIT_MAP.put('卌', 40);
+
+        // 中文位值单位
+        UNIT_MAP.put('十', 10);
+        UNIT_MAP.put('拾', 10);
+        UNIT_MAP.put('百', 100);
+        UNIT_MAP.put('佰', 100);
+        UNIT_MAP.put('千', 1000);
+        UNIT_MAP.put('仟', 1000);
+        UNIT_MAP.put('萬', 10000);
+        UNIT_MAP.put('万', 10000);
+        UNIT_MAP.put('億', 100000000);
+        UNIT_MAP.put('亿', 100000000);
+
+        // 运算符(长的放前面保证优先匹配)
+        OPERATOR_MAP.put("加", "+");
+        OPERATOR_MAP.put("减", "-");
+        OPERATOR_MAP.put("减去", "-");
+        OPERATOR_MAP.put("乘", "*");
+        OPERATOR_MAP.put("乘以", "*");
+        OPERATOR_MAP.put("除", "/");
+        OPERATOR_MAP.put("除以", "/");
+    }
+
+    /**
+     * 中文数字转阿拉伯数字(支持单字符和多字符组合)
+     * <p>
+     * 支持格式:
+     * <ul>
+     *   <li>单字符:捌(8)、陆(6)、廿(20)、卅(30)、卌(40)</li>
+     *   <li>十位:十五(15)、叁拾(30)</li>
+     *   <li>百位:一百二十三(123)、贰佰叁拾肆(234)</li>
+     *   <li>千位:二千零二十(2020)</li>
+     *   <li>万位:一万二千三百四十五(12345)</li>
+     *   <li>亿位:一亿二千三百万(123000000)</li>
+     * </ul>
+     *
+     * @param chineseNum 中文数字字符串
+     * @return 阿拉伯数字
+     */
+    public static int toArabicNumber(String chineseNum) {
+        if (chineseNum == null || chineseNum.isEmpty()) {
+            throw new IllegalArgumentException("中文数字不能为空");
+        }
+
+        // 单字符快速路径
+        if (chineseNum.length() == 1) {
+            char ch = chineseNum.charAt(0);
+            Integer digitVal = DIGIT_MAP.get(ch);
+            if (digitVal != null) {
+                return digitVal;
+            }
+            throw new IllegalArgumentException("无法识别的中文数字: " + chineseNum);
+        }
+
+        long total = 0;      // 亿级以上累计
+        long section = 0;    // 当前万段累计值
+        long current = 0;    // 当前数字(尚未与单位结合)
+
+        for (int i = 0; i < chineseNum.length(); i++) {
+            char ch = chineseNum.charAt(i);
+
+            // 个位数字(0-9 或 特殊数字 廿/卅/卌)
+            Integer digitVal = DIGIT_MAP.get(ch);
+            if (digitVal != null) {
+                if (digitVal >= 20) {
+                    // 廿(20)/卅(30)/卌(40) → 完整数字,直接累加到当前段
+                    section += digitVal;
+                    current = 0;
+                } else {
+                    current = digitVal;
+                }
+                continue;
+            }
+
+            // 位值单位(十/百/千/万/亿)
+            Integer unitVal = UNIT_MAP.get(ch);
+            if (unitVal != null) {
+                if (current == 0) {
+                    current = 1; // "十" → 10, "百" → 100, "万" → 10000
+                }
+
+                if (unitVal >= 10000) {
+                    // 万/亿 → 将当前段结算并乘量级
+                    section = (section + current) * unitVal;
+                    if (unitVal >= 100000000) {
+                        // 亿 → 转移到 total
+                        total += section;
+                        section = 0;
+                    }
+                } else {
+                    // 十/百/千 → 乘以单位后加入当前段
+                    section += current * unitVal;
+                }
+                current = 0;
+                continue;
+            }
+
+            throw new IllegalArgumentException("无法识别的中文字符: " + ch);
+        }
+
+        return (int) (total + section + current);
+    }
+
+    /**
+     * 解析中文等式并计算结果(如 "捌加陆等于?" → 14)
+     *
+     * @param equation 中文等式,格式:{中文数字}{运算符}{中文数字}等于?
+     * @return 计算结果
+     */
+    public static int solve(String equation) {
+        if (equation == null || equation.isEmpty()) {
+            throw new IllegalArgumentException("等式不能为空");
+        }
+
+        // 构建所有中文数字字符集
+        StringBuilder numChars = new StringBuilder();
+        DIGIT_MAP.keySet().forEach(numChars::append);
+        UNIT_MAP.keySet().forEach(numChars::append);
+        String numPattern = "[" + Pattern.quote(numChars.toString()) + "]+";
+
+        // 运算符(长的放前面保证优先匹配)
+        String opPattern = "减去|乘以|除以|加|减|乘|除";
+
+        // 等?于?[??]? → 兼容"等于?"/"等于"/"等?"/"?"/无后缀等格式
+        Pattern pattern = Pattern.compile("(" + numPattern + ")(" + opPattern + ")(" + numPattern + ")等?于?[??]?");
+        Matcher matcher = pattern.matcher(equation);
+
+        if (!matcher.find()) {
+            throw new IllegalArgumentException("验证码有误,请重试" + equation);
+        }
+
+        String leftStr = matcher.group(1);
+        String operatorStr = matcher.group(2);
+        String rightStr = matcher.group(3);
+
+        int left = toArabicNumber(leftStr);
+        int right = toArabicNumber(rightStr);
+
+        return calculate(left, operatorStr, right);
+    }
+
+    /**
+     * 执行运算
+     *
+     * @param a        左操作数
+     * @param operator 运算符
+     * @param b        右操作数
+     * @return 计算结果
+     */
+    private static int calculate(int a, String operator, int b) {
+        switch (OPERATOR_MAP.getOrDefault(operator, operator)) {
+            case "+":
+                return a + b;
+            case "-":
+                return a - b;
+            case "*":
+                return a * b;
+            case "/":
+                if (b == 0) {
+                    throw new ArithmeticException("除数不能为零");
+                }
+                return a / b;
+            default:
+                throw new IllegalArgumentException("不支持的运算符: " + operator);
+        }
+    }
+
+    /**
+     * 解析中文等式并以字符串形式返回结果
+     *
+     * @param equation 中文等式
+     * @return 结果字符串
+     */
+    public static String solveToString(String equation) {
+        return String.valueOf(solve(equation));
+    }
+
+    /**
+     * 测试示例
+     */
+    public static void main(String[] args) {
+        // 基础单字符:捌加陆等于? → 8 + 6 = 14
+        System.out.println("捌加陆等于? → " + solve("捌加陆等于?"));
+
+        // 基础:玖减叁等于? → 9 - 3 = 6
+        System.out.println("玖减叁等于? → " + solve("玖减叁等于?"));
+
+        // 基础:柒乘伍等于? → 7 * 5 = 35
+        System.out.println("柒乘伍等于? → " + solve("柒乘伍等于?"));
+
+        // 十位:壹拾除以贰等于? → 10 / 2 = 5
+        System.out.println("壹拾除以贰等于? → " + solve("壹拾除以贰等于?"));
+
+        // 大写小写混用
+        System.out.println("五加九等于? → " + solve("五加九等于?"));
+
+        // 百位:贰佰加叁拾等于? → 200 + 30 = 230
+        System.out.println("贰佰加叁拾等于? → " + solve("贰佰加叁拾等于?"));
+
+        // 多字符:一百二十三乘二等于? → 123 * 2 = 246
+        System.out.println("一百二十三乘二等于? → " + solve("一百二十三乘二等于?"));
+
+        // 万位:一万贰仟叁佰肆拾伍加壹万等于? → 12345 + 10000 = 22345
+        System.out.println("一万贰仟叁佰肆拾伍加壹万等于? → " + solve("一万贰仟叁佰肆拾伍加壹万等于?"));
+
+        // 亿位:壹亿贰仟万加伍佰万等于? → 120000000 + 5000000 = 125000000
+        System.out.println("壹亿贰仟万加伍佰万等于? → " + solve("壹亿贰仟万加伍佰万等于?"));
+
+        // 特殊数字廿(20):廿加卅等于? → 20 + 30 = 50
+        System.out.println("廿加卅等于? → " + solve("廿加卅等于?"));
+
+        // 特殊数字卌(40):卌加六等于? → 40 + 6 = 46
+        System.out.println("卌加六等于? → " + solve("卌加六等于?"));
+
+        // 大写百位:贰佰叁拾肆加壹佰陆拾陆等于? → 234 + 166 = 400
+        System.out.println("贰佰叁拾肆加壹佰陆拾陆等于? → " + solve("贰佰叁拾肆加壹佰陆拾陆等于?"));
+
+        // 小写百位:二百三十四加一百六十六等于? → 234 + 166 = 400
+        System.out.println("二百三十四加一百六十六等于? → " + solve("二百三十四加一百六十六等于?"));
+
+        // 亿级:叁亿伍仟陆佰万减去捌佰万等于? → 356000000 - 8000000 = 348000000
+        System.out.println("叁亿伍仟陆佰万减去捌佰万等于? → " + solve("叁亿伍仟陆佰万减去捌佰万等于?"));
+
+        // solveToString 方法
+        System.out.println("五加捌等于? → " + solveToString("五加捌等于?"));
+
+        // ====== 兼容格式测试 ======
+        System.out.println("\n======== 兼容格式(等?/等于/?等变体) ========");
+        // "贰加六等?" → 2 + 6 = 8 (OCR可能漏识别"于")
+        System.out.println("贰加六等? → " + solve("贰加六等?"));
+
+        // "贰加六等于" → 2 + 6 = 8 (无问号)
+        System.out.println("贰加六等于 → " + solve("贰加六等于"));
+
+        // "贰加六?" → 2 + 6 = 8 (无"等于")
+        System.out.println("贰加六? → " + solve("贰加六?"));
+
+        // "贰加六" → 2 + 6 = 8 (纯等式)
+        System.out.println("贰加六 → " + solve("贰加六"));
+
+        // 半角问号
+        System.out.println("叁减壹等于? → " + solve("叁减壹等于?"));
+    }
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 60 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/utils/DaDiAESUtil.java


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

@@ -64,6 +64,12 @@
             <version>1.0-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>com.jzg</groupId>
+            <artifactId>quotation-dadi</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
         <dependency>
             <groupId>com.jzg</groupId>
             <artifactId>quotation-taikang</artifactId>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor