瀏覽代碼

Merge branch 'master' into wrq_dev

wangrq 1 月之前
父節點
當前提交
a7a4a6c055
共有 43 個文件被更改,包括 1370 次插入 和 380 次删除
  1. 2 1
      .gitignore
  2. 2 0
      commons/src/main/java/com/jzg/commons/entity/account/po/SysUserAccountChangeLog.java
  3. 3 0
      commons/src/main/java/com/jzg/commons/entity/finance/vo/SettlementReportQueryVo.java
  4. 1 2
      commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/ExcelContent4Platform.java
  5. 1 3
      commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/ExcelContent4PrivateSuperviseCar.java
  6. 1 3
      commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/ExcelContent4PrivateSuperviseNoCar.java
  7. 43 0
      commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/InsuranceData.java
  8. 41 29
      commons/src/main/java/com/jzg/commons/util/OrderComponents.java
  9. 118 0
      commons/src/main/java/com/jzg/commons/util/SchemaDescriptionParser.java
  10. 1 0
      platform/src/main/java/com/jzg/controller/QrBarcodeController.java
  11. 23 28
      tenant/insurance/quotation-ansheng/src/main/java/com/jzg/quotation/ansheng/crawler/build/AnShengCrawlerQuoteResultsVoBuild.java
  12. 2 0
      tenant/insurance/quotation-ansheng/src/main/java/com/jzg/quotation/ansheng/crawler/entity/response/AnShengCrawlerCalculatePremiumApplyResponse.java
  13. 13 0
      tenant/insurance/quotation-commons/src/main/java/com/jzg/quotation/commons/client/OrgClient.java
  14. 45 0
      tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/build/DaDiCrawlerQuoteResultVoBuild.java
  15. 60 11
      tenant/insurance/quotation-guoren/src/main/java/com/jzg/quotation/guoren/crawler/build/GuoRenCrawlerQuoteResultsVoBuild.java
  16. 46 0
      tenant/insurance/quotation-hengbang/src/main/java/com/jzg/quotation/hengbang/crawler/build/HbCrawlerQuoteResultVoBuild.java
  17. 1 1
      tenant/insurance/quotation-huanong/src/main/java/com/jzg/quotation/huanong/crawler/service/impl/HuaNongCrawlerRequestImpl.java
  18. 8 9
      tenant/insurance/quotation-huatai/src/main/java/com/jzg/quotation/huatai/crawler/build/HuaTaiCrawlerQuoteResultsVoBuild.java
  19. 35 19
      tenant/insurance/quotation-huatai/src/main/java/com/jzg/quotation/huatai/crawler/service/Impl/HuaTaiCrawlerRequestImpl.java
  20. 3 2
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/OrderOperationLogAspect.java
  21. 1 1
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/aspect/QuoteVerificationAspect.java
  22. 10 0
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/mapper/InsOrdersMapper.java
  23. 59 5
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsOrdersServiceImpl.java
  24. 430 6
      tenant/insurance/quotation-summary/src/main/resources/mapper/InsOrdersMapper.xml
  25. 3 2
      tenant/organization/src/main/java/com/jzg/organization/aop/OrderOperationLogAspect.java
  26. 10 0
      tenant/organization/src/main/java/com/jzg/organization/controller/AreaController.java
  27. 12 10
      tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java
  28. 4 0
      tenant/organization/src/main/java/com/jzg/organization/controller/UserController.java
  29. 40 0
      tenant/organization/src/main/java/com/jzg/organization/excel/listener/InvoiceReceivbleExcel4AllListener.java
  30. 0 25
      tenant/organization/src/main/java/com/jzg/organization/excel/listener/InvoiceReceivbleExcel4PlatformListener.java
  31. 0 28
      tenant/organization/src/main/java/com/jzg/organization/excel/listener/InvoiceReceivbleExcel4PrivateListener.java
  32. 8 0
      tenant/organization/src/main/java/com/jzg/organization/mapper/ReceivableMapper.java
  33. 1 1
      tenant/organization/src/main/java/com/jzg/organization/mapper/SysUserAccountIncomeLogMapper.java
  34. 1 8
      tenant/organization/src/main/java/com/jzg/organization/service/ReceivableService.java
  35. 7 0
      tenant/organization/src/main/java/com/jzg/organization/service/SysUserService.java
  36. 61 5
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementDispatchServiceImpl.java
  37. 120 23
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlSchemeServiceImpl.java
  38. 73 135
      tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java
  39. 6 0
      tenant/organization/src/main/java/com/jzg/organization/service/impl/SysUserServiceImpl.java
  40. 41 16
      tenant/organization/src/main/java/com/jzg/organization/service/impl/importincome/ImportIncomeServiceImpl.java
  41. 17 6
      tenant/organization/src/main/java/com/jzg/organization/service/importincome/ImportIncomeService.java
  42. 1 1
      tenant/organization/src/main/resources/mapper/InsPlyIncomeInvoiceSettlementMapper.xml
  43. 16 0
      tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

+ 2 - 1
.gitignore

@@ -85,4 +85,5 @@ tenant/insurance/quotation-zhongmei/outPath/
 tenant/insurance/quotation-zijin/outPath/
 tenant/organization/outPath/
 
-.reasonix
+.reasonix
+reasonix.toml

+ 2 - 0
commons/src/main/java/com/jzg/commons/entity/account/po/SysUserAccountChangeLog.java

@@ -93,6 +93,8 @@ public class SysUserAccountChangeLog extends BaseModel {
     @ExcelIgnore
     private static Map<Integer,String> operClassMap = new  HashMap<Integer,String>();
     static {
+
+        operClassMap.put(0,"支出"); // 有点提现完成,不知道为什么会是0, 所以这里添加一个
         operClassMap.put(1,"收入");
         operClassMap.put(2,"收入");
         operClassMap.put(3,"支出");

+ 3 - 0
commons/src/main/java/com/jzg/commons/entity/finance/vo/SettlementReportQueryVo.java

@@ -72,6 +72,9 @@ public class SettlementReportQueryVo extends PageRequest {
     @Schema(description = "开票状态 0-未开票 1-已开票")
     private String invoiceStatus;
 
+    @Schema(description = "结算状态 0-已开票未结清 1-已结清 2-未开票")
+    private String settlementStatus;
+
     @Schema(description = "租户代码")
     private String systemCode;
 

+ 1 - 2
commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/ExcelContent4Platform.java

@@ -6,7 +6,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.io.Serial;
-import java.io.Serializable;
 
 /**
  * @author tz
@@ -16,7 +15,7 @@ import java.io.Serializable;
 @EqualsAndHashCode
 @Data
 @Schema(description = "财务应收表")
-public class ExcelContent4Platform implements Serializable {
+public class ExcelContent4Platform implements InsuranceData {
 
     @Serial
     private static final long serialVersionUID = 6263862008363938379L;

+ 1 - 3
commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/ExcelContent4PrivateSuperviseCar.java

@@ -6,8 +6,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.io.Serial;
-import java.io.Serializable;
-
 /**
  * 私有手续费
  *
@@ -18,7 +16,7 @@ import java.io.Serializable;
 @EqualsAndHashCode
 @Data
 @Schema(description = "财务应收表")
-public class ExcelContent4PrivateSuperviseCar implements Serializable {
+public class ExcelContent4PrivateSuperviseCar implements InsuranceData {
 
     @Serial
     private static final long serialVersionUID = 6263862008363938379L;

+ 1 - 3
commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/ExcelContent4PrivateSuperviseNoCar.java

@@ -6,8 +6,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.io.Serial;
-import java.io.Serializable;
-
 /**
  * 私有手续费
  *
@@ -18,7 +16,7 @@ import java.io.Serializable;
 @EqualsAndHashCode
 @Data
 @Schema(description = "财务应收表")
-public class ExcelContent4PrivateSuperviseNoCar implements Serializable {
+public class ExcelContent4PrivateSuperviseNoCar implements InsuranceData {
 
     @Serial
     private static final long serialVersionUID = 6263862008363938379L;

+ 43 - 0
commons/src/main/java/com/jzg/commons/entity/finance/vo/importimcome/InsuranceData.java

@@ -0,0 +1,43 @@
+package com.jzg.commons.entity.finance.vo.importimcome;
+
+import java.io.Serializable;
+
+/**
+ * 车险和非车险的公共方法
+ *
+ * @author lipf
+ * @date 2026/8/17 15:49
+ */
+public interface InsuranceData extends Serializable {
+
+    /**
+     * 交强险保单号。
+     * <p>
+     * 用于在统一处理各 {@link InsuranceData} 实体时按接口多态读取,
+     * 实体若不存在该字段则返回 {@code null}。
+     * </p>
+     *
+     * @return 交强险保单号,实体无此字段时返回 null
+     */
+    default String getJqPolicyNo() {
+        return null;
+    }
+
+    /**
+     * 商业险保单号。
+     *
+     * @return 商业险保单号,实体无此字段时返回 null
+     */
+    default String getSyPolicyNo() {
+        return null;
+    }
+
+    /**
+     * 非车险保单号。
+     *
+     * @return 非车险保单号,实体无此字段时返回 null
+     */
+    default String getJyPolicyNo() {
+        return null;
+    }
+}

+ 41 - 29
commons/src/main/java/com/jzg/commons/util/OrderComponents.java

@@ -9,65 +9,57 @@ public class OrderComponents {
     public static Map<String, String> fillKeyNameMap(){
 
         Map<String,String> nameMap = new HashMap<>();
-        nameMap.put("costRatio.jqExportRatio","交强出口比例");
-        nameMap.put("costRatio.jqFollowRatio","交强跟单比例");
-        nameMap.put("costRatio.jqInletRatio","交强入口比例");
-        nameMap.put("costRatio.jqKeepPointRatio","交强留点比例");
-
 
         nameMap.put("insFeeOrders.jqExportRatio","交强出口比例");
         nameMap.put("insFeeOrders.syExportRatio","商业出口比例");
         nameMap.put("insFeeOrders.jyExportRatio","驾意出口比例");
-
-        nameMap.put("costRatio.syExportRatio","商业出口比例");
-        nameMap.put("costRatio.syFollowRatio","商业跟单比例");
-        nameMap.put("costRatio.syInletRatio","商业入口比例");
-        nameMap.put("costRatio.syKeepPointRatio","商业留点比例");
-
-        nameMap.put("costRatio.jyExportRatio","驾意出口比例");
-        nameMap.put("costRatio.jyFollowRatio","驾意跟单比例");
-        nameMap.put("costRatio.jyInletRatio","驾意入口比例");
-        nameMap.put("costRatio.jyKeepPointRatio","驾意留点比例");
-
         nameMap.put("insFeeOrders.jqExportPremium","交强出口费用");
         nameMap.put("insFeeOrders.jqReceivablePremium","交强应收费用");
         nameMap.put("insFeeOrders.jqKeepPointPremium","交强留点费用");
         nameMap.put("insFeeOrders.jqFollowPremium","交强跟单费用");
         nameMap.put("insFeeOrders.jqPayablePremium","交强应付费用");
-
         nameMap.put("insFeeOrders.syExportPremium","商业出口费用");
         nameMap.put("insFeeOrders.syReceivablePremium","商业应收费用");
         nameMap.put("insFeeOrders.syKeepPointPremium","商业留点费用");
         nameMap.put("insFeeOrders.syFollowPremium","商业跟单费用");
         nameMap.put("insFeeOrders.syPayablePremium","商业应付费用");
-
         nameMap.put("insFeeOrders.jyExportPremium","驾意出口费用");
         nameMap.put("insFeeOrders.jyReceivablePremium","驾意应收费用");
         nameMap.put("insFeeOrders.jyKeepPointPremium","驾意留点费用");
         nameMap.put("insFeeOrders.jyFollowPremium","驾意跟单费用");
         nameMap.put("insFeeOrders.jyPayablePremium","驾意应付费用");
-
         nameMap.put("insFeeOrders.totalReceivablePremium","总应收费用");
         nameMap.put("insFeeOrders.totalPayablePremium","总应付费用");
         nameMap.put("insFeeOrders.totalExportPremium","总出口费用");
-
-        nameMap.put("costRatio.jqCommissionRatio","交强险手续费比例");
-        nameMap.put("costRatio.syCommissionRatio","商业险手续费比例");
-        nameMap.put("costRatio.jyCommissionRatio","驾意险手续费比例");
+        nameMap.put("insFeeOrders.syAdditionalPremium","商业险加投费费费用");
+        nameMap.put("insFeeOrders.jyAdditionalPremium","驾意险加投费费费用");
+        nameMap.put("insFeeOrders.jqAdditionalPremium","交强险加投费费费用");
+        nameMap.put("insFeeOrders.signTime","签单时间");
         nameMap.put("insFeeOrders.jqCommissionPremium","交强险手续费费用");
         nameMap.put("insFeeOrders.syCommissionPremium","商业险手续费费用");
         nameMap.put("insFeeOrders.jyCommissionPremium","驾意险手续费费用");
+        nameMap.put("insFeeOrders.agreementId","协议id");
+
 
+        nameMap.put("costRatio.jqCommissionRatio","交强险手续费比例");
+        nameMap.put("costRatio.syCommissionRatio","商业险手续费比例");
+        nameMap.put("costRatio.jyCommissionRatio","驾意险手续费比例");
         nameMap.put("costRatio.jyAdditionalRatio","驾意险加投比例");
         nameMap.put("costRatio.syAdditionalRatio","商业险加投比例");
         nameMap.put("costRatio.jqAdditionalRatio","交强险加投比例");
-        nameMap.put("insFeeOrders.syAdditionalPremium","商业险加投费费费用");
-        nameMap.put("insFeeOrders.jyAdditionalPremium","驾意险加投费费费用");
-        nameMap.put("insFeeOrders.jqAdditionalPremium","交强险加投费费费用");
+        nameMap.put("costRatio.syExportRatio","商业出口比例");
+        nameMap.put("costRatio.syFollowRatio","商业跟单比例");
+        nameMap.put("costRatio.syInletRatio","商业入口比例");
+        nameMap.put("costRatio.syKeepPointRatio","商业留点比例");
+        nameMap.put("costRatio.jyExportRatio","驾意出口比例");
+        nameMap.put("costRatio.jyFollowRatio","驾意跟单比例");
+        nameMap.put("costRatio.jyInletRatio","驾意入口比例");
+        nameMap.put("costRatio.jyKeepPointRatio","驾意留点比例");
+        nameMap.put("costRatio.jqExportRatio","交强出口比例");
+        nameMap.put("costRatio.jqFollowRatio","交强跟单比例");
+        nameMap.put("costRatio.jqInletRatio","交强入口比例");
+        nameMap.put("costRatio.jqKeepPointRatio","交强留点比例");
 
-        nameMap.put("insFeeOrders.signTime","签单时间");
-        nameMap.put("order.dockingPerson","对接人姓名");
-        nameMap.put("order.dockingPersonPhone","对接人手机号");
 
         nameMap.put("insCompanyVo[0].companyCode","保司编码");
         nameMap.put("insCompanyVo[0].nameSimple","保司简称");
@@ -76,11 +68,31 @@ public class OrderComponents {
         nameMap.put("insCompanyVo[0].name","保司全称");
         nameMap.put("insCompanyVo[0].logo","保司logo");
         nameMap.put("insCompanyVo[0].id","保司ID");
+
+        nameMap.put("order.dockingPerson","对接人姓名");
+        nameMap.put("order.dockingPersonPhone","对接人手机号");
         nameMap.put("order.companyName","保司名称");
         nameMap.put("order.insuranceCompanyCode","保司ID");
+        nameMap.put("order.agreementType","协议类型");
+        nameMap.put("order.agreementName","协议名称");
+        nameMap.put("order.agreementId","协议id");
+
+
         nameMap.put("isProblem","是否是疑问订单");
         nameMap.put("problemReason","疑问订单原因");
         nameMap.put("problemTime","设为疑问订单的时间");
+        nameMap.put("id","订单id");
+
+        nameMap.put("systemCode","租户代码");
+        nameMap.put("parentId","父订单id");
+        nameMap.put("quoteNo","报价订单号");
+        nameMap.put("agreementId","协议ID");
+        nameMap.put("schemeId","方案ID");
+        nameMap.put("apiType","请求类型");
+        nameMap.put("orderStatus","订单状态");
+        nameMap.put("companyOrderNo","保司订单单号");
+        nameMap.put("companyId","保司ID");
+
         return nameMap;
     }
 

+ 118 - 0
commons/src/main/java/com/jzg/commons/util/SchemaDescriptionParser.java

@@ -0,0 +1,118 @@
+package com.jzg.commons.util;
+
+import cn.hutool.core.annotation.Alias;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.json.JSONUtil;
+import com.jzg.commons.entity.quote.vo.aggregated.QuoteEchoVo;
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+public class SchemaDescriptionParser {
+
+    private static final Logger log = LoggerFactory.getLogger(SchemaDescriptionParser.class);
+    /**
+     * 用于存储解析结果的缓存 Map
+     * key: 完全模拟 Hutool JSONUtil.toJsonStr() 序列化后的 Key
+     * value: @Schema 的 description 值;如果没有注解,则 value 等于 key
+     */
+    private static final Map<String, String> SCHEMA_CACHE = new HashMap<>();
+
+    static {
+        try {
+            parseClassHierarchy(QuoteEchoVo.class, null);
+
+            log.info("初始化的SCHEMA_CACHE的大小是[{}]", CollUtil.size(SCHEMA_CACHE));
+            log.info("SCHEMA_CACHE.before=[{}]", JSONUtil.toJsonStr(SCHEMA_CACHE));
+            Map<String, String> otherMap = OrderComponents.fillKeyNameMap();
+            SCHEMA_CACHE.putAll(otherMap);
+            log.info("初始化的SCHEMA_CACHE的大小是[{}]. otherMap.size=[{}]", CollUtil.size(SCHEMA_CACHE), CollUtil.size(otherMap));
+            log.info("SCHEMA_CACHE.after=[{}]", JSONUtil.toJsonStr(SCHEMA_CACHE));
+            log.info("==============");
+            List<String> sortedKeys = new ArrayList<>(SCHEMA_CACHE.keySet()).stream().sorted().toList();
+            for (String sortedKey : sortedKeys) {
+                System.out.println(sortedKey);
+            }
+            log.info("==============");
+
+            log.info(">>>>>>>>>>>>>>>>>>>>>");
+            for (String s : otherMap.keySet().stream().toList().stream().sorted().toList()) {
+                System.out.println(s);
+            }
+            log.info(">>>>>>>>>>>>>>>>>>>>>");
+            log.info("sortedKeys=[{}]", JSONUtil.toJsonStr(sortedKeys));
+
+        } catch (Exception e) {
+            log.error("初始化 Schema 描述映射失败: ",e);
+        }
+    }
+
+    /**
+     * 递归解析类及其内部类
+     */
+    private static void parseClassHierarchy(Class<?> clazz, String parentPrefix) {
+        if (clazz == null || clazz.isPrimitive() || clazz.getName().startsWith("java.")) {
+            return;
+        }
+
+        Field[] fields = clazz.getDeclaredFields();
+
+        for (Field field : fields) {
+            Class<?> fieldType = field.getType();
+
+            // 1. 处理内部类(嵌套对象)
+            if (fieldType.isMemberClass()) {
+                String jsonFieldName = resolveJsonFieldName(field);
+                String newPrefix = (parentPrefix == null ? "" : parentPrefix + ".") + jsonFieldName;
+                parseClassHierarchy(fieldType, newPrefix);
+                continue;
+            }
+
+            // 2. 处理普通字段(无论有没有 @Schema 注解都会收录)
+            String jsonFieldName = resolveJsonFieldName(field);
+            String key = (parentPrefix == null ? "" : parentPrefix + ".") + jsonFieldName;
+
+            // 获取 @Schema 注解的 description
+            Schema schema = field.getAnnotation(Schema.class);
+            String value;
+            if (schema != null && !schema.description().isEmpty()) {
+                value = schema.description();
+            } else {
+                // 没有注解或 description 为空时,value 等于 key
+                value = key;
+            }
+
+            SCHEMA_CACHE.put(key, value);
+        }
+    }
+
+    /**
+     * 解析字段的 JSON Key 名称
+     * 模拟 Hutool JSONUtil.toJsonStr() 的行为:
+     * 1. 优先读取 @Alias 注解的值
+     * 2. 没有 @Alias 注解时,直接使用字段名
+     */
+    private static String resolveJsonFieldName(Field field) {
+        Alias alias = field.getAnnotation(Alias.class);
+        if (alias != null && !alias.value().isEmpty()) {
+            return alias.value();
+        }
+        return field.getName();
+    }
+
+    /**
+     * 获取解析后的 Map (只读)
+     */
+    public static Map<String, String> getSchemaMap() {
+        return Collections.unmodifiableMap(SCHEMA_CACHE);
+    }
+
+    // --- 测试主函数 ---
+    public static void main(String[] args) {
+        Map<String, String> result = SchemaDescriptionParser.getSchemaMap();
+        //result.forEach((k, v) -> System.out.println(k + " = " + v));
+    }
+}

+ 1 - 0
platform/src/main/java/com/jzg/controller/QrBarcodeController.java

@@ -55,6 +55,7 @@ public class QrBarcodeController {
         BeanUtil.copyProperties(barcodeConfigAddVO, barcodeConfigAdd);
         LambdaQueryWrapper<QrBarcodeConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
         lambdaQueryWrapper.eq(QrBarcodeConfig::getCompanyCode, barcodeConfigAdd.getCompanyCode());
+        lambdaQueryWrapper.eq(QrBarcodeConfig::getApiType, barcodeConfigAdd.getApiType());
         AssertionUtils.isFail(qrBarcodeService.count(lambdaQueryWrapper) > 0, "保险公司编码重复");
         return qrBarcodeService.save(BeanUtil.copyProperties(barcodeConfigAdd, QrBarcodeConfig.class)) ? HttpResult.ok("保存成功") : HttpResult.error("保存失败");
     }

+ 23 - 28
tenant/insurance/quotation-ansheng/src/main/java/com/jzg/quotation/ansheng/crawler/build/AnShengCrawlerQuoteResultsVoBuild.java

@@ -21,6 +21,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 
@@ -154,39 +155,33 @@ public final class AnShengCrawlerQuoteResultsVoBuild {
                 "scoreKey", "bussinessLevel",
                 "score", data.getBussinessLevel()
         );
-
-
         AnShengCrawlerCalculatePremiumApplyResponse.DataDTO.ContractsDTO contractsDTO =
                 data.getContracts().stream()
                         .filter(c -> c.getPlanDefine() != null)
-                        .filter(c -> "105".equals(c.getPlanDefine().getPlanCode()))
+                        .filter(c -> "109".equals(c.getPlanDefine().getPlanCode()))
                         .findAny()
-                        .orElseThrow(() -> new IllegalStateException("未找到 planCode=105 的合约"));
-        JSONObject compulsoryInsure = new JSONObject();
-        compulsoryInsure.put("scoreName","交强存在费用");
-        compulsoryInsure.put("scoreKey","compulsoryInsure");
-        compulsoryInsure.put("score",contractsDTO.getPlanDefine().getCompulsoryInsure() ? "是" : "否");
-        scoreArray.add(compulsoryInsure);
+                        .orElse(null);
+        for (AnShengCrawlerCalculatePremiumApplyResponse.DataDTO.ContractsDTO contract : data.getContracts()) {
+            JSONObject jsonObject = new JSONObject();
+            if (StringUtils.equals("105",contract.getPlanDefine().getPlanCode())){
+                jsonObject.put("scoreName","交强存在费用");
+                jsonObject.put("scoreKey","compulsoryInsure");
+                jsonObject.put("score",contract.getPlanDefine().getCompulsoryInsure() ? "是" : "否");
+            }else if (StringUtils.equals("109",contract.getPlanDefine().getPlanCode())){
+                jsonObject.put("scoreName","商业存在费用");
+                jsonObject.put("scoreKey","businessInsure");
+                jsonObject.put("score",contract.getPlanDefine().getBusinessInsure() ? "是" : "否");
+            }
 
-        JSONObject businessInsure = new JSONObject();
-        businessInsure.put("scoreName","商业存在费用");
-        businessInsure.put("scoreKey","businessInsure");
-        businessInsure.put("score",contractsDTO.getPlanDefine().getBusinessInsure() ? "是" : "否");
-        scoreArray.add(businessInsure);
-//        for (AnShengCrawlerCalculatePremiumApplyResponse.DataDTO.ContractsDTO contract : data.getContracts()) {
-//            JSONObject jsonObject = new JSONObject();
-//            if (StringUtils.equals("105",contract.getPlanDefine().getPlanCode())){
-//                jsonObject.put("scoreName","交强存在费用");
-//                jsonObject.put("scoreKey","compulsoryInsure");
-//                jsonObject.put("score",contract.getPlanDefine().getCompulsoryInsure() ? "是" : "否");
-//            }else if (StringUtils.equals("109",contract.getPlanDefine().getPlanCode())){
-//                jsonObject.put("scoreName","商业存在费用");
-//                jsonObject.put("scoreKey","businessInsure");
-//                jsonObject.put("score",contract.getPlanDefine().getBusinessInsure() ? "是" : "否");
-//            }
-//
-//            scoreArray.add(jsonObject);
-//        }
+            scoreArray.add(jsonObject);
+        }
+        if (Objects.nonNull(contractsDTO)){
+            JSONObject claimTimes = new JSONObject();
+            claimTimes.put("scoreName","连续承保期间出险次数");
+            claimTimes.put("scoreKey","claimTimes");
+            claimTimes.put("score",contractsDTO.getVehicle().getPolicyPricing().getClaimTimes());
+            scoreArray.add(claimTimes);
+        }
         scoreArray.add(bussinessLevel);
         scoreVo.setScoreJson(scoreArray);
         return scoreVo;

+ 2 - 0
tenant/insurance/quotation-ansheng/src/main/java/com/jzg/quotation/ansheng/crawler/entity/response/AnShengCrawlerCalculatePremiumApplyResponse.java

@@ -779,6 +779,8 @@ public class AnShengCrawlerCalculatePremiumApplyResponse  implements Serializabl
                     private List<ElectronicCertInfoDTO> electronicCertInfo;
                     @JsonProperty("newColor")
                     private String newColor;
+                    @JsonProperty("claimTimes")
+                    private String claimTimes;
 
                     @NoArgsConstructor
                     @Data

+ 13 - 0
tenant/insurance/quotation-commons/src/main/java/com/jzg/quotation/commons/client/OrgClient.java

@@ -33,6 +33,7 @@ public interface OrgClient {
     HttpResult<SysUserJzgInfo> queryUserByUserId(@RequestParam("userId") String userId,
                                                  @RequestParam("systemCode") String systemCode);
 
+
     /**
      * 查询所有成员和业务员的身份
      *
@@ -54,6 +55,9 @@ public interface OrgClient {
     HttpResult<PersonAreaVo> queryByAddress(@RequestParam("address") String address,
                                             @RequestParam("idCard") String idCard);
 
+    @GetMapping(value = "/area/queryAllParent")
+    HttpResult<List<SysArea>> queryAllParent(@RequestParam("countyCode") String countyCode);
+
     @GetMapping(value = "/agreement/getByCompanyId")
     HttpResult<List<PtlAgreement>> getByCompanyId(@RequestParam("companyId") String companyId,
                                                   @RequestParam("systemCode") String code
@@ -255,4 +259,13 @@ public interface OrgClient {
      */
     @GetMapping("/userInfo/querySysUserByUserName")
     public HttpResult<SysUser> querySysUserByUserName(@RequestParam("userName") String userName);
+
+    /**
+     * 根据用户手机号获取用户对象
+     * @param userName
+     * @return
+     */
+    @GetMapping("/userInfo/querySysUserByMobile")
+    public HttpResult<SysUser> querySysUserByMobile(@RequestParam("mobile") String mobile);
+
 }

+ 45 - 0
tenant/insurance/quotation-dadi/src/main/java/com/jzg/quotation/dadi/crawler/build/DaDiCrawlerQuoteResultVoBuild.java

@@ -6,6 +6,7 @@ import com.jzg.commons.constants.dict.InsOrderStatusEnum;
 import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.commons.entity.quote.vo.RiskInfoVo;
 import com.jzg.commons.entity.quote.vo.aggregated.QuoteResultsVo;
+import com.jzg.quotation.commons.constant.enums.quote.RenewalEnum;
 import com.jzg.quotation.commons.utils.DateTimeUtil;
 import com.jzg.quotation.dadi.crawler.entity.response.DaDiQuoteResponse;
 import com.jzg.quotation.dadi.crawler.entity.response.DaDiVehiclePricResponse;
@@ -14,6 +15,7 @@ import org.apache.http.util.TextUtils;
 
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @author Liub
@@ -65,6 +67,14 @@ public class DaDiCrawlerQuoteResultVoBuild {
 
         // 保司评分数据(用于规则引擎匹配)
         QuoteResultsVo.ScoreVo scoreVo = new QuoteResultsVo.ScoreVo();
+        DaDiQuoteResponse.InsurancePlanDTO insurancePlan = daDiQuoteResponse.getInsurancePlan();
+        // 出险次数、续保标志
+        if (Objects.nonNull(insurancePlan)) {
+            scoreVo.setCiClaims(insurancePlan.getClaimTimes());
+            scoreVo.setBiClaims(insurancePlan.getClaimTimes());
+            scoreVo.setJqRenewal("0".equals(insurancePlan.getTrafficRenewalFlag()) ? String.valueOf(RenewalEnum.Transfer.getCode()) : String.valueOf(RenewalEnum.Renewal.getCode()));
+            scoreVo.setSyRenewal("0".equals(insurancePlan.getBusinessRenewalFlag()) ? String.valueOf(RenewalEnum.Transfer.getCode()) : String.valueOf(RenewalEnum.Renewal.getCode()));
+        }
         JSONArray scoreJson = new JSONArray();
         // 上年保费
         if (daDiQuoteResponse.getLastPremium() != null) {
@@ -108,6 +118,41 @@ public class DaDiCrawlerQuoteResultVoBuild {
                     .fluentPut("scoreKey", "xcarscore")
                     .fluentPut("score", daDiQuoteResponse.getXcarscore()));
         }
+        // 保险计划评分(出险次数、承保年数、续保标志、违章等级等)
+        if (Objects.nonNull(insurancePlan)) {
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "出险次数")
+                    .fluentPut("scoreKey", "claimTimes")
+                    .fluentPut("score", insurancePlan.getClaimTimes()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "承保年数")
+                    .fluentPut("scoreKey", "insureYears")
+                    .fluentPut("score", insurancePlan.getInsureYears()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "交强续保标志")
+                    .fluentPut("scoreKey", "trafficRenewalFlag")
+                    .fluentPut("score", insurancePlan.getTrafficRenewalFlag()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "交强续保类型")
+                    .fluentPut("scoreKey", "trafficRenewalType")
+                    .fluentPut("score", insurancePlan.getTrafficRenewalType()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "商业续保标志")
+                    .fluentPut("scoreKey", "businessRenewalFlag")
+                    .fluentPut("score", insurancePlan.getBusinessRenewalFlag()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "商业续保类型")
+                    .fluentPut("scoreKey", "businessRenewalType")
+                    .fluentPut("score", insurancePlan.getBusinessRenewalType()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "违章等级")
+                    .fluentPut("scoreKey", "violationLevel")
+                    .fluentPut("score", insurancePlan.getViolationLevel()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "商业险折扣率")
+                    .fluentPut("scoreKey", "cDiscountRate")
+                    .fluentPut("score", insurancePlan.getCDiscountRate()));
+        }
         scoreVo.setScoreJson(scoreJson);
         quoteResultsVo.setScoreVo(scoreVo);
 

+ 60 - 11
tenant/insurance/quotation-guoren/src/main/java/com/jzg/quotation/guoren/crawler/build/GuoRenCrawlerQuoteResultsVoBuild.java

@@ -7,6 +7,7 @@ import com.jzg.commons.constants.quote.enums.quote.KindCode;
 import com.jzg.commons.entity.quote.vo.KindInfoVo;
 import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.commons.entity.quote.vo.aggregated.QuoteResultsVo;
+import com.jzg.quotation.guoren.crawler.entity.dto.CiInsureDemandDTO;
 import com.jzg.quotation.guoren.crawler.entity.response.GuoRenCrawlerBaseResponse;
 import com.jzg.quotation.guoren.crawler.entity.response.GuoRenCrawlerCalculationPremiumData;
 import com.jzg.quotation.guoren.crawler.entity.response.GuoRenCrawlerProposalNoSaveData;
@@ -72,26 +73,74 @@ public final class GuoRenCrawlerQuoteResultsVoBuild {
 
 
         QuoteResultsVo.ScoreVo scoreVo = new QuoteResultsVo.ScoreVo();
-        scoreVo.setLossRation(calculationPremium.getBc().getAutoPriceOutputXOMRespVo().getStrBillELR2());
-        scoreVo.setJqLossRation(calculationPremium.getBc().getAutoPriceOutputXOMRespVo().getStrBillCTPELR2());
-        scoreVo.setSyLossRation(calculationPremium.getBc().getAutoPriceOutputXOMRespVo().getStrBillCOMELR2());
-        scoreVo.setJqRenewal(Integer.parseInt(calculationPremium.getBc().getPrpTitemCar().getOriginalRouteRenewalFlagci()) + 1 + "");
-        scoreVo.setSyRenewal(Integer.parseInt(calculationPremium.getBc().getPrpTitemCar().getOriginalRouteRenewalFlagbi()) + 1 + "");
+        // 赔付率(总/交强/商业)
+        Optional.ofNullable(calculationPremium.getBc())
+                .map(GuoRenCrawlerCalculationPremiumData.BcDTO::getAutoPriceOutputXOMRespVo)
+                .ifPresent(autoPriceOutputXOMRespVo -> {
+                    scoreVo.setLossRation(autoPriceOutputXOMRespVo.getStrBillELR2());
+                    scoreVo.setJqLossRation(autoPriceOutputXOMRespVo.getStrBillCTPELR2());
+                    scoreVo.setSyLossRation(autoPriceOutputXOMRespVo.getStrBillCOMELR2());
+                });
+        // 续保/转保标志
+        Optional.ofNullable(calculationPremium.getBc())
+                .map(GuoRenCrawlerCalculationPremiumData.BcDTO::getPrpTitemCar)
+                .ifPresent(prpTitemCar -> {
+                    scoreVo.setJqRenewal(Integer.parseInt(prpTitemCar.getOriginalRouteRenewalFlagci()) + 1 + "");
+                    scoreVo.setSyRenewal(Integer.parseInt(prpTitemCar.getOriginalRouteRenewalFlagbi()) + 1 + "");
+                });
+        // 交强险出险次数
+        Optional.ofNullable(calculationPremium.getCi())
+                .map(GuoRenCrawlerCalculationPremiumData.CiDTO::getCiInsureDemand)
+                .map(CiInsureDemandDTO::getClaimTimes)
+                .ifPresent(scoreVo::setCiClaims);
+        // 商业险出险次数
+        Optional.ofNullable(calculationPremium.getBi())
+                .map(GuoRenCrawlerCalculationPremiumData.BiDTO::getCiInsureDemand)
+                .map(CiInsureDemandDTO::getClaimTimes)
+                .ifPresent(scoreVo::setBiClaims);
 
         // 保司评分
         JSONArray scoreJson = new JSONArray();
         //光博评分
-        scoreJson.add(new JSONObject()
-                .fluentPut("scoreName", "交强光博分")
-                .fluentPut("scoreKey", "jqScore")
-                .fluentPut("score", calculationPremium.getCi().getPrpTmainRate().getBillcomeGroup()));
-
-        if (calculationPremium.getBi().getPrpTmainRate() != null) {
+        Optional.ofNullable(calculationPremium.getCi())
+                .map(GuoRenCrawlerCalculationPremiumData.CiDTO::getPrpTmainRate)
+                .map(GuoRenCrawlerCalculationPremiumData.CiDTO.PrpTmainRateDTO::getBillcomeGroup)
+                .ifPresent(billcomeGroup -> scoreJson.add(new JSONObject()
+                        .fluentPut("scoreName", "交强光博分")
+                        .fluentPut("scoreKey", "jqScore")
+                        .fluentPut("score", billcomeGroup)));
+
+        if (calculationPremium.getBi() != null && calculationPremium.getBi().getPrpTmainRate() != null) {
             scoreJson.add(new JSONObject()
                     .fluentPut("scoreName", "商业光博分")
                     .fluentPut("scoreKey", "syScore")
                     .fluentPut("score", calculationPremium.getBi().getPrpTmainRate().getBillcomeGroup()));
         }
+        // 保司评分(阳光评分/全保评分/责任险评分/交强险评分/推荐折扣评分)
+        Optional.ofNullable(calculationPremium.getBc())
+                .map(GuoRenCrawlerCalculationPremiumData.BcDTO::getAutoPriceOutputXOMRespVo)
+                .ifPresent(autoPriceOutputXOMRespVo -> {
+                    scoreJson.add(new JSONObject()
+                            .fluentPut("scoreName", "阳光评分")
+                            .fluentPut("scoreKey", "sunlightScore")
+                            .fluentPut("score", autoPriceOutputXOMRespVo.getSunlightScore()));
+                    scoreJson.add(new JSONObject()
+                            .fluentPut("scoreName", "全保评分")
+                            .fluentPut("scoreKey", "fullCoverageScore")
+                            .fluentPut("score", autoPriceOutputXOMRespVo.getFullCoverageScore()));
+                    scoreJson.add(new JSONObject()
+                            .fluentPut("scoreName", "责任险评分")
+                            .fluentPut("scoreKey", "liabilityOnlyScore")
+                            .fluentPut("score", autoPriceOutputXOMRespVo.getLiabilityOnlyScore()));
+                    scoreJson.add(new JSONObject()
+                            .fluentPut("scoreName", "交强险评分")
+                            .fluentPut("scoreKey", "ctpOnlyScore")
+                            .fluentPut("score", autoPriceOutputXOMRespVo.getCtpOnlyScore()));
+                    scoreJson.add(new JSONObject()
+                            .fluentPut("scoreName", "推荐折扣评分")
+                            .fluentPut("scoreKey", "recommenDiscountScore")
+                            .fluentPut("score", autoPriceOutputXOMRespVo.getRecommenDiscountScore()));
+                });
         // 重试成功时,将提前记录的重复投保信息放入评分字段
         if (duplicateMessage != null) {
             scoreJson.add(new JSONObject()

+ 46 - 0
tenant/insurance/quotation-hengbang/src/main/java/com/jzg/quotation/hengbang/crawler/build/HbCrawlerQuoteResultVoBuild.java

@@ -9,6 +9,7 @@ import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.commons.entity.quote.vo.RiskInfoVo;
 import com.jzg.commons.entity.quote.vo.aggregated.QuoteResultsVo;
 import com.jzg.commons.util.StringUtils;
+import com.jzg.quotation.commons.constant.enums.quote.RenewalEnum;
 import com.jzg.quotation.commons.utils.DateTimeUtil;
 import com.jzg.quotation.hengbang.crawler.entity.response.HbCrawlerProposalResponse;
 import lombok.extern.slf4j.Slf4j;
@@ -57,6 +58,31 @@ public final class HbCrawlerQuoteResultVoBuild {
         quoteResultsVo.setKindInfoVo(buildKindInfoList(proposalResponse, quoteVo));
 
         QuoteResultsVo.ScoreVo scoreVo = new QuoteResultsVo.ScoreVo();
+        HbCrawlerProposalResponse.ForceCarInsureRiskDTO forceCarInsureRisk = proposalResponse.getForceCarInsureRisk();
+        HbCrawlerProposalResponse.BusiCarInsureRiskDTO busiCarInsureRisk = proposalResponse.getBusiCarInsureRisk();
+        // 交强险赔付率、出险次数
+        if (Objects.nonNull(forceCarInsureRisk)) {
+            scoreVo.setJqLossRation(forceCarInsureRisk.getBillctpelr());
+            scoreVo.setCiClaims(forceCarInsureRisk.getClaimTimes());
+        }
+        // 商业险赔付率、出险次数
+        if (Objects.nonNull(busiCarInsureRisk)) {
+            scoreVo.setSyLossRation(busiCarInsureRisk.getBillcomelr());
+            scoreVo.setBiClaims(busiCarInsureRisk.getClaimTimes());
+        }
+        // 总赔付率
+        if (Objects.nonNull(forceCarInsureRisk)) {
+            scoreVo.setLossRation(forceCarInsureRisk.getBillelr());
+        } else if (Objects.nonNull(busiCarInsureRisk)) {
+            scoreVo.setLossRation(busiCarInsureRisk.getBillelr());
+        }
+        // 续保/转保标志(0:转保,其他:续保)
+        HbCrawlerProposalResponse.CarInsureMainDTO carInsureMain = proposalResponse.getCarInsureMain();
+        if (Objects.nonNull(carInsureMain) && StringUtils.isNotBlank(carInsureMain.getRenewind())) {
+            String renewind = carInsureMain.getRenewind();
+            scoreVo.setJqRenewal(String.valueOf("0".equals(renewind) ? RenewalEnum.Transfer.getCode() : RenewalEnum.Renewal.getCode()));
+            scoreVo.setSyRenewal(String.valueOf("0".equals(renewind) ? RenewalEnum.Transfer.getCode() : RenewalEnum.Renewal.getCode()));
+        }
         // 保司评分
         JSONArray scoreJson = new JSONArray();
         if (proposalResponse.getForceLiability() != null && proposalResponse.getCarInsureLiabilityList().size() > 0) {
@@ -70,6 +96,26 @@ public final class HbCrawlerQuoteResultVoBuild {
             scoreJson.add(new JSONObject().fluentPut("scoreName", "交强光博分").fluentPut("scoreKey", "score").fluentPut("score", proposalResponse.getBusiCarInsureRisk().getBillelr2()));
 
         }
+        // 保司评分列表
+        if (CollUtil.isNotEmpty(proposalResponse.getCarInsureScoreList())) {
+            for (HbCrawlerProposalResponse.CarInsureScoreDTO carInsureScoreDTO : proposalResponse.getCarInsureScoreList()) {
+                scoreJson.add(new JSONObject()
+                        .fluentPut("scoreName", carInsureScoreDTO.getScoringType())
+                        .fluentPut("scoreKey", carInsureScoreDTO.getScoringType())
+                        .fluentPut("score", carInsureScoreDTO.getScoring()));
+            }
+        }
+        // 违章评分、承保年数
+        if (Objects.nonNull(forceCarInsureRisk)) {
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "违章评分")
+                    .fluentPut("scoreKey", "trafficViolationValue")
+                    .fluentPut("score", forceCarInsureRisk.getTrafficViolationValue()));
+            scoreJson.add(new JSONObject()
+                    .fluentPut("scoreName", "承保年数")
+                    .fluentPut("scoreKey", "insureYears")
+                    .fluentPut("score", forceCarInsureRisk.getInsureYears()));
+        }
         // 重试成功时,将提前记录的重复投保信息放入评分字段
         if (duplicateMessage != null) {
             scoreJson.add(new JSONObject().fluentPut("scoreName", "重复投保信息").fluentPut("scoreKey", "duplicateInfo").fluentPut("score", duplicateMessage));

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

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

+ 8 - 9
tenant/insurance/quotation-huatai/src/main/java/com/jzg/quotation/huatai/crawler/build/HuaTaiCrawlerQuoteResultsVoBuild.java

@@ -177,12 +177,12 @@ public class HuaTaiCrawlerQuoteResultsVoBuild {
         quoteResultsVo.getCosts().setNiPremium(StringUtils.isBlank(niPremium) ? "0" : niPremium);
         // 计算总保费 = 交强险 + 商业险 + 驾意险 + 车船税
         QuoteResultsVo.CostsVo costs = quoteResultsVo.getCosts();
-        double sumPremium = 0.0;
-        if (StringUtils.isNotBlank(costs.getCiPremium())) sumPremium += Double.parseDouble(costs.getCiPremium());
-        if (StringUtils.isNotBlank(costs.getBiPremium())) sumPremium += Double.parseDouble(costs.getBiPremium());
-        if (StringUtils.isNotBlank(costs.getNiPremium())) sumPremium += Double.parseDouble(costs.getNiPremium());
-        if (StringUtils.isNotBlank(costs.getVvTax())) sumPremium += Double.parseDouble(costs.getVvTax());
-        costs.setSumPremium(String.valueOf(sumPremium));
+        BigDecimal sumPremium = BigDecimal.ZERO;
+        if (StringUtils.isNotBlank(costs.getCiPremium())) sumPremium = sumPremium.add(new BigDecimal(costs.getCiPremium()));
+        if (StringUtils.isNotBlank(costs.getBiPremium())) sumPremium = sumPremium.add(new BigDecimal(costs.getBiPremium()));
+        if (StringUtils.isNotBlank(costs.getNiPremium())) sumPremium = sumPremium.add(new BigDecimal(costs.getNiPremium()));
+        if (StringUtils.isNotBlank(costs.getVvTax())) sumPremium = sumPremium.add(new BigDecimal(costs.getVvTax()));
+        costs.setSumPremium(sumPremium.toString());
     }
 
     /**
@@ -191,12 +191,11 @@ public class HuaTaiCrawlerQuoteResultsVoBuild {
      * @return
      */
     public static String getBiPremium(HtCrawlerQuoteResponse.DataDTO quoteResponseData) {
-        Double result = 0D;
+        BigDecimal result = BigDecimal.ZERO;
         List<HtCrawlerQuoteResponse.DataDTO.CoverageDTOList.CoverageDTO> coverageDTOList = quoteResponseData.getCoveragedtolist() == null ? null : quoteResponseData.getCoveragedtolist().getCoveragedto();
         for (HtCrawlerQuoteResponse.DataDTO.CoverageDTOList.CoverageDTO coverageDTO : coverageDTOList) {
             if (!ContractEnum.C_BZ.getKindCode().equals(coverageDTO.getComcoveragecode())) {
-                result += Double.parseDouble(coverageDTO.getStandardpremium());
-                break;
+                result = result.add(new BigDecimal(coverageDTO.getStandardpremium()));
             }
         }
         return String.valueOf(result == null ? "" : result);

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

@@ -52,6 +52,7 @@ import com.jzg.quotation.huatai.crawler.util.UploadUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
@@ -442,9 +443,9 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     private String executeCarModelCodexhQuery(HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO,
                                             CarInfoVo car, String cookie, String quotationNo) {
         MultiValueMap<String, String> fd = new LinkedMultiValueMap<>();
-        fd.add("modelCode", carDTO.getModelcode());
+        fd.add("modelCode", carDTO.getModelcode()); //"BCHFCBUB0001"  carDTO.getModelcode()
         fd.add("licenseNo", car.getLicenseNo());
-        fd.add("licenseKindCode", car.getLicenseKindCode() + " " + car.getLicenseKindName()); // "02 小型汽车号牌"
+        fd.add("licenseKindCode", "02 小型汽车号牌"); // "02 小型汽车号牌"  car.getLicenseKindCode() + " " + car.getLicenseKindName()
         fd.add("engineNo", car.getEngineNo());
         fd.add("frameNo", car.getVinNo());
         // fd.add("useNatureCode", "8A 家庭自用");
@@ -668,14 +669,14 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
                 "postalCode", "bulidTypeCode", "bulidTypeQiTaMes", "provinceName", "cityName", "regionName")) {
             m.put(k, "");
         }
-        m.put("amount", set != null && set.getCoverage() != null ? set.getCoverage().toString().replace(".00", "") : "");
+        m.put("amount", set != null && set.getCoverage() != null ? set.getCoverage().toString().replace(".00", "") : cfg.getCoverage());
         m.put("car_limitloadperson", q.getCarInfoVo().getSeatCount());
         m.put("productcode", cfg != null ? cfg.getParentProductCode() : "");
         m.put("mealcode", cfg != null ? cfg.getProductCode() : "");
         m.put("startdate", q.getCiRiskInfoVo().getStartDate());
         m.put("enddate", q.getCiRiskInfoVo().getEndDate());
         m.put("num", "1");
-        m.put("premium", set != null && set.getPremium() != null ? set.getPremium().toString().replace(".00", ".0") : "");
+        m.put("premium", set != null && set.getPremium() != null ? set.getPremium().toString().replace(".00", ".0") : cfg.getPremium());
         m.put("isInsuredSizesFlag", "0");
         m.put("perinsuredList", perinsuredList);
         return m;
@@ -925,13 +926,16 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     }
 
     private UnderwritingResultsVo handlePassedUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters params, UnderwritingVo vo, Map<String, Object> map) {
+        UnderwritingResultsVo r = new UnderwritingResultsVo();
+        r.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
         HtCrawlerPaymentLinkResponse pl = queryPaymentLink(order, params, new PaymentLinkVo());
         log.info("handlePassedUnderwriting_paymentLinkResponse: {}", JSONObject.toJSONString(pl));
-        UnderwritingResultsVo r = new UnderwritingResultsVo();
+        if (pl == null || pl.getImg() == null) {
+            return r;
+        }
         r.setPaymentLink(pl.getImg());
         r.setJqPolicyno(map.get("jqProposalno") == null ? "" : map.get("jqProposalno").toString());
         r.setSyPolicyno(map.get("syProposalno") == null ? "" : map.get("syProposalno").toString());
-        r.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
 
         order.setJqPolicyno(r.getJqPolicyno());
         order.setSyPolicyno(r.getSyPolicyno());
@@ -956,6 +960,9 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         HtCrawlerConfigureParameters params = ConfigureParametersConversion.conversionEntity(
                 HtCrawlerConfigureParameters.class, attr.getConfigInfo());
         HtCrawlerPaymentLinkResponse pl = queryPaymentLink(order, params, vo);
+        if (pl == null || pl.getImg() == null) {
+            return new PaymentLinkResultsVo(false, null, "暂时获取不到支付链接,请耐心等待~");
+        }
         log.info("paymentLinkResponse: {}", JSONObject.toJSONString(pl));
         order.setPaymentLink(pl.getImg());
         orderService.update(order);
@@ -971,8 +978,17 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         qp.add("quotationno", order.getQuotationRelaNo());
         String body = get(ORIGIN + "/htcsp/PaymentAction.do", buildPaymentListHeaders(req.getCookie()), qp);
         //返回的是html 页面,暂不打印
-        //log.info("queryPaymentList response: {}", body);
-        return req.getPaymentLink(new HtCrawlerPaymentLinkRequest(params, vo, body), buildPaymentListHeaders(req.getCookie()));
+        // log.info("queryPaymentList body: {}", body);
+        HtCrawlerPaymentLinkRequest htCrawlerPaymentLinkRequest = new HtCrawlerPaymentLinkRequest(params, vo, body);
+        log.info("htCrawlerPaymentLinkRequest: {}", JSONObject.toJSONString(htCrawlerPaymentLinkRequest));
+        HtCrawlerPaymentLinkResponse paymentLink = new HtCrawlerPaymentLinkResponse();
+        try {
+            paymentLink = req.getPaymentLink(htCrawlerPaymentLinkRequest, buildPaymentListHeaders(req.getCookie()));
+        } catch (Exception e) {
+            log.error(e.getMessage());
+            return null;
+        }
+        return paymentLink;
     }
 
     // ====================== Cookie 检查 ======================
@@ -1469,11 +1485,11 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     private static void fillVehicleTypeCodes(CarInfoVo car, Map<String, Object> data, String motorTypeKey, String motorUsageKey) {
         String use = car.getVehicleUseCode(), kind = car.getCarKindCode();
         switch (use) {
-            case "04" -> data.putAll(Map.of(motorTypeKey, "H0", motorUsageKey, "9D"));
-            case "05" -> data.putAll(Map.of(motorTypeKey, "A0", motorUsageKey, "8A"));
+            case "04" -> data.putAll(Map.of(motorTypeKey, "H0 货车", motorUsageKey, "9D 营业货运"));
+            case "05" -> data.putAll(Map.of(motorTypeKey, "A0 客车", motorUsageKey, "8A 家庭自用"));
             case "06" -> {
-                if ("A0".equals(kind)) data.putAll(Map.of(motorTypeKey, "A0", motorUsageKey, "8C"));
-                else if ("A1".equals(kind)) data.putAll(Map.of(motorTypeKey, "H0", motorUsageKey, "8D"));
+                if ("A0".equals(kind)) data.putAll(Map.of(motorTypeKey, "A0 客车", motorUsageKey, "8C"));
+                else if ("A1".equals(kind)) data.putAll(Map.of(motorTypeKey, "H0 货车", motorUsageKey, "8D 非营业货运"));
             }
             case "07" -> {
                 if ("A0".equals(kind)) data.putAll(Map.of(motorTypeKey, "A0", motorUsageKey, "8B"));
@@ -1486,17 +1502,17 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
     private static void fillVehicleTypeCodes2(CarInfoVo car, MultiValueMap<String, String> data, String motorTypeKey, String motorUsageKey) {
         String use = car.getVehicleUseCode(), kind = car.getCarKindCode();
         switch (use) {
-            case "04" -> { data.add(motorTypeKey, "H0"); data.add(motorUsageKey, "9D"); }
-            case "05" -> { data.add(motorTypeKey, "A0"); data.add(motorUsageKey, "8A"); }
+            case "04" -> { data.add(motorTypeKey, "H0 货车"); data.add(motorUsageKey, "9D 营业货运"); }
+            case "05" -> { data.add(motorTypeKey, "A0 客车"); data.add(motorUsageKey, "8A 家庭自用"); }
             case "06" -> {
-                if ("A0".equals(kind)) { data.add(motorTypeKey, "A0"); data.add(motorUsageKey, "8C"); }
-                else if ("A1".equals(kind)) { data.add(motorTypeKey, "H0"); data.add(motorUsageKey, "8D"); }
+                if ("A0".equals(kind)) { data.add(motorTypeKey, "A0 客车"); data.add(motorUsageKey, "8C"); }
+                else if ("A1".equals(kind)) { data.add(motorTypeKey, "H0 货车"); data.add(motorUsageKey, "8D 非营业货运"); }
             }
             case "07" -> {
-                if ("A0".equals(kind)) { data.add(motorTypeKey, "A0"); data.add(motorUsageKey, "8B"); }
-                else if ("A1".equals(kind)) { data.add(motorTypeKey, "H0"); data.add(motorUsageKey, "8D"); }
+                if ("A0".equals(kind)) { data.add(motorTypeKey, "A0 客车"); data.add(motorUsageKey, "8B"); }
+                else if ("A1".equals(kind)) { data.add(motorTypeKey, "H0 货车"); data.add(motorUsageKey, "8D 非营业货运"); }
             }
-            case "08" -> { data.add(motorTypeKey, "H0"); data.add(motorUsageKey, "8D"); }
+            case "08" -> { data.add(motorTypeKey, "H0 货车"); data.add(motorUsageKey, "8D 非营业货运"); }
         }
     }
 

+ 3 - 2
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/OrderOperationLogAspect.java

@@ -18,7 +18,7 @@ import com.jzg.commons.entity.vo.AdjustAllRefundVo;
 import com.jzg.commons.entity.vo.PtlAgreementCostRatioVo;
 import com.jzg.commons.entity.vo.QuestionOrder;
 import com.jzg.commons.util.JsonDiffUtil;
-import com.jzg.commons.util.OrderComponents;
+import com.jzg.commons.util.SchemaDescriptionParser;
 import com.jzg.quotation.commons.constant.SpElMapping;
 import com.jzg.quotation.commons.utils.SpElFieldExtractor;
 import com.jzg.quotation.summary.aop.aspect.OrderOperationLog;
@@ -293,7 +293,8 @@ public class OrderOperationLogAspect {
         if(CollUtil.isNotEmpty(diffMap)){
             List<String> oldItems = new ArrayList<>();
             List<String> newItems = new ArrayList<>();
-            Map<String,String> keyMap = OrderComponents.fillKeyNameMap();
+            // Map<String,String> keyMap = OrderComponents.fillKeyNameMap();
+            Map<String,String> keyMap = SchemaDescriptionParser.getSchemaMap();
             diffMap.forEach((path, values) ->{
                         System.out.println("路径: " + path + " -> 值1: " + values.get(0) + " | 值2: " + values.get(1));
                         oldItems.add(keyMap.getOrDefault(path,path)  + ": " + values.get(0));

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

@@ -159,7 +159,7 @@ public class QuoteVerificationAspect {
         if(StrUtil.isEmpty(userName)){
             return StrUtil.EMPTY;
         }
-        HttpResult<SysUser> sysUserHttpResult = orgClient.querySysUserByUserName(userName);
+        HttpResult<SysUser> sysUserHttpResult = orgClient.querySysUserByMobile(userName);
         if(sysUserHttpResult.isSuccess()){
             return sysUserHttpResult.getData().getId();
         }

+ 10 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/mapper/InsOrdersMapper.java

@@ -43,6 +43,16 @@ public interface InsOrdersMapper extends BaseMapper<InsOrders> {
 
     List<OrderListVo> queryOrderListAll(@Param("insOrdersParam") InsOrdersParamVO insOrdersParam);
 
+    /**
+     * 手动分页版:按车牌+状态分组去重(每组取最新一条),返回当前页数据
+     */
+    List<OrderListVo> queryOrderListDistinct(@Param("insOrdersParam") InsOrdersParamVO insOrdersParam, @Param("offset") long offset, @Param("size") long size);
+
+    /**
+     * 手动分页版:统计按车牌+状态分组去重后的总条数
+     */
+    Long countOrderListDistinct(@Param("insOrdersParam") InsOrdersParamVO insOrdersParam);
+
     List<HistoryQuoteResultVo> getHistoryQuote(@Param("userName") String userName);
 
     Page<HistoryQuoteResultVo> getHistoryQuoteList(@Param("page") Page page, @Param("params") HistoryQuoteQueryVo historyQuoteQueryVo, @Param("userName") String userName);

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

@@ -80,6 +80,7 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
 @RequiredArgsConstructor
@@ -159,6 +160,7 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
     @Value("${minio.bucket-name}")
     private String bucketName;
 
+
     /**
      * null-safe → BigDecimal.ZERO
      */
@@ -1038,7 +1040,21 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
             jzgInfoId = sysUserJzgInfo.getId();
             insOrdersParam.setJzgInfoId(jzgInfoId);
         }
-        Page<OrderListVo> orderListVoPage = insOrdersMapper.queryOrderList(insOrdersParam.getPage(), insOrdersParam);
+        Page<OrderListVo> orderListVoPage;
+        if (baseController.getUserSystemCode().equals("APP")) {
+            // 手动分页:按车牌+状态分组去重,先统计总数再取当前页(避免 MP 自动 count 解析窗口函数报错)
+            Page<OrderListVo> page = insOrdersParam.getPage();
+            long current = page.getCurrent();
+            long size = page.getSize();
+            long offset = (current - 1) * size;
+            long total = insOrdersMapper.countOrderListDistinct(insOrdersParam);
+            List<OrderListVo> records = insOrdersMapper.queryOrderListDistinct(insOrdersParam, offset, size);
+            orderListVoPage = new Page<>(current, size, total);
+            orderListVoPage.setRecords(records != null ? records : java.util.Collections.emptyList());
+        } else {
+            // 非 APP 走原 MP 自动分页查询
+            orderListVoPage = insOrdersMapper.queryOrderList(insOrdersParam.getPage(), insOrdersParam);
+        }
         // modify by lipf, 2026年4月29日11:06:02 解决业务员类型缺失的问题
         List<OrderListVo> records = orderListVoPage.getRecords();
         if (CollUtil.isNotEmpty(records)) {
@@ -1071,14 +1087,27 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
         if (CollUtil.isEmpty(insOrders)) {
             return;
         }
+        Map<String, String> logoMap = new ConcurrentHashMap<>();
         for (OrderQuotationCompany insOrder : insOrders) {
-            HttpResult<EsmInsCompany> esmInsCompanyHttpResult = platformClient.findLogoById(insOrder.getCompanyId());
-            if (esmInsCompanyHttpResult.getCode() == 200) {
-                insOrder.setLogo(esmInsCompanyHttpResult.getData().getLogo());
+            String companyId = insOrder.getCompanyId();
+            if (StrUtil.isBlank(companyId)) {
+                continue;
+            }
+            String logo = logoMap.get(companyId);
+            if (StrUtil.isBlank(logo)) {
+                HttpResult<EsmInsCompany> result = platformClient.findLogoById(companyId);
+                if (result.getCode() == 200 && result.getData() != null) {
+                    logo = result.getData().getLogo();
+                    if (StrUtil.isNotBlank(logo)) {
+                        logoMap.put(companyId, logo);
+                    }
+                }
+            }
+            if (StrUtil.isNotBlank(logo)) {
+                insOrder.setLogo(logo);
             }
         }
 
-
         Map<String, Map<String, List<OrderQuotationCompany>>> groupMap = insOrders.stream().collect(Collectors.groupingBy(OrderQuotationCompany::getQuoteNo, Collectors.groupingBy(OrderQuotationCompany::getOrderStatus)));
         for (OrderListVo orders : orderList) {
             String orderNo = orders.getNo();
@@ -1801,6 +1830,31 @@ public class InsOrdersServiceImpl extends ServiceImpl<InsOrdersMapper, InsOrders
         } else {
             insOrdersVo = selectById(Long.parseLong(ordersNo));
         }
+
+        HttpResult<List<SysArea>> sysAreasResult = orgClient.queryAllParent(insOrdersVo.getOwnersInfo().getCountyCode());
+        if(sysAreasResult.getCode() == 200) {
+            List<SysArea> sysAreas = sysAreasResult.getData();
+            insOrdersVo.getOwnersInfo().setProvince(sysAreas.get(3).getAreaCname());
+            insOrdersVo.getOwnersInfo().setCity(sysAreas.get(2).getAreaCname());
+            insOrdersVo.getOwnersInfo().setCounty(sysAreas.get(1).getAreaCname());
+        }
+
+        HttpResult<List<SysArea>> sysPoliCyAreasResult = orgClient.queryAllParent(insOrdersVo.getPolicyHolderInfo().getCountyCode());
+        if(sysPoliCyAreasResult.getCode() == 200) {
+            List<SysArea> sysAreas = sysAreasResult.getData();
+            insOrdersVo.getPolicyHolderInfo().setProvince(sysAreas.get(3).getAreaCname());
+            insOrdersVo.getPolicyHolderInfo().setCity(sysAreas.get(2).getAreaCname());
+            insOrdersVo.getPolicyHolderInfo().setCounty(sysAreas.get(1).getAreaCname());
+        }
+
+        HttpResult<List<SysArea>> sysInsuredAreasResult = orgClient.queryAllParent(insOrdersVo.getInsuredPersonInfo().getCountyCode());
+        if(sysInsuredAreasResult.getCode() == 200) {
+            List<SysArea> sysAreas = sysAreasResult.getData();
+            insOrdersVo.getInsuredPersonInfo().setProvince(sysAreas.get(3).getAreaCname());
+            insOrdersVo.getInsuredPersonInfo().setCity(sysAreas.get(2).getAreaCname());
+            insOrdersVo.getInsuredPersonInfo().setCounty(sysAreas.get(1).getAreaCname());
+        }
+
         log.info("根据orderNo=[{}]查询到的订单明细[{}]", ordersNo, JSONUtil.toJsonStr(insOrdersVo));
         AssertionUtils.isFail(Objects.isNull(insOrdersVo), "订单不存在");
         QuoteEchoVo resultVo = new QuoteEchoVo(insOrdersVo);

+ 430 - 6
tenant/insurance/quotation-summary/src/main/resources/mapper/InsOrdersMapper.xml

@@ -882,7 +882,7 @@
         su.username as recorder,
         suji.name as salesmanInfo,
         suji.id as jzgInfoId,
-        suji.type_attr as salesmanType,
+        sujis.type_attr as salesmanType,
         pa.agreement_name as agreementName,
         sd.name as deptName,
         io.pay_link as paymentLink,
@@ -909,6 +909,8 @@
         left join
         sys_user_jzg_info suji on suji.user_id = su.id and suji.system_code = #{insOrdersParam.systemCode} and suji.is_delete = 0
         left join
+        sys_user_jzg_info_salesman sujis ON suji.id = sujis.sys_user_jzg_info_id AND sujis.is_delete = 0
+        left join
         sys_dept sd on sd.id = suji.dept_id and sd.is_delete = 0
         left join
         ptl_agreement pa on pa.id = io.agreement_id and pa.is_delete = 0
@@ -931,7 +933,7 @@
         ) x WHERE x.rn = 1
         ) ioa1 ON io.id = ioa1.order_no
         <where>
-            and io.is_delete = 0  and io.parent_id != '0'
+            and io.is_delete = 0 and io.parent_id != '0' and sujis.type_attr !=3
             <if test="insOrdersParam.jzgInfoId != null and insOrdersParam.jzgInfoId != ''">
                 and io.real_quote_user_id in (select bbb.mobile from sys_user bbb where bbb.id in ( select ss.user_id
                 from sys_user_jzg_info ss where 1 =1 and (ss.leader_id = #{insOrdersParam.jzgInfoId} or ss.id
@@ -1014,7 +1016,7 @@
                 AND su.username = #{insOrdersParam.salesmanInfo}
             </if>
             <if test="insOrdersParam.salesmanType != null and insOrdersParam.salesmanType != ''">
-                AND suji.type_attr = #{insOrdersParam.salesmanType}
+                AND sujis.type_attr = #{insOrdersParam.salesmanType}
             </if>
             <if test="insOrdersParam.agreementName != null and insOrdersParam.agreementName != ''">
                 AND pa.agreement_name = #{insOrdersParam.agreementName}
@@ -1070,7 +1072,7 @@
         iorco.tax_premium as vvTax,
         su.username as recorder,
         suji.name as salesmanInfo,
-        suji.type_attr as salesmanType,
+        sujis.type_attr as salesmanType,
         pa.agreement_name as agreementName,
         sd.name as deptName,
         io.pay_link as paymentLink,
@@ -1097,6 +1099,8 @@
         left join
         sys_user_jzg_info suji on suji.user_id = su.id and suji.system_code = #{insOrdersParam.systemCode} and suji.is_delete = 0
         left join
+        sys_user_jzg_info_salesman sujis ON suji.id = sujis.sys_user_jzg_info_id AND sujis.is_delete = 0
+        left join
         sys_dept sd on sd.id = suji.dept_id and sd.is_delete = 0
         left join
         ptl_agreement pa on pa.id = io.agreement_id and pa.is_delete = 0
@@ -1119,7 +1123,7 @@
         ) x WHERE x.rn = 1
         ) ioa1 ON io.id = ioa1.order_no
         <where>
-            and io.is_delete = 0
+            and io.is_delete = 0 and sujis.type_attr !=3
             <if test="insOrdersParam.orderNo != null and insOrdersParam.orderNo != ''">
                 AND io.id = #{insOrdersParam.orderNo}
             </if>
@@ -1203,7 +1207,213 @@
                 AND suji.name = #{insOrdersParam.salesmanInfo}
             </if>
             <if test="insOrdersParam.salesmanType != null and insOrdersParam.salesmanType != ''">
-                AND suji.type_attr = #{insOrdersParam.salesmanType}
+                AND sujis.type_attr = #{insOrdersParam.salesmanType}
+            </if>
+            <if test="insOrdersParam.agreementName != null and insOrdersParam.agreementName != ''">
+                AND pa.agreement_name = #{insOrdersParam.agreementName}
+            </if>
+            <if test="insOrdersParam.deptId != null and insOrdersParam.deptId != ''">
+                AND sd.id = #{insOrdersParam.deptId}
+            </if>
+            <if test="insOrdersParam.deptName != null and insOrdersParam.deptName != ''">
+                AND sd.name = #{insOrdersParam.deptName}
+            </if>
+            <if test="insOrdersParam.paymentLink != null and insOrdersParam.paymentLink != ''">
+                AND io.pay_link = #{insOrdersParam.paymentLink}
+            </if>
+            <if test="insOrdersParam.adjustId != null">
+                AND ioa.id = #{insOrdersParam.adjustId}
+            </if>
+            <if test="insOrdersParam.adjustPremium != null">
+                AND ioa1.after_premium = #{insOrdersParam.adjustPremium}
+            </if>
+            <if test="insOrdersParam.startSigningTime != null and insOrdersParam.startSigningTime != ''and insOrdersParam.endSigningTime != null and insOrdersParam.endSigningTime != ''">
+                AND io.signing_time BETWEEN #{insOrdersParam.startSigningTime} and #{insOrdersParam.endSigningTime}
+            </if>
+            <if test="insOrdersParam.startPayTime != null and insOrdersParam.startPayTime != ''and insOrdersParam.endPayTime != null and insOrdersParam.endPayTime != ''">
+                AND io.pay_time BETWEEN #{insOrdersParam.startPayTime} and #{insOrdersParam.endPayTime}
+            </if>
+        </where>
+        order by io.create_time desc
+    </select>
+
+    <!-- 手动分页版:按车牌+状态分组去重(每组取最新一条),返回当前页数据;不触发 MP 自动 count -->
+    <select id="queryOrderListDistinct" resultType="com.jzg.commons.entity.orders.vo.OrderListVo">
+        SELECT
+        io.id as order_no,
+        io.quote_no as no,
+        io.company_id,
+        io.company_name,
+        io.product_id as productCode,
+        io.product_name as productName,
+        io.order_status,
+        io.create_time,
+        io.create_by,
+        io.error_message,
+        ioci.license_no,
+        ioci.vin_no,
+        owner_u.name as owner_name,
+        owner_u.mobile as owner_mobile,
+        policy_u.name as policy_name,
+        policy_u.mobile as policy_mobile,
+        insur_u.name as insur_name,
+        insur_u.mobile as insur_mobile,
+        iorci.start_date as ci_start_date,
+        iorbi.start_date as bi_start_date,
+        iorco.sum_premium as sumPremium,
+        iorco.jq_premium as ciPremium,
+        iorco.sy_premium as biPremium,
+        iorco.jy_premium as niPremium,
+        iorco.tax_premium as vvTax,
+        su.username as recorder,
+        suji.name as salesmanInfo,
+        suji.id as jzgInfoId,
+        sujis.type_attr as salesmanType,
+        pa.agreement_name as agreementName,
+        sd.name as deptName,
+        io.pay_link as paymentLink,
+        ioa.status as adjustStatus,
+        ioa.id as adjustId,
+        ioa1.after_premium as adjustPremium
+        FROM (
+        SELECT dedup.order_id
+        FROM (
+        SELECT
+        io.id AS order_id,
+        io.create_time,
+        ROW_NUMBER() OVER(PARTITION BY COALESCE(ioci.license_no, io.id), io.order_status ORDER BY io.create_time DESC)
+        AS rn
+        FROM
+        ins_orders io
+        LEFT JOIN ins_orders_car_info ioci ON ioci.order_no = io.id and ioci.is_delete = 0
+        LEFT JOIN
+        ins_orders_car_user_info owner_u on owner_u.order_no = io.id and owner_u.policy_person_type = 1 and
+        owner_u.is_delete = 0
+        left JOIN
+        ins_orders_car_user_info policy_u on policy_u.order_no = io.id and policy_u.policy_person_type = 2 and
+        policy_u.is_delete = 0
+        left JOIN
+        ins_orders_car_user_info insur_u on insur_u.order_no = io.id and insur_u.policy_person_type = 3 and
+        insur_u.is_delete = 0
+        left join
+        ins_orders_risk iorci on iorci.order_no = io.id and iorci.risk_code = '0507' and iorci.is_delete = 0
+        left join
+        ins_orders_risk iorbi on iorbi.order_no = io.id and iorbi.risk_code = '0510' and iorbi.is_delete = 0
+        LEFT JOIN
+        ins_orders_costs iorco on iorco.order_no = io.id and iorco.is_delete = 0
+        left join
+        sys_user su on su.mobile = io.real_quote_user_id and su.is_delete = 0
+        left join
+        sys_user_jzg_info suji on suji.user_id = su.id and suji.system_code = #{insOrdersParam.systemCode} and
+        suji.is_delete = 0
+        left join
+        sys_user_jzg_info_salesman sujis ON suji.id = sujis.sys_user_jzg_info_id AND sujis.is_delete = 0
+        left join
+        sys_dept sd on sd.id = suji.dept_id and sd.is_delete = 0
+        left join
+        ptl_agreement pa on pa.id = io.agreement_id and pa.is_delete = 0
+        left join
+        (
+        SELECT *
+        FROM (
+        SELECT t.*,
+        ROW_NUMBER() OVER(PARTITION BY t.order_no ORDER BY t.create_time DESC) AS rn
+        FROM ins_order_adjust t where t.is_delete = 0
+        ) x WHERE x.rn = 1
+        ) ioa ON io.id = ioa.order_no
+        left join
+        (
+        SELECT *
+        FROM (
+        SELECT t.*,
+        ROW_NUMBER() OVER(PARTITION BY t.order_no ORDER BY t.create_time DESC) AS rn
+        FROM ins_order_adjust t where t.status = 2 and t.is_delete = 0
+        ) x WHERE x.rn = 1
+        ) ioa1 ON io.id = ioa1.order_no
+        <where>
+            and io.is_delete = 0 and io.parent_id != '0' and sujis.type_attr !=3
+            <if test="insOrdersParam.jzgInfoId != null and insOrdersParam.jzgInfoId != ''">
+                and io.real_quote_user_id in (select bbb.mobile from sys_user bbb where bbb.id in ( select ss.user_id
+                from sys_user_jzg_info ss where 1 =1 and (ss.leader_id = #{insOrdersParam.jzgInfoId} or ss.id
+                =#{insOrdersParam.jzgInfoId}) and ss.is_delete = 0 ) and bbb.is_delete = 0 )
+            </if>
+            <if test="insOrdersParam.orderNo != null and insOrdersParam.orderNo != ''">
+                AND io.id = #{insOrdersParam.orderNo}
+            </if>
+            <if test="insOrdersParam.licenseNo != null and insOrdersParam.licenseNo != ''">
+                AND ioci.license_no = #{insOrdersParam.licenseNo}
+            </if>
+            <if test="insOrdersParam.orderStatus!= null and insOrdersParam.orderStatus!= ''">
+                AND io.order_status = #{insOrdersParam.orderStatus}
+            </if>
+            <if test="insOrdersParam.adjustStatus!= null and insOrdersParam.adjustStatus!= ''">
+                AND ioa.status = #{insOrdersParam.adjustStatus}
+            </if>
+            <if test="insOrdersParam.salesman!= null">
+                AND io.real_quote_user_id = #{insOrdersParam.salesman}
+            </if>
+            <if test="insOrdersParam.companyId != null and insOrdersParam.companyId != ''">
+                AND io.company_id = #{insOrdersParam.companyId}
+            </if>
+            <if test="insOrdersParam.startDate != null and insOrdersParam.startDate != ''and insOrdersParam.endDate != null and insOrdersParam.endDate != ''">
+                AND io.create_time BETWEEN #{insOrdersParam.startDate} and #{insOrdersParam.endDate}
+            </if>
+            <if test="insOrdersParam.companyName != null and insOrdersParam.companyName != ''">
+                AND io.company_name = #{insOrdersParam.companyName}
+            </if>
+            <if test="insOrdersParam.productCode != null and insOrdersParam.productCode != ''">
+                AND io.product_id = #{insOrdersParam.productCode}
+            </if>
+            <if test="insOrdersParam.productName != null and insOrdersParam.productName != ''">
+                AND io.product_name = #{insOrdersParam.productName}
+            </if>
+            <if test="insOrdersParam.vinNo != null and insOrdersParam.vinNo != ''">
+                AND ioci.vin_no = #{insOrdersParam.vinNo}
+            </if>
+            <if test="insOrdersParam.ownerName != null and insOrdersParam.ownerName != ''">
+                AND owner_u.name = #{insOrdersParam.ownerName}
+            </if>
+            <if test="insOrdersParam.ownerMobile != null and insOrdersParam.ownerMobile != ''">
+                AND owner_u.mobile = #{insOrdersParam.ownerMobile}
+            </if>
+            <if test="insOrdersParam.policyName != null and insOrdersParam.policyName != ''">
+                AND policy_u.name = #{insOrdersParam.policyName}
+            </if>
+            <if test="insOrdersParam.policyMobile != null and insOrdersParam.policyMobile != ''">
+                AND policy_u.mobile = #{insOrdersParam.policyMobile}
+            </if>
+            <if test="insOrdersParam.insurName != null and insOrdersParam.insurName != ''">
+                AND insur_u.name = #{insOrdersParam.insurName}
+            </if>
+            <if test="insOrdersParam.insurMobile != null and insOrdersParam.insurMobile != ''">
+                AND insur_u.mobile = #{insOrdersParam.insurMobile}
+            </if>
+            <if test="insOrdersParam.ciStartDate != null">
+                AND iorci.start_date = #{insOrdersParam.ciStartDate}
+            </if>
+            <if test="insOrdersParam.biStartDate != null">
+                AND iorbi.start_date = #{insOrdersParam.biStartDate}
+            </if>
+            <if test="insOrdersParam.sumPremium != null">
+                AND iorco.sum_premium = #{insOrdersParam.sumPremium}
+            </if>
+            <if test="insOrdersParam.ciPremium != null">
+                AND iorco.jq_premium = #{insOrdersParam.ciPremium}
+            </if>
+            <if test="insOrdersParam.biPremium != null">
+                AND iorco.sy_premium = #{insOrdersParam.biPremium}
+            </if>
+            <if test="insOrdersParam.niPremium != null">
+                AND iorco.jy_premium = #{insOrdersParam.niPremium}
+            </if>
+            <if test="insOrdersParam.vvTax != null">
+                AND iorco.tax_premium = #{insOrdersParam.vvTax}
+            </if>
+            <if test="insOrdersParam.salesmanInfo != null and insOrdersParam.salesmanInfo != ''">
+                AND su.username = #{insOrdersParam.salesmanInfo}
+            </if>
+            <if test="insOrdersParam.salesmanType != null and insOrdersParam.salesmanType != ''">
+                AND sujis.type_attr = #{insOrdersParam.salesmanType}
             </if>
             <if test="insOrdersParam.agreementName != null and insOrdersParam.agreementName != ''">
                 AND pa.agreement_name = #{insOrdersParam.agreementName}
@@ -1230,9 +1440,223 @@
                 AND io.pay_time BETWEEN #{insOrdersParam.startPayTime} and #{insOrdersParam.endPayTime}
             </if>
         </where>
+        ) dedup
+        WHERE dedup.rn = 1
+        ORDER BY dedup.create_time DESC
+        LIMIT #{offset}, #{size}
+        ) p
+        JOIN ins_orders io ON io.id = p.order_id
+        LEFT JOIN ins_orders_car_info ioci ON ioci.order_no = io.id and ioci.is_delete = 0
+        LEFT JOIN
+        ins_orders_car_user_info owner_u on owner_u.order_no = io.id and owner_u.policy_person_type = 1 and
+        owner_u.is_delete = 0
+        left JOIN
+        ins_orders_car_user_info policy_u on policy_u.order_no = io.id and policy_u.policy_person_type = 2 and
+        policy_u.is_delete = 0
+        left JOIN
+        ins_orders_car_user_info insur_u on insur_u.order_no = io.id and insur_u.policy_person_type = 3 and
+        insur_u.is_delete = 0
+        left join
+        ins_orders_risk iorci on iorci.order_no = io.id and iorci.risk_code = '0507' and iorci.is_delete = 0
+        left join
+        ins_orders_risk iorbi on iorbi.order_no = io.id and iorbi.risk_code = '0510' and iorbi.is_delete = 0
+        LEFT JOIN
+        ins_orders_costs iorco on iorco.order_no = io.id and iorco.is_delete = 0
+        left join
+        sys_user su on su.mobile = io.real_quote_user_id and su.is_delete = 0
+        left join
+        sys_user_jzg_info suji on suji.user_id = su.id and suji.system_code = #{insOrdersParam.systemCode} and
+        suji.is_delete = 0
+        left join
+        sys_user_jzg_info_salesman sujis ON suji.id = sujis.sys_user_jzg_info_id AND sujis.is_delete = 0
+        left join
+        sys_dept sd on sd.id = suji.dept_id and sd.is_delete = 0
+        left join
+        ptl_agreement pa on pa.id = io.agreement_id and pa.is_delete = 0
+        left join
+        (
+        SELECT *
+        FROM (
+        SELECT t.*,
+        ROW_NUMBER() OVER(PARTITION BY t.order_no ORDER BY t.create_time DESC) AS rn
+        FROM ins_order_adjust t where t.is_delete = 0
+        ) x WHERE x.rn = 1
+        ) ioa ON io.id = ioa.order_no
+        left join
+        (
+        SELECT *
+        FROM (
+        SELECT t.*,
+        ROW_NUMBER() OVER(PARTITION BY t.order_no ORDER BY t.create_time DESC) AS rn
+        FROM ins_order_adjust t where t.status = 2 and t.is_delete = 0
+        ) x WHERE x.rn = 1
+        ) ioa1 ON io.id = ioa1.order_no
         order by io.create_time desc
     </select>
 
+    <!-- 手动分页版:统计按车牌+状态分组去重后的总条数 -->
+    <select id="countOrderListDistinct" resultType="java.lang.Long">
+        SELECT COUNT(*) FROM (
+            SELECT
+                io.id AS order_id,
+                ROW_NUMBER() OVER(PARTITION BY COALESCE(ioci.license_no, io.id), io.order_status ORDER BY io.create_time DESC) AS rn
+            FROM
+            ins_orders io
+            LEFT JOIN ins_orders_car_info ioci ON ioci.order_no = io.id and ioci.is_delete = 0
+            LEFT JOIN
+            ins_orders_car_user_info owner_u on owner_u.order_no = io.id and owner_u.policy_person_type = 1 and owner_u.is_delete = 0
+            left JOIN
+            ins_orders_car_user_info policy_u on policy_u.order_no = io.id and policy_u.policy_person_type = 2 and policy_u.is_delete = 0
+            left JOIN
+            ins_orders_car_user_info insur_u on insur_u.order_no = io.id and insur_u.policy_person_type = 3 and insur_u.is_delete = 0
+            left join
+            ins_orders_risk iorci on iorci.order_no = io.id and iorci.risk_code = '0507' and iorci.is_delete = 0
+            left join
+            ins_orders_risk iorbi on iorbi.order_no = io.id and iorbi.risk_code = '0510' and iorbi.is_delete = 0
+            LEFT JOIN
+            ins_orders_costs iorco on iorco.order_no = io.id and iorco.is_delete = 0
+            left join
+            sys_user su on su.mobile = io.real_quote_user_id and su.is_delete = 0
+            left join
+            sys_user_jzg_info suji on suji.user_id = su.id and suji.system_code = #{insOrdersParam.systemCode} and suji.is_delete = 0
+        left join
+        sys_user_jzg_info_salesman sujis ON suji.id = sujis.sys_user_jzg_info_id AND sujis.is_delete = 0
+            left join
+            sys_dept sd on sd.id = suji.dept_id and sd.is_delete = 0
+            left join
+            ptl_agreement pa on pa.id = io.agreement_id and pa.is_delete = 0
+            left join
+            (
+            SELECT *
+            FROM (
+            SELECT t.*,
+            ROW_NUMBER() OVER(PARTITION BY t.order_no ORDER BY t.create_time DESC) AS rn
+            FROM ins_order_adjust t where t.is_delete = 0
+            ) x WHERE x.rn = 1
+            ) ioa ON io.id = ioa.order_no
+            left join
+            (
+            SELECT *
+            FROM (
+            SELECT t.*,
+            ROW_NUMBER() OVER(PARTITION BY t.order_no ORDER BY t.create_time DESC) AS rn
+            FROM ins_order_adjust t where t.status = 2 and t.is_delete = 0
+            ) x WHERE x.rn = 1
+            ) ioa1 ON io.id = ioa1.order_no
+            <where>
+                and io.is_delete = 0 and io.parent_id != '0' and sujis.type_attr !=3
+                <if test="insOrdersParam.jzgInfoId != null and insOrdersParam.jzgInfoId != ''">
+                    and io.real_quote_user_id in (select bbb.mobile from sys_user bbb where bbb.id in ( select ss.user_id
+                    from sys_user_jzg_info ss where 1 =1 and (ss.leader_id = #{insOrdersParam.jzgInfoId} or ss.id
+                    =#{insOrdersParam.jzgInfoId}) and ss.is_delete = 0 ) and bbb.is_delete = 0 )
+                </if>
+                <if test="insOrdersParam.orderNo != null and insOrdersParam.orderNo != ''">
+                    AND io.id = #{insOrdersParam.orderNo}
+                </if>
+                <if test="insOrdersParam.licenseNo != null and insOrdersParam.licenseNo != ''">
+                    AND ioci.license_no = #{insOrdersParam.licenseNo}
+                </if>
+                <if test="insOrdersParam.orderStatus!= null and insOrdersParam.orderStatus!= ''">
+                    AND io.order_status = #{insOrdersParam.orderStatus}
+                </if>
+                <if test="insOrdersParam.adjustStatus!= null and insOrdersParam.adjustStatus!= ''">
+                    AND ioa.status = #{insOrdersParam.adjustStatus}
+                </if>
+                <if test="insOrdersParam.salesman!= null">
+                    AND io.real_quote_user_id = #{insOrdersParam.salesman}
+                </if>
+                <if test="insOrdersParam.companyId != null and insOrdersParam.companyId != ''">
+                    AND io.company_id = #{insOrdersParam.companyId}
+                </if>
+                <if test="insOrdersParam.startDate != null and insOrdersParam.startDate != ''and insOrdersParam.endDate != null and insOrdersParam.endDate != ''">
+                    AND io.create_time BETWEEN #{insOrdersParam.startDate} and #{insOrdersParam.endDate}
+                </if>
+                <if test="insOrdersParam.companyName != null and insOrdersParam.companyName != ''">
+                    AND io.company_name = #{insOrdersParam.companyName}
+                </if>
+                <if test="insOrdersParam.productCode != null and insOrdersParam.productCode != ''">
+                    AND io.product_id = #{insOrdersParam.productCode}
+                </if>
+                <if test="insOrdersParam.productName != null and insOrdersParam.productName != ''">
+                    AND io.product_name = #{insOrdersParam.productName}
+                </if>
+                <if test="insOrdersParam.vinNo != null and insOrdersParam.vinNo != ''">
+                    AND ioci.vin_no = #{insOrdersParam.vinNo}
+                </if>
+                <if test="insOrdersParam.ownerName != null and insOrdersParam.ownerName != ''">
+                    AND owner_u.name = #{insOrdersParam.ownerName}
+                </if>
+                <if test="insOrdersParam.ownerMobile != null and insOrdersParam.ownerMobile != ''">
+                    AND owner_u.mobile = #{insOrdersParam.ownerMobile}
+                </if>
+                <if test="insOrdersParam.policyName != null and insOrdersParam.policyName != ''">
+                    AND policy_u.name = #{insOrdersParam.policyName}
+                </if>
+                <if test="insOrdersParam.policyMobile != null and insOrdersParam.policyMobile != ''">
+                    AND policy_u.mobile = #{insOrdersParam.policyMobile}
+                </if>
+                <if test="insOrdersParam.insurName != null and insOrdersParam.insurName != ''">
+                    AND insur_u.name = #{insOrdersParam.insurName}
+                </if>
+                <if test="insOrdersParam.insurMobile != null and insOrdersParam.insurMobile != ''">
+                    AND insur_u.mobile = #{insOrdersParam.insurMobile}
+                </if>
+                <if test="insOrdersParam.ciStartDate != null">
+                    AND iorci.start_date = #{insOrdersParam.ciStartDate}
+                </if>
+                <if test="insOrdersParam.biStartDate != null">
+                    AND iorbi.start_date = #{insOrdersParam.biStartDate}
+                </if>
+                <if test="insOrdersParam.sumPremium != null">
+                    AND iorco.sum_premium = #{insOrdersParam.sumPremium}
+                </if>
+                <if test="insOrdersParam.ciPremium != null">
+                    AND iorco.jq_premium = #{insOrdersParam.ciPremium}
+                </if>
+                <if test="insOrdersParam.biPremium != null">
+                    AND iorco.sy_premium = #{insOrdersParam.biPremium}
+                </if>
+                <if test="insOrdersParam.niPremium != null">
+                    AND iorco.jy_premium = #{insOrdersParam.niPremium}
+                </if>
+                <if test="insOrdersParam.vvTax != null">
+                    AND iorco.tax_premium = #{insOrdersParam.vvTax}
+                </if>
+                <if test="insOrdersParam.salesmanInfo != null and insOrdersParam.salesmanInfo != ''">
+                    AND su.username = #{insOrdersParam.salesmanInfo}
+                </if>
+                <if test="insOrdersParam.salesmanType != null and insOrdersParam.salesmanType != ''">
+                    AND sujis.type_attr = #{insOrdersParam.salesmanType}
+                </if>
+                <if test="insOrdersParam.agreementName != null and insOrdersParam.agreementName != ''">
+                    AND pa.agreement_name = #{insOrdersParam.agreementName}
+                </if>
+                <if test="insOrdersParam.deptId != null and insOrdersParam.deptId != ''">
+                    AND sd.id = #{insOrdersParam.deptId}
+                </if>
+                <if test="insOrdersParam.deptName != null and insOrdersParam.deptName != ''">
+                    AND sd.name = #{insOrdersParam.deptName}
+                </if>
+                <if test="insOrdersParam.paymentLink != null and insOrdersParam.paymentLink != ''">
+                    AND io.pay_link = #{insOrdersParam.paymentLink}
+                </if>
+                <if test="insOrdersParam.adjustId != null">
+                    AND ioa.id = #{insOrdersParam.adjustId}
+                </if>
+                <if test="insOrdersParam.adjustPremium != null">
+                    AND ioa1.after_premium = #{insOrdersParam.adjustPremium}
+                </if>
+                <if test="insOrdersParam.startSigningTime != null and insOrdersParam.startSigningTime != ''and insOrdersParam.endSigningTime != null and insOrdersParam.endSigningTime != ''">
+                    AND io.signing_time BETWEEN #{insOrdersParam.startSigningTime} and #{insOrdersParam.endSigningTime}
+                </if>
+                <if test="insOrdersParam.startPayTime != null and insOrdersParam.startPayTime != ''and insOrdersParam.endPayTime != null and insOrdersParam.endPayTime != ''">
+                    AND io.pay_time BETWEEN #{insOrdersParam.startPayTime} and #{insOrdersParam.endPayTime}
+                </if>
+            </where>
+        ) dedup
+        WHERE dedup.rn = 1
+    </select>
+
     <select id="getHistoryQuote" resultType="com.jzg.commons.entity.orders.vo.HistoryQuoteResultVo">
         SELECT t.id as order_no,
                t.license_no

+ 3 - 2
tenant/organization/src/main/java/com/jzg/organization/aop/OrderOperationLogAspect.java

@@ -11,7 +11,7 @@ import com.jzg.commons.entity.orders.po.InsOrdersTrack;
 import com.jzg.commons.entity.quote.vo.aggregated.QuoteEchoVo;
 import com.jzg.commons.entity.vo.QuestionOrder;
 import com.jzg.commons.util.JsonDiffUtil;
-import com.jzg.commons.util.OrderComponents;
+import com.jzg.commons.util.SchemaDescriptionParser;
 import com.jzg.organization.client.InsOrdersClient;
 import com.jzg.quotation.summary.aop.aspect.OrderOperationLog;
 import org.aspectj.lang.ProceedingJoinPoint;
@@ -160,7 +160,8 @@ public class OrderOperationLogAspect {
             if(CollUtil.isNotEmpty(diffMap)){
                 List<String> oldItems = new ArrayList<>();
                 List<String> newItems = new ArrayList<>();
-                Map<String,String> keyMap = OrderComponents.fillKeyNameMap();
+                //Map<String,String> keyMap = OrderComponents.fillKeyNameMap();
+                Map<String,String> keyMap = SchemaDescriptionParser.getSchemaMap();
                 diffMap.forEach((path, values) ->{
                             System.out.println("路径: " + path + " -> 值1: " + values.get(0) + " | 值2: " + values.get(1));
                             oldItems.add(keyMap.getOrDefault(path,path)  + ": " + values.get(0));

+ 10 - 0
tenant/organization/src/main/java/com/jzg/organization/controller/AreaController.java

@@ -2,6 +2,7 @@ package com.jzg.organization.controller;
 
 import com.jzg.commons.aop.PremissionCheck;
 import com.jzg.commons.core.page.HttpResult;
+import com.jzg.commons.entity.po.SysArea;
 import com.jzg.commons.entity.vo.PersonAreaVo;
 import com.jzg.commons.entity.vo.SysAreaVo;
 import com.jzg.organization.service.SysAreaService;
@@ -35,4 +36,13 @@ public class AreaController {
                                                    @RequestParam("idCard") String idCard) {
         return HttpResult.ok(sysAreaService.queryByAddress(address, idCard));
     }
+
+    @Schema(description = "根据县获取省市县类型")
+    @GetMapping(value = "queryAllParent")
+    public HttpResult<List<SysArea>> queryAllParent(@RequestParam("countyCode") String countyCode){
+        SysArea sysArea = new SysArea();
+        sysArea.setLevel(3);
+        sysArea.setUpperCode(countyCode);
+        return HttpResult.ok(sysAreaService.queryAllParent(sysArea));
+    }
 }

+ 12 - 10
tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java

@@ -150,7 +150,7 @@ public class ReceivableController {
     /**
      * 导入应收的模板
      *
-     * @param paramVO  20 表示平台协议  11表示车险手续费 12 表示非车险手续费 13 表示车险跟单费 14 表示非车险跟单费
+     * @param paramVO  20 表示平台协议  11表示车险手续费 12 表示非车险手续费 13 表示车险跟单费 14 表示非车险跟单费 (13、14 暂时不需要实现)
      * @author lipf
      * @date 2026/8/3 10:23
      */
@@ -161,17 +161,19 @@ public class ReceivableController {
         return HttpResult.ok(receivablePageIds);
     }
 
-    @PostMapping("/importAccountsReceivableInvoice")
-    @Operation(summary = "导入应收开票数据")
-    public HttpResult<ImportUpdateExcelResultVo> importAccountsReceivableInvoice(@RequestParam("file") MultipartFile file){
-        ImportUpdateExcelResultVo importExcelResultVo = receivableService.importAccountsReceivableInvoice(file);
-        return HttpResult.ok(importExcelResultVo);
-    }
 
+
+    /**
+     * 导入应收开票数据
+     *      私有车险应收/私有非车险应收/平台应收
+     * @author lipf
+     * @date 2026/8/17 17:05
+     */
     @PostMapping("/importPlatformReceivableInvoice")
-    @Operation(summary = "导入平台应收开票数据")
-    public HttpResult<ImportUpdateExcelResultVo> importPlatformReceivableInvoice(@RequestParam("file") MultipartFile file){
-        ImportUpdateExcelResultVo importExcelResultVo = receivableService.importPlatformReceivableInvoice(file);
+    @Operation(summary = "导入应收开票数据")
+    public HttpResult<ImportUpdateExcelResultVo> importPlatformReceivableInvoice(@RequestParam("file") MultipartFile file,
+                                                                                @RequestParam(value = "type",required = false) String type){
+        ImportUpdateExcelResultVo importExcelResultVo = receivableService.importPlatformReceivableInvoice(file, type);
         return HttpResult.ok(importExcelResultVo);
     }
 

+ 4 - 0
tenant/organization/src/main/java/com/jzg/organization/controller/UserController.java

@@ -363,5 +363,9 @@ public class UserController extends BaseController {
         return HttpResult.ok(sysUserService.querySysUserByUserName(userName));
     }
 
+    @GetMapping("/querySysUserByMobile")
+    public HttpResult<SysUser> querySysUserByMobile(@RequestParam("mobile") String mobile){
+        return HttpResult.ok(sysUserService.querySysUserByMobile(mobile));
+    }
 
 }

+ 40 - 0
tenant/organization/src/main/java/com/jzg/organization/excel/listener/InvoiceReceivbleExcel4AllListener.java

@@ -0,0 +1,40 @@
+package com.jzg.organization.excel.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.jzg.commons.entity.finance.vo.importimcome.InsuranceData;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Excel 数据统一读取监听器。
+ * <p>
+ * 该监听器为泛型设计,可统一处理所有实现了 {@link InsuranceData} 的实体,
+ * 例如车险/非车险/平台应收等不同实体:{@code ExcelContent4PrivateSuperviseCar}、
+ * {@code ExcelContent4PrivateSuperviseNoCar}、{@code ExcelContent4Platform} 等。
+ * </p>
+ *
+ * @author lipf
+ * @date 2026/8/17 15:40
+ */
+@Getter
+public class InvoiceReceivbleExcel4AllListener<T extends InsuranceData> extends AnalysisEventListener<T> {
+
+    private final List<T> dataList = new ArrayList<>();
+
+    @Override
+    public void invoke(T data, AnalysisContext context) {
+        dataList.add(data);
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext context) {
+        System.out.println("Total rows: " + dataList.size());
+    }
+
+    public List<T> getDataList() {
+        return dataList;
+    }
+}

+ 0 - 25
tenant/organization/src/main/java/com/jzg/organization/excel/listener/InvoiceReceivbleExcel4PlatformListener.java

@@ -1,25 +0,0 @@
-package com.jzg.organization.excel.listener;
-
-import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.event.AnalysisEventListener;
-import com.jzg.commons.entity.finance.vo.importimcome.ExcelContent4Platform;
-import lombok.Getter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Getter
-public class InvoiceReceivbleExcel4PlatformListener extends AnalysisEventListener<ExcelContent4Platform> {
-    private final List<ExcelContent4Platform> dataList = new ArrayList<>();
-
-    @Override
-    public void invoke(ExcelContent4Platform data, AnalysisContext context) {
-        dataList.add(data);
-    }
-
-    @Override
-    public void doAfterAllAnalysed(AnalysisContext context) {
-        System.out.println("Total rows: " + dataList.size());
-    }
-
-}

+ 0 - 28
tenant/organization/src/main/java/com/jzg/organization/excel/listener/InvoiceReceivbleExcel4PrivateListener.java

@@ -1,28 +0,0 @@
-package com.jzg.organization.excel.listener;
-
-import com.alibaba.excel.context.AnalysisContext;
-import com.alibaba.excel.event.AnalysisEventListener;
-import com.jzg.commons.entity.finance.vo.importimcome.ExcelContent4PrivateSuperviseNoCar;
-import lombok.Getter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Getter
-public class InvoiceReceivbleExcel4PrivateListener extends AnalysisEventListener<ExcelContent4PrivateSuperviseNoCar> {
-    private final List<ExcelContent4PrivateSuperviseNoCar> dataList = new ArrayList<>();
-
-    @Override
-    public void invoke(ExcelContent4PrivateSuperviseNoCar data, AnalysisContext context) {
-        dataList.add(data);
-    }
-
-    @Override
-    public void doAfterAllAnalysed(AnalysisContext context) {
-        System.out.println("Total rows: " + dataList.size());
-    }
-
-    public List<ExcelContent4PrivateSuperviseNoCar> getDataList() {
-        return dataList;
-    }
-}

+ 8 - 0
tenant/organization/src/main/java/com/jzg/organization/mapper/ReceivableMapper.java

@@ -284,6 +284,14 @@ public interface ReceivableMapper extends BaseMapper<InsPlyIncome> {
      */
     InsPlyIncomeInvoiceSettlementVo querySettledAmountByInvoiceIds(@Param("invoiceIdList") List<String> invoiceIdList);
 
+    /**
+     * 查询未结清发票数量(status=0的发票数量)
+     *
+     * @param invoiceIdList 发票ID列表
+     * @return 未结清发票数量
+     */
+    int countUnsettledInvoicesByInvoiceIds(@Param("invoiceIdList") List<String> invoiceIdList);
+
     List<PlatformCompanyFeeVO> selectPlatformCompanySettlementReport(@Param("query") SettlementReportQueryVo settlementReportQueryVo);
 
     /**

+ 1 - 1
tenant/organization/src/main/java/com/jzg/organization/mapper/SysUserAccountIncomeLogMapper.java

@@ -72,7 +72,7 @@ public interface SysUserAccountIncomeLogMapper extends BaseMapper<SysUserAccount
                 5 AS oper_type,
                 NULL AS related_order_id,
                 NULL AS bank_card_id_to,
-                NULL AS bank_card_no_to,
+                saa.bank_card_num AS bank_card_no_to,
                 NULL AS bank_card_id_in,
                 NULL AS bank_card_no_in,
                 NULL AS is_delete,

+ 1 - 8
tenant/organization/src/main/java/com/jzg/organization/service/ReceivableService.java

@@ -442,14 +442,7 @@ public interface ReceivableService extends IService<InsPlyIncome> {
      * @param file
      * @return
      */
-    ImportUpdateExcelResultVo importAccountsReceivableInvoice(MultipartFile file);
-
-    /**
-     * 导入应收开票数据
-     * @param file
-     * @return
-     */
-    ImportUpdateExcelResultVo importPlatformReceivableInvoice(MultipartFile file);
+    ImportUpdateExcelResultVo importPlatformReceivableInvoice(MultipartFile file, String type);
 
     /**
      * 删除结算记录

+ 7 - 0
tenant/organization/src/main/java/com/jzg/organization/service/SysUserService.java

@@ -303,4 +303,11 @@ public interface SysUserService extends IService<SysUser> {
      * @date 2026/7/10 15:04
      */
     SysUser querySysUserByUserName(String userName);
+
+    /**
+     * 根据用户手机号查询sysUser对象
+     * @param mobile
+     * @return
+     */
+    SysUser querySysUserByMobile(String mobile);
 }

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

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

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

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

+ 73 - 135
tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java

@@ -2534,143 +2534,16 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                 "应收开票-导出模板(平台)-" + Instant.now());
     }
 
-    /**
-     * 导入应收开票数据
-     * <p>
-     * 该方法用于从Excel文件中导入并处理应收开票数据,支持新增和更新操作,包括以下处理逻辑:
-     * 1. 解析Excel文件获取应收数据列表
-     * 2. 获取所有保险公司信息用于后续匹配
-     * 3. 校验Excel内部保单号是否重复
-     * 4. 校验导入数据是否只包含一个保险公司
-     * 5. 遍历每条数据进行以下校验和处理:
-     *    - 检查必填字段是否为空
-     *    - 检查Excel内部保单号是否重复
-     *    - 查询订单是否存在
-     *    - 验证协议编码和类型是否匹配
-     *    - 构建InsPlyIncome对象并设置相关信息
-     *    - 如果数据库中不存在该保单号,则作为新增记录处理
-     *    - 如果数据库中存在该保单号,检查是否已结算,未结算则作为更新记录处理
-     * 6. 批量插入或更新成功的记录到数据库
-     * 7. 如果有失败数据,生成失败数据Excel文件并提供下载链接
-     * 8. 返回导入结果(包含成功数、失败数、失败数据、下载链接和成功的订单号列表)
-     * </p>
-     *
-     * @param file Excel文件,包含应收开票数据,文件格式应符合InvoiceReceivableExportExcelVo的定义
-     * @return ImportUpdateExcelResultVo 返回导入结果对象,包含:
-     *         - successNumber: 成功导入的记录数(新增或更新)
-     *         - failedNumber: 失败的记录数
-     *         - failedData: 失败的数据列表,包含错误原因说明
-     *         - failFileUrl: 失败数据Excel文件的下载链接(如果有失败数据)
-     *         - orderNos: 成功导入的订单号列表
-     */
-    @Override
-    public ImportUpdateExcelResultVo importAccountsReceivableInvoice(MultipartFile file) {
-        String userName = baseController.getUserName();
-        log.info("用户[{}]导入私有应设有文件",userName);
-
-        List<ExcelContent4PrivateSuperviseNoCar> excelContents = importIncomeService.parseImportExcel4Private(file);
-        if (CollUtil.isEmpty(excelContents)){
-            throw new SystemException("数据不能为空,导入失败");
-        }
-        AssertionUtils.isEmpty(excelContents, "数据处理失败,导入失败");
-        List<ImportContentExt> datas = importIncomeService.fillExcelContent4Private(excelContents);
-
-
-        // int failedNumber = 0;
-        List<ImportContentExt> failedExcel = new ArrayList<>();
-        // 只存储需要【修改】的数据
-        List<InsPlyIncome> updateExcel = new ArrayList<>();
-        List<InsPlyIncome> insertExcel = new ArrayList<>();
-        // 存储导入成功的订单号
-        List<String> successOrderNoList = new ArrayList<>();
-
-        // 校验Excel内部保单号重复
-        Set<String> existPolicyNoSet = new HashSet<>();
-        Set<String> repeatPolicyNoSet = new HashSet<>();
-        Set<String> existCompanyIdSet = new HashSet<>();
-
-        for (ImportContentExt vo : datas) {
-            String policyNo = vo.getJqPolicyNo();
-            if (existPolicyNoSet.contains(policyNo)) {
-                repeatPolicyNoSet.add(policyNo);
-            } else {
-                existPolicyNoSet.add(policyNo);
-            }
-            existCompanyIdSet.add(vo.getCompanyName());
-        }
-
-        // 导入只能一个保司
-        if (existCompanyIdSet.size() > 1) {
-            throw new SystemException("导入数据不能包含多个保险公司");
-        }
-
-        // 处理数据
-        for (ImportContentExt vo : datas) {
-            // 1. 空数据校验
-            ImportResultVo resultVo = vo.checkEmpty();
-            if (!resultVo.isSuccess()) {
-                vo.setErrorMessage(resultVo.convert2Str());
-                failedExcel.add(vo);
-                continue;
-            }
-
-            // 2. Excel内部保单号重复
-            if (repeatPolicyNoSet.contains(vo.getJqPolicyNo())) {
-                vo.setErrorMessage("保单号重复");
-                failedExcel.add(vo);
-                continue;
-            }
-
-            // 查询订单
-            HttpResult<InsOrdersVo> insOrdersVoHttpResult = insOrdersClient.selectById(vo.getOrderNo());
-            InsOrdersVo data = insOrdersVoHttpResult.getData();
-            if (null == data){
-                vo.setErrorMessage("订单号不存在");
-                failedExcel.add(vo);
-                continue;
-            }
-
-            // 查询数据库中是否已存在该协议
-            PtlAgreement ptlAgreement = ptlAgreementMapper.selectOne(new LambdaQueryWrapper<PtlAgreement>()
-                    .eq(PtlAgreement::getId, data.getAgreementId()));
-
-            // 数据库不存在 → 直接失败
-            if (Objects.isNull(ptlAgreement) || !"2".equals(ptlAgreement.getAgreementType().toString())) {
-                vo.setErrorMessage("协议编码在协议中不存在");
-                failedExcel.add(vo);
-                continue;
-            }
-
-            // 查询数据库中是否已存在该保单号
-            ImportContentExt failedVO = importIncomeService.spliceData(vo, insertExcel, updateExcel);
-            if(failedVO != null){
-                failedExcel.add(failedVO);
-            }
-        }
-        ImportUpdateExcelResultVo importExcelResultVo = importIncomeService.getDataManipulationResult(updateExcel, insertExcel, failedExcel);
-        log.info("私有应收:导入结果。importExcelResultVo=[{}]", JSONUtil.toJsonStr(importExcelResultVo));
-        return importExcelResultVo;
-    }
-
     /**
      * 导入平台的应收数据
      * @param file
      * @return
      */
     @Override
-    public ImportUpdateExcelResultVo importPlatformReceivableInvoice(MultipartFile file) {
+    public ImportUpdateExcelResultVo importPlatformReceivableInvoice(MultipartFile file, String type) {
         String userName = baseController.getUserName();
         log.info("用户[{}]导入平台应收文件",userName);
-
-        List<ExcelContent4Platform> excelContents = importIncomeService.parseImportExcel4Platform(file);
-        log.info("从Excel文件中读取到[{}]条记录", CollUtil.size(excelContents));
-        if (CollUtil.isEmpty(excelContents)){
-            log.error("用户[{}]导入平台应收文件,数据不能为空,导入失败",userName);
-            throw new SystemException("数据不能为空,导入失败");
-        }
-        AssertionUtils.isEmpty(excelContents, "数据处理失败,导入失败");
-        List<ImportContentExt> datas = importIncomeService.fillExcelContent4Platform(excelContents);
-
+        List<ImportContentExt> datas = this.parseAndFillContent(file, type);
         // 只存储需要【修改】的数据
         List<InsPlyIncome> updateExcel = new ArrayList<>();
         List<InsPlyIncome> insertExcel = new ArrayList<>();
@@ -2726,6 +2599,33 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         return importExcelResultVo;
     }
 
+    /**
+     * 解析Excel内容并填充缺失的字段
+     *
+     * @param type 类型 20 表示平台协议  11表示车险手续费 12 表示非车险手续费
+     * @param file 上传的文件
+     * @author lipf
+     * @date 2026/8/17 16:57
+     */
+    private List<ImportContentExt> parseAndFillContent(MultipartFile file, String type) {
+        log.info("解析Excel内容并填充缺失的字段. type=[{}]", type);
+
+        if("11".equals(type)){
+            List<ExcelContent4PrivateSuperviseCar> excelContents2 = importIncomeService.parseImportExcel4PrivateCar(file);
+            return importIncomeService.fillExcelContent4All(excelContents2);
+        } if("12".equals(type)){
+            List<ExcelContent4PrivateSuperviseNoCar> excelContents3 = importIncomeService.parseImportExcel4PrivateNoCar(file);
+            return importIncomeService.fillExcelContent4All(excelContents3);
+//        } if("20".equals(type)){
+//            List<ExcelContent4Platform> excelContents = importIncomeService.parseImportExcel4Platform(file);
+//            return importIncomeService.fillExcelContent4All(excelContents);
+        }else{
+            List<ExcelContent4Platform> excelContents = importIncomeService.parseImportExcel4Platform(file);
+            return importIncomeService.fillExcelContent4All(excelContents);
+//            log.info("解析Excel内容并填充缺失的字段.类型不支持 type=[{}]", type);
+//            return Collections.emptyList();
+        }
+    }
 
 
     /**
@@ -3941,12 +3841,24 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             // updateAgreementId不为空时,从ins_ply_income(income)查询比例覆盖batchModifyVo,用于后续calRatio和calPremium计算
             // ins_ply_income中的比例是字符串形式的小数值(如"0.20000"),转为BigDecimal后与batchModifyVo.divide100()后的格式一致
             if (StrUtil.isNotBlank(updateAgreementId)) {
-                batchModifyVo.setJqSuperviseCostsProportion(StrUtil.isNotBlank(income.getJqSuperviseCostsProportion()) ? new BigDecimal(income.getJqSuperviseCostsProportion()) : BigDecimal.ZERO);
-                batchModifyVo.setJqOtherCostsProportion(StrUtil.isNotBlank(income.getJqOtherCostsProportion()) ? new BigDecimal(income.getJqOtherCostsProportion()) : BigDecimal.ZERO);
-                batchModifyVo.setSySuperviseCostsProportion(StrUtil.isNotBlank(income.getSySuperviseCostsProportion()) ? new BigDecimal(income.getSySuperviseCostsProportion()) : BigDecimal.ZERO);
-                batchModifyVo.setSyOtherCostsProportion(StrUtil.isNotBlank(income.getSyOtherCostsProportion()) ? new BigDecimal(income.getSyOtherCostsProportion()) : BigDecimal.ZERO);
-                batchModifyVo.setJySuperviseCostsProportion(StrUtil.isNotBlank(income.getJySuperviseCostsProportion()) ? new BigDecimal(income.getJySuperviseCostsProportion()) : BigDecimal.ZERO);
-                batchModifyVo.setJyOtherCostsProportion(StrUtil.isNotBlank(income.getJyOtherCostsProportion()) ? new BigDecimal(income.getJyOtherCostsProportion()) : BigDecimal.ZERO);
+                if (null == batchModifyVo.getJqSuperviseCostsProportion() || BigDecimal.ZERO.compareTo(batchModifyVo.getJqSuperviseCostsProportion()) == 0){
+                    batchModifyVo.setJqSuperviseCostsProportion(StrUtil.isNotBlank(income.getJqSuperviseCostsProportion()) ? new BigDecimal(income.getJqSuperviseCostsProportion()) : BigDecimal.ZERO);
+                }
+                if (null == batchModifyVo.getJqOtherCostsProportion() || BigDecimal.ZERO.compareTo(batchModifyVo.getJqOtherCostsProportion()) == 0) {
+                    batchModifyVo.setJqOtherCostsProportion(StrUtil.isNotBlank(income.getJqOtherCostsProportion()) ? new BigDecimal(income.getJqOtherCostsProportion()) : BigDecimal.ZERO);
+                }
+                if (null == batchModifyVo.getSySuperviseCostsProportion() || BigDecimal.ZERO.compareTo(batchModifyVo.getSySuperviseCostsProportion()) == 0) {
+                    batchModifyVo.setSySuperviseCostsProportion(StrUtil.isNotBlank(income.getSySuperviseCostsProportion()) ? new BigDecimal(income.getSySuperviseCostsProportion()) : BigDecimal.ZERO);
+                }
+                if (null == batchModifyVo.getSyOtherCostsProportion() || BigDecimal.ZERO.compareTo(batchModifyVo.getSyOtherCostsProportion()) == 0) {
+                    batchModifyVo.setSyOtherCostsProportion(StrUtil.isNotBlank(income.getSyOtherCostsProportion()) ? new BigDecimal(income.getSyOtherCostsProportion()) : BigDecimal.ZERO);
+                }
+                if (null == batchModifyVo.getJySuperviseCostsProportion() || BigDecimal.ZERO.compareTo(batchModifyVo.getJySuperviseCostsProportion()) == 0) {
+                    batchModifyVo.setJySuperviseCostsProportion(StrUtil.isNotBlank(income.getJySuperviseCostsProportion()) ? new BigDecimal(income.getJySuperviseCostsProportion()) : BigDecimal.ZERO);
+                }
+                if (null == batchModifyVo.getJyOtherCostsProportion() || BigDecimal.ZERO.compareTo(batchModifyVo.getJyOtherCostsProportion()) == 0) {
+                    batchModifyVo.setJyOtherCostsProportion(StrUtil.isNotBlank(income.getJyOtherCostsProportion()) ? new BigDecimal(income.getJyOtherCostsProportion()) : BigDecimal.ZERO);
+                }
                 log.info("切换协议后,从ins_ply_income查询比例覆盖batchModifyVo。orderNo=[{}], batchModifyVo=[{}]", income.getOrderNo(), JSONUtil.toJsonStr(batchModifyVo));
             }
 
@@ -6413,6 +6325,32 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                     records = records.stream().filter(action-> !"0".equals(action.getUnSettledAmount())).toList();
                 }
             }
+            // 根据结算状态过滤:0-已开票未结清 1-已结清 2-未开票
+            if(StrUtil.isNotEmpty(settlementReportQueryVo.getSettlementStatus())){
+                String settlementStatus = settlementReportQueryVo.getSettlementStatus();
+                if("2".equals(settlementStatus)){
+                    // 未开票:ins_ply_income_invoice没有数据
+                    records = records.stream().filter(action -> StrUtil.isEmpty(action.getInvoiceIds())).toList();
+                } else if("0".equals(settlementStatus)){
+                    // 已开票未结清:有发票数据,且存在status=0的发票
+                    records = records.stream().filter(action -> {
+                        if(StrUtil.isEmpty(action.getInvoiceIds())){
+                            return false;
+                        }
+                        List<String> invoiceIdList = Arrays.asList(action.getInvoiceIds().split(","));
+                        return baseMapper.countUnsettledInvoicesByInvoiceIds(invoiceIdList) > 0;
+                    }).toList();
+                } else if("1".equals(settlementStatus)){
+                    // 已结清:有发票数据,且所有发票status=1
+                    records = records.stream().filter(action -> {
+                        if(StrUtil.isEmpty(action.getInvoiceIds())){
+                            return false;
+                        }
+                        List<String> invoiceIdList = Arrays.asList(action.getInvoiceIds().split(","));
+                        return baseMapper.countUnsettledInvoicesByInvoiceIds(invoiceIdList) == 0;
+                    }).toList();
+                }
+            }
             receiverSettlementReport.setRecords(records);
         }
         return receiverSettlementReport;

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

@@ -1678,6 +1678,12 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
                 .eq(SysUser::getUsername,userName));
     }
 
+    @Override
+    public SysUser querySysUserByMobile(String mobile) {
+        return baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+                .eq(SysUser::getMobile,mobile));
+    }
+
 }
 
 

+ 41 - 16
tenant/organization/src/main/java/com/jzg/organization/service/impl/importincome/ImportIncomeServiceImpl.java

@@ -9,18 +9,14 @@ import com.jzg.commons.constants.ProductsType;
 import com.jzg.commons.core.base.BaseController;
 import com.jzg.commons.core.page.HttpResult;
 import com.jzg.commons.entity.finance.po.InsPlyIncome;
-import com.jzg.commons.entity.finance.vo.importimcome.ExcelContent4PrivateSuperviseNoCar;
-import com.jzg.commons.entity.finance.vo.importimcome.ImportUpdateExcelResultVo;
-import com.jzg.commons.entity.finance.vo.importimcome.ExcelContent4Platform;
-import com.jzg.commons.entity.finance.vo.importimcome.ImportContentExt;
+import com.jzg.commons.entity.finance.vo.importimcome.*;
 import com.jzg.commons.entity.orders.po.InsOrdersPolicy;
 import com.jzg.commons.entity.quote.vo.orders.InsOrdersVo;
 import com.jzg.commons.entity.vo.AgreementVo;
 import com.jzg.commons.entity.vo.InsFeeOrdersVo;
 import com.jzg.commons.util.idgen.IdGenerate;
 import com.jzg.organization.client.InsOrdersClient;
-import com.jzg.organization.excel.listener.InvoiceReceivbleExcel4PlatformListener;
-import com.jzg.organization.excel.listener.InvoiceReceivbleExcel4PrivateListener;
+import com.jzg.organization.excel.listener.InvoiceReceivbleExcel4AllListener;
 import com.jzg.organization.mapper.InsOrdersPolicyMapper;
 import com.jzg.organization.mapper.InsPlyIncomeMapper;
 import com.jzg.organization.mapper.PtlAgreementMapper;
@@ -196,18 +192,24 @@ public class ImportIncomeServiceImpl implements ImportIncomeService {
 
     /**
      * 对表格中的内容进行扩展
+     * <p>
+     * 支持同时传入不同的 {@link InsuranceData} 实现类集合(如平台、私有车险、私有非车险),
+     * 统一进行数据扩展处理。
+     * </p>
      *
+     * @param excelContents {@link InsuranceData} 实现类集合
+     * @return 扩展后的数据列表
      * @author lipf
      * @date 2026/8/4 9:22
      */
     @Override
-    public List<ImportContentExt> fillExcelContent4Platform(List<ExcelContent4Platform> excelContents) {
+    public <T extends InsuranceData> List<ImportContentExt> fillExcelContent4All(List<T> excelContents) {
         log.info("填充excel中没有的内容: excelContents.size=[{}]", CollUtil.size(excelContents));
         if(CollUtil.isEmpty(excelContents)){
             return Collections.emptyList();
         }
         List<ImportContentExt> res = new ArrayList<>();
-        for (ExcelContent4Platform excelContent : excelContents) {
+        for (InsuranceData excelContent : excelContents) {
             ImportContentExt ext = new ImportContentExt();
             BeanUtil.copyProperties(excelContent,ext);
             // 查询订单
@@ -250,9 +252,11 @@ public class ImportIncomeServiceImpl implements ImportIncomeService {
                     ext.setSigningTime(data.getSigningTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                 }
                 String agreementId = data.getAgreementId();
-                AgreementVo agreementVo = ptlAgreementMapper.queryById(agreementId);
-                if(agreementVo != null){
-                    ext.setPartnerCompanyId(agreementVo.getPartnerCompanyId());
+                if(StrUtil.isNotEmpty(agreementId)){
+                    AgreementVo agreementVo = ptlAgreementMapper.queryById(agreementId);
+                    if(agreementVo != null){
+                        ext.setPartnerCompanyId(agreementVo.getPartnerCompanyId());
+                    }
                 }
                 InsFeeOrdersVo feeOrdersVo = data.getFeeOrdersVo();
                 if(BeanUtil.isEmpty(feeOrdersVo)){
@@ -274,14 +278,14 @@ public class ImportIncomeServiceImpl implements ImportIncomeService {
      * @date 2026/8/4 9:07
      */
     public List<ExcelContent4Platform> parseImportExcel4Platform(MultipartFile file) {
-        InvoiceReceivbleExcel4PlatformListener listener = new InvoiceReceivbleExcel4PlatformListener();
+        InvoiceReceivbleExcel4AllListener<ExcelContent4Platform> listener = new InvoiceReceivbleExcel4AllListener<>();
         try (InputStream inputStream = file.getInputStream()) {
             EasyExcel.read(inputStream, ExcelContent4Platform.class, listener)
                     .sheet()
                     .doRead();
             return listener.getDataList();
         } catch (Exception e) {
-            log.error("InvoiceReceivbleExcel4PlatformListenery读取文件异常",e);
+            log.error("InvoiceReceivbleExcel4AllListener处理平台应收数据读取文件异常",e);
             return null;
         }
     }
@@ -292,15 +296,36 @@ public class ImportIncomeServiceImpl implements ImportIncomeService {
      * @author lipf
      * @date 2026/8/4 9:07
      */
-    public List<ExcelContent4PrivateSuperviseNoCar> parseImportExcel4Private(MultipartFile file) {
-        InvoiceReceivbleExcel4PrivateListener listener = new InvoiceReceivbleExcel4PrivateListener();
+    public List<ExcelContent4PrivateSuperviseNoCar> parseImportExcel4PrivateNoCar(MultipartFile file) {
+        InvoiceReceivbleExcel4AllListener<ExcelContent4PrivateSuperviseNoCar> listener = new InvoiceReceivbleExcel4AllListener<>();
         try (InputStream inputStream = file.getInputStream()) {
             EasyExcel.read(inputStream, ExcelContent4PrivateSuperviseNoCar.class, listener)
                     .sheet()
                     .doRead();
             return listener.getDataList();
         } catch (Exception e) {
-            log.error("InvoiceReceivbleExcel4PlatformListenery读取文件异常",e);
+            log.error("InvoiceReceivbleExcel4AllListener处理私有非车险数据读取文件异常",e);
+            return null;
+        }
+    }
+
+    /**
+     * 私有车险数据导入
+     *
+     * @param file
+     * @author lipf
+     * @date 2026/8/17 15:38
+     */
+    @Override
+    public List<ExcelContent4PrivateSuperviseCar> parseImportExcel4PrivateCar(MultipartFile file) {
+        InvoiceReceivbleExcel4AllListener<ExcelContent4PrivateSuperviseCar> listener = new InvoiceReceivbleExcel4AllListener<>();
+        try (InputStream inputStream = file.getInputStream()) {
+            EasyExcel.read(inputStream, ExcelContent4PrivateSuperviseCar.class, listener)
+                    .sheet()
+                    .doRead();
+            return listener.getDataList();
+        } catch (Exception e) {
+            log.error("parseImportExcel4PrivateCar读取文件异常",e);
             return null;
         }
     }

+ 17 - 6
tenant/organization/src/main/java/com/jzg/organization/service/importincome/ImportIncomeService.java

@@ -1,10 +1,7 @@
 package com.jzg.organization.service.importincome;
 
 import com.jzg.commons.entity.finance.po.InsPlyIncome;
-import com.jzg.commons.entity.finance.vo.importimcome.ExcelContent4PrivateSuperviseNoCar;
-import com.jzg.commons.entity.finance.vo.importimcome.ImportUpdateExcelResultVo;
-import com.jzg.commons.entity.finance.vo.importimcome.ExcelContent4Platform;
-import com.jzg.commons.entity.finance.vo.importimcome.ImportContentExt;
+import com.jzg.commons.entity.finance.vo.importimcome.*;
 import org.springframework.stereotype.Service;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -15,11 +12,17 @@ public interface ImportIncomeService {
 
     /**
      * 对表格中的内容进行扩展
+     * <p>
+     * 支持同时传入不同的 {@link InsuranceData} 实现类集合(如平台、私有车险、私有非车险),
+     * 统一进行数据扩展处理。
+     * </p>
      *
+     * @param excelContents {@link InsuranceData} 实现类集合
+     * @return 扩展后的数据列表
      * @author lipf
      * @date 2026/8/4 9:22
      */
-    public List<ImportContentExt> fillExcelContent4Platform(List<ExcelContent4Platform> excelContents);
+    <T extends InsuranceData> List<ImportContentExt> fillExcelContent4All(List<T> excelContents);
 
     /**
      * 对表格中的内容进行扩展
@@ -60,7 +63,15 @@ public interface ImportIncomeService {
      * @author lipf
      * @date 2026/8/4 9:07
      */
-    public List<ExcelContent4PrivateSuperviseNoCar> parseImportExcel4Private(MultipartFile file);
+    public List<ExcelContent4PrivateSuperviseNoCar> parseImportExcel4PrivateNoCar(MultipartFile file);
+
+    /**
+     * 私有车险数据导入
+     *
+     * @author lipf
+     * @date 2026/8/17 15:38
+     */
+    public List<ExcelContent4PrivateSuperviseCar> parseImportExcel4PrivateCar(MultipartFile file);
 
     /**
      * 解析并读取Excel中的内容

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

@@ -33,7 +33,7 @@
         ipiis.invoice_id = ipii.id
         <where>
             ipii.invoice_type in (5, 6)
-            and ipiis.receive_payment_date &gt;= #{vo.settlementStartTime} and ipiis.receive_payment_date &lt;= #{vo.settlementEndTime}
+            and ipiis.create_time &gt;= #{vo.settlementStartTime} and ipiis.create_time &lt;= #{vo.settlementEndTime}
             <if test="vo.contactPerson != null and vo.contactPerson != ''">
                 and ipii.contact_person = #{vo.contactPerson}
             </if>

+ 16 - 0
tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

@@ -2198,6 +2198,22 @@
         </where>
     </select>
 
+    <!-- 查询未结清发票数量(status=0的发票数量) -->
+    <select id="countUnsettledInvoicesByInvoiceIds" resultType="int">
+        select count(1)
+        from ins_ply_income_invoice ipii
+        <where>
+            ipii.is_delete = 0
+            and ipii.status = 0
+            <if test="invoiceIdList != null and invoiceIdList.size() > 0">
+                and ipii.id in
+                <foreach collection="invoiceIdList" item="item" open="(" separator="," close=")">
+                    ${item}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
 
     <select id="selectPlatformCompanySettlementReport" resultType="com.jzg.commons.entity.finance.vo.PlatformCompanyFeeVO">
         SELECT