Ver código fonte

Merge remote-tracking branch 'origin/master'

wanghao 3 meses atrás
pai
commit
9b38dbc684
32 arquivos alterados com 785 adições e 269 exclusões
  1. 5 1
      commons/src/main/java/com/jzg/commons/entity/finance/vo/FollowCompanyFeeVO.java
  2. 4 0
      commons/src/main/java/com/jzg/commons/entity/finance/vo/PlatformCompanyFeeVO.java
  3. 70 19
      commons/src/main/java/com/jzg/commons/util/FileUtils.java
  4. 152 4
      commons/src/main/java/com/jzg/commons/util/ImageUtil.java
  5. 73 34
      platform/src/main/java/com/jzg/controller/FileUploadController.java
  6. 8 1
      platform/src/main/java/com/jzg/service/impl/PtlAgreementAttributionImpl.java
  7. 9 0
      tenant/insurance/quotation-commons/src/main/java/com/jzg/quotation/commons/client/OrgClient.java
  8. 2 1
      tenant/insurance/quotation-dajia/src/main/java/com/jzg/quotation/dajia/crawler/entity/request/DaJiaCrawlerPriceRequest.java
  9. 2 2
      tenant/insurance/quotation-dajia/src/main/java/com/jzg/quotation/dajia/crawler/entity/request/quote/DriveInsuranceDTO.java
  10. 1 1
      tenant/insurance/quotation-guoren/src/main/java/com/jzg/quotation/guoren/crawler/build/GuoRenCrawlerQuoteResultsVoBuild.java
  11. 130 149
      tenant/insurance/quotation-huatai/src/main/java/com/jzg/quotation/huatai/crawler/service/Impl/HuaTaiCrawlerRequestImpl.java
  12. 26 0
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/client/SysUserClient.java
  13. 109 19
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeAuditServiceImpl.java
  14. 30 9
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeOrdersServiceImpl.java
  15. 2 2
      tenant/insurance/quotation-summary/src/main/resources/mapper/InsFeeAuditMapper.xml
  16. 3 1
      tenant/insurance/quotation-zijin/src/main/java/com/jzg/quotation/zijin/crawler/build/ZiJinCrawlerUnderwritingResultsVoBuild.java
  17. 1 2
      tenant/insurance/quotation-zijin/src/main/java/com/jzg/quotation/zijin/crawler/service/impl/ZiJinCrawlerRequestImpl.java
  18. 1 1
      tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java
  19. 16 0
      tenant/organization/src/main/java/com/jzg/organization/controller/SysUserJzgInfoController.java
  20. 15 0
      tenant/organization/src/main/java/com/jzg/organization/controller/UserController.java
  21. 11 1
      tenant/organization/src/main/java/com/jzg/organization/mapper/InsPlyIncomeInvoiceSettlementMapper.java
  22. 1 1
      tenant/organization/src/main/java/com/jzg/organization/mapper/ReceivableMapper.java
  23. 1 1
      tenant/organization/src/main/java/com/jzg/organization/service/ReceivableService.java
  24. 9 0
      tenant/organization/src/main/java/com/jzg/organization/service/SysUserJzgInfoService.java
  25. 8 0
      tenant/organization/src/main/java/com/jzg/organization/service/SysUserService.java
  26. 4 1
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementServiceImpl.java
  27. 18 9
      tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java
  28. 29 0
      tenant/organization/src/main/java/com/jzg/organization/service/impl/SysUserJzgInfoServiceImpl.java
  29. 11 0
      tenant/organization/src/main/java/com/jzg/organization/service/impl/SysUserServiceImpl.java
  30. 23 0
      tenant/organization/src/main/resources/mapper/InsPlyIncomeInvoiceSettlementMapper.xml
  31. 10 9
      tenant/organization/src/main/resources/mapper/ReceivableMapper.xml
  32. 1 1
      tenant/organization/src/main/resources/mapper/SysUserJzgInfoBankCardMapper.xml

+ 5 - 1
commons/src/main/java/com/jzg/commons/entity/finance/vo/FollowCompanyFeeVO.java

@@ -1,6 +1,5 @@
 package com.jzg.commons.entity.finance.vo;
 package com.jzg.commons.entity.finance.vo;
 
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.Data;
 
 
@@ -37,6 +36,11 @@ public class FollowCompanyFeeVO {
     /** 未结算总金额  totalInvoiced - totalSettlementAmount */
     /** 未结算总金额  totalInvoiced - totalSettlementAmount */
     private BigDecimal totalUnSettlementAmount;
     private BigDecimal totalUnSettlementAmount;
 
 
+    /**
+     * 已结算记录的序号集
+     */
+    private String settleIdsStr;
+
     /** 回款差额 */
     /** 回款差额 */
     private BigDecimal totalPaymentDifference;
     private BigDecimal totalPaymentDifference;
 
 

+ 4 - 0
commons/src/main/java/com/jzg/commons/entity/finance/vo/PlatformCompanyFeeVO.java

@@ -0,0 +1,4 @@
+package com.jzg.commons.entity.finance.vo;
+
+public class PlatformCompanyFeeVO extends FollowCompanyFeeVO{
+}

+ 70 - 19
commons/src/main/java/com/jzg/commons/util/FileUtils.java

@@ -8,9 +8,18 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchAlgorithmException;
 import java.util.Formatter;
 import java.util.Formatter;
 
 
+/**
+ * 文件工具类
+ * 提供文件哈希值计算(MD5、ETag)等功能
+ */
 public class FileUtils {
 public class FileUtils {
 
 
-    // 将字节数组转换为十六进制字符串
+    /**
+     * 将字节数组转换为十六进制字符串
+     *
+     * @param byteArray 字节数组
+     * @return 十六进制字符串
+     */
     private static String byteArrayToHex(byte[] byteArray) {
     private static String byteArrayToHex(byte[] byteArray) {
         try (Formatter formatter = new Formatter()) {
         try (Formatter formatter = new Formatter()) {
             for (byte b : byteArray) {
             for (byte b : byteArray) {
@@ -21,11 +30,12 @@ public class FileUtils {
     }
     }
 
 
     /**
     /**
-     * 获取文件ETAG
-     * @param file
-     * @return
-     * @throws NoSuchAlgorithmException
-     * @throws IOException
+     * 获取文件的 ETag(基于 MD5 计算)
+     *
+     * @param file 上传的文件
+     * @return 文件的 ETag 值
+     * @throws NoSuchAlgorithmException MD5 算法不可用时抛出
+     * @throws IOException              文件读取失败时抛出
      */
      */
     public static String getFileETag(MultipartFile file) throws NoSuchAlgorithmException, IOException {
     public static String getFileETag(MultipartFile file) throws NoSuchAlgorithmException, IOException {
         MessageDigest md5Digest = MessageDigest.getInstance("MD5");
         MessageDigest md5Digest = MessageDigest.getInstance("MD5");
@@ -44,38 +54,79 @@ public class FileUtils {
     }
     }
 
 
     /**
     /**
-     * 获取文件md5
-     * @param file
-     * @return
-     * @throws IOException
-     * @throws NoSuchAlgorithmException
+     * 获取文件的 MD5 值
+     *
+     * @param file 上传的文件
+     * @return 文件的 MD5 值
+     * @throws IOException              文件读取失败时抛出
+     * @throws NoSuchAlgorithmException MD5 算法不可用时抛出
      */
      */
     public static String getFileMD5(MultipartFile file) throws IOException, NoSuchAlgorithmException {
     public static String getFileMD5(MultipartFile file) throws IOException, NoSuchAlgorithmException {
         // 获取文件输入流
         // 获取文件输入流
         InputStream inputStream = file.getInputStream();
         InputStream inputStream = file.getInputStream();
+        try {
+            return getFileMD5(inputStream);
+        } finally {
+            inputStream.close();
+        }
+    }
 
 
-        // 创建 MessageDigest 对象用于计算 MD5
+    /**
+     * 获取字节数组的 MD5 值
+     * 用于压缩后的图片数据计算哈希值
+     *
+     * @param data 字节数组
+     * @return MD5 值
+     * @throws NoSuchAlgorithmException MD5 算法不可用时抛出
+     */
+    public static String getFileMD5(byte[] data) throws NoSuchAlgorithmException {
         MessageDigest messageDigest = MessageDigest.getInstance("MD5");
         MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+        messageDigest.update(data);
+        byte[] md5Bytes = messageDigest.digest();
+        StringBuilder sb = new StringBuilder();
+        for (byte b : md5Bytes) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
 
 
+    /**
+     * 获取输入流的 MD5 值(内部方法)
+     *
+     * @param inputStream 输入流
+     * @return MD5 值
+     * @throws NoSuchAlgorithmException MD5 算法不可用时抛出
+     * @throws IOException              读取失败时抛出
+     */
+    private static String getFileMD5(InputStream inputStream) throws NoSuchAlgorithmException, IOException {
+        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
         // 使用 1KB 缓冲区读取文件内容
         // 使用 1KB 缓冲区读取文件内容
         byte[] buffer = new byte[1024];
         byte[] buffer = new byte[1024];
         int bytesRead;
         int bytesRead;
         while ((bytesRead = inputStream.read(buffer)) != -1) {
         while ((bytesRead = inputStream.read(buffer)) != -1) {
             messageDigest.update(buffer, 0, bytesRead);
             messageDigest.update(buffer, 0, bytesRead);
         }
         }
-
-        // 关闭输入流
-        inputStream.close();
-
-        // 获取 MD5 校验和
         byte[] md5Bytes = messageDigest.digest();
         byte[] md5Bytes = messageDigest.digest();
-
         // 转换为 16 进制字符串
         // 转换为 16 进制字符串
         StringBuilder sb = new StringBuilder();
         StringBuilder sb = new StringBuilder();
         for (byte b : md5Bytes) {
         for (byte b : md5Bytes) {
             sb.append(String.format("%02x", b & 0xff));
             sb.append(String.format("%02x", b & 0xff));
         }
         }
+        return sb.toString();
+    }
 
 
-        return sb.toString();  // 返回 MD5 字符串
+    /**
+     * 获取字节数组的 ETag 值(基于 MD5 计算)
+     * 用于压缩后的图片数据计算 ETag
+     *
+     * @param data 字节数组
+     * @return ETag 值
+     * @throws NoSuchAlgorithmException MD5 算法不可用时抛出
+     */
+    public static String getFileETag(byte[] data) throws NoSuchAlgorithmException {
+        MessageDigest md5Digest = MessageDigest.getInstance("MD5");
+        md5Digest.update(data);
+        byte[] md5Bytes = md5Digest.digest();
+        return byteArrayToHex(md5Bytes);
     }
     }
 }
 }

+ 152 - 4
commons/src/main/java/com/jzg/commons/util/ImageUtil.java

@@ -4,12 +4,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 
 
 import javax.imageio.ImageIO;
 import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.*;
 import java.util.Base64;
 import java.util.Base64;
+import java.util.Iterator;
 
 
 /**
 /**
  * 图片工具类
  * 图片工具类
@@ -121,4 +124,149 @@ public class ImageUtil {
         return ".jpg"; // 默认返回 jpg
         return ".jpg"; // 默认返回 jpg
     }
     }
 
 
+    /**
+     * 图片压缩参数配置
+     */
+    private static final int MAX_WIDTH = 1920;
+    private static final int MAX_HEIGHT = 1080;
+    private static final float QUALITY = 0.7f;
+
+    /**
+     * 判断文件是否为图片类型(通过 Content-Type 判断)
+     *
+     * @param contentType 文件的 Content-Type
+     * @return 是否为图片类型
+     */
+    public static boolean isImage(String contentType) {
+        return contentType != null && contentType.startsWith("image/");
+    }
+
+    /**
+     * 判断文件扩展名是否为图片类型
+     *
+     * @param extension 文件扩展名(含点号,如 ".jpg")
+     * @return 是否为图片扩展名
+     */
+    public static boolean isImageExtension(String extension) {
+        if (extension == null) {
+            return false;
+        }
+        String ext = extension.toLowerCase();
+        return ext.equals(".jpg") || ext.equals(".jpeg") || ext.equals(".png") ||
+               ext.equals(".gif") || ext.equals(".bmp") || ext.equals(".webp");
+    }
+
+    /**
+     * 图片压缩方法
+     * 压缩策略:
+     * 1. 如果图片尺寸超过 MAX_WIDTH x MAX_HEIGHT,先按比例缩放
+     * 2. 无论是否缩放,都进行质量压缩(压缩质量为 QUALITY)
+     * 3. 保持原图片格式,PNG 保持透明通道
+     *
+     * @param file 上传的图片文件
+     * @return 压缩后的字节数组,压缩失败返回 null
+     */
+    public static byte[] compressImage(MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            return null;
+        }
+
+        try (InputStream is = file.getInputStream()) {
+            BufferedImage originalImage = ImageIO.read(is);
+            if (originalImage == null) {
+                return null;
+            }
+
+            int width = originalImage.getWidth();
+            int height = originalImage.getHeight();
+
+            // 如果图片尺寸在限制范围内,直接进行质量压缩
+            if (width <= MAX_WIDTH && height <= MAX_HEIGHT) {
+                return compressWithQuality(originalImage, file.getOriginalFilename());
+            }
+
+            // 计算缩放比例,保持宽高比
+            double scale = Math.min((double) MAX_WIDTH / width, (double) MAX_HEIGHT / height);
+            int newWidth = (int) (width * scale);
+            int newHeight = (int) (height * scale);
+
+            // 创建缩放后的图片,使用双线性插值算法保证清晰度
+            BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
+            Graphics2D g2d = resizedImage.createGraphics();
+            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
+            g2d.dispose();
+
+            // 对缩放后的图片进行质量压缩
+            return compressWithQuality(resizedImage, file.getOriginalFilename());
+        } catch (IOException e) {
+            log.error("图片压缩失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 图片质量压缩
+     * 使用 ImageWriter 进行高质量压缩,保持原格式
+     *
+     * @param image    待压缩的图片对象
+     * @param filename 原文件名,用于确定图片格式
+     * @return 压缩后的字节数组
+     */
+    private static byte[] compressWithQuality(BufferedImage image, String filename) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            String format = getImageFormat(filename);
+            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(format);
+
+            // 如果找不到对应格式的 ImageWriter,使用默认方式写入
+            if (!writers.hasNext()) {
+                ImageIO.write(image, format, baos);
+                return baos.toByteArray();
+            }
+
+            // 使用 ImageWriter 进行高质量压缩
+            ImageWriter writer = writers.next();
+            ImageWriteParam writeParam = writer.getDefaultWriteParam();
+
+            if (writeParam.canWriteCompressed()) {
+                writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+                writeParam.setCompressionQuality(QUALITY);
+            }
+
+            writer.setOutput(ImageIO.createImageOutputStream(baos));
+            writer.write(null, new javax.imageio.IIOImage(image, null, null), writeParam);
+            writer.dispose();
+
+            return baos.toByteArray();
+        } catch (IOException e) {
+            log.error("图片质量压缩失败", e);
+            try {
+                // 压缩失败时回退到普通写入方式
+                ImageIO.write(image, getImageFormat(filename), baos);
+                return baos.toByteArray();
+            } catch (IOException ex) {
+                log.error("图片回退保存失败", ex);
+                return null;
+            }
+        }
+    }
+
+    /**
+     * 根据文件名获取图片格式
+     *
+     * @param filename 文件名
+     * @return 图片格式(如 "jpg", "png", "gif")
+     */
+    private static String getImageFormat(String filename) {
+        if (filename == null) {
+            return "jpg";
+        }
+        String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
+        if ("jpeg".equals(ext)) {
+            return "jpg";
+        }
+        return ext;
+    }
+
 }
 }

+ 73 - 34
platform/src/main/java/com/jzg/controller/FileUploadController.java

@@ -5,25 +5,23 @@ import com.jzg.commons.core.base.BaseController;
 import com.jzg.commons.core.page.HttpResult;
 import com.jzg.commons.core.page.HttpResult;
 import com.jzg.commons.entity.po.SysUploadFiles;
 import com.jzg.commons.entity.po.SysUploadFiles;
 import com.jzg.commons.exception.SystemException;
 import com.jzg.commons.exception.SystemException;
-import com.jzg.commons.request.RequestSingleParam;
 import com.jzg.commons.util.FileUtils;
 import com.jzg.commons.util.FileUtils;
+import com.jzg.commons.util.ImageUtil;
 import com.jzg.commons.util.MinioUtils;
 import com.jzg.commons.util.MinioUtils;
 import com.jzg.commons.util.idgen.IdGenerate;
 import com.jzg.commons.util.idgen.IdGenerate;
 import com.jzg.mapper.SysUploadFilesMapper;
 import com.jzg.mapper.SysUploadFilesMapper;
 import io.minio.*;
 import io.minio.*;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Operation;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartFile;
 
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLEncoder;
+import java.net.*;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 
 
@@ -47,24 +45,60 @@ public class FileUploadController extends BaseController {
     private String bucketName;
     private String bucketName;
 
 
 
 
+    /**
+     * 文件上传接口
+     * 支持图片自动压缩:上传图片时先判断类型,若是图片则进行尺寸和质量压缩后再上传
+     *
+     * @param file 上传的文件
+     * @return 上传结果,包含文件信息和下载链接
+     */
     @PostMapping("/upload")
     @PostMapping("/upload")
-    @Operation(summary = "文件上传接口", description = "文件上传接口")
+    @Operation(summary = "文件上传接口", description = "文件上传接口,图片自动压缩")
     public HttpResult uploadFile(@RequestParam("file") MultipartFile file) {
     public HttpResult uploadFile(@RequestParam("file") MultipartFile file) {
         System.out.printf("调用文件上传接口");
         System.out.printf("调用文件上传接口");
         try {
         try {
             // 获取文件原始名称和扩展名
             // 获取文件原始名称和扩展名
             String originalFileName = file.getOriginalFilename();
             String originalFileName = file.getOriginalFilename();
             String extension = getFileExtension(originalFileName);
             String extension = getFileExtension(originalFileName);
-            // MD5,ETag
-            String fileMd5 = FileUtils.getFileMD5(file);
-            String objectName = generateObjectName(originalFileName, fileMd5, extension);
-            String fileEtag = FileUtils.getFileETag(file);
-            // 查找文件是否已经存在于MinIO
+
+            // 判断是否为图片文件,若是则进行压缩
+            // 双重校验:通过 Content-Type 和文件扩展名判断
+            byte[] compressedBytes = null;
+            if (ImageUtil.isImage(file.getContentType()) || ImageUtil.isImageExtension(extension)) {
+                compressedBytes = ImageUtil.compressImage(file);
+            }
+
+            // 根据是否压缩成功,计算文件的 MD5 和 ETag
+            // 注意:MD5/ETag 必须基于最终上传的文件内容计算,确保与 MinIO 存储一致
+            String fileMd5;
+            String fileEtag;
+            String objectName;
+
+            if (compressedBytes != null && compressedBytes.length > 0) {
+                // 使用压缩后的字节数组计算哈希值
+                fileMd5 = FileUtils.getFileMD5(compressedBytes);
+                fileEtag = FileUtils.getFileETag(compressedBytes);
+                objectName = generateObjectName(originalFileName, fileMd5, extension);
+            } else {
+                // 使用原始文件计算哈希值(非图片或压缩失败时回退)
+                fileMd5 = FileUtils.getFileMD5(file);
+                fileEtag = FileUtils.getFileETag(file);
+                objectName = generateObjectName(originalFileName, fileMd5, extension);
+            }
+
 //            if (isFileExistsInMinIo(objectName, fileEtag)) {
 //            if (isFileExistsInMinIo(objectName, fileEtag)) {
 //                return HttpResult.ok(getFileFromDatabase(fileEtag,objectName, extension));
 //                return HttpResult.ok(getFileFromDatabase(fileEtag,objectName, extension));
 //            }
 //            }
-            //如果文件不存在,执行上传操作
-            SysUploadFiles sysUploadFiles = uploadFileToMinIo(file, objectName, fileEtag, extension);
+
+            // 根据是否压缩成功,选择对应的上传方式
+            SysUploadFiles sysUploadFiles;
+            if (compressedBytes != null && compressedBytes.length > 0) {
+                // 上传压缩后的图片字节数组
+                sysUploadFiles = uploadFileToMinIo(compressedBytes, objectName, fileEtag, extension, file.getContentType());
+            } else {
+                // 上传原始文件(非图片或压缩失败时回退)
+                sysUploadFiles = uploadFileToMinIo(file, objectName, fileEtag, extension);
+            }
             return HttpResult.ok(sysUploadFiles);
             return HttpResult.ok(sysUploadFiles);
         } catch (Exception e) {
         } catch (Exception e) {
             e.printStackTrace();
             e.printStackTrace();
@@ -87,8 +121,7 @@ public class FileUploadController extends BaseController {
             String contentType = connection.getContentType();
             String contentType = connection.getContentType();
             String extension = "";
             String extension = "";
 
 
-            if(contentType.contains("application/pdf") || contentType.contains("text/html"))
-            {
+            if (contentType.contains("application/pdf") || contentType.contains("text/html")) {
                 extension = ".pdf";
                 extension = ".pdf";
             }
             }
             try (InputStream inputStream = connection.getInputStream()) {
             try (InputStream inputStream = connection.getInputStream()) {
@@ -96,7 +129,7 @@ public class FileUploadController extends BaseController {
             } catch (Exception e) {
             } catch (Exception e) {
                 throw new RuntimeException(e);
                 throw new RuntimeException(e);
             }
             }
-        }catch (MalformedURLException e){
+        } catch (MalformedURLException e) {
             throw new RuntimeException("url格式错误");
             throw new RuntimeException("url格式错误");
         } catch (IOException e) {
         } catch (IOException e) {
             throw new SystemException("url错误");
             throw new SystemException("url错误");
@@ -169,7 +202,7 @@ public class FileUploadController extends BaseController {
         }
         }
     }
     }
 
 
-    private SysUploadFiles getFileFromDatabase(String fileEtag,String fileName,String fileType) {
+    private SysUploadFiles getFileFromDatabase(String fileEtag, String fileName, String fileType) {
         SysUploadFiles sysUploadFiles = sysUploadFilesMapper.selectOne(
         SysUploadFiles sysUploadFiles = sysUploadFilesMapper.selectOne(
                 new LambdaQueryWrapper<SysUploadFiles>().eq(SysUploadFiles::getEtag, fileEtag));
                 new LambdaQueryWrapper<SysUploadFiles>().eq(SysUploadFiles::getEtag, fileEtag));
 
 
@@ -182,11 +215,11 @@ public class FileUploadController extends BaseController {
             sysUploadFiles.setEtag(fileEtag);
             sysUploadFiles.setEtag(fileEtag);
             sysUploadFiles.setCreateTime(LocalDateTime.now());
             sysUploadFiles.setCreateTime(LocalDateTime.now());
             sysUploadFiles.setCreateBy(getUserName());
             sysUploadFiles.setCreateBy(getUserName());
-            StatObjectResponse fileContent = MinioUtils.getFileStatusInfo(bucketName,fileName);
+            StatObjectResponse fileContent = MinioUtils.getFileStatusInfo(bucketName, fileName);
             sysUploadFiles.setFileSize(fileContent.size() + "");
             sysUploadFiles.setFileSize(fileContent.size() + "");
             sysUploadFilesMapper.insert(sysUploadFiles);
             sysUploadFilesMapper.insert(sysUploadFiles);
         }
         }
-        sysUploadFiles.setDownloadUrl(MinioUtils.getPresignedObjectUrl(bucketName,fileName));
+        sysUploadFiles.setDownloadUrl(MinioUtils.getPresignedObjectUrl(bucketName, fileName));
         return sysUploadFiles;
         return sysUploadFiles;
     }
     }
 
 
@@ -200,18 +233,19 @@ public class FileUploadController extends BaseController {
                 .contentType(file.getContentType())
                 .contentType(file.getContentType())
                 .build());
                 .build());
 
 
-        SysUploadFiles sysUploadFiles = new SysUploadFiles();
-        sysUploadFiles.setId(IdGenerate.nextId());
-        sysUploadFiles.setFileName(objectName);
-        sysUploadFiles.setFileType(extension.substring(1));
-        StatObjectResponse fileContent = MinioUtils.getFileStatusInfo(bucketName,objectName);
-        sysUploadFiles.setFileSize(fileContent.size() + "");
-        sysUploadFiles.setBucketName(bucketName);
-        sysUploadFiles.setEtag(objectWriteResponse.etag());
-        sysUploadFiles.setCreateTime(LocalDateTime.now());
-        sysUploadFiles.setDownloadUrl(MinioUtils.getPresignedObjectUrl(bucketName,objectName));
-        sysUploadFilesMapper.insert(sysUploadFiles);
-        return sysUploadFiles;
+        return insertSysUploadFiles(objectName, extension, objectWriteResponse);
+    }
+
+    private SysUploadFiles uploadFileToMinIo(byte[] fileBytes, String objectName, String fileEtag, String extension, String contentType) throws Exception {
+        InputStream fileInputStream = new ByteArrayInputStream(fileBytes);
+        ObjectWriteResponse objectWriteResponse = minioClient.putObject(PutObjectArgs.builder()
+                .bucket(bucketName)
+                .object(objectName)
+                .stream(fileInputStream, fileBytes.length, -1)
+                .contentType(contentType)
+                .build());
+
+        return insertSysUploadFiles(objectName, extension, objectWriteResponse);
     }
     }
 
 
 
 
@@ -224,16 +258,21 @@ public class FileUploadController extends BaseController {
                 .contentType(contentType)
                 .contentType(contentType)
                 .build());
                 .build());
 
 
+        return insertSysUploadFiles(objectName, extension, objectWriteResponse);
+    }
+
+    @NotNull
+    private SysUploadFiles insertSysUploadFiles(String objectName, String extension, ObjectWriteResponse objectWriteResponse) {
         SysUploadFiles sysUploadFiles = new SysUploadFiles();
         SysUploadFiles sysUploadFiles = new SysUploadFiles();
         sysUploadFiles.setId(IdGenerate.nextId());
         sysUploadFiles.setId(IdGenerate.nextId());
         sysUploadFiles.setFileName(objectName);
         sysUploadFiles.setFileName(objectName);
         sysUploadFiles.setFileType(extension.substring(1));
         sysUploadFiles.setFileType(extension.substring(1));
-        StatObjectResponse fileContent = MinioUtils.getFileStatusInfo(bucketName,objectName);
+        StatObjectResponse fileContent = MinioUtils.getFileStatusInfo(bucketName, objectName);
         sysUploadFiles.setFileSize(fileContent.size() + "");
         sysUploadFiles.setFileSize(fileContent.size() + "");
         sysUploadFiles.setBucketName(bucketName);
         sysUploadFiles.setBucketName(bucketName);
         sysUploadFiles.setEtag(objectWriteResponse.etag());
         sysUploadFiles.setEtag(objectWriteResponse.etag());
         sysUploadFiles.setCreateTime(LocalDateTime.now());
         sysUploadFiles.setCreateTime(LocalDateTime.now());
-        sysUploadFiles.setDownloadUrl(MinioUtils.getPresignedObjectUrl(bucketName,objectName));
+        sysUploadFiles.setDownloadUrl(MinioUtils.getPresignedObjectUrl(bucketName, objectName));
         sysUploadFilesMapper.insert(sysUploadFiles);
         sysUploadFilesMapper.insert(sysUploadFiles);
         return sysUploadFiles;
         return sysUploadFiles;
     }
     }

+ 8 - 1
platform/src/main/java/com/jzg/service/impl/PtlAgreementAttributionImpl.java

@@ -80,7 +80,14 @@ public class PtlAgreementAttributionImpl extends ServiceImpl<PtlAgreementAttribu
 
 
     @Override
     @Override
     public Page<PtlAgreementAttribution> getAgreementAttributionList(Page page, PtlAgreementAttributionQueryVo ptlAgreementAttributionQueryVo) {
     public Page<PtlAgreementAttribution> getAgreementAttributionList(Page page, PtlAgreementAttributionQueryVo ptlAgreementAttributionQueryVo) {
-        return baseMapper.getAgreementAttributionList(page,ptlAgreementAttributionQueryVo);
+        Page<PtlAgreementAttribution> agreementAttributionList = baseMapper.getAgreementAttributionList(page, ptlAgreementAttributionQueryVo);
+        agreementAttributionList.getRecords().forEach(item->{
+            // 将用户名密码设置为空
+            if(Objects.isNull(item.getUsername())){
+                item.setUsername("");
+            }
+        });
+        return agreementAttributionList;
     }
     }
 
 
     @Override
     @Override

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

@@ -236,4 +236,13 @@ public interface OrgClient {
      */
      */
     @PostMapping("/userAccount/addUserAccountChangeLog")
     @PostMapping("/userAccount/addUserAccountChangeLog")
     HttpResult<String> addUserAccountChangeLog(@RequestBody SysUserAccountChangeLog changeLog);
     HttpResult<String> addUserAccountChangeLog(@RequestBody SysUserAccountChangeLog changeLog);
+
+    /**
+     * 查询sys_user_jzg_info 表的id和userId的对应关系
+     *
+     * @author lipf
+     * @date 2026/6/30 14:15
+     */
+    @PostMapping("/api/v1/organization/queryJzgInfoId2UserId")
+    public HttpResult<Map<String,String>> queryJzgInfoId2UserId(@RequestBody List<String> jzgInfoTids);
 }
 }

+ 2 - 1
tenant/insurance/quotation-dajia/src/main/java/com/jzg/quotation/dajia/crawler/entity/request/DaJiaCrawlerPriceRequest.java

@@ -1,5 +1,6 @@
 package com.jzg.quotation.dajia.crawler.entity.request;
 package com.jzg.quotation.dajia.crawler.entity.request;
 
 
+import cn.hutool.core.collection.CollectionUtil;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.commons.entity.quote.vo.QuoteVo;
 import com.jzg.quotation.dajia.crawler.entity.request.quote.*;
 import com.jzg.quotation.dajia.crawler.entity.request.quote.*;
@@ -168,7 +169,7 @@ public class DaJiaCrawlerPriceRequest implements Serializable {
             startTime = businessInsurance.getProductInfo().getStartDate();
             startTime = businessInsurance.getProductInfo().getStartDate();
             endTime = businessInsurance.getProductInfo().getEndDate();
             endTime = businessInsurance.getProductInfo().getEndDate();
         }
         }
-
+        proposalInfo.setJyMark(CollectionUtil.isNotEmpty(quoteVo.getAccidentalDrivings()) ? "1" : "0");
         this.driveInsurance = new DriveInsuranceDTO(quoteVo.getAccidentalDrivings(),startTime,endTime);
         this.driveInsurance = new DriveInsuranceDTO(quoteVo.getAccidentalDrivings(),startTime,endTime);
         this.jabFamilyDriveInsurance = new Object();
         this.jabFamilyDriveInsurance = new Object();
         this.rqbFamilyDriveInsurance = new Object();
         this.rqbFamilyDriveInsurance = new Object();

+ 2 - 2
tenant/insurance/quotation-dajia/src/main/java/com/jzg/quotation/dajia/crawler/entity/request/quote/DriveInsuranceDTO.java

@@ -186,12 +186,12 @@ public class DriveInsuranceDTO implements Serializable {
             this.proposalNo = "";
             this.proposalNo = "";
             this.proposalTime = "";
             this.proposalTime = "";
             this.planId = accidentalDrivingVo.getProductCode();
             this.planId = accidentalDrivingVo.getProductCode();
-            this.number = accidentalDrivingVo.getQuantity();
+            this.number = 1;
             this.startDate = startTime;
             this.startDate = startTime;
             this.premium = "0.00";
             this.premium = "0.00";
             this.sumInsured = "";
             this.sumInsured = "";
             this.perPrmSum = Double.parseDouble(accidentalDrivingVo.getPremium());
             this.perPrmSum = Double.parseDouble(accidentalDrivingVo.getPremium());
-            this.perAmtSum = 1;
+            this.perAmtSum = accidentalDrivingVo.getQuantity();
             this.uncarDateMark = "1";
             this.uncarDateMark = "1";
         }
         }
     }
     }

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

@@ -57,7 +57,7 @@ public final class GuoRenCrawlerQuoteResultsVoBuild {
         quoteResultsVo.getCosts().setBiPremium(biPremium); // 注意这里CI和BI保费相同
         quoteResultsVo.getCosts().setBiPremium(biPremium); // 注意这里CI和BI保费相同
         quoteResultsVo.getCosts().setNiPremium(bcPremium);
         quoteResultsVo.getCosts().setNiPremium(bcPremium);
         quoteResultsVo.getCosts().setVvTax(vvTax);
         quoteResultsVo.getCosts().setVvTax(vvTax);
-        String sumPremium = String.valueOf(Integer.parseInt(biPremium) + Double.parseDouble(ciPremium) + Integer.parseInt(bcPremium) + Double.parseDouble(vvTax));
+        String sumPremium = String.valueOf(Double.parseDouble(biPremium) + Double.parseDouble(ciPremium) + Double.parseDouble(bcPremium) + Double.parseDouble(vvTax));
         quoteResultsVo.getCosts().setSumPremium(sumPremium);
         quoteResultsVo.getCosts().setSumPremium(sumPremium);
         quoteResultsVo.setQuoteStatusEnum(InsOrderStatusEnum.WAIT_AUDIT);
         quoteResultsVo.setQuoteStatusEnum(InsOrderStatusEnum.WAIT_AUDIT);
 
 

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

@@ -64,6 +64,7 @@ import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
@@ -213,7 +214,8 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
 
 
         String cookie = extractCookie(mmap);
         String cookie = extractCookie(mmap);
         CarInfoVo car = quoteVo.getCarInfoVo();
         CarInfoVo car = quoteVo.getCarInfoVo();
-
+        QuoteResultsVo quoteResultsVo = new QuoteResultsVo();
+        quoteResultsVo.setQuoteStatusEnum(InsOrderStatusEnum.QUOTE_FAIL);
         // 带重试的获取报价编号、车型型号
         // 带重试的获取报价编号、车型型号
         Map<String, Object> xbResult = retry(() -> {
         Map<String, Object> xbResult = retry(() -> {
             try { return xbQuery(dto.getUsername(), cookie, car); }
             try { return xbQuery(dto.getUsername(), cookie, car); }
@@ -222,14 +224,26 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
 
 
         String quotationNo = str(xbResult, "quotationNo");
         String quotationNo = str(xbResult, "quotationNo");
         String modelcodexh = StringUtils.isBlank(str(xbResult, "modelcodexh")) ? car.getCarModelNo() : str(xbResult, "modelcodexh");
         String modelcodexh = StringUtils.isBlank(str(xbResult, "modelcodexh")) ? car.getCarModelNo() : str(xbResult, "modelcodexh");
-        log.info("modelcodexh: {}", str(xbResult, "modelcodexh"));
-        log.info("modelcodexh: {}", modelcodexh);
+        log.info("XBResult_modelCodeXH: {}", str(xbResult, "modelcodexh"));
+        log.info("car.getCarModelNo()_modelCode_XH: {}", car.getCarModelNo());
 
 
         // 报价前预处理-保存车辆信息、过滤车型等处理
         // 报价前预处理-保存车辆信息、过滤车型等处理
-        PreResult pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo, xbResult);
+        PreResult pre = null;
+        try {
+            pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo, xbResult);
+        } catch (Exception e) {
+            log.error("报价失败:保存车辆信息、过滤车型异常,{}",e.getMessage());
+            throw new SystemException(e.getMessage());
+        }
         // 报价
         // 报价
-        CoreResult core = executeQuote(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
-        if (!core.success()) throw new SystemException("报价失败");
+        CoreResult core = null;
+        try {
+            core = executeQuote(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
+        } catch (Exception e) {
+            log.error("报价失败,{}",e.getMessage());
+            throw new SystemException(e.getMessage());
+        }
+        if (!core.success()) return quoteResultsVo;
         // 保存订单到MongoDB
         // 保存订单到MongoDB
         saveOrder(quoteVo, core);
         saveOrder(quoteVo, core);
         // 组装费用、评分、险种信息、续保标志
         // 组装费用、评分、险种信息、续保标志
@@ -436,84 +450,101 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
 
 
     private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
     private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
                                          String cookie, PreResult pre, Map<String, Object> gsInfo) {
                                          String cookie, PreResult pre, Map<String, Object> gsInfo) {
-        // 初始化重试次数和最大重试阈值
-        int modelCodeRetryCount = 0;
-        final int MAX_MODEL_CODE_RETRY = 2; // 限制最大重试次数,避免死循环
-        String currentModelCodexh = pre.carDTO().getModelcodexh();
+        // 线程安全计数器,限制最多2次循环(初始0,最多执行2次)
+        AtomicInteger retryCount = new AtomicInteger(0);
         PreResult currentPre = pre;
         PreResult currentPre = pre;
-        while (modelCodeRetryCount < MAX_MODEL_CODE_RETRY) {
-            String decryptData = "";
+        StepResult stepResult = null;
+        final int MAX_RETRY_TIMES = 2;
+
+        while (retryCount.get() < MAX_RETRY_TIMES) {
             try {
             try {
-                HttpHeaders h = buildQuoteStep1Headers(cookie);
-                HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, currentPre.carDTO(),
-                        currentPre.params(), quotationNo, currentPre.dataDTO(), dto, gsInfo);
-                log.info("saveOneStept: {}", JSONObject.toJSONString(r));
-                String body = req.saveOneStept(r, h).getBody().toString();
-                String mealid = extractMealId(body);
-                //机动车损失保险
-                String limitAmount = extractLimitAmount(body);
-                log.info("mealid: {}", mealid);
-                log.info("limitAmount: {}", limitAmount);
-                //组装驾意险参数,没有就空字符串
-                String personalInsuredJSON = buildPersonalInsuredJSON(q);
-
-                h = buildQuoteStep2Headers(cookie);
-                //组装报价参数
-                HtCrawlerQuoteRequest qr = new HtCrawlerQuoteRequest(q, mealid, limitAmount, "", personalInsuredJSON);
-                //报价第一次
-                decryptData = req.quote(qr, h);
-                //处理重复投保返回终保日期的
-                DuplQuoteResult duplQuoteResult = handleQuoteErrors(decryptData, q);
-                if (duplQuoteResult.dupl()) {
-                    qr = new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON);
-                    decryptData = req.quote(qr, h);
+                stepResult = executeQuoteStepInternal(q, quotationNo, dto, cookie, currentPre, gsInfo);
+                // 正常获取到数据则跳出循环
+                if (stepResult != null && stepResult.data() != null && stepResult.data().getApplicationdto() != null) {
+                    break;
                 }
                 }
-
-                // 处理可能的录入的校验码有误
-                HtCrawlerQuoteResponse.DataDTO data = null;
-                try {
-                    data = resolveQuoteResponse(duplQuoteResult, decryptData, mealid,
-                            limitAmount, h, personalInsuredJSON);
-                } catch (Exception e) {
-                    decryptData = e.getMessage();
-                    // 检测modelcodexh不在平台车型范围内的异常
-                    if (decryptData.contains("errrorFlag") && decryptData.contains("carChange")) {
-                        modelCodeRetryCount++;
-                        log.warn("检测到modelcodexh[{}]不在平台车型范围内,开始第{}次重试获取新编码",
-                                currentModelCodexh, modelCodeRetryCount);
-
-                        // 提取新的modelcodexh
-                        Map<String, Object> map = MAPPER.readValue(decryptData, Map.class);
-                        List<Map<String, String>> list = (List)map.get("carModelList");
-                        String newModelCodexh = list.get(0).get("vehiclecode");
-
-                        currentModelCodexh = newModelCodexh;
-
-                        // 重新执行报价预处理流程
-                        AttributionInformationVo attr = q.getOrder().getAttributionInformationVo();
-                        log.info(map.get("unMatchVehicleFrameMessage")+"已重新执行prepareQuote,新modelcodexh:{}", currentModelCodexh);
-                        currentPre = prepareQuote(attr, gsInfo, q.getCarInfoVo(),
-                                currentModelCodexh, cookie, quotationNo, map);
-                        executeQuoteSteps(q, quotationNo, dto, cookie, currentPre, gsInfo);
-
-                        // 跳过当前循环,重新执行报价流程
-                        continue;
-                    } else {
-                        throw new SystemException(decryptData);
+            } catch (SystemException e) {
+                log.error("第{}次报价步骤执行异常: {}", retryCount.get() + 1, e.getMessage());
+                // 检测是否是车型不匹配需要重新查询的异常
+                if (e.getMessage().contains("errrorFlag") && e.getMessage().contains("carChange")) {
+                    // 累加计数,超过次数则抛出异常
+                    if (retryCount.incrementAndGet() >= MAX_RETRY_TIMES) {
+                        if(e.getMessage().contains("上传的行业车型编码不在平台车型范围内,请核实。")) {
+                            throw new SystemException("报价重试次数已达上限(" + MAX_RETRY_TIMES + "次),车型匹配失败。上传的行业车型编码不在平台车型范围内,请核实。", e.getMessage());
+                        }else {
+                            throw new SystemException("报价重试次数已达上限(" + MAX_RETRY_TIMES + "次),车型匹配失败。" + e.getMessage());
+                        }
                     }
                     }
+                    // 提取新的modelcodexh并重新执行预处理
+                    currentPre = rebuildPreResult(q, cookie, quotationNo, e.getMessage(), gsInfo);
+                    continue; // 继续下一次循环
                 }
                 }
-                return new StepResult(data, personalInsuredJSON);
-
-            } catch (Exception e) {
-                modelCodeRetryCount++;
-                if (modelCodeRetryCount >= MAX_MODEL_CODE_RETRY) {
-                    throw new SystemException(decryptData);
-                }
-                // 重试前短暂休眠,避免高频请求
-                sleep(SHORT_DELAY_MS);
+                // 非车型匹配异常,直接抛出
+                throw e;
             }
             }
+            // 无有效数据且未触发异常时,累加计数
+            retryCount.incrementAndGet();
+        }
+
+        // 最终仍无结果则返回空StepResult(或抛出异常,根据业务要求调整)
+        return stepResult != null ? stepResult : new StepResult(null, "");
+    }
+
+    /**
+     * 重构:抽离单次报价步骤执行的核心逻辑
+     */
+    private StepResult executeQuoteStepInternal(QuoteVo q, String quotationNo, LoginDTO dto,
+                                                String cookie, PreResult pre, Map<String, Object> gsInfo) {
+        String decryptData = "";
+        HttpHeaders h = buildQuoteStep1Headers(cookie);
+        HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, pre.carDTO(),
+                pre.params(), quotationNo, pre.dataDTO(), dto, gsInfo);
+        log.info("saveOneStept: {}", JSONObject.toJSONString(r));
+        String body = req.saveOneStept(r, h).getBody().toString();
+        String mealid = extractMealId(body);
+        String limitAmount = extractLimitAmount(body);
+        log.info("mealid: {}", mealid);
+        log.info("limitAmount: {}", limitAmount);
+        //组装驾意险参数,没有就空字符串
+        String personalInsuredJSON = buildPersonalInsuredJSON(q);
+
+        h = buildQuoteStep2Headers(cookie);
+        //组装报价参数
+        HtCrawlerQuoteRequest qr = new HtCrawlerQuoteRequest(q, mealid, limitAmount, "", personalInsuredJSON);
+        //报价第一次
+        decryptData = req.quote(qr, h);
+        //处理重复投保返回终保日期的
+        DuplQuoteResult duplQuoteResult = handleQuoteErrors(decryptData, q);
+        if (duplQuoteResult.dupl()) {
+            qr = new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON);
+            decryptData = req.quote(qr, h);
+        }
+
+        // 处理报价响应各种结果
+        HtCrawlerQuoteResponse.DataDTO data = resolveQuoteResponse(duplQuoteResult, decryptData, mealid,
+                limitAmount, h, personalInsuredJSON);
+        return new StepResult(data, personalInsuredJSON);
+    }
+
+    /**
+     * 重构:抽离重新构建PreResult的逻辑(原递归中重新执行prepareQuote的部分)
+     */
+    private PreResult rebuildPreResult(QuoteVo q, String cookie, String quotationNo, String errorMsg, Map<String, Object> gsInfo) {
+        try {
+            // 提取新的modelcodexh
+            Map<String, Object> map = MAPPER.readValue(errorMsg, Map.class);
+            List<Map<String, String>> list = (List) map.get("carModelList");
+            String newModelCodexh = list.get(0).get("vehiclecode");
+
+            // 重新执行报价预处理流程
+            AttributionInformationVo attr = q.getOrder().getAttributionInformationVo();
+            log.info(map.get("unMatchVehicleFrameMessage") + "已重新执行prepareQuote,新modelcodexh:{}", newModelCodexh);
+            return prepareQuote(attr, gsInfo, q.getCarInfoVo(),
+                    newModelCodexh, cookie, quotationNo, map);
+        } catch (Exception e) {
+            log.error("重新构建PreResult失败", e);
+            throw new SystemException("重新获取车型信息失败", e.getMessage());
         }
         }
-        throw new SystemException("报价失败");
     }
     }
 
 
     private String extractMealId(String body) {
     private String extractMealId(String body) {
@@ -661,10 +692,6 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
             }
             }
         }
         }
         if (decryptData.contains("传送了车辆过户标志,请确认")) {
         if (decryptData.contains("传送了车辆过户标志,请确认")) {
-            //HtCrawlerQuoteResponse.DataDTO dataDTO = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
-            //List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartDTO =
-            //        dataDTO.getBasepartdtolist() != null ? dataDTO.getBasepartdtolist().getBasepartdto() : null;
-            //String basePartJSON = buildBasePartJSON(basePartDTO==null?new ArrayList<>():basePartDTO);
             Pattern pattern = Pattern.compile(TRANSFER_FLAG.pattern());
             Pattern pattern = Pattern.compile(TRANSFER_FLAG.pattern());
             Matcher matcher = pattern.matcher(decryptData);
             Matcher matcher = pattern.matcher(decryptData);
             String transferFlag =  "";
             String transferFlag =  "";
@@ -672,82 +699,32 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
             decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount+","+transferFlag, "", personalInsuredJSON), h);
             decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount+","+transferFlag, "", personalInsuredJSON), h);
             return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
             return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
         }
         }
-        if (!decryptData.contains("录入的校验码有误") && decryptData.contains("erroeInfo") && !duplQuoteResult.dupl()) {
+
+        // autocheckcode 可能不准确,重新获取 quote 刷新验证码
+        if (decryptData.contains("录入的校验码有误")) {
+            // 必须传空 basePart,接口才会返回新的 basePart 列表(含新 autocheckcode)
+            String fresh = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
+            return resolveQuoteResponse(duplQuoteResult, fresh, mealid, limitAmount, h, personalInsuredJSON);
+        }
+
+        if (decryptData.contains("erroeInfo")) {
+            log.error("报价失败: {}", decryptData);
             log.error("报价失败: {}", convertResponseMsg(decryptData));
             log.error("报价失败: {}", convertResponseMsg(decryptData));
             throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
             throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
         }
         }
         HtCrawlerQuoteResponse.DataDTO data = null;
         HtCrawlerQuoteResponse.DataDTO data = null;
         data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
         data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
 
 
-        if (data.getApplicationdto() != null && !decryptData.contains("车损险保额不能高于")) return data;
+        if (data.getApplicationdto() != null) return data;
 
 
         List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartDTO =
         List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartDTO =
                 data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
                 data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
-        if ((basePartDTO == null || basePartDTO.isEmpty()) && !decryptData.contains("车损险保额不能高于")) throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
+        if ((basePartDTO == null || basePartDTO.isEmpty())) throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
 
 
-        for (int i = 0; i < MAX_RETRIES; i++) {
-            String basePartJSON = buildBasePartJSON(basePartDTO);
+        String basePartJSON = buildBasePartJSON(basePartDTO);
+        if (StringUtils.isNotBlank(basePartJSON)) {
             decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, basePartJSON, personalInsuredJSON), h);
             decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, basePartJSON, personalInsuredJSON), h);
-            log.info("resolveQuoteResponse attempt {}/{}: {}", i + 1, MAX_RETRIES, decryptData);
-
-            if (decryptData.contains("TRANS_MESSAGE") && decryptData.contains("终保日期")) {
-                Map<String, String> map = JSONObject.parseObject(decryptData, Map.class);
-                if (map.containsKey("TRANS_MESSAGE") && map.get("TRANS_MESSAGE").contains("交强")) {
-                    Matcher m = PAT_END_DATE2.matcher(decryptData);
-                    if (m.find()) {
-                        String jiaoqiang_startDate = m.group(1);
-                        log.info("报价响应结果CI,终保日期{}", jiaoqiang_startDate);
-                        duplQuoteResult.q().getCiRiskInfoVo().setStartDate(jiaoqiang_startDate + ":00");
-                        LocalDateTime dt = LocalDateTime.parse(jiaoqiang_startDate.replace(" ", "T"), DateTimeFormatter.ofPattern(DATE_FMT_T));
-                        String newEnd = dt.plusYears(1).format(DateTimeFormatter.ofPattern(DATE_FMT));
-                        duplQuoteResult.q().getCiRiskInfoVo().setEndDate(newEnd);
-                        decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
-                        return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
-                    }
-                }
-                if (map.containsKey("TRANS_MESSAGE") && map.get("TRANS_MESSAGE").contains("商业")) {
-                    Matcher m = PAT_END_DATE2.matcher(decryptData);
-                    if (m.find()) {
-                        String chesun_startDate = m.group(1);
-                        log.info("报价响应结果BI,终保日期{}", chesun_startDate);
-                        duplQuoteResult.q().getBiRiskInfoVo().setStartDate(chesun_startDate);
-                        LocalDateTime dt = LocalDateTime.parse(chesun_startDate.replace(" ", "T"), DateTimeFormatter.ofPattern(DATE_FMT_T));
-                        String newEnd = dt.plusYears(1).format(DateTimeFormatter.ofPattern(DATE_FMT));
-                        duplQuoteResult.q().getBiRiskInfoVo().setEndDate(newEnd);
-                        decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
-                        return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
-                    }
-                }
-            }
-
-            HtCrawlerQuoteResponse.DataDTO result = null;
-            try {
-                result = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
-            } catch (Exception e) {
-                throw new RuntimeException(decryptData);
-            }
-            if (result != null && result.getApplicationdto() != null) {
-                return result;
-            }
-
-            // autocheckcode 可能不准确,重新获取 quote 刷新验证码
-            if (decryptData.contains("录入的校验码有误") && i < MAX_RETRIES - 1) {
-                log.warn("验证码 校验失败,重新获取 刷新验证码 (尝试 {}/{})", i + 1, MAX_RETRIES);
-                // 必须传空 basePart,接口才会返回新的 basePart 列表(含新 autocheckcode)
-                String fresh = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
-                result = JSONObject.parseObject(fresh, HtCrawlerQuoteResponse.DataDTO.class);
-                if (result != null && result.getApplicationdto() != null) {
-                    return result;
-                }
-                // 用新的 basePart 列表更新 list,下一轮循环会自动重新 buildBasePartJSON
-                basePartDTO = result != null && result.getBasepartdtolist() != null
-                        ? result.getBasepartdtolist().getBasepartdto() : null;
-                if (basePartDTO == null || basePartDTO.isEmpty()) {
-                    return result != null ? result : data;
-                }
-                continue;
-            }
-            return result != null ? result : data;
+            return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
         }
         }
         return data;
         return data;
     }
     }
@@ -807,10 +784,14 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
         log.info("提交核保参数: {}", JSONObject.toJSONString(submit));
         log.info("提交核保参数: {}", JSONObject.toJSONString(submit));
         String res = req.submit2(submit, req.getHeaders());
         String res = req.submit2(submit, req.getHeaders());
         log.info("提交核保结果: {}", res);
         log.info("提交核保结果: {}", res);
-
+        //cookie还在,但服务器已断开连接,需重新连接
         if(res.contains("<html>")) {
         if(res.contains("<html>")) {
-            r.setUnderwritingResult("核保失败, 服务器繁忙, 请稍后重试");
-            return r;
+            refreshLogin(buildLoginDTO(attr));
+            Map<String, Object> m = login(buildLoginDTO(attr));
+            String cookie = (String) m.get("cookie");
+            req.getHeaders().remove(HtRequestConstant.COOKIE);
+            req.getHeaders().add(HtRequestConstant.COOKIE, cookie);
+            return underwriting(vo);
         }
         }
         if (res.contains("起保时间不正确")) {
         if (res.contains("起保时间不正确")) {
             r.setUnderwritingResult("起保时间不正确-------即时起保分钟数必须为00/15/30/45\n请重新选择起保时间!");
             r.setUnderwritingResult("起保时间不正确-------即时起保分钟数必须为00/15/30/45\n请重新选择起保时间!");

+ 26 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/client/SysUserClient.java

@@ -0,0 +1,26 @@
+package com.jzg.quotation.summary.client;
+
+import com.jzg.commons.core.page.HttpResult;
+import com.jzg.commons.entity.po.SysUser;
+import com.jzg.quotation.summary.utils.FeignConfig;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+
+/**
+ * 调用生活服务平台client
+ */
+@FeignClient(value = "jzg-organization", configuration = FeignConfig.class)
+public interface SysUserClient {
+
+
+    /**
+     * 根据userId查询用户信息SysUser
+     *
+     * @author lipf
+     * @date 2026/6/30 11:27
+     */
+    @GetMapping(value = "/userInfo/querySysUserByUserId")
+    public HttpResult<SysUser> querySysUserByUserId(@RequestParam String userId);
+}

+ 109 - 19
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeAuditServiceImpl.java

@@ -1,6 +1,7 @@
 package com.jzg.quotation.summary.service.impl;
 package com.jzg.quotation.summary.service.impl;
 
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -35,6 +36,7 @@ import com.jzg.quotation.commons.client.PartnerDistributionClient;
 import com.jzg.quotation.commons.client.PlatformClient;
 import com.jzg.quotation.commons.client.PlatformClient;
 import com.jzg.quotation.summary.client.EsmInsCompanyClient;
 import com.jzg.quotation.summary.client.EsmInsCompanyClient;
 import com.jzg.quotation.summary.client.LocalLivingClient;
 import com.jzg.quotation.summary.client.LocalLivingClient;
+import com.jzg.quotation.summary.client.SysUserClient;
 import com.jzg.quotation.summary.entity.Result;
 import com.jzg.quotation.summary.entity.Result;
 import com.jzg.quotation.summary.entity.dto.ChannelRightsApiGrantReceiverDTO;
 import com.jzg.quotation.summary.entity.dto.ChannelRightsApiGrantReceiverDTO;
 import com.jzg.quotation.summary.entity.dto.ChannelRightsApiGrantRecordDTO;
 import com.jzg.quotation.summary.entity.dto.ChannelRightsApiGrantRecordDTO;
@@ -121,6 +123,9 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
     @Autowired
     @Autowired
     private InsOrderRightsPackageMapper insOrderRightsPackageMapper;
     private InsOrderRightsPackageMapper insOrderRightsPackageMapper;
 
 
+    @Autowired
+    private SysUserClient sysUserClient;
+
     @Autowired
     @Autowired
     private ExportBaseServiceImpl exportBaseService;
     private ExportBaseServiceImpl exportBaseService;
 
 
@@ -130,6 +135,19 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
 
 
     private final PartnerDistributionClient partnerDistributionClient;
     private final PartnerDistributionClient partnerDistributionClient;
 
 
+    /**
+     * 订单审核-任务中心,查询待审核任务
+     * <p>
+     * 功能说明:
+     * 1. 根据查询条件分页获取待审核的订单费用审计任务
+     * 2. 若指定了保险公司ID,则自动包含其下级保险公司的数据
+     * 3. 为每条记录填充保险公司完整层级路径名称
+     * 4. 计算每条订单的权益金额:
+     *    权益金额 = (交强出口费用 + 商业出口费用 + 驾意出口费用) - (交强出口留点费用 + 商业出口留点费用 + 驾意出口留点费用)
+     *
+     * @param param 查询参数,包含分页信息和筛选条件
+     * @return 分页结果,包含订单审核信息及计算后的权益金额
+     */
     @Override
     @Override
     public Page<FeeAuditVo> queryPage(FeeAuditParam param) {
     public Page<FeeAuditVo> queryPage(FeeAuditParam param) {
         log.info("订单审核-任务中心,查询待审核任务。param=[{}]", JSONUtil.toJsonStr(param));
         log.info("订单审核-任务中心,查询待审核任务。param=[{}]", JSONUtil.toJsonStr(param));
@@ -261,6 +279,15 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
 
 
     /**
     /**
      * 领取审核订单
      * 领取审核订单
+     * <p>
+     * 功能说明:
+     * 1. 检查订单是否已被Redis锁定,防止重复领取
+     * 2. 验证订单审核状态,已审核的订单不允许领取
+     * 3. 处理订单领取逻辑:
+     *    - 若订单已被当前用户领取,则刷新Redis锁
+     *    - 若订单已被其他用户领取,则拒绝操作
+     *    - 若订单未被领取,则在满足条件下进行领取
+     * 4. 限制每个用户最多同时领取10个未审核订单
      *
      *
      * @param orderNo 订单编号
      * @param orderNo 订单编号
      */
      */
@@ -299,6 +326,7 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
                 // 领取订单
                 // 领取订单
                 audit.setReceiveUser(userName);
                 audit.setReceiveUser(userName);
                 audit.setReceiveTime(LocalDateTime.now());
                 audit.setReceiveTime(LocalDateTime.now());
+//                audit.setAuditStatus(1);
                 this.updateById(audit);
                 this.updateById(audit);
 
 
                 // redis 锁定按钮
                 // redis 锁定按钮
@@ -501,7 +529,7 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
             exportChangeLog.setAmount(feeOrders.getTotalPayablePremium());
             exportChangeLog.setAmount(feeOrders.getTotalPayablePremium());
             exportChangeLog.setOperType(1);
             exportChangeLog.setOperType(1);
             exportChangeLog.setIsDelete(0);
             exportChangeLog.setIsDelete(0);
-            exportChangeLog.setRemark("订单提成");
+            exportChangeLog.setRemark("保单费用");
             exportChangeLog.setAmountBefore(sumAmountUnpaid);
             exportChangeLog.setAmountBefore(sumAmountUnpaid);
             orgClient.addUserAccountChangeLog(exportChangeLog);
             orgClient.addUserAccountChangeLog(exportChangeLog);
 
 
@@ -560,6 +588,38 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
     private void dealDistribution(InsFeeOrders feeOrders, SysUserAccount userAccount){
     private void dealDistribution(InsFeeOrders feeOrders, SysUserAccount userAccount){
         log.info("处理分销逻辑。 feeOrders=[{}],userAccount=[{}]", JSONUtil.toJsonStr(feeOrders), JSONUtil.toJsonStr(userAccount));
         log.info("处理分销逻辑。 feeOrders=[{}],userAccount=[{}]", JSONUtil.toJsonStr(feeOrders), JSONUtil.toJsonStr(userAccount));
         SysUserAccount distributor1 = null,distributor2 = null,distributor3 = null;
         SysUserAccount distributor1 = null,distributor2 = null,distributor3 = null;
+        List<String> jzgInfoTids = new ArrayList<>();
+        if(StrUtil.isNotEmpty(feeOrders.getFirstDistributorId())){
+            jzgInfoTids.add(feeOrders.getFirstDistributorId());
+        }
+        if(StrUtil.isNotEmpty(feeOrders.getSecondDistributorId())){
+            jzgInfoTids.add(feeOrders.getSecondDistributorId());
+        }
+        if(StrUtil.isNotEmpty(feeOrders.getThirdDistributorId())){
+            jzgInfoTids.add(feeOrders.getThirdDistributorId());
+        }
+        List<SysUserAccountChangeLog> builderIncomeLog =  new ArrayList<>();
+        if(CollUtil.isNotEmpty(jzgInfoTids)){
+            HttpResult<Map<String, String>> mapHttpResult = orgClient.queryJzgInfoId2UserId(jzgInfoTids);
+            if(mapHttpResult.getCode() != 200){
+                throw new ServiceException("服务间调用异常");
+            }
+            Map<String, String> idMaps = mapHttpResult.getData();
+            String distributor1UserId = "";
+            String distributor2UserId = "";
+            String distributor3UserId = "";
+            if(StrUtil.isNotEmpty(feeOrders.getFirstDistributorId())){
+                distributor1UserId = idMaps.getOrDefault(feeOrders.getFirstDistributorId(),"");
+            }
+            if(StrUtil.isNotEmpty(feeOrders.getSecondDistributorId())){
+                distributor2UserId = idMaps.getOrDefault(feeOrders.getSecondDistributorId(),"");
+            }
+            if(StrUtil.isNotEmpty(feeOrders.getThirdDistributorId())){
+                distributor3UserId = idMaps.getOrDefault(feeOrders.getThirdDistributorId(),"");
+            }
+            builderIncomeLog = this.builderIncomeLog(feeOrders.getOrderNo(),feeOrders,userAccount,distributor1UserId,distributor2UserId,distributor3UserId);
+        }
+
         // 一级分销费用户进账
         // 一级分销费用户进账
         if (feeOrders.getFirstDistributorId() != null && feeOrders.getFirstDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
         if (feeOrders.getFirstDistributorId() != null && feeOrders.getFirstDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
             HttpResult<SysUserJzgInfo> jzgInfoResult = orgClient.getUserInfoById(feeOrders.getFirstDistributorId());
             HttpResult<SysUserJzgInfo> jzgInfoResult = orgClient.getUserInfoById(feeOrders.getFirstDistributorId());
@@ -592,7 +652,7 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         }
         }
         // 增加账户的金额记录
         // 增加账户的金额记录
         // modify by lipf, 2026年5月20日11:31:59 审核通过后,才需要 生成收入明细日志
         // modify by lipf, 2026年5月20日11:31:59 审核通过后,才需要 生成收入明细日志
-        List<SysUserAccountChangeLog>builderIncomeLog = this.builderIncomeLog(feeOrders.getOrderNo(),feeOrders,userAccount,distributor1,distributor2,distributor3);
+
         HttpResult result2 = orgClient.addUserAccountIncomeLog(builderIncomeLog);
         HttpResult result2 = orgClient.addUserAccountIncomeLog(builderIncomeLog);
         AssertionUtils.isFail(result2.getCode() != 200,"账户记录添加失败,审核失败");
         AssertionUtils.isFail(result2.getCode() != 200,"账户记录添加失败,审核失败");
     }
     }
@@ -711,39 +771,58 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
      * @param orderNo      订单号
      * @param orderNo      订单号
      * @param feeOrders    费用
      * @param feeOrders    费用
      * @param userAccount  分账用户
      * @param userAccount  分账用户
-     * @param distributor1 1级分销人员
-     * @param distributor2 2级分销人员
-     * @param distributor3 3级分销人员
-     * @return
+     * @param distributor1UserId 1级分销人员
+     * @param distributor2UserId 2级分销人员
+     * @param distributor3UserId 3级分销人员
      */
      */
     private List<SysUserAccountChangeLog> builderIncomeLog(String orderNo,
     private List<SysUserAccountChangeLog> builderIncomeLog(String orderNo,
                                                            InsFeeOrders feeOrders,
                                                            InsFeeOrders feeOrders,
                                                            SysUserAccount userAccount,
                                                            SysUserAccount userAccount,
-                                                           SysUserAccount distributor1,
-                                                           SysUserAccount distributor2,
-                                                           SysUserAccount distributor3){
+                                                           String distributor1UserId,
+                                                           String distributor2UserId,
+                                                           String distributor3UserId){
         log.info("生成收入明细日志:feeOrders=[{}],userAccount=[{}],distributor1=[{}],distributor2=[{}],distributor3=[{}]",
         log.info("生成收入明细日志:feeOrders=[{}],userAccount=[{}],distributor1=[{}],distributor2=[{}],distributor3=[{}]",
-                JSONUtil.toJsonStr(feeOrders), JSONUtil.toJsonStr(userAccount), JSONUtil.toJsonStr(distributor1), JSONUtil.toJsonStr(distributor2), JSONUtil.toJsonStr(distributor3));
+                JSONUtil.toJsonStr(feeOrders), JSONUtil.toJsonStr(userAccount), distributor1UserId, distributor2UserId, distributor3UserId);
         List<SysUserAccountChangeLog> incomeLogs = new ArrayList<>();
         List<SysUserAccountChangeLog> incomeLogs = new ArrayList<>();
         // 1级分销费
         // 1级分销费
         if (feeOrders.getFirstDistributorId() != null && feeOrders.getFirstDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
         if (feeOrders.getFirstDistributorId() != null && feeOrders.getFirstDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
             SysUserAccountChangeLog distributor1IncomeLog = new SysUserAccountChangeLog();
             SysUserAccountChangeLog distributor1IncomeLog = new SysUserAccountChangeLog();
             distributor1IncomeLog.setRelatedOrderId(orderNo);
             distributor1IncomeLog.setRelatedOrderId(orderNo);
-            distributor1IncomeLog.setUserId(distributor1.getUserId());
+            distributor1IncomeLog.setUserId(distributor1UserId);
             distributor1IncomeLog.setAmount(feeOrders.getFirstDistributionFee());
             distributor1IncomeLog.setAmount(feeOrders.getFirstDistributionFee());
-            distributor1IncomeLog.setAmountBefore(userAccount.getSumAmount());
-            //distributor1IncomeLog.setUserName(); TODO
+            HttpResult<SysUserAccount> result = orgClient.accountGet(distributor1UserId);
+            if(result.getCode() == 200 && result.getData() != null){
+                distributor1IncomeLog.setAmountBefore(result.getData().getSumAmountUnpaid());
+            }
+            distributor1IncomeLog.setOperType(2);
+            distributor1IncomeLog.setRemark("订单提成");
+            distributor1IncomeLog.setIsDelete(0);
+            HttpResult<SysUser> sysUserHttpResult = sysUserClient.querySysUserByUserId(distributor1UserId);
+            if(sysUserHttpResult.isSuccess() && sysUserHttpResult.getData() != null ){
+                distributor1IncomeLog.setUserName(sysUserHttpResult.getData().getUsername());
+            }
             incomeLogs.add(distributor1IncomeLog);
             incomeLogs.add(distributor1IncomeLog);
+
         }
         }
 
 
         // 2级分销费
         // 2级分销费
         if (feeOrders.getSecondDistributorId() != null && feeOrders.getSecondDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
         if (feeOrders.getSecondDistributorId() != null && feeOrders.getSecondDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
             SysUserAccountChangeLog distributor2IncomeLog = new SysUserAccountChangeLog();
             SysUserAccountChangeLog distributor2IncomeLog = new SysUserAccountChangeLog();
             distributor2IncomeLog.setRelatedOrderId(orderNo);
             distributor2IncomeLog.setRelatedOrderId(orderNo);
-            distributor2IncomeLog.setUserId(distributor2.getUserId());
+            distributor2IncomeLog.setUserId(distributor2UserId);
             distributor2IncomeLog.setAmount(feeOrders.getFirstDistributionFee());
             distributor2IncomeLog.setAmount(feeOrders.getFirstDistributionFee());
-            distributor2IncomeLog.setAmountBefore(userAccount.getSumAmount());
-            //distributor2IncomeLog.setUserName(); TODO
+            HttpResult<SysUserAccount> result = orgClient.accountGet(distributor2UserId);
+            if(result.getCode() == 200 && result.getData() != null){
+                distributor2IncomeLog.setAmountBefore(result.getData().getSumAmountUnpaid());
+            }
+
+            distributor2IncomeLog.setOperType(2);
+            distributor2IncomeLog.setRemark("订单提成");
+            distributor2IncomeLog.setIsDelete(0);
+            HttpResult<SysUser> sysUserHttpResult = sysUserClient.querySysUserByUserId(distributor2UserId);
+            if(sysUserHttpResult.isSuccess() && sysUserHttpResult.getData() != null ){
+                distributor2IncomeLog.setUserName(sysUserHttpResult.getData().getUsername());
+            }
             incomeLogs.add(distributor2IncomeLog);
             incomeLogs.add(distributor2IncomeLog);
         }
         }
 
 
@@ -751,10 +830,19 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         if (feeOrders.getThirdDistributorId() != null && feeOrders.getThirdDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
         if (feeOrders.getThirdDistributorId() != null && feeOrders.getThirdDistributionFee().compareTo(BigDecimal.ZERO) > 0) {
             SysUserAccountChangeLog distributor3IncomeLog = new SysUserAccountChangeLog();
             SysUserAccountChangeLog distributor3IncomeLog = new SysUserAccountChangeLog();
             distributor3IncomeLog.setRelatedOrderId(orderNo);
             distributor3IncomeLog.setRelatedOrderId(orderNo);
-            distributor3IncomeLog.setUserId(distributor3.getUserId());
+            distributor3IncomeLog.setUserId(distributor3UserId);
             distributor3IncomeLog.setAmount(feeOrders.getFirstDistributionFee());
             distributor3IncomeLog.setAmount(feeOrders.getFirstDistributionFee());
-            distributor3IncomeLog.setAmountBefore(userAccount.getSumAmount());
-            //distributor3IncomeLog.setUserName(); TODO
+            HttpResult<SysUserAccount> result = orgClient.accountGet(distributor3UserId);
+            if(result.getCode() == 200 && result.getData() != null){
+                distributor3IncomeLog.setAmountBefore(result.getData().getSumAmountUnpaid());
+            }
+            distributor3IncomeLog.setOperType(2);
+            distributor3IncomeLog.setRemark("订单提成");
+            distributor3IncomeLog.setIsDelete(0);
+            HttpResult<SysUser> sysUserHttpResult = sysUserClient.querySysUserByUserId(distributor3UserId);
+            if(sysUserHttpResult.isSuccess() && sysUserHttpResult.getData() != null ){
+                distributor3IncomeLog.setUserName(sysUserHttpResult.getData().getUsername());
+            }
             incomeLogs.add(distributor3IncomeLog);
             incomeLogs.add(distributor3IncomeLog);
         }
         }
         return incomeLogs;
         return incomeLogs;
@@ -906,6 +994,8 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         param.getPage().setPages(1);
         param.getPage().setPages(1);
         param.getPage().setSize(Integer.MAX_VALUE);
         param.getPage().setSize(Integer.MAX_VALUE);
         param.setPages(1);
         param.setPages(1);
+        param.setSystemCode(baseController.getUserSystemCode());
+        param.setAuditStatus(param.getAuditStatus());
         param.setSize(Integer.MAX_VALUE);
         param.setSize(Integer.MAX_VALUE);
         Page<FeeAuditVo> feeAuditVoPage = this.queryPage(param);
         Page<FeeAuditVo> feeAuditVoPage = this.queryPage(param);
         List<FeeAuditVo> result = feeAuditVoPage.getRecords();
         List<FeeAuditVo> result = feeAuditVoPage.getRecords();

+ 30 - 9
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeOrdersServiceImpl.java

@@ -224,8 +224,8 @@ public class InsFeeOrdersServiceImpl extends ServiceImpl<InsFeeOrdersMapper, Ins
         // 加投直接乘
         // 加投直接乘
         BigDecimal addThrow = premium.multiply(addThrowRatio).setScale(scale, RoundingMode.HALF_EVEN);
         BigDecimal addThrow = premium.multiply(addThrowRatio).setScale(scale, RoundingMode.HALF_EVEN);
         // 出口直接乘
         // 出口直接乘
-        BigDecimal export = premium.multiply(exportRatio).setScale(scale, RoundingMode.HALF_EVEN);
-        BigDecimal exportKeepPoint = premium.multiply(exportKeepPointRatio).setScale(scale, RoundingMode.HALF_EVEN);
+        BigDecimal export = premium.multiply(exportRatio).setScale(scale, RoundingMode.DOWN);
+        BigDecimal exportKeepPoint = premium.multiply(exportKeepPointRatio).setScale(scale, RoundingMode.DOWN);
         // 留点比例直接乘, modify by lipf ,留点比例在infFeeOrder中计算得到。这里直接使用 2026年6月16日17:32:09, 为了保持金额一致,留点比例不适用百分比乘积,而是使用金额相减
         // 留点比例直接乘, modify by lipf ,留点比例在infFeeOrder中计算得到。这里直接使用 2026年6月16日17:32:09, 为了保持金额一致,留点比例不适用百分比乘积,而是使用金额相减
         // BigDecimal keepPoint = premium.multiply(keepPointRatio).setScale(scale, RoundingMode.HALF_EVEN);
         // BigDecimal keepPoint = premium.multiply(keepPointRatio).setScale(scale, RoundingMode.HALF_EVEN);
         BigDecimal keepPoint = BigDecimalUtil.subtract(BigDecimalUtil.add(inlet,addThrow),export);
         BigDecimal keepPoint = BigDecimalUtil.subtract(BigDecimalUtil.add(inlet,addThrow),export);
@@ -379,20 +379,41 @@ public class InsFeeOrdersServiceImpl extends ServiceImpl<InsFeeOrdersMapper, Ins
         BigDecimal jqCommissionRatio = covertPercent(ptlAgreementCostRatioVo.getJqCommissionRatio());
         BigDecimal jqCommissionRatio = covertPercent(ptlAgreementCostRatioVo.getJqCommissionRatio());
         BigDecimal syCommissionRatio = covertPercent(ptlAgreementCostRatioVo.getSyCommissionRatio());
         BigDecimal syCommissionRatio = covertPercent(ptlAgreementCostRatioVo.getSyCommissionRatio());
         BigDecimal jyCommissionRatio = covertPercent(ptlAgreementCostRatioVo.getJyCommissionRatio());
         BigDecimal jyCommissionRatio = covertPercent(ptlAgreementCostRatioVo.getJyCommissionRatio());
-        insFeeOrders.setJqCommissionRatio(jqCommissionRatio);
-        insFeeOrders.setSyCommissionRatio(syCommissionRatio);
-        insFeeOrders.setJyCommissionRatio(jyCommissionRatio);
+
         // 入口比例
         // 入口比例
         BigDecimal jqInletRatio = covertPercent(ptlAgreementCostRatioVo.getJqInletRatio());
         BigDecimal jqInletRatio = covertPercent(ptlAgreementCostRatioVo.getJqInletRatio());
         BigDecimal syInletRatio = covertPercent(ptlAgreementCostRatioVo.getSyInletRatio());
         BigDecimal syInletRatio = covertPercent(ptlAgreementCostRatioVo.getSyInletRatio());
         BigDecimal jyInletRatio = covertPercent(ptlAgreementCostRatioVo.getJyInletRatio());
         BigDecimal jyInletRatio = covertPercent(ptlAgreementCostRatioVo.getJyInletRatio());
+
+        BigDecimal jqFollowRatio = BigDecimal.ZERO;
+        BigDecimal syFollowRatio = BigDecimal.ZERO;
+        BigDecimal jyFollowRatio = BigDecimal.ZERO;
+        // 跟单比例
+        if (jqInletRatio.compareTo(jqCommissionRatio) > 0){
+            jqFollowRatio = jqInletRatio.subtract(jqCommissionRatio);
+        }else{
+            jqCommissionRatio = jqInletRatio;
+        }
+        if (syInletRatio.compareTo(syCommissionRatio) > 0){
+            syFollowRatio = syInletRatio.subtract(syCommissionRatio);
+        }else{
+            syCommissionRatio = syInletRatio;
+        }
+        if (jyInletRatio.compareTo(jyCommissionRatio) > 0){
+            jyFollowRatio = jyInletRatio.subtract(jyCommissionRatio);
+        }else{
+            jyCommissionRatio = jyInletRatio;
+        }
+
+        // 手续费
+        insFeeOrders.setJqCommissionRatio(jqCommissionRatio);
+        insFeeOrders.setSyCommissionRatio(syCommissionRatio);
+        insFeeOrders.setJyCommissionRatio(jyCommissionRatio);
+        // 入口费用
         insFeeOrders.setJqInletRatio(jqInletRatio);
         insFeeOrders.setJqInletRatio(jqInletRatio);
         insFeeOrders.setSyInletRatio(syInletRatio);
         insFeeOrders.setSyInletRatio(syInletRatio);
         insFeeOrders.setJyInletRatio(jyInletRatio);
         insFeeOrders.setJyInletRatio(jyInletRatio);
-        // 跟单比例 
-        BigDecimal jqFollowRatio = jqInletRatio.subtract(jqCommissionRatio);
-        BigDecimal syFollowRatio = syInletRatio.subtract(syCommissionRatio);
-        BigDecimal jyFollowRatio = jyInletRatio.subtract(jyCommissionRatio);
+        // 跟单费
         insFeeOrders.setJqFollowRatio(jqFollowRatio);
         insFeeOrders.setJqFollowRatio(jqFollowRatio);
         insFeeOrders.setSyFollowRatio(syFollowRatio);
         insFeeOrders.setSyFollowRatio(syFollowRatio);
         insFeeOrders.setJyFollowRatio(jyFollowRatio);
         insFeeOrders.setJyFollowRatio(jyFollowRatio);

+ 2 - 2
tenant/insurance/quotation-summary/src/main/resources/mapper/InsFeeAuditMapper.xml

@@ -89,9 +89,9 @@
             <if test="param.receiveUser != null and param.receiveUser != ''">
             <if test="param.receiveUser != null and param.receiveUser != ''">
                 and ifa.receive_user = #{param.receiveUser}
                 and ifa.receive_user = #{param.receiveUser}
             </if>
             </if>
-            <if test="param.receiveUser == null or param.receiveUser == ''">
+            <!--<if test="param.receiveUser == null or param.receiveUser == ''">
                 and ifa.receive_user is null
                 and ifa.receive_user is null
-            </if>
+            </if>-->
             <if test="param.allTodoReceive != null and param.allTodoReceive == true">
             <if test="param.allTodoReceive != null and param.allTodoReceive == true">
                 and ifa.receive_user is null
                 and ifa.receive_user is null
             </if>
             </if>

+ 3 - 1
tenant/insurance/quotation-zijin/src/main/java/com/jzg/quotation/zijin/crawler/build/ZiJinCrawlerUnderwritingResultsVoBuild.java

@@ -17,10 +17,12 @@ import org.jetbrains.annotations.NotNull;
 public class ZiJinCrawlerUnderwritingResultsVoBuild {
 public class ZiJinCrawlerUnderwritingResultsVoBuild {
 
 
     @NotNull
     @NotNull
-    public static UnderwritingResultsVo buildUnderwritingResultsVo(ZiJinCrawlerUnderwritingResponse ziJinCrawlerUnderwritingResponse) {
+    public static UnderwritingResultsVo buildUnderwritingResultsVo(ZiJinCrawlerUnderwritingResponse ziJinCrawlerUnderwritingResponse, String ordersNo) {
         UnderwritingResultsVo underwritingResultsVo = new UnderwritingResultsVo();
         UnderwritingResultsVo underwritingResultsVo = new UnderwritingResultsVo();
+        underwritingResultsVo.setOrdersNo(ordersNo);
         // 核保成功
         // 核保成功
         if (ResponseCode.R_0000.getCode().equals(ziJinCrawlerUnderwritingResponse.getRtnCode())) {
         if (ResponseCode.R_0000.getCode().equals(ziJinCrawlerUnderwritingResponse.getRtnCode())) {
+            underwritingResultsVo.setCompanyOrderNo(ziJinCrawlerUnderwritingResponse.getData().getOrderNo());
             underwritingResultsVo.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
             underwritingResultsVo.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
             underwritingResultsVo.setJqApplyNo(ziJinCrawlerUnderwritingResponse.getData().getResultObj().getProposalNoCI());
             underwritingResultsVo.setJqApplyNo(ziJinCrawlerUnderwritingResponse.getData().getResultObj().getProposalNoCI());
             underwritingResultsVo.setSyApplyNo(ziJinCrawlerUnderwritingResponse.getData().getResultObj().getProposalNo());
             underwritingResultsVo.setSyApplyNo(ziJinCrawlerUnderwritingResponse.getData().getResultObj().getProposalNo());

+ 1 - 2
tenant/insurance/quotation-zijin/src/main/java/com/jzg/quotation/zijin/crawler/service/impl/ZiJinCrawlerRequestImpl.java

@@ -206,8 +206,7 @@ public class ZiJinCrawlerRequestImpl implements ZiJinCrawlerRequest {
             e.printStackTrace();
             e.printStackTrace();
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
-
-        return ZiJinCrawlerUnderwritingResultsVoBuild.buildUnderwritingResultsVo(ziJinCrawlerUnderwritingResponse);
+        return ZiJinCrawlerUnderwritingResultsVoBuild.buildUnderwritingResultsVo(ziJinCrawlerUnderwritingResponse, underwritingVo.getOrder().getOrdersNo());
     }
     }
 
 
 
 

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

@@ -732,7 +732,7 @@ public class ReceivableController {
      */
      */
     @PostMapping("/platformCompanySuperviseSettlementReport")
     @PostMapping("/platformCompanySuperviseSettlementReport")
     @Operation(summary = "平台公司结算报表")
     @Operation(summary = "平台公司结算报表")
-    public HttpResult<List<FollowCompanyFeeVO>> platformCompanySuperviseSettlementReport(@RequestBody SettlementReportQueryVo settlementReportQueryVo) {
+    public HttpResult<List<PlatformCompanyFeeVO>> platformCompanySuperviseSettlementReport(@RequestBody SettlementReportQueryVo settlementReportQueryVo) {
         return HttpResult.ok(receivableService.platformCompanySuperviseSettlementReport(settlementReportQueryVo));
         return HttpResult.ok(receivableService.platformCompanySuperviseSettlementReport(settlementReportQueryVo));
     }
     }
 
 

+ 16 - 0
tenant/organization/src/main/java/com/jzg/organization/controller/SysUserJzgInfoController.java

@@ -9,8 +9,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
 
 
+import java.util.List;
+import java.util.Map;
+
 
 
 @RestController
 @RestController
 public class SysUserJzgInfoController {
 public class SysUserJzgInfoController {
@@ -34,4 +39,15 @@ public class SysUserJzgInfoController {
         SysUserJzgInfo jzgInfo = sysUserJzgInfoService.getUserByUserId(userId);
         SysUserJzgInfo jzgInfo = sysUserJzgInfoService.getUserByUserId(userId);
         return  HttpResult.ok(jzgInfo);
         return  HttpResult.ok(jzgInfo);
     }
     }
+
+    /**
+     * 查询sys_user_jzg_info 表的id和userId的对应关系
+     *
+     * @author lipf
+     * @date 2026/6/30 14:15
+     */
+    @PostMapping("/api/v1/organization/queryJzgInfoId2UserId")
+    public HttpResult<Map<String,String>> queryJzgInfoId2UserId(@RequestBody List<String> jzgInfoTids){
+        return HttpResult.ok(sysUserJzgInfoService.queryJzgInfoId2UserId(jzgInfoTids));
+    }
 }
 }

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

@@ -337,4 +337,19 @@ public class UserController extends BaseController {
         return sysUserService.getPartUserInfoByMobile(mobile);
         return sysUserService.getPartUserInfoByMobile(mobile);
     }
     }
 
 
+
+    /**
+     * 根据userId查询用户信息SysUser
+     *
+     * @author lipf
+     * @date 2026/6/30 11:27
+     */
+    @Operation(summary = "根据userId查询用户信息SysUser", description = "根据userId查询用户信息SysUser")
+    @GetMapping(value = "/querySysUserByUserId")
+    public HttpResult<SysUser> querySysUserByUserId(@RequestParam String userId){
+        SysUser sysUser = sysUserService.querySysUserByUserId(userId);
+        return HttpResult.ok(sysUser);
+    }
+
+
 }
 }

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

@@ -1,11 +1,21 @@
 package com.jzg.organization.mapper;
 package com.jzg.organization.mapper;
 
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoice;
 import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoiceSettlement;
 import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoiceSettlement;
+import com.jzg.commons.entity.finance.vo.SettlementVo;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 
 @Mapper
 @Mapper
 public interface InsPlyIncomeInvoiceSettlementMapper extends BaseMapper<InsPlyIncomeInvoiceSettlement> {
 public interface InsPlyIncomeInvoiceSettlementMapper extends BaseMapper<InsPlyIncomeInvoiceSettlement> {
 
 
+    /**
+     * 查询所有已结算记录的结算金额和回款差额的汇总值
+     *
+     * @author lipf
+     * @date 2026/6/30 15:39
+     */
+    SettlementVo querySettlementAndDiff(@Param("settlementIds") List<String> settlementIds);
 }
 }

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

@@ -286,5 +286,5 @@ public interface ReceivableMapper extends BaseMapper<InsPlyIncome> {
      */
      */
     InsPlyIncomeInvoiceSettlementVo querySettledAmountByInvoiceIds(@Param("invoiceIdList") List<String> invoiceIdList);
     InsPlyIncomeInvoiceSettlementVo querySettledAmountByInvoiceIds(@Param("invoiceIdList") List<String> invoiceIdList);
 
 
-    List<FollowCompanyFeeVO> selectPlatformCompanySettlementReport(@Param("query") SettlementReportQueryVo settlementReportQueryVo);
+    List<PlatformCompanyFeeVO> selectPlatformCompanySettlementReport(@Param("query") SettlementReportQueryVo settlementReportQueryVo);
 }
 }

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

@@ -511,5 +511,5 @@ public interface ReceivableService extends IService<InsPlyIncome> {
 
 
     List<FollowCompanyFeeVO> followCompanySuperviseSettlementReport(SettlementReportQueryVo settlementReportQueryVo);
     List<FollowCompanyFeeVO> followCompanySuperviseSettlementReport(SettlementReportQueryVo settlementReportQueryVo);
 
 
-    List<FollowCompanyFeeVO> platformCompanySuperviseSettlementReport(SettlementReportQueryVo settlementReportQueryVo);
+    List<PlatformCompanyFeeVO> platformCompanySuperviseSettlementReport(SettlementReportQueryVo settlementReportQueryVo);
 }
 }

+ 9 - 0
tenant/organization/src/main/java/com/jzg/organization/service/SysUserJzgInfoService.java

@@ -7,6 +7,7 @@ import com.jzg.commons.entity.po.SysUserJzgInfo;
 import com.jzg.commons.entity.vo.PartnerRecommenderVo;
 import com.jzg.commons.entity.vo.PartnerRecommenderVo;
 
 
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 public interface SysUserJzgInfoService extends IService<SysUserJzgInfo> {
 public interface SysUserJzgInfoService extends IService<SysUserJzgInfo> {
 
 
@@ -61,4 +62,12 @@ public interface SysUserJzgInfoService extends IService<SysUserJzgInfo> {
      * @date 2026/4/24 15:29
      * @date 2026/4/24 15:29
      */
      */
     void logicDeleteJzgInfo(Long userId);
     void logicDeleteJzgInfo(Long userId);
+
+    /**
+     * 查询sys_user_jzg_info 表的id和userId的对应关系
+     *
+     * @author lipf
+     * @date 2026/6/30 14:15
+     */
+    Map<String, String> queryJzgInfoId2UserId(List<String> jzgInfoTids);
 }
 }

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

@@ -286,4 +286,12 @@ public interface SysUserService extends IService<SysUser> {
     SysUserJzgInfo selectByUserIdInfo(String userId);
     SysUserJzgInfo selectByUserIdInfo(String userId);
 
 
     SysUserJzgInfo getPartUserInfoByMobile(String mobile);
     SysUserJzgInfo getPartUserInfoByMobile(String mobile);
+
+    /**
+     * 根据userId查询用户信息 SysUser
+     *
+     * @author lipf
+     * @date 2026/6/30 11:27
+     */
+    SysUser querySysUserByUserId(String userId);
 }
 }

+ 4 - 1
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementServiceImpl.java

@@ -173,6 +173,9 @@ public class PtlAgreementServiceImpl extends ServiceImpl<PtlAgreementMapper, Ptl
             log.info("协议id不存在:id=[{}]",id);
             log.info("协议id不存在:id=[{}]",id);
             throw new SystemException("协议id不存在!id=" + id);
             throw new SystemException("协议id不存在!id=" + id);
         }
         }
+        if (Objects.isNull(agreementVo.getUsername())){
+            agreementVo.setUsername("");
+        }
         return agreementVo;
         return agreementVo;
     }
     }
 
 
@@ -228,7 +231,7 @@ public class PtlAgreementServiceImpl extends ServiceImpl<PtlAgreementMapper, Ptl
 
 
 
 
     @Override
     @Override
-    @GlobalTransactional(rollbackFor = Exception.class)
+//    @GlobalTransactional(rollbackFor = Exception.class)
     public void agreementAdd(AgreementAddParam param) {
     public void agreementAdd(AgreementAddParam param) {
         PtlAgreement ptlAgreement = new PtlAgreement();
         PtlAgreement ptlAgreement = new PtlAgreement();
         BeanUtils.copyProperties(param,ptlAgreement);
         BeanUtils.copyProperties(param,ptlAgreement);

+ 18 - 9
tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java

@@ -761,20 +761,29 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
      * - companyName: 保险公司名称  - companyId: 保险公司ID - contactPerson: 对接人   - contactPersonPhone: 对接人手机号  - partnerCompanyId: 分支保险公司ID  - totalInvoiced: 已开票总金额  - totalUnInvoiced: 未开票总金额  - totalSettlementAmount: 已结算总金额  - totalUnSettlementAmount: 未结算总金额(统一设置为0) - totalPaymentDifference: 回款差额  - totalReceivable: 累计应收
      * - companyName: 保险公司名称  - companyId: 保险公司ID - contactPerson: 对接人   - contactPersonPhone: 对接人手机号  - partnerCompanyId: 分支保险公司ID  - totalInvoiced: 已开票总金额  - totalUnInvoiced: 未开票总金额  - totalSettlementAmount: 已结算总金额  - totalUnSettlementAmount: 未结算总金额(统一设置为0) - totalPaymentDifference: 回款差额  - totalReceivable: 累计应收
      */
      */
     @Override
     @Override
-    public List<FollowCompanyFeeVO> platformCompanySuperviseSettlementReport(SettlementReportQueryVo settlementReportQueryVo) {
+    public List<PlatformCompanyFeeVO> platformCompanySuperviseSettlementReport(SettlementReportQueryVo settlementReportQueryVo) {
         log.info("平台协议-结算记录-结算报表: settlementReportQueryVo=[{}]", JSONUtil.toJsonStr(settlementReportQueryVo));
         log.info("平台协议-结算记录-结算报表: settlementReportQueryVo=[{}]", JSONUtil.toJsonStr(settlementReportQueryVo));
-
-        List<FollowCompanyFeeVO> platformCompanyFeeVos = baseMapper.selectPlatformCompanySettlementReport(settlementReportQueryVo);
+        List<PlatformCompanyFeeVO> platformCompanyFeeVos = baseMapper.selectPlatformCompanySettlementReport(settlementReportQueryVo);
         // 过滤掉对接人和对接人手机号为空的数据
         // 过滤掉对接人和对接人手机号为空的数据
-        List<FollowCompanyFeeVO> list = platformCompanyFeeVos.stream().filter(plat -> StrUtil.isNotBlank(plat.getContactPerson()) && StrUtil.isNotBlank(plat.getContactPersonPhone())).toList();
+        // List<PlatformCompanyFeeVO> list = platformCompanyFeeVos.stream().filter(plat -> StrUtil.isNotBlank(plat.getContactPerson()) && StrUtil.isNotBlank(plat.getContactPersonPhone())).toList();
         // 查询所有保险公司,匹配保险公司的id和名称
         // 查询所有保险公司,匹配保险公司的id和名称
         HttpResult<Map<String, EsmInsCompany>> mapHttpResult = esmInsCompanyClient.queryAllCompanyMap();
         HttpResult<Map<String, EsmInsCompany>> mapHttpResult = esmInsCompanyClient.queryAllCompanyMap();
         Map<String, EsmInsCompany> data = mapHttpResult.getData();
         Map<String, EsmInsCompany> data = mapHttpResult.getData();
-        for (FollowCompanyFeeVO platformCompanyFeeVo : list) {
+        for (PlatformCompanyFeeVO platformCompanyFeeVo : platformCompanyFeeVos) {
             platformCompanyFeeVo.setCompanyName(null != data.get(platformCompanyFeeVo.getCompanyId()) ? data.get(platformCompanyFeeVo.getCompanyId()).getName() : "");
             platformCompanyFeeVo.setCompanyName(null != data.get(platformCompanyFeeVo.getCompanyId()) ? data.get(platformCompanyFeeVo.getCompanyId()).getName() : "");
-            platformCompanyFeeVo.setTotalUnSettlementAmount(BigDecimal.ZERO);
+            String settleIdsStr = platformCompanyFeeVo.getSettleIdsStr();
+            if(StrUtil.isNotEmpty(settleIdsStr)){
+                List<String> settlementIds = Arrays.asList(settleIdsStr.split(","));
+                SettlementVo vo =  insPlyIncomeInvoiceSettlementMapper.querySettlementAndDiff(settlementIds);
+                platformCompanyFeeVo.setTotalSettlementAmount(vo.getActualReceivedAmount());
+                platformCompanyFeeVo.setTotalPaymentDifference(vo.getSettlementPaymentDifference());
+            }else{
+                platformCompanyFeeVo.setTotalSettlementAmount(BigDecimal.ZERO);
+                platformCompanyFeeVo.setTotalPaymentDifference(BigDecimal.ZERO);
+            }
+            platformCompanyFeeVo.setTotalUnSettlementAmount(BigDecimalUtil.subtract(BigDecimalUtil.subtract(platformCompanyFeeVo.getTotalReceivable(),platformCompanyFeeVo.getTotalSettlementAmount()), platformCompanyFeeVo.getTotalPaymentDifference()));
         }
         }
-        return list;
+        return platformCompanyFeeVos;
     }
     }
 
 
 
 
@@ -2970,7 +2979,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         BigDecimal jqCommissionRatio = BigDecimal.ZERO;
         BigDecimal jqCommissionRatio = BigDecimal.ZERO;
         BigDecimal jqFollowRatio = BigDecimal.ZERO;
         BigDecimal jqFollowRatio = BigDecimal.ZERO;
         if(batchModifyVo.getJqSuperviseCostsProportion() != null && batchModifyVo.getJqOtherCostsProportion() == null){
         if(batchModifyVo.getJqSuperviseCostsProportion() != null && batchModifyVo.getJqOtherCostsProportion() == null){
-            jqInletRatio = insFeeOrders .getJqInletRatio();
+            jqInletRatio = insFeeOrders.getJqInletRatio();
             jqCommissionRatio = batchModifyVo.getJqSuperviseCostsProportion();
             jqCommissionRatio = batchModifyVo.getJqSuperviseCostsProportion();
             if (jqCommissionRatio.compareTo(jqInletRatio) > 0){
             if (jqCommissionRatio.compareTo(jqInletRatio) > 0){
                 jqCommissionRatio = jqInletRatio;
                 jqCommissionRatio = jqInletRatio;
@@ -3070,7 +3079,6 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
      */
      */
     private PtlAgreementCostRatioVo calRatio(InsPlyIncome insPlyIncome, BatchModifyVo batchModifyVo) {
     private PtlAgreementCostRatioVo calRatio(InsPlyIncome insPlyIncome, BatchModifyVo batchModifyVo) {
         log.info("batchModifyVo.转换百分比之前的数据=【{}】", JSONUtil.toJsonStr(batchModifyVo));
         log.info("batchModifyVo.转换百分比之前的数据=【{}】", JSONUtil.toJsonStr(batchModifyVo));
-        batchModifyVo.divide100();
         PtlAgreementCostRatioVo vo = new PtlAgreementCostRatioVo();
         PtlAgreementCostRatioVo vo = new PtlAgreementCostRatioVo();
         vo.setOrderNo(insPlyIncome.getOrderNo());
         vo.setOrderNo(insPlyIncome.getOrderNo());
 
 
@@ -3161,6 +3169,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
 
 
         // 准备批量更新的实体列表
         // 准备批量更新的实体列表
         List<InsPlyIncome> updateList = new ArrayList<>();
         List<InsPlyIncome> updateList = new ArrayList<>();
+        batchModifyVo.divide100();
 
 
         for (InsPlyIncome income : incomeList) {
         for (InsPlyIncome income : incomeList) {
             BigDecimal taxRate = taxRateMap.getOrDefault(income.getOrderNo(), BigDecimal.ONE);
             BigDecimal taxRate = taxRateMap.getOrDefault(income.getOrderNo(), BigDecimal.ONE);

+ 29 - 0
tenant/organization/src/main/java/com/jzg/organization/service/impl/SysUserJzgInfoServiceImpl.java

@@ -1,5 +1,6 @@
 package com.jzg.organization.service.impl;
 package com.jzg.organization.service.impl;
 
 
+import cn.hutool.core.collection.CollUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -11,7 +12,10 @@ import com.jzg.organization.service.SysUserJzgInfoService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 /**
 /**
  * @author quchen
  * @author quchen
@@ -102,4 +106,29 @@ public class SysUserJzgInfoServiceImpl extends ServiceImpl<SysUserJzgInfoMapper,
     public void logicDeleteJzgInfo(Long userId) {
     public void logicDeleteJzgInfo(Long userId) {
         sysUserJzgInfoMapper.updateUserByUserId(String.valueOf(userId));
         sysUserJzgInfoMapper.updateUserByUserId(String.valueOf(userId));
     }
     }
+
+    /**
+     * 查询sys_user_jzg_info 表的id和userId的对应关系
+     *
+     * @param jzgInfoTids sys_user_jzg_info 表的序号集
+     * @author lipf
+     * @date 2026/6/30 14:15
+     */
+    @Override
+    public Map<String, String> queryJzgInfoId2UserId(List<String> jzgInfoTids) {
+        if(CollUtil.isEmpty(jzgInfoTids)){
+            return Collections.emptyMap();
+        }
+
+        Map<String,String> res = new HashMap<>();
+        for (String jzgInfoTid : jzgInfoTids) {
+            SysUserJzgInfo sysUserJzgInfo = baseMapper.selectById(jzgInfoTid);
+            if(sysUserJzgInfo == null){
+                continue;
+            }
+            res.put(jzgInfoTid,sysUserJzgInfo.getUserId());
+
+        }
+        return res;
+    }
 }
 }

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

@@ -1539,6 +1539,17 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
         return sysUserJzgInfoMapper.getPartUserInfoByMobile(mobile);
         return sysUserJzgInfoMapper.getPartUserInfoByMobile(mobile);
     }
     }
 
 
+    /**
+     * 根据userId查询用户信息 SysUser
+     *
+     * @param userId sys_user 表的序号
+     * @author lipf
+     * @date 2026/6/30 11:27
+     */
+    @Override
+    public SysUser querySysUserByUserId(String userId) {
+        return baseMapper.selectById(userId);
+    }
 
 
     public void addPartner(SysUserVo sysUserVo){
     public void addPartner(SysUserVo sysUserVo){
         String referrerId = sysUserVo.getReferrerId();
         String referrerId = sysUserVo.getReferrerId();

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

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jzg.organization.mapper.InsPlyIncomeInvoiceSettlementMapper">
+    <!-- 查询所有已结算记录的结算金额和回款差额的汇总值 lipf 2026年6月30日15:43:15  -->
+    <select id="querySettlementAndDiff" resultType="com.jzg.commons.entity.finance.vo.SettlementVo">
+        select
+            sum(COALESCE(ipiis.actual_received_amount, 0.0)) as actual_received_amount ,
+            sum(COALESCE(ipiis.settlement_payment_difference,0.0) ) AS settlement_payment_difference
+        from
+            ins_ply_income_invoice_settlement ipiis
+        <where>
+            ipiis.is_delete = 0
+            <if test="settlementIds != null and settlementIds.size() > 0 ">
+                AND ipiis.id in
+                <foreach collection="settlementIds" item="id" open="(" separator="," close=")">
+                    #{id}
+                </foreach>
+            </if>
+        </where>
+    </select>
+</mapper>

+ 10 - 9
tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

@@ -2087,28 +2087,28 @@
     </select>
     </select>
 
 
 
 
-    <select id="selectPlatformCompanySettlementReport" resultType="com.jzg.commons.entity.finance.vo.FollowCompanyFeeVO">
+    <select id="selectPlatformCompanySettlementReport" resultType="com.jzg.commons.entity.finance.vo.PlatformCompanyFeeVO">
         SELECT
         SELECT
         ipi.company_id,
         ipi.company_id,
-        ipii.contact_person,
-        ipii.contact_person_phone,
-        COALESCE(SUM(sett.actual_received_amount), 0.00) AS totalSettlementAmount,
-        COALESCE(SUM(ipii.receivable_supervise_premium), 0.00) AS totalReceivable,
-        COALESCE(SUM(sett.settlement_payment_difference), 0.00) AS totalPaymentDifference
+        io.docking_person as contact_person ,
+        io.docking_person_phone as contact_person_phone,
+        SUM(COALESCE(ipi.jq_receivable_premium,0) + COALESCE(ipi.sy_receivable_premium,0) + COALESCE(ipi.jy_receivable_premium,0)) AS totalReceivable,
+        group_concat(distinct sett.id) as settle_idsStr
         FROM ins_ply_income ipi
         FROM ins_ply_income ipi
         LEFT JOIN ins_ply_income_invoice_link ipil ON ipi.id = ipil.income_id AND ipil.is_delete = 0
         LEFT JOIN ins_ply_income_invoice_link ipil ON ipi.id = ipil.income_id AND ipil.is_delete = 0
         LEFT JOIN ins_ply_income_invoice ipii ON ipil.invoice_id = ipii.id AND ipii.is_delete = 0
         LEFT JOIN ins_ply_income_invoice ipii ON ipil.invoice_id = ipii.id AND ipii.is_delete = 0
         LEFT JOIN ins_ply_income_invoice_settlement sett ON ipii.id = sett.invoice_id AND sett.is_delete = 0
         LEFT JOIN ins_ply_income_invoice_settlement sett ON ipii.id = sett.invoice_id AND sett.is_delete = 0
+        left join ins_orders io on ipi.order_no = io.id
         <where>
         <where>
             ipi.is_delete = 0
             ipi.is_delete = 0
             <if test="query.companyId != null and query.companyId != ''">
             <if test="query.companyId != null and query.companyId != ''">
                 AND ipi.company_id = #{query.companyId}
                 AND ipi.company_id = #{query.companyId}
             </if>
             </if>
             <if test="query.contactPersonPhone != null and query.contactPersonPhone != ''">
             <if test="query.contactPersonPhone != null and query.contactPersonPhone != ''">
-                AND ipii.contact_person_phone LIKE CONCAT('%', #{query.contactPersonPhone}, '%')
+                AND io.docking_person_phone LIKE CONCAT('%', #{query.contactPersonPhone}, '%')
             </if>
             </if>
             <if test="query.contactPerson != null and query.contactPerson != ''">
             <if test="query.contactPerson != null and query.contactPerson != ''">
-                AND ipii.contact_person LIKE CONCAT('%', #{query.contactPerson}, '%')
+                AND io.docking_person LIKE CONCAT('%', #{query.contactPerson}, '%')
             </if>
             </if>
             -- 跟单订单创建时间范围
             -- 跟单订单创建时间范围
             <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
             <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
@@ -2127,7 +2127,8 @@
                 AND sett.create_time BETWEEN #{query.settlementStartTime} AND #{query.settlementEndTime}
                 AND sett.create_time BETWEEN #{query.settlementStartTime} AND #{query.settlementEndTime}
             </if>
             </if>
         </where>
         </where>
-        GROUP BY ipii.contact_person_phone, ipii.contact_person, ipi.company_id
+        GROUP BY ipi.company_id, io.docking_person,io.docking_person_phone
+        order by settle_idsStr desc
     </select>
     </select>
 
 
 
 

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

@@ -72,7 +72,7 @@
                 and sujibc.audit_status = #{sysUserJzgInfoBankCardVo.auditStatus}
                 and sujibc.audit_status = #{sysUserJzgInfoBankCardVo.auditStatus}
             </if>
             </if>
             <if test="sysUserJzgInfoBankCardVo.userId != null and sysUserJzgInfoBankCardVo.userId != ''">
             <if test="sysUserJzgInfoBankCardVo.userId != null and sysUserJzgInfoBankCardVo.userId != ''">
-                and su.id = #{sysUserJzgInfoBankCardVo.userId}
+                and sujibc.user_info_id = #{sysUserJzgInfoBankCardVo.userId}
             </if>
             </if>
         </where>
         </where>
         order by
         order by