Răsfoiți Sursa

物流合同增加派车方式字段
自动派单评分管理功能

tangyishan 1 lună în urmă
părinte
comite
ec2815c0d0
35 a modificat fișierele cu 3788 adăugiri și 20 ștergeri
  1. 1018 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/Convert.java
  2. 36 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/PageUtils.java
  3. 254 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/ServletUtils.java
  4. 599 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/StringUtil.java
  5. 71 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/sql/SqlUtil.java
  6. 6 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/config/CustomConfig.java
  7. 70 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/controller/BaseController.java
  8. 102 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/page/PageDomain.java
  9. 57 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/page/TableSupport.java
  10. 5 1
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/response/result/PageDataResult.java
  11. 20 0
      sckw-common/sckw-common-redis/src/main/java/com/sckw/redis/constant/RedisConstant.java
  12. 16 0
      sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/feign/LogisticsScoreFeignService.java
  13. 46 0
      sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/model/dto/req/LogisticsScoreDetailFeignDto.java
  14. 31 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/api/KwcContractLogisticsScoreApiController.java
  15. 102 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/controller/KwcContractLogisticsScoreController.java
  16. 84 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dao/KwcContractLogisticsScoreDetailMapper.java
  17. 87 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dao/KwcContractLogisticsScoreMapper.java
  18. 24 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreApprovalDto.java
  19. 54 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreDetailAddDto.java
  20. 39 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreDetailQueryDto.java
  21. 22 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreQueryDto.java
  22. 41 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/entity/KwcContractLogisticsScore.java
  23. 49 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/entity/KwcContractLogisticsScoreDetail.java
  24. 1 1
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/req/LogisticListReq.java
  25. 50 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/res/LogisticsScoreDetailResVo.java
  26. 35 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/res/LogisticsScoreResVo.java
  27. 22 1
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/repository/KwcContractLogisticsRepository.java
  28. 8 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/repository/KwcContractLogisticsUnitRepository.java
  29. 96 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/IKwcContractLogisticsScoreService.java
  30. 476 0
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/impl/KwcContractLogisticsScoreServiceImpl.java
  31. 30 17
      sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractLogisticsService.java
  32. 110 0
      sckw-modules/sckw-contract/src/main/resources/mapper/KwcContractLogisticsScoreDetailMapper.xml
  33. 95 0
      sckw-modules/sckw-contract/src/main/resources/mapper/KwcContractLogisticsScoreMapper.xml
  34. 1 0
      sql/2025/12/01/2025_12_03_tys_alert.sql
  35. 31 0
      sql/2025/12/09/2025_12_09_tys_creat.sql

+ 1018 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/Convert.java

@@ -0,0 +1,1018 @@
+package com.sckw.core.utils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.text.NumberFormat;
+import java.util.Set;
+
+/**
+ * 类型转换器
+ * 
+ * @author tangyishan
+ */
+public class Convert
+{
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static String toStr(Object value, String defaultValue)
+    {
+        if (null == value)
+        {
+            return defaultValue;
+        }
+        if (value instanceof String)
+        {
+            return (String) value;
+        }
+        return value.toString();
+    }
+
+    /**
+     * 转换为字符串<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static String toStr(Object value)
+    {
+        return toStr(value, null);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为null,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Character toChar(Object value, Character defaultValue)
+    {
+        if (null == value)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Character)
+        {
+            return (Character) value;
+        }
+
+        final String valueStr = toStr(value, null);
+        return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
+    }
+
+    /**
+     * 转换为字符<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Character toChar(Object value)
+    {
+        return toChar(value, null);
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Byte toByte(Object value, Byte defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Byte)
+        {
+            return (Byte) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).byteValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Byte.parseByte(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Byte toByte(Object value)
+    {
+        return toByte(value, null);
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Short toShort(Object value, Short defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Short)
+        {
+            return (Short) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).shortValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Short.parseShort(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Short toShort(Object value)
+    {
+        return toShort(value, null);
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Number toNumber(Object value, Number defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Number)
+        {
+            return (Number) value;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return NumberFormat.getInstance().parse(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Number toNumber(Object value)
+    {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Integer toInt(Object value, Integer defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Integer)
+        {
+            return (Integer) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).intValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Integer.parseInt(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Integer toInt(Object value)
+    {
+        return toInt(value, null);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     * 
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String str)
+    {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 转换为Long数组<br>
+     * 
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String str)
+    {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     * 
+     * @param split 分隔符
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String split, String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new Integer[] {};
+        }
+        String[] arr = str.split(split);
+        final Integer[] ints = new Integer[arr.length];
+        for (int i = 0; i < arr.length; i++)
+        {
+            final Integer v = toInt(arr[i], 0);
+            ints[i] = v;
+        }
+        return ints;
+    }
+
+    /**
+     * 转换为Long数组<br>
+     * 
+     * @param split 分隔符
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String split, String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new Long[] {};
+        }
+        String[] arr = str.split(split);
+        final Long[] longs = new Long[arr.length];
+        for (int i = 0; i < arr.length; i++)
+        {
+            final Long v = toLong(arr[i], null);
+            longs[i] = v;
+        }
+        return longs;
+    }
+
+    /**
+     * 转换为String数组<br>
+     * 
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new String[] {};
+        }
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 转换为String数组<br>
+     * 
+     * @param split 分隔符
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String split, String str)
+    {
+        return str.split(split);
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Long toLong(Object value, Long defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Long)
+        {
+            return (Long) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).longValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).longValue();
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Long toLong(Object value)
+    {
+        return toLong(value, null);
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Double toDouble(Object value, Double defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Double)
+        {
+            return (Double) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).doubleValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            // 支持科学计数法
+            return new BigDecimal(valueStr.trim()).doubleValue();
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Double toDouble(Object value)
+    {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Float toFloat(Object value, Float defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Float)
+        {
+            return (Float) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).floatValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Float.parseFloat(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Float toFloat(Object value)
+    {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 转换为boolean<br>
+     * String支持的值为:true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value, Boolean defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Boolean)
+        {
+            return (Boolean) value;
+        }
+        String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        valueStr = valueStr.trim().toLowerCase();
+        switch (valueStr)
+        {
+            case "true":
+            case "yes":
+            case "ok":
+            case "1":
+            case "是":
+                return true;
+            case "false":
+            case "no":
+            case "0":
+            case "否":
+                return false;
+            default:
+                return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为boolean<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value)
+    {
+        return toBool(value, null);
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 
+     * @param clazz Enum的Class
+     * @param value 值
+     * @param defaultValue 默认值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (clazz.isAssignableFrom(value.getClass()))
+        {
+            @SuppressWarnings("unchecked")
+            E myE = (E) value;
+            return myE;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Enum.valueOf(clazz, valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 
+     * @param clazz Enum的Class
+     * @param value 值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
+    {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof BigInteger)
+        {
+            return (BigInteger) value;
+        }
+        if (value instanceof Long)
+        {
+            return BigInteger.valueOf((Long) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return new BigInteger(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value)
+    {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @param defaultValue 转换错误时的默认值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal)
+        {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Long)
+        {
+            return new BigDecimal((Long) value);
+        }
+        if (value instanceof Double)
+        {
+            return BigDecimal.valueOf((Double) value);
+        }
+        if (value instanceof Integer)
+        {
+            return new BigDecimal((Integer) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return new BigDecimal(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     * 
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value)
+    {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     * 
+     * @param obj 对象
+     * @return 字符串
+     */
+    public static String utf8Str(Object obj)
+    {
+        return str(obj, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     * 
+     * @param obj 对象
+     * @param charsetName 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, String charsetName)
+    {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     * 
+     * @param obj 对象
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, Charset charset)
+    {
+        if (null == obj)
+        {
+            return null;
+        }
+
+        if (obj instanceof String)
+        {
+            return (String) obj;
+        }
+        else if (obj instanceof byte[] || obj instanceof Byte[])
+        {
+            if (obj instanceof byte[])
+            {
+                return str((byte[]) obj, charset);
+            }
+            else
+            {
+                Byte[] bytes = (Byte[]) obj;
+                int length = bytes.length;
+                byte[] dest = new byte[length];
+                for (int i = 0; i < length; i++)
+                {
+                    dest[i] = bytes[i];
+                }
+                return str(dest, charset);
+            }
+        }
+        else if (obj instanceof ByteBuffer)
+        {
+            return str((ByteBuffer) obj, charset);
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 将byte数组转为字符串
+     * 
+     * @param bytes byte数组
+     * @param charset 字符集
+     * @return 字符串
+     */
+    public static String str(byte[] bytes, String charset)
+    {
+        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+    }
+
+    /**
+     * 解码字节码
+     * 
+     * @param data 字符串
+     * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+     * @return 解码后的字符串
+     */
+    public static String str(byte[] data, Charset charset)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        if (null == charset)
+        {
+            return new String(data);
+        }
+        return new String(data, charset);
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     * 
+     * @param data 数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, String charset)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        return str(data, Charset.forName(charset));
+    }
+
+    /**
+     * 将编码的byteBuffer数据转换为字符串
+     * 
+     * @param data 数据
+     * @param charset 字符集,如果为空使用当前系统字符集
+     * @return 字符串
+     */
+    public static String str(ByteBuffer data, Charset charset)
+    {
+        if (null == charset)
+        {
+            charset = Charset.defaultCharset();
+        }
+        return charset.decode(data).toString();
+    }
+
+    // ----------------------------------------------------------------------- 全角半角转换
+    /**
+     * 半角转全角
+     * 
+     * @param input String.
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input)
+    {
+        return toSBC(input, null);
+    }
+
+    /**
+     * 半角转全角
+     * 
+     * @param input String
+     * @param notConvertSet 不替换的字符集合
+     * @return 全角字符串.
+     */
+    public static String toSBC(String input, Set<Character> notConvertSet)
+    {
+        char[] c = input.toCharArray();
+        for (int i = 0; i < c.length; i++)
+        {
+            if (null != notConvertSet && notConvertSet.contains(c[i]))
+            {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == ' ')
+            {
+                c[i] = '\u3000';
+            }
+            else if (c[i] < '\177')
+            {
+                c[i] = (char) (c[i] + 65248);
+
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 全角转半角
+     * 
+     * @param input String.
+     * @return 半角字符串
+     */
+    public static String toDBC(String input)
+    {
+        return toDBC(input, null);
+    }
+
+    /**
+     * 替换全角为半角
+     * 
+     * @param text 文本
+     * @param notConvertSet 不替换的字符集合
+     * @return 替换后的字符
+     */
+    public static String toDBC(String text, Set<Character> notConvertSet)
+    {
+        char[] c = text.toCharArray();
+        for (int i = 0; i < c.length; i++)
+        {
+            if (null != notConvertSet && notConvertSet.contains(c[i]))
+            {
+                // 跳过不替换的字符
+                continue;
+            }
+
+            if (c[i] == '\u3000')
+            {
+                c[i] = ' ';
+            }
+            else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
+            {
+                c[i] = (char) (c[i] - 65248);
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 数字金额大写转换 先写个完整的然后将如零拾替换成零
+     * 
+     * @param n 数字
+     * @return 中文大写数字
+     */
+    public static String digitUppercase(double n)
+    {
+        String[] fraction = { "角", "分" };
+        String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
+        String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } };
+
+        String head = n < 0 ? "负" : "";
+        n = Math.abs(n);
+
+        String s = "";
+        for (int i = 0; i < fraction.length; i++)
+        {
+            // 优化double计算精度丢失问题
+            BigDecimal nNum = new BigDecimal(n);
+            BigDecimal decimal = new BigDecimal(10);
+            BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
+            double d = scale.doubleValue();
+            s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
+        }
+        if (s.length() < 1)
+        {
+            s = "整";
+        }
+        int integerPart = (int) Math.floor(n);
+
+        for (int i = 0; i < unit[0].length && integerPart > 0; i++)
+        {
+            String p = "";
+            for (int j = 0; j < unit[1].length && n > 0; j++)
+            {
+                p = digit[integerPart % 10] + unit[1][j] + p;
+                integerPart = integerPart / 10;
+            }
+            s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
+        }
+        return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
+    }
+}

+ 36 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/PageUtils.java

@@ -0,0 +1,36 @@
+package com.sckw.core.utils;
+
+import com.github.pagehelper.PageHelper;
+import com.sckw.core.utils.sql.SqlUtil;
+import com.sckw.core.web.page.PageDomain;
+import com.sckw.core.web.page.TableSupport;
+
+/**
+ * 分页工具类
+ * 
+ * @author tangyishan
+ */
+public class PageUtils extends PageHelper
+{
+    /**
+     * 设置请求分页数据
+     */
+    public static PageDomain startPage()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+        Boolean reasonable = pageDomain.getReasonable();
+        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
+        return pageDomain;
+    }
+
+    /**
+     * 清理分页的线程变量
+     */
+    public static void clearPage()
+    {
+        PageHelper.clearPage();
+    }
+}

+ 254 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/ServletUtils.java

@@ -0,0 +1,254 @@
+package com.sckw.core.utils;
+
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.LinkedCaseInsensitiveMap;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 客户端工具类
+ * 
+ * @author tangyishan
+ */
+public class ServletUtils
+{
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name)
+    {
+        return getRequest().getParameter(name);
+    }
+
+    /**
+     * 获取String参数
+     */
+    public static String getParameter(String name, String defaultValue)
+    {
+        return Convert.toStr(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获取Integer参数
+     */
+    public static Integer getParameterToInt(String name)
+    {
+        return Convert.toInt(getRequest().getParameter(name));
+    }
+
+    /**
+     * 获取Integer参数
+     */
+    public static Integer getParameterToInt(String name, Integer defaultValue)
+    {
+        return Convert.toInt(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获取Boolean参数
+     */
+    public static Boolean getParameterToBool(String name)
+    {
+        return Convert.toBool(getRequest().getParameter(name));
+    }
+
+    /**
+     * 获取Boolean参数
+     */
+    public static Boolean getParameterToBool(String name, Boolean defaultValue)
+    {
+        return Convert.toBool(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获得所有请求参数
+     *
+     * @param request 请求对象{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String[]> getParams(ServletRequest request)
+    {
+        final Map<String, String[]> map = request.getParameterMap();
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * 获得所有请求参数
+     *
+     * @param request 请求对象{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String> getParamMap(ServletRequest request)
+    {
+        Map<String, String> params = new HashMap<>();
+        for (Map.Entry<String, String[]> entry : getParams(request).entrySet())
+        {
+            params.put(entry.getKey(), StringUtil.join(entry.getValue(), ","));
+        }
+        return params;
+    }
+
+    /**
+     * 获取request
+     */
+    public static HttpServletRequest getRequest()
+    {
+        try
+        {
+            return getRequestAttributes().getRequest();
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * 获取response
+     */
+    public static HttpServletResponse getResponse()
+    {
+        try
+        {
+            return getRequestAttributes().getResponse();
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * 获取session
+     */
+    public static HttpSession getSession()
+    {
+        return getRequest().getSession();
+    }
+
+    public static ServletRequestAttributes getRequestAttributes()
+    {
+        try
+        {
+            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+            return (ServletRequestAttributes) attributes;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    public static String getHeader(HttpServletRequest request, String name)
+    {
+        String value = request.getHeader(name);
+        if (StringUtils.isEmpty(value))
+        {
+            return StringUtil.EMPTY;
+        }
+        return urlDecode(value);
+    }
+
+    public static Map<String, String> getHeaders(HttpServletRequest request)
+    {
+        Map<String, String> map = new LinkedCaseInsensitiveMap<>();
+        Enumeration<String> enumeration = request.getHeaderNames();
+        if (enumeration != null)
+        {
+            while (enumeration.hasMoreElements())
+            {
+                String key = enumeration.nextElement();
+                String value = request.getHeader(key);
+                map.put(key, value);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 将字符串渲染到客户端
+     * 
+     * @param response 渲染对象
+     * @param string 待渲染的字符串
+     */
+    public static void renderString(HttpServletResponse response, String string)
+    {
+        try
+        {
+            response.setStatus(HttpStatus.OK.value());
+            response.setContentType("application/json");
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(string);
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 是否是Ajax异步请求
+     * 
+     * @param request
+     */
+    public static boolean isAjaxRequest(HttpServletRequest request)
+    {
+        String accept = request.getHeader("accept");
+        if (accept != null && accept.contains("application/json"))
+        {
+            return true;
+        }
+
+        String xRequestedWith = request.getHeader("X-Requested-With");
+        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
+        {
+            return true;
+        }
+
+        String uri = request.getRequestURI();
+        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
+        {
+            return true;
+        }
+
+        String ajax = request.getParameter("__ajax");
+        return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
+    }
+
+    /**
+     * 内容编码
+     * 
+     * @param str 内容
+     * @return 编码后的内容
+     */
+    public static String urlEncode(String str)
+    {
+        return URLEncoder.encode(str, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * 内容解码
+     * 
+     * @param str 内容
+     * @return 解码后的内容
+     */
+    public static String urlDecode(String str)
+    {
+        return URLDecoder.decode(str, StandardCharsets.UTF_8);
+    }
+
+}

+ 599 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/StringUtil.java

@@ -0,0 +1,599 @@
+package com.sckw.core.utils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import org.springframework.util.AntPathMatcher;
+
+/**
+ * 字符串工具类
+ *
+ * @author tangyishan
+ */
+public class StringUtil extends org.apache.commons.lang3.StringUtils
+{
+    /** 空字符串 */
+    private static final String NULLSTR = "";
+
+    /** 下划线 */
+    private static final char SEPARATOR = '_';
+
+    /** 星号 */
+    private static final char ASTERISK = '*';
+
+    /**
+     * 获取参数不为空值
+     *
+     * @param value defaultValue 要判断的value
+     * @return value 返回值
+     */
+    public static <T> T nvl(T value, T defaultValue)
+    {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 判断一个Collection是否为空, 包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Collection<?> coll)
+    {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 判断一个Collection是否非空,包含List,Set,Queue
+     *
+     * @param coll 要判断的Collection
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Collection<?> coll)
+    {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 判断一个对象数组是否为空
+     *
+     * @param objects 要判断的对象数组
+     ** @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Object[] objects)
+    {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 判断一个对象数组是否非空
+     *
+     * @param objects 要判断的对象数组
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Object[] objects)
+    {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Map<?, ?> map)
+    {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     *
+     * @param map 要判断的Map
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Map<?, ?> map)
+    {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 判断一个字符串是否为空串
+     *
+     * @param str String
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(String str)
+    {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 判断一个字符串是否为非空串
+     *
+     * @param str String
+     * @return true:非空串 false:空串
+     */
+    public static boolean isNotEmpty(String str)
+    {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 判断一个对象是否为空
+     *
+     * @param object Object
+     * @return true:为空 false:非空
+     */
+    public static boolean isNull(Object object)
+    {
+        return object == null;
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object)
+    {
+        return !isNull(object);
+    }
+
+    /**
+     * * 判断一个对象是否是数组类型(Java基本型别的数组)
+     *
+     * @param object 对象
+     * @return true:是数组 false:不是数组
+     */
+    public static boolean isArray(Object object)
+    {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 去空格
+     */
+    public static String trim(String str)
+    {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 替换指定字符串的指定区间内字符为"*"
+     *
+     * @param str 字符串
+     * @param startInclude 开始位置(包含)
+     * @param endExclude 结束位置(不包含)
+     * @return 替换后的字符串
+     */
+    public static String hide(CharSequence str, int startInclude, int endExclude)
+    {
+        if (isEmpty(str))
+        {
+            return NULLSTR;
+        }
+        final int strLength = str.length();
+        if (startInclude > strLength)
+        {
+            return NULLSTR;
+        }
+        if (endExclude > strLength)
+        {
+            endExclude = strLength;
+        }
+        if (startInclude > endExclude)
+        {
+            // 如果起始位置大于结束位置,不替换
+            return NULLSTR;
+        }
+        final char[] chars = new char[strLength];
+        for (int i = 0; i < strLength; i++)
+        {
+            if (i >= startInclude && i < endExclude)
+            {
+                chars[i] = ASTERISK;
+            }
+            else
+            {
+                chars[i] = str.charAt(i);
+            }
+        }
+        return new String(chars);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str 字符串
+     * @param start 开始
+     * @return 结果
+     */
+    public static String substring(final String str, int start)
+    {
+        if (str == null)
+        {
+            return NULLSTR;
+        }
+
+        if (start < 0)
+        {
+            start = str.length() + start;
+        }
+
+        if (start < 0)
+        {
+            start = 0;
+        }
+        if (start > str.length())
+        {
+            return NULLSTR;
+        }
+
+        return str.substring(start);
+    }
+
+    /**
+     * 截取字符串
+     *
+     * @param str 字符串
+     * @param start 开始
+     * @param end 结束
+     * @return 结果
+     */
+    public static String substring(final String str, int start, int end)
+    {
+        if (str == null)
+        {
+            return NULLSTR;
+        }
+
+        if (end < 0)
+        {
+            end = str.length() + end;
+        }
+        if (start < 0)
+        {
+            start = str.length() + start;
+        }
+
+        if (end > str.length())
+        {
+            end = str.length();
+        }
+
+        if (start > end)
+        {
+            return NULLSTR;
+        }
+
+        if (start < 0)
+        {
+            start = 0;
+        }
+        if (end < 0)
+        {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+
+    /**
+     * 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
+     *
+     * @param str 要截取的字符串
+     * @param open 起始字符串
+     * @param close 结束字符串
+     * @return 截取结果
+     */
+    public static String substringBetweenLast(final String str, final String open, final String close)
+    {
+        if (isEmpty(str) || isEmpty(open) || isEmpty(close))
+        {
+            return NULLSTR;
+        }
+        final int start = str.indexOf(open);
+        if (start != INDEX_NOT_FOUND)
+        {
+            final int end = str.lastIndexOf(close);
+            if (end != INDEX_NOT_FOUND)
+            {
+                return str.substring(start + open.length(), end);
+            }
+        }
+        return NULLSTR;
+    }
+
+    /**
+     * 判断是否为空,并且不是空白字符
+     *
+     * @param str 要判断的value
+     * @return 结果
+     */
+    public static boolean hasText(String str)
+    {
+        return (str != null && !str.isEmpty() && containsText(str));
+    }
+
+    private static boolean containsText(CharSequence str)
+    {
+        int strLen = str.length();
+        for (int i = 0; i < strLen; i++)
+        {
+            if (!Character.isWhitespace(str.charAt(i)))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
+     *
+     * @param collection 给定的集合
+     * @param array 给定的数组
+     * @return boolean 结果
+     */
+    public static boolean containsAny(Collection<String> collection, String... array)
+    {
+        if (isEmpty(collection) || isEmpty(array))
+        {
+            return false;
+        }
+        else
+        {
+            for (String str : array)
+            {
+                if (collection.contains(str))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * 驼峰转下划线命名
+     */
+    public static String toUnderScoreCase(String str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 前置字符是否大写
+        boolean preCharIsUpperCase = true;
+        // 当前字符是否大写
+        boolean curreCharIsUpperCase = true;
+        // 下一字符是否大写
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++)
+        {
+            char c = str.charAt(i);
+            if (i > 0)
+            {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            }
+            else
+            {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1))
+            {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
+            {
+                sb.append(SEPARATOR);
+            }
+            else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
+            {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 是否包含字符串
+     *
+     * @param str 验证字符串
+     * @param strs 字符串组
+     * @return 包含返回true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs)
+    {
+        if (str != null && strs != null)
+        {
+            for (String s : strs)
+            {
+                if (str.equalsIgnoreCase(trim(s)))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+     *
+     * @param name 转换前的下划线大写方式命名的字符串
+     * @return 转换后的驼峰式命名的字符串
+     */
+    public static String convertToCamelCase(String name)
+    {
+        StringBuilder result = new StringBuilder();
+        // 快速检查
+        if (name == null || name.isEmpty())
+        {
+            // 没必要转换
+            return "";
+        }
+        else if (!name.contains("_"))
+        {
+            // 不含下划线,仅将首字母大写
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 用下划线将原始字符串分割
+        String[] camels = name.split("_");
+        for (String camel : camels)
+        {
+            // 跳过原始字符串中开头、结尾的下换线或双重下划线
+            if (camel.isEmpty())
+            {
+                continue;
+            }
+            // 首字母大写
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    /**
+     * 驼峰式命名法
+     * 例如:user_name->userName
+     */
+    public static String toCamelCase(String s)
+    {
+        if (s == null)
+        {
+            return null;
+        }
+        if (s.indexOf(SEPARATOR) == -1)
+        {
+            return s;
+        }
+        s = s.toLowerCase();
+        StringBuilder sb = new StringBuilder(s.length());
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++)
+        {
+            char c = s.charAt(i);
+
+            if (c == SEPARATOR)
+            {
+                upperCase = true;
+            }
+            else if (upperCase)
+            {
+                sb.append(Character.toUpperCase(c));
+                upperCase = false;
+            }
+            else
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
+     *
+     * @param str 指定字符串
+     * @param strs 需要检查的字符串数组
+     * @return 是否匹配
+     */
+    public static boolean matches(String str, List<String> strs)
+    {
+        if (isEmpty(str) || isEmpty(strs))
+        {
+            return false;
+        }
+        for (String pattern : strs)
+        {
+            if (isMatch(pattern, str))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断url是否与规则配置:
+     * ? 表示单个字符;
+     * * 表示一层路径内的任意字符串,不可跨层级;
+     * ** 表示任意层路径;
+     *
+     * @param pattern 匹配规则
+     * @param url 需要匹配的url
+     * @return
+     */
+    public static boolean isMatch(String pattern, String url)
+    {
+        AntPathMatcher matcher = new AntPathMatcher();
+        return matcher.match(pattern, url);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj)
+    {
+        return (T) obj;
+    }
+
+    /**
+     * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
+     *
+     * @param num 数字对象
+     * @param size 字符串指定长度
+     * @return 返回数字的字符串格式,该字符串为指定长度。
+     */
+    public static final String padl(final Number num, final int size)
+    {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
+     *
+     * @param s 原始字符串
+     * @param size 字符串指定长度
+     * @param c 用于补齐的字符
+     * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
+     */
+    public static final String padl(final String s, final int size, final char c)
+    {
+        final StringBuilder sb = new StringBuilder(size);
+        if (s != null)
+        {
+            final int len = s.length();
+            if (s.length() <= size)
+            {
+                for (int i = size - len; i > 0; i--)
+                {
+                    sb.append(c);
+                }
+                sb.append(s);
+            }
+            else
+            {
+                return s.substring(len - size, len);
+            }
+        }
+        else
+        {
+            for (int i = size; i > 0; i--)
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+}

+ 71 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/utils/sql/SqlUtil.java

@@ -0,0 +1,71 @@
+package com.sckw.core.utils.sql;
+
+
+import cn.hutool.core.exceptions.UtilException;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * sql操作工具类
+ * 
+ * @author tangyishan
+ */
+public class SqlUtil
+{
+    /**
+     * 定义常用的 sql关键字
+     */
+    public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
+
+    /**
+     * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
+     */
+    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
+
+    /**
+     * 限制orderBy最大长度
+     */
+    private static final int ORDER_BY_MAX_LENGTH = 500;
+
+    /**
+     * 检查字符,防止注入绕过
+     */
+    public static String escapeOrderBySql(String value)
+    {
+        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
+        {
+            throw new UtilException("参数不符合规范,不能进行查询");
+        }
+        if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
+        {
+            throw new UtilException("参数已超过最大限制,不能进行查询");
+        }
+        return value;
+    }
+
+    /**
+     * 验证 order by 语法是否符合规范
+     */
+    public static boolean isValidOrderBySql(String value)
+    {
+        return value.matches(SQL_PATTERN);
+    }
+
+    /**
+     * SQL关键字检查
+     */
+    public static void filterKeyword(String value)
+    {
+        if (StringUtils.isEmpty(value))
+        {
+            return;
+        }
+        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
+        for (String sqlKeyword : sqlKeywords)
+        {
+            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
+            {
+                throw new UtilException("参数存在SQL注入风险");
+            }
+        }
+    }
+}

+ 6 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/config/CustomConfig.java

@@ -25,6 +25,12 @@ public class CustomConfig {
     @Value("${specialLinks}")
     private String specialLinks;
 
+    /**
+     * 物流企业初始化分
+     */
+    @Value("${logistics.init.score:60.00}")
+    private String logisticsInitScore;
+
 //    /**
 //     * 是否允许一个账号绑定多个角色
 //     */

+ 70 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/controller/BaseController.java

@@ -0,0 +1,70 @@
+package com.sckw.core.web.controller;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.sckw.core.utils.PageUtils;
+import com.sckw.core.utils.StringUtil;
+import com.sckw.core.utils.sql.SqlUtil;
+import com.sckw.core.web.page.PageDomain;
+import com.sckw.core.web.page.TableSupport;
+import com.sckw.core.web.response.result.PageDataResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * web层通用数据处理
+ * 
+ * @author tangyishan
+ */
+public class BaseController
+{
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 设置请求分页数据
+     */
+    protected PageDomain startPage()
+    {
+        return PageUtils.startPage();
+    }
+
+    /**
+     * 设置请求排序数据
+     */
+    protected void startOrderBy()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        if (StringUtil.isNotEmpty(pageDomain.getOrderBy()))
+        {
+            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+            PageHelper.orderBy(orderBy);
+        }
+    }
+
+    /**
+     * 清理分页的线程变量
+     */
+    protected void clearPage()
+    {
+        PageUtils.clearPage();
+    }
+
+    /**
+     * 响应请求分页数据
+     */
+    protected PageDataResult<?> getDataTable(List<?> list,PageDomain pageDomain)
+    {
+        PageInfo<?> pageInfo = new PageInfo<>(list);
+        return PageDataResult.success(pageDomain.getPageNum(), pageDomain.getPageSize(), pageInfo.getTotal(), pageInfo.getList());
+    }
+
+    /**
+     * 响应请求分页数据
+     */
+    protected PageDataResult<?> getDataTable(PageInfo<?> pageInfo,PageDomain pageDomain)
+    {
+        return PageDataResult.success(pageDomain.getPageNum(), pageDomain.getPageSize(), pageInfo.getTotal(), pageInfo.getList());
+    }
+}

+ 102 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/page/PageDomain.java

@@ -0,0 +1,102 @@
+package com.sckw.core.web.page;
+
+
+import com.sckw.core.utils.StringUtil;
+
+/**
+ * 分页数据
+ * 
+ * @author ruoyi
+ */
+public class PageDomain
+{
+    /** 当前记录起始索引 */
+    private Integer pageNum;
+
+    /** 每页显示记录数 */
+    private Integer pageSize;
+
+    /** 排序列 */
+    private String orderByColumn;
+
+    /** 排序的方向desc或者asc */
+    private String isAsc = "asc";
+
+    /** 分页参数合理化 */
+    private Boolean reasonable = true;
+
+    public String getOrderBy()
+    {
+        if (StringUtil.isEmpty(orderByColumn))
+        {
+            return "";
+        }
+        return StringUtil.toUnderScoreCase(orderByColumn) + " " + isAsc;
+    }
+
+    public Integer getPageNum()
+    {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum)
+    {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getPageSize()
+    {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize)
+    {
+        this.pageSize = pageSize;
+    }
+
+    public String getOrderByColumn()
+    {
+        return orderByColumn;
+    }
+
+    public void setOrderByColumn(String orderByColumn)
+    {
+        this.orderByColumn = orderByColumn;
+    }
+
+    public String getIsAsc()
+    {
+        return isAsc;
+    }
+
+    public void setIsAsc(String isAsc)
+    {
+        if (StringUtil.isNotEmpty(isAsc))
+        {
+            // 兼容前端排序类型
+            if ("ascending".equals(isAsc))
+            {
+                isAsc = "asc";
+            }
+            else if ("descending".equals(isAsc))
+            {
+                isAsc = "desc";
+            }
+            this.isAsc = isAsc;
+        }
+    }
+
+    public Boolean getReasonable()
+    {
+        if (StringUtil.isNull(reasonable))
+        {
+            return Boolean.TRUE;
+        }
+        return reasonable;
+    }
+
+    public void setReasonable(Boolean reasonable)
+    {
+        this.reasonable = reasonable;
+    }
+}

+ 57 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/page/TableSupport.java

@@ -0,0 +1,57 @@
+package com.sckw.core.web.page;
+
+
+import com.sckw.core.utils.Convert;
+import com.sckw.core.utils.ServletUtils;
+
+/**
+ * 表格数据处理
+ * 
+ * @author tangyishan
+ */
+public class TableSupport
+{
+    /**
+     * 当前记录起始索引
+     */
+    public static final String PAGE_NUM = "pageNum";
+
+    /**
+     * 每页显示记录数
+     */
+    public static final String PAGE_SIZE = "pageSize";
+
+    /**
+     * 排序列
+     */
+    public static final String ORDER_BY_COLUMN = "orderByColumn";
+
+    /**
+     * 排序的方向 "desc" 或者 "asc".
+     */
+    public static final String IS_ASC = "isAsc";
+
+    /**
+     * 分页参数合理化
+     */
+    public static final String REASONABLE = "reasonable";
+
+    /**
+     * 封装分页对象
+     */
+    public static PageDomain getPageDomain()
+    {
+        PageDomain pageDomain = new PageDomain();
+        pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
+        pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
+        pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
+        pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
+        pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
+        return pageDomain;
+    }
+
+    public static PageDomain buildPageRequest()
+    {
+        return getPageDomain();
+    }
+}

+ 5 - 1
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/response/result/PageDataResult.java

@@ -57,7 +57,11 @@ public class PageDataResult<T> implements Serializable {
         pageResult.setPageSize(pageSize);
         pageResult.setTotal(total);
         // 修正总页数计算
-        pageResult.setPages((int) ((total + pageSize - 1) / pageSize));
+        if(total==0){
+            pageResult.setPages(0);
+        }else{
+            pageResult.setPages((int) ((total + pageSize - 1) / pageSize));
+        }
         pageResult.setList(data);
         return pageResult;
     }

+ 20 - 0
sckw-common/sckw-common-redis/src/main/java/com/sckw/redis/constant/RedisConstant.java

@@ -124,4 +124,24 @@ public class RedisConstant {
     public static final String WALLET_TIME = "%s:%s:%s";
     public static final String HOT_KEY = "hot:key";
 
+    /**
+     * 物流评分记录初始化锁,score:logistics:record:init:供应商企业id:物流企业id
+     */
+    public static final String LOGISTICS_SCORE_RECORD_INIT_KEY = "score:logistics:record:init:%s:%s";
+
+    /**
+     * 物流评分记录审批锁,score:logistics:record:approval:评分id
+     */
+    public static final String LOGISTICS_SCORE_RECORD_APPROVAL_KEY = "score:logistics:record:approval:%s";
+
+    /**
+     * 物流评分记录修改锁,score:logistics:record:update:评分id
+     */
+    public static final String LOGISTICS_SCORE_RECORD_UPDATE_KEY = "score:logistics:record:update:%s";
+
+    /**
+     * 物流评分记录重置锁,score:logistics:record:reset:评分id
+     */
+    public static final String LOGISTICS_SCORE_RECORD_RESET_KEY = "score:logistics:record:reset:%s";
+
 }

+ 16 - 0
sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/feign/LogisticsScoreFeignService.java

@@ -0,0 +1,16 @@
+package com.sckw.contract.api.feign;
+
+import com.sckw.contract.api.model.dto.req.LogisticsScoreDetailFeignDto;
+import com.sckw.core.web.response.BaseResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+@FeignClient(name = "sckw-contract",path = "/api/logisticsScore")
+public interface LogisticsScoreFeignService {
+    /**
+     * 系统修改物流企业评分
+     */
+    @PostMapping("/updateLogisticsScore")
+    public BaseResult<Boolean> updateLogisticsScore(@RequestBody LogisticsScoreDetailFeignDto detailDto);
+}

+ 46 - 0
sckw-modules-api/sckw-contract-api/src/main/java/com/sckw/contract/api/model/dto/req/LogisticsScoreDetailFeignDto.java

@@ -0,0 +1,46 @@
+package com.sckw.contract.api.model.dto.req;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-08  09:12
+ * @Description: 评分明细参数
+ */
+@Data
+public class LogisticsScoreDetailFeignDto {
+    /**
+     * 供应商企业id
+     */
+    @NotNull(message = "供应商企业id不能为空")
+    private Long providerEntId;
+    /**
+     * 物流企业id
+     */
+    @NotNull(message = "物流企业id不能为空")
+    private Long logisticsEntId;
+    /**
+     * 评分行为影响人id
+     */
+    @NotNull(message = "影响人id不能为空")
+    private Long influenceBy;
+    /**
+     * 评分行为影响人名称
+     */
+    @NotNull(message = "影响人名称不能为空")
+    private String influenceByName;
+    /**
+     * 评分行为
+     */
+    @NotBlank(message = "行为不能为空")
+    private String action;
+    /**
+     * 评分变动
+     */
+    @NotNull(message = "评分变动不能为空")
+    private BigDecimal scoreChange;
+}

+ 31 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/api/KwcContractLogisticsScoreApiController.java

@@ -0,0 +1,31 @@
+package com.sckw.contract.api;
+
+import com.sckw.contract.api.model.dto.req.LogisticsScoreDetailFeignDto;
+import com.sckw.contract.service.IKwcContractLogisticsScoreService;
+import com.sckw.core.web.response.BaseResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 物流企业评分Controller
+ *
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+@RestController
+@RequestMapping("/api/logisticsScore")
+public class KwcContractLogisticsScoreApiController {
+    @Autowired
+    private IKwcContractLogisticsScoreService kwcContractLogisticsScoreService;
+    /**
+     * 系统修改物流企业评分
+     */
+    @PostMapping("/updateLogisticsScore")
+    public BaseResult<Boolean> updateLogisticsScore(@Validated @RequestBody LogisticsScoreDetailFeignDto detailDto) {
+        return BaseResult.success(kwcContractLogisticsScoreService.updateLogisticsScoreBySystem(detailDto));
+    }
+}

+ 102 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/controller/KwcContractLogisticsScoreController.java

@@ -0,0 +1,102 @@
+package com.sckw.contract.controller;
+
+
+import com.github.pagehelper.PageInfo;
+import com.sckw.contract.model.dto.req.LogisticsScoreApprovalDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailAddDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailQueryDto;
+import com.sckw.contract.model.vo.res.LogisticsScoreDetailResVo;
+import com.sckw.contract.model.vo.res.LogisticsScoreResVo;
+import com.sckw.core.web.context.LoginUserHolder;
+import com.sckw.core.web.controller.BaseController;
+import com.sckw.core.web.page.PageDomain;
+import com.sckw.core.web.page.TableSupport;
+import com.sckw.core.web.response.BaseResult;
+import com.sckw.core.web.response.result.PageDataResult;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import com.sckw.contract.service.IKwcContractLogisticsScoreService;
+
+/**
+ * 物流企业评分Controller
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+@Tag(name = "物流企业评分接口")
+@RestController
+@RequestMapping("/logisticsScore")
+public class KwcContractLogisticsScoreController extends BaseController
+{
+    @Autowired
+    private IKwcContractLogisticsScoreService kwcContractLogisticsScoreService;
+
+    /**
+     * 查询物流企业评分列表
+     */
+    @GetMapping("/queryListByPage")
+    @Operation(summary = "分页查询供应商物流企业评分")
+    public BaseResult<PageDataResult<?>> queryListByPage()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        PageInfo<LogisticsScoreResVo> list = kwcContractLogisticsScoreService.selectLogisticsScoreWithPendingSocreList(LoginUserHolder.getEntId());
+        return BaseResult.success(getDataTable(list,pageDomain));
+    }
+
+    /**
+     * 查询物流企业评分明细列表
+     */
+    @PostMapping("/queryDetailListByPage")
+    @Operation(summary = "分页查指定评分的明细记录")
+    public BaseResult<PageDataResult<?>> queryDetailListByPage(@Validated @RequestBody LogisticsScoreDetailQueryDto detailReqDto)
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        PageInfo<LogisticsScoreDetailResVo> list = kwcContractLogisticsScoreService.selectKwcContractLogisticsScoreDetailList(detailReqDto,LoginUserHolder.getEntId());
+        return BaseResult.success(getDataTable(list,pageDomain));
+    }
+
+    /**
+     * 查询物流企业待审评分明细
+     */
+    @GetMapping("/queryLogisticsPendingScore")
+    @Operation(summary = "查询物流企业待审评分明细")
+    public BaseResult<LogisticsScoreDetailResVo> queryLogisticsPendingScore(@RequestParam Long scoreId)
+    {
+        LogisticsScoreDetailResVo logisticsScoreDetailResVo = kwcContractLogisticsScoreService.selectLogisticsPendingScoreDetail(scoreId,LoginUserHolder.getEntId());
+        return BaseResult.success(logisticsScoreDetailResVo);
+    }
+
+    /**
+     * 用户修改物流企业评分
+     */
+    @PostMapping("/updateLogisticsScore")
+    @Operation(summary = "用户修改物流企业评分")
+    public BaseResult<Boolean> updateLogisticsScore(@Validated @RequestBody LogisticsScoreDetailAddDto detailDto) {
+        return BaseResult.success(kwcContractLogisticsScoreService.insertLogisticsScoreDetailByUser(detailDto,LoginUserHolder.getEntId()));
+    }
+
+
+    /**
+     * 审核物流企业评分
+     */
+    @PostMapping("/approvalLogisticsScore")
+    @Operation(summary = "审核物流企业评分")
+    public BaseResult<Boolean> approvalLogisticsScore(@Validated @RequestBody LogisticsScoreApprovalDto approvalDto) {
+        kwcContractLogisticsScoreService.approvalLogisticsScoreDetail(approvalDto,LoginUserHolder.getEntId());
+        return BaseResult.success();
+    }
+
+
+    /**
+     * 重置物流企业评分
+     */
+    @PostMapping("/resetLogisticsScore")
+    @Operation(summary = "重置物流企业评分")
+    public BaseResult<Boolean> resetLogisticsScore(@RequestParam Long scoreId) {
+        kwcContractLogisticsScoreService.resetLogisticsScore(scoreId,LoginUserHolder.getEntId());
+        return BaseResult.success();
+    }
+}

+ 84 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dao/KwcContractLogisticsScoreDetailMapper.java

@@ -0,0 +1,84 @@
+package com.sckw.contract.dao;
+
+import java.util.List;
+
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailQueryDto;
+import com.sckw.contract.model.entity.KwcContractLogisticsScoreDetail;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 物流企业评分明细Mapper接口
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+@Mapper
+public interface KwcContractLogisticsScoreDetailMapper
+{
+    /**
+     * 查询物流企业评分明细
+     * 
+     * @param id 物流企业评分明细主键
+     * @return 物流企业评分明细
+     */
+    public KwcContractLogisticsScoreDetail selectKwcContractLogisticsScoreDetailById(Long id);
+
+    /**
+     * 查询物流企业评分明细列表
+     * 
+     * @param detailReqDto 物流企业评分明细
+     * @return 物流企业评分明细集合
+     */
+    public List<KwcContractLogisticsScoreDetail> selectKwcContractLogisticsScoreDetailList(LogisticsScoreDetailQueryDto detailReqDto);
+
+
+    /**
+     * 查询物流企业待审评分明细
+     *
+     * @param scoreId 物流企业评分id
+     * @return 物流企业评分明细集合
+     */
+    public KwcContractLogisticsScoreDetail selectLogisticsPendingScoreDetail(Long scoreId);
+    /**
+     * 新增物流企业评分明细
+     * 
+     * @param kwcContractLogisticsScoreDetail 物流企业评分明细
+     * @return 结果
+     */
+    public int insertKwcContractLogisticsScoreDetail(KwcContractLogisticsScoreDetail kwcContractLogisticsScoreDetail);
+
+    /**
+     * 修改物流企业评分明细
+     * 
+     * @param kwcContractLogisticsScoreDetail 物流企业评分明细
+     * @return 结果
+     */
+    public int updateKwcContractLogisticsScoreDetail(KwcContractLogisticsScoreDetail kwcContractLogisticsScoreDetail);
+
+    /**
+     * 删除物流企业评分明细
+     * 
+     * @param id 物流企业评分明细主键
+     * @param status 待审状态
+     * @return 结果
+     */
+    public int deleteKwcContractLogisticsScoreDetailById(@Param("id") Long id, @Param("status") Integer status);
+
+    /**
+     * 删除物流企业评分明细
+     *
+     * @param scoreId 物流企业评分主键
+     * @param status 待审状态
+     * @return 结果
+     */
+    public int deleteKwcContractLogisticsScoreDetailByScoreId(@Param("scoreId") Long scoreId, @Param("status") Integer status);
+
+    /**
+     * 批量删除物流企业评分明细
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteKwcContractLogisticsScoreDetailByIds(Long[] ids);
+}

+ 87 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/dao/KwcContractLogisticsScoreMapper.java

@@ -0,0 +1,87 @@
+package com.sckw.contract.dao;
+
+import java.util.List;
+
+import com.sckw.contract.model.dto.req.LogisticsScoreQueryDto;
+import com.sckw.contract.model.entity.KwcContractLogisticsScore;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 物流企业评分Mapper接口
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+@Mapper
+public interface KwcContractLogisticsScoreMapper
+{
+    /**
+     * 查询物流企业评分
+     * 
+     * @param id 物流企业评分主键
+     * @return 物流企业评分
+     */
+    public KwcContractLogisticsScore selectKwcContractLogisticsScoreById(Long id);
+
+
+    /**
+     * 查询供应商对应物流企业评分
+     *
+     * @param providerEntId 供应商企业id
+     * @param logisticsEntId 物流企业id
+     * @return 数量
+     */
+    public KwcContractLogisticsScore selectLogisticsScoreByEntId(@Param("providerEntId") Long providerEntId, @Param("logisticsEntId") Long logisticsEntId);
+
+
+    /**
+     * 查询指定供应企业下的指定物流评分
+     *
+     * @param providerEntId 供应商企业id
+     * @param scoreId 物流企业评分id
+     * @return 数量
+     */
+    public KwcContractLogisticsScore selectLogisticsScoreByEntIdAndScoreId(@Param("providerEntId") Long providerEntId, @Param("scoreId") Long scoreId);
+
+
+    /**
+     * 查询物流企业评分列表
+     * 
+     * @param logisticsScoreReqDto 物流企业评分
+     * @return 物流企业评分集合
+     */
+    public List<KwcContractLogisticsScore> selectKwcContractLogisticsScoreList(LogisticsScoreQueryDto logisticsScoreReqDto);
+
+    /**
+     * 新增物流企业评分
+     * 
+     * @param kwcContractLogisticsScore 物流企业评分
+     * @return 结果
+     */
+    public int insertKwcContractLogisticsScore(KwcContractLogisticsScore kwcContractLogisticsScore);
+
+    /**
+     * 修改物流企业评分
+     * 
+     * @param kwcContractLogisticsScore 物流企业评分
+     * @return 结果
+     */
+    public int updateKwcContractLogisticsScore(KwcContractLogisticsScore kwcContractLogisticsScore);
+
+    /**
+     * 删除物流企业评分
+     * 
+     * @param id 物流企业评分主键
+     * @return 结果
+     */
+    public int deleteKwcContractLogisticsScoreById(Long id);
+
+    /**
+     * 批量删除物流企业评分
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteKwcContractLogisticsScoreByIds(Long[] ids);
+}

+ 24 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreApprovalDto.java

@@ -0,0 +1,24 @@
+package com.sckw.contract.model.dto.req;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-09  10:01
+ * @Description: 物流评分审批参数
+ */
+@Data
+public class LogisticsScoreApprovalDto {
+    /**
+     * 评分id
+     */
+    @NotNull(message = "评分id不能为空")
+    private Long scoreId;
+
+    /**
+     * 审批结果 0-拒绝 1-通过
+     */
+    @NotNull(message = "审批结果不能为空")
+    private Integer approval;
+}

+ 54 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreDetailAddDto.java

@@ -0,0 +1,54 @@
+package com.sckw.contract.model.dto.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-08  09:12
+ * @Description: 评分明细参数
+ */
+@Data
+public class LogisticsScoreDetailAddDto {
+    /**
+     * 评分id
+     */
+    @NotNull
+    private Long scoreId;
+    /**
+     * 评分行为影响人id
+     */
+    @Schema(hidden = true)
+    private Long influenceBy;
+    /**
+     * 评分行为影响人名称
+     */
+    @Schema(hidden = true)
+    private String influenceByName;
+    /**
+     * 评分行为
+     */
+    @NotBlank
+    private String action;
+    /**
+     *
+     * 评分变动
+     */
+    @NotNull
+    private BigDecimal scoreChange;
+    /**
+     * 评分状态 0-待审核 1-审核通过
+     */
+    @Schema(hidden = true)
+    private Integer status;
+
+    /**
+     * 变动后评分
+     */
+    @Schema(hidden = true)
+    private BigDecimal score;
+}

+ 39 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreDetailQueryDto.java

@@ -0,0 +1,39 @@
+package com.sckw.contract.model.dto.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-06  13:45
+ * @Description: 评分明细查询参数
+ */
+@Data
+public class
+LogisticsScoreDetailQueryDto {
+    /**
+     * 评分id
+     */
+    @NotNull(message = "评分id不能为空")
+    private Long scoreId;
+    /**
+     * 行为
+     */
+    private String action;
+
+    /**
+     * 评分id列表
+     */
+    @Schema(hidden = true)
+    private List<Long> scoreIds;
+
+    /**
+     * 审核状态 0-待审核 1-审核通过
+     */
+    @Schema(hidden = true)
+    private Integer status;
+}

+ 22 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/dto/req/LogisticsScoreQueryDto.java

@@ -0,0 +1,22 @@
+package com.sckw.contract.model.dto.req;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-05  15:31
+ * @Description: 物流评分查询参数
+ */
+@Data
+public class LogisticsScoreQueryDto {
+    /**
+     * 供应商id
+     */
+    private Long providerEntId;
+    /**
+     * 物流公司id列表
+     */
+    private List<Long> logisticsEntIds;
+}

+ 41 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/entity/KwcContractLogisticsScore.java

@@ -0,0 +1,41 @@
+package com.sckw.contract.model.entity;
+
+import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.sckw.core.model.base.BaseModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 物流企业评分对象 kwc_contract_logistics_score
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Accessors(chain = true)
+public class KwcContractLogisticsScore extends BaseModel
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 供应商企业id */
+    private Long providerEntId;
+
+    /** 物流企业id */
+    private Long logisticsEntId;
+
+    /** 物流企业名称 */
+    private String logisticsEntName;
+
+    /** 物流企业评分 */
+    private BigDecimal score;
+
+    /** 待审物流企业评分 */
+    @TableField(exist = false)
+    private BigDecimal pendingScore;
+}

+ 49 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/entity/KwcContractLogisticsScoreDetail.java

@@ -0,0 +1,49 @@
+package com.sckw.contract.model.entity;
+
+import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.sckw.core.model.base.BaseModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * 物流企业评分明细对象 kwc_contract_logistics_score_detail
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Accessors(chain = true)
+public class KwcContractLogisticsScoreDetail extends BaseModel
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 评分主键id */
+    private Long scoreId;
+
+    /** 影响人id */
+    private Long influenceBy;
+
+    /** 影响人名字 */
+    private String influenceByName;
+
+    /** 行为 */
+    private String action;
+
+    /** 评分变动 */
+    private BigDecimal scoreChange;
+
+    /** 变动后评分 */
+    private BigDecimal score;
+
+    /** 审核状态 0-待审核,1-审核通过 */
+    private Integer status;
+
+    /** 物流企业名称 */
+    @TableField(exist = false)
+    private String logisticsEntName;
+}

+ 1 - 1
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/req/LogisticListReq.java

@@ -133,7 +133,7 @@ public class LogisticListReq implements Serializable {
          */
         @NotNull(message = "派车方式不能为空")
         @Schema(description = "签约方式,1-手动派车,2-自动派车",example = "1",defaultValue = "1")
-        private Integer dispatching;
+        private Integer dispatching = 1;
 
         /**
          * 生效时间

+ 50 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/res/LogisticsScoreDetailResVo.java

@@ -0,0 +1,50 @@
+package com.sckw.contract.model.vo.res;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-10  10:18
+ * @Description: 物流企业评分明细列表响应VO
+ */
+@Data
+public class LogisticsScoreDetailResVo {
+    /**
+     * 评分明细主键id
+     */
+    private Long id;
+
+    /** 评分主键id */
+    private Long scoreId;
+
+    /** 物流企业名称 */
+    private String logisticsEntName;
+
+    /** 影响人id */
+    private Long influenceBy;
+
+    /** 影响人名字 */
+    private String influenceByName;
+
+    /** 行为 */
+    private String action;
+
+    /** 评分变动 */
+    private String scoreChange;
+
+    /** 变动后评分 */
+    private String score;
+
+    /** 审核状态 0-待审核,1-审核通过 */
+    private Integer status;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updateTime;
+}

+ 35 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/model/vo/res/LogisticsScoreResVo.java

@@ -0,0 +1,35 @@
+package com.sckw.contract.model.vo.res;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @Author: tangyishan
+ * @CreateTime: 2025-12-10  09:25
+ * @Description: 物流企业评分列表响应VO
+ */
+@Data
+public class LogisticsScoreResVo {
+
+    /**
+     * 评分主键id
+     */
+    private Long id;
+
+    /** 物流企业名称 */
+    private String logisticsEntName;
+
+    /** 物流企业评分 */
+    private String score;
+
+    /** 待审物流企业评分 */
+    private String pendingScore;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updateTime;
+}

+ 22 - 1
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/repository/KwcContractLogisticsRepository.java

@@ -69,6 +69,22 @@ public class KwcContractLogisticsRepository extends ServiceImpl<KwcContractLogis
                 .eq(KwcContractLogistics::getDelFlag, 0));
     }
 
+    /**
+     * 查询供应商有效的物流合同
+     * @param entId
+     * @return
+     */
+    public List<KwcContractLogistics> queryValidByEntId(Long entId) {
+        return list(Wrappers.<KwcContractLogistics>lambdaQuery()
+                .eq(KwcContractLogistics::getEntId, entId)
+                .eq(KwcContractLogistics::getDelFlag, 0)
+                .eq(KwcContractLogistics::getStatus, 0)
+                .and(queryWrapper -> queryWrapper.apply("{0} between start_time and end_time",new Date())
+                        //.or(queryWrapper1->queryWrapper1.le(KwcContractLogistics::getStartTime, new Date()).isNull(KwcContractLogistics::getEndTime))
+                ));
+    }
+
+
     public List<KwcContractLogistics> queryList(Set<Long> contractIdList, String contractNo, String contractName, String status) {
         return list(Wrappers.<KwcContractLogistics>lambdaQuery()
                 .eq(KwcContractLogistics::getDelFlag, 0)
@@ -91,8 +107,13 @@ public class KwcContractLogisticsRepository extends ServiceImpl<KwcContractLogis
                 .eq(KwcContractLogistics::getDelFlag, 0)
                 .in(KwcContractLogistics::getId, contractIdList)
                 .eq(KwcContractLogistics::getDispatching, dispatchingType)
+                .eq(KwcContractLogistics::getStatus,0)
                 .and(queryWrapper -> queryWrapper.between(KwcContractLogistics::getStartTime, startTime, endTime)
+                        //结束日期不为空
                         .or().between(KwcContractLogistics::getEndTime, startTime, endTime)
-                        .or(queryWrapper1->queryWrapper1.le(KwcContractLogistics::getStartTime, startTime).ge(KwcContractLogistics::getEndTime, endTime))));
+                        .or(queryWrapper1->queryWrapper1.le(KwcContractLogistics::getStartTime, startTime).ge(KwcContractLogistics::getEndTime, endTime))
+                        // 结束日期为空,代表长期有效
+                        //.or(queryWrapper2->queryWrapper2.ge(KwcContractLogistics::getStartTime, endTime).isNull(KwcContractLogistics::getEndTime))
+                ));
     }
 }

+ 8 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/repository/KwcContractLogisticsUnitRepository.java

@@ -33,6 +33,14 @@ public class KwcContractLogisticsUnitRepository extends ServiceImpl<KwcContractL
                 .in(KwcContractLogisticsUnit::getContractId, contractIds));
     }
 
+    public List<KwcContractLogisticsUnit> queryByContractIds(List<Long> contractIds,Integer entType) {
+        return list(Wrappers.<KwcContractLogisticsUnit>lambdaQuery()
+                .in(KwcContractLogisticsUnit::getContractId, contractIds)
+                .eq(KwcContractLogisticsUnit::getUnitType, entType)
+                .eq(KwcContractLogisticsUnit::getDelFlag,0));
+
+    }
+
     @Transactional
     public void saveUnits(List<KwcContractLogisticsUnit> units) {
         saveBatch( units);

+ 96 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/IKwcContractLogisticsScoreService.java

@@ -0,0 +1,96 @@
+package com.sckw.contract.service;
+
+import java.util.Map;
+
+import com.github.pagehelper.PageInfo;
+import com.sckw.contract.api.model.dto.req.LogisticsScoreDetailFeignDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreApprovalDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailAddDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailQueryDto;
+import com.sckw.contract.model.vo.req.LogisticListReq;
+import com.sckw.contract.model.vo.res.LogisticsScoreDetailResVo;
+import com.sckw.contract.model.vo.res.LogisticsScoreResVo;
+import com.sckw.system.api.model.dto.res.EntCacheResDto;
+
+/**
+ * 物流企业评分Service接口
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+public interface IKwcContractLogisticsScoreService 
+{
+
+    /**
+     * 查询供应商企业对应的物流企业评分列表带待审核评分
+     * @param providerEntId 供应商企业id
+     * @return 物流企业评分集合
+     */
+    PageInfo<LogisticsScoreResVo> selectLogisticsScoreWithPendingSocreList(Long providerEntId);
+
+
+    /**
+     * 查询物流企业评分明细列表
+     *
+     * @param detailReqDto 物流企业评分明细
+     * @param providerEntId 供应商企业id
+     * @return 物流企业评分明细集合
+     */
+    PageInfo<LogisticsScoreDetailResVo> selectKwcContractLogisticsScoreDetailList(LogisticsScoreDetailQueryDto detailReqDto, Long providerEntId);
+
+
+    /**
+     * 查询物流企业待审评分明细
+     *
+     * @param scoreId 物流企业评分id
+     * @param providerEntId 供应商企业id
+     * @return 物流企业评分明细集合
+     */
+    LogisticsScoreDetailResVo selectLogisticsPendingScoreDetail(Long scoreId, Long providerEntId);
+
+    /**
+     * 初始化物流企业评分
+     * @param baseInfo
+     */
+    void initLogisticsScore(LogisticListReq.TradeBaseInfo baseInfo, Map<Long, EntCacheResDto> entCacheResDtoMap);
+
+    /**
+     * 初始化物流企业评分明细
+     * @param detailDto
+     */
+    void initLogisticsScoreDetail(LogisticsScoreDetailAddDto detailDto);
+
+
+    /**
+     * 审批物流企业评分明细
+     *
+     * @param approvalDto 审批参数
+     * @param providerEntId 供应商企业id
+     * @return 结果
+     */
+    void approvalLogisticsScoreDetail(LogisticsScoreApprovalDto approvalDto, Long providerEntId);
+
+
+    /**
+     * 用户修改物流企业评分
+     *
+     * @param detailDto 物流企业评分明细
+     * @return 结果
+     */
+    boolean insertLogisticsScoreDetailByUser(LogisticsScoreDetailAddDto detailDto,Long providerEntId);
+
+
+    /**
+     * 系统修改物流企业评分
+     * @param detailDto
+     * @return
+     */
+    boolean updateLogisticsScoreBySystem(LogisticsScoreDetailFeignDto detailDto);
+
+    /**
+     * 重置物流企业评分
+     * @param scoreId
+     * @param entId
+     */
+    void resetLogisticsScore(Long scoreId, Long entId);
+}

+ 476 - 0
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/impl/KwcContractLogisticsScoreServiceImpl.java

@@ -0,0 +1,476 @@
+package com.sckw.contract.service.impl;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageInfo;
+import com.sckw.contract.api.model.dto.req.LogisticsScoreDetailFeignDto;
+import com.sckw.contract.dao.KwcContractLogisticsScoreDetailMapper;
+import com.sckw.contract.model.dto.req.LogisticsScoreApprovalDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailQueryDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreQueryDto;
+import com.sckw.contract.model.dto.req.LogisticsScoreDetailAddDto;
+import com.sckw.contract.model.entity.KwcContractLogistics;
+import com.sckw.contract.model.entity.KwcContractLogisticsScoreDetail;
+import com.sckw.contract.model.entity.KwcContractLogisticsUnit;
+import com.sckw.contract.model.vo.req.LogisticListReq;
+import com.sckw.contract.model.vo.res.LogisticsScoreDetailResVo;
+import com.sckw.contract.model.vo.res.LogisticsScoreResVo;
+import com.sckw.contract.repository.KwcContractLogisticsRepository;
+import com.sckw.contract.repository.KwcContractLogisticsUnitRepository;
+import com.sckw.core.exception.BusinessException;
+import com.sckw.core.model.constant.NumberConstant;
+import com.sckw.core.model.enums.EntTypeEnum;
+import com.sckw.core.utils.BeanUtils;
+import com.sckw.core.utils.CollectionUtils;
+import com.sckw.core.utils.IdWorker;
+import com.sckw.core.utils.PageUtils;
+import com.sckw.core.web.config.CustomConfig;
+import com.sckw.core.web.context.LoginUserHolder;
+import com.sckw.redis.constant.RedisConstant;
+import com.sckw.redis.utils.RedissonUtils;
+import com.sckw.system.api.model.dto.res.EntCacheResDto;
+import org.apache.commons.collections4.MapUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.sckw.contract.dao.KwcContractLogisticsScoreMapper;
+import com.sckw.contract.model.entity.KwcContractLogisticsScore;
+import com.sckw.contract.service.IKwcContractLogisticsScoreService;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 物流企业评分Service业务层处理
+ * 
+ * @author tangyishan
+ * @date 2025-12-05
+ */
+@Service
+public class KwcContractLogisticsScoreServiceImpl implements IKwcContractLogisticsScoreService 
+{
+    @Autowired
+    private KwcContractLogisticsScoreMapper kwcContractLogisticsScoreMapper;
+    @Autowired
+    private KwcContractLogisticsRepository kwcContractLogisticsRepository;
+    @Autowired
+    private KwcContractLogisticsUnitRepository kwcContractLogisticsUnitRepository;
+    @Autowired
+    private KwcContractLogisticsScoreDetailMapper kwcContractLogisticsScoreDetailMapper;
+    @Autowired
+    private CustomConfig customConfig;
+
+    /**
+     * 查询物流企业评分列表
+     * providerEntId 供应商企业id
+     * isPage 是否是分页查询
+     * @return 物流企业评分
+     */
+    @Override
+    public PageInfo<LogisticsScoreResVo> selectLogisticsScoreWithPendingSocreList(Long providerEntId)
+    {
+        //查询评分列表
+        PageInfo<LogisticsScoreResVo> pageInfo = new PageInfo<>(new ArrayList<>());
+        List<KwcContractLogisticsScore> logisticsScores = selectLogisticsScoreList(providerEntId, true);
+        List<Long> logisticsScoreIds = logisticsScores.stream().map(KwcContractLogisticsScore::getId).toList();
+        if(CollectionUtils.isNotEmpty(logisticsScoreIds)){
+            //查询待审评分
+            LogisticsScoreDetailQueryDto detailReqDto = new LogisticsScoreDetailQueryDto();
+            detailReqDto.setScoreIds(logisticsScoreIds);
+            detailReqDto.setStatus(NumberConstant.ZERO);
+            List<KwcContractLogisticsScoreDetail> logisticsScoreDetails = kwcContractLogisticsScoreDetailMapper.selectKwcContractLogisticsScoreDetailList(detailReqDto);
+            if(CollectionUtils.isNotEmpty(logisticsScoreDetails)){
+                Map<Long, BigDecimal> scoreChangeMap = logisticsScoreDetails.stream().collect(Collectors.toMap(KwcContractLogisticsScoreDetail::getScoreId, KwcContractLogisticsScoreDetail::getScoreChange, (v1, v2) -> v1));
+                for (KwcContractLogisticsScore logisticsScore : logisticsScores) {
+                    logisticsScore.setPendingScore(scoreChangeMap.getOrDefault(logisticsScore.getId(), null));
+                }
+            }
+            pageInfo = ((Page<KwcContractLogisticsScore>) logisticsScores).toPageInfo(e -> {
+                LogisticsScoreResVo logisticsScoreResVo = new LogisticsScoreResVo();
+                BeanUtils.copyProperties(e, logisticsScoreResVo);
+                if(e.getPendingScore()!=null && e.getPendingScore().compareTo(BigDecimal.ZERO) > 0){
+                    logisticsScoreResVo.setPendingScore("+"+e.getPendingScore());
+                }else if(e.getPendingScore()==null){
+                    logisticsScoreResVo.setPendingScore("");
+                }
+                return logisticsScoreResVo;
+            });
+        }
+
+        return pageInfo;
+    }
+
+
+    /**
+     * 查询物流企业评分明细列表
+     *
+     * @param detailReqDto 物流企业评分明细
+     * @param providerEntId 供应商企业id
+     * @return 物流企业评分明细
+     */
+    @Override
+    public PageInfo<LogisticsScoreDetailResVo> selectKwcContractLogisticsScoreDetailList(LogisticsScoreDetailQueryDto detailReqDto, Long providerEntId)
+    {
+        //校验评分权限
+        KwcContractLogisticsScore logisticsScore = checkLogisticsScoreAuth(providerEntId, detailReqDto.getScoreId());
+        PageInfo<LogisticsScoreDetailResVo> pageInfo = new PageInfo<>(new ArrayList<>());
+        PageUtils.startPage();
+        detailReqDto.setScoreIds(Collections.singletonList(detailReqDto.getScoreId()));
+        List<KwcContractLogisticsScoreDetail> logisticsScoreDetails = kwcContractLogisticsScoreDetailMapper.selectKwcContractLogisticsScoreDetailList(detailReqDto);
+        if(CollectionUtils.isNotEmpty(logisticsScoreDetails)){
+            pageInfo = ((Page<KwcContractLogisticsScoreDetail>) logisticsScoreDetails).toPageInfo(e -> {
+                LogisticsScoreDetailResVo logisticsScoreDetailResVo = new LogisticsScoreDetailResVo();
+                BeanUtils.copyProperties(e, logisticsScoreDetailResVo);
+                if(e.getScoreChange()!=null && e.getScoreChange().compareTo(BigDecimal.ZERO) > 0){
+                    logisticsScoreDetailResVo.setScoreChange("+"+e.getScoreChange());
+                }else if(e.getScoreChange() == null){
+                    logisticsScoreDetailResVo.setScoreChange("");
+                }
+                if(e.getScore() == null){
+                    logisticsScoreDetailResVo.setScore("");
+                }
+                logisticsScoreDetailResVo.setLogisticsEntName(logisticsScore.getLogisticsEntName());
+                return logisticsScoreDetailResVo;
+            });
+        }
+        return pageInfo;
+    }
+
+    /**
+     * 查询物流企业待审评分
+     *
+     * @param scoreId 物流企业评分id
+     * @param providerEntId 供应商企业id
+     * @return 物流企业评分明细
+     */
+    @Override
+    public LogisticsScoreDetailResVo selectLogisticsPendingScoreDetail(Long scoreId, Long providerEntId)
+    {
+        //校验评分权限
+        KwcContractLogisticsScore logisticsScore = checkLogisticsScoreAuth(providerEntId,scoreId);
+        KwcContractLogisticsScoreDetail logisticsScoreDetail = kwcContractLogisticsScoreDetailMapper.selectLogisticsPendingScoreDetail(scoreId);
+        if(logisticsScoreDetail == null){
+            return null;
+        }
+        logisticsScoreDetail.setLogisticsEntName(logisticsScore.getLogisticsEntName());
+        LogisticsScoreDetailResVo logisticsScoreDetailResVo = new LogisticsScoreDetailResVo();
+        BeanUtils.copyProperties(logisticsScoreDetail,logisticsScoreDetailResVo);
+        logisticsScoreDetailResVo.setScore(logisticsScore.getScore().toString());
+        return logisticsScoreDetailResVo;
+    }
+
+
+    /**
+     * 查询物流企业评分列表
+     * providerEntId 供应商企业id
+     * isPage 是否是分页查询
+     * @return 物流企业评分
+     */
+    private List<KwcContractLogisticsScore> selectLogisticsScoreList(Long providerEntId, boolean isPage)
+    {
+        LogisticsScoreQueryDto scoreReqDto = new LogisticsScoreQueryDto();
+        providerEntId = providerEntId !=null ? providerEntId : LoginUserHolder.getEntId();
+        //1.查询当前供应商企业有效的物流合同
+        List<KwcContractLogistics> logisticsContracts = kwcContractLogisticsRepository.queryValidByEntId(providerEntId);
+        List<Long> contractIds = logisticsContracts.stream().map(KwcContractLogistics::getId).toList();
+        if(CollectionUtils.isNotEmpty(contractIds)){
+            //2.根据物流合同id列表和托运商类型查询物流企业列表并得到物流企业id列表
+            List<KwcContractLogisticsUnit> logisticsUnits = kwcContractLogisticsUnitRepository.queryByContractIds(contractIds, EntTypeEnum.LOGISTICS4.getCode());
+            List<Long> logisticsEntIds = logisticsUnits.stream().map(KwcContractLogisticsUnit::getEntId).toList();
+            if(CollectionUtils.isNotEmpty(logisticsEntIds)){
+                //3.根据物流企业id列表和供应商企业id查询物流企业评分列表
+                scoreReqDto.setProviderEntId(providerEntId);
+                scoreReqDto.setLogisticsEntIds(logisticsEntIds);
+                if (isPage){
+                    PageUtils.startPage();
+                }
+                return kwcContractLogisticsScoreMapper.selectKwcContractLogisticsScoreList(scoreReqDto);
+            }
+        }
+        return Collections.emptyList();
+    }
+
+
+
+
+
+    /**
+     * 校验供应商企业评分权限
+     * @param providerEntId 供应商企业id
+     * @param scoreId 评分id
+     * @return 评分id集合
+     */
+    private KwcContractLogisticsScore checkLogisticsScoreAuth(Long providerEntId,Long scoreId){
+        KwcContractLogisticsScore logisticsScore = kwcContractLogisticsScoreMapper.selectLogisticsScoreByEntIdAndScoreId(providerEntId,scoreId);
+        if(logisticsScore == null){
+            throw new BusinessException("无当前评分记录权限");
+        }
+        return logisticsScore;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void initLogisticsScore(LogisticListReq.TradeBaseInfo baseInfo,Map<Long, EntCacheResDto> entCacheResDtoMap) {
+        KwcContractLogisticsScore logisticsScore = new KwcContractLogisticsScore();
+
+        long scoreId = new IdWorker(1L).nextId();
+        logisticsScore.setId(scoreId);
+        //自动派单合同的托运单位等于当前登陆企业
+        logisticsScore.setProviderEntId(baseInfo.getProvideEntId());
+        logisticsScore.setLogisticsEntId(baseInfo.getPurchaseEntId());
+        EntCacheResDto logisticsEnt = entCacheResDtoMap.get(baseInfo.getPurchaseEntId());
+        logisticsScore.setLogisticsEntName(logisticsEnt != null ? logisticsEnt.getFirmName() : null);
+        logisticsScore.setScore(new BigDecimal(customConfig.getLogisticsInitScore()));
+        logisticsScore.setCreateBy(LoginUserHolder.getUserId());
+        Date date = new Date();
+        logisticsScore.setCreateTime(date);
+        logisticsScore.setUpdateBy(LoginUserHolder.getUserId());
+        logisticsScore.setUpdateTime(date);
+        //判断是否存在,存在则不创建
+        String lockKey = String.format(RedisConstant.LOGISTICS_SCORE_RECORD_INIT_KEY,logisticsScore.getProviderEntId(),logisticsScore.getLogisticsEntId());
+        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
+            throw new BusinessException("业务繁忙,请稍后再试!");
+        }
+        try {
+            if(kwcContractLogisticsScoreMapper.selectLogisticsScoreByEntId(baseInfo.getPurchaseEntId(),baseInfo.getPurchaseEntId())==null){
+                //初始化物流企业评分记录
+                kwcContractLogisticsScoreMapper.insertKwcContractLogisticsScore(logisticsScore);
+                //初始化物流企业评分明细
+                LogisticsScoreDetailAddDto detailDto  = new LogisticsScoreDetailAddDto();
+                detailDto.setScoreId(scoreId);
+                detailDto.setInfluenceBy(LoginUserHolder.getUserId());
+                detailDto.setInfluenceByName(LoginUserHolder.getUserName());
+                detailDto.setAction("物流企业评分初始化");
+                detailDto.setScoreChange(logisticsScore.getScore());
+                detailDto.setScore(logisticsScore.getScore());
+                detailDto.setStatus(NumberConstant.ONE);
+                initLogisticsScoreDetail(detailDto);
+
+                //todo tys初始化司机评分,需要传参供应企业id,物流企业id,评分变动,变动原因
+                logisticsScore.getProviderEntId();
+                logisticsScore.getLogisticsEntId();
+                logisticsScore.getScore();
+                detailDto.getAction();
+            }
+        } finally {
+            RedissonUtils.unlock(lockKey);
+        }
+    }
+
+
+    @Override
+    public void initLogisticsScoreDetail(LogisticsScoreDetailAddDto detailDto) {
+        KwcContractLogisticsScoreDetail logisticsScoreDetail = buildLogisticsScoreDetail(detailDto);
+        logisticsScoreDetail.setScore(logisticsScoreDetail.getScoreChange());
+        kwcContractLogisticsScoreDetailMapper.insertKwcContractLogisticsScoreDetail(logisticsScoreDetail);
+    }
+
+
+    /**
+     * 审批物流企业评分明细
+     *
+     * @param approvalDto 审批参数
+     * @param providerEntId 供应商企业id
+     * @return 结果
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void approvalLogisticsScoreDetail(LogisticsScoreApprovalDto approvalDto, Long providerEntId)
+    {
+        String lockKey = String.format(RedisConstant.LOGISTICS_SCORE_RECORD_APPROVAL_KEY,approvalDto.getScoreId());
+        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
+            throw new BusinessException("业务繁忙,请稍后再试!");
+        }
+        try {
+            //校验评分权限
+            KwcContractLogisticsScore logisticsScore = checkLogisticsScoreAuth(providerEntId,approvalDto.getScoreId());
+            KwcContractLogisticsScoreDetail logisticsScoreDetail = kwcContractLogisticsScoreDetailMapper.selectLogisticsPendingScoreDetail(approvalDto.getScoreId());
+            if(logisticsScoreDetail != null && Objects.equals(logisticsScoreDetail.getStatus(),NumberConstant.ZERO)){
+                if(approvalDto.getApproval()==0){
+                    //驳回,清除待审核评分
+                    kwcContractLogisticsScoreDetailMapper.deleteKwcContractLogisticsScoreDetailById(logisticsScoreDetail.getId(),NumberConstant.ZERO);
+                }else{
+                    //通过
+                    //校验分数扣减是否会超过上下限
+                    BigDecimal score = logisticsScore.getScore();
+                    BigDecimal resultScore = score.add(logisticsScoreDetail.getScoreChange());
+                    double scoreDouble = resultScore.doubleValue();
+                    if (scoreDouble < 0 || scoreDouble > 100) {
+                        throw new BusinessException("通过后企业评分将超过100或小于0,请驳回");
+                    }
+                    //1、更新企业评分
+                    logisticsScore.setScore(resultScore);
+                    logisticsScore.setUpdateBy(LoginUserHolder.getUserId());
+                    logisticsScore.setUpdateTime(new Date());
+                    kwcContractLogisticsScoreMapper.updateKwcContractLogisticsScore(logisticsScore);
+                    //2、修改待审评分状态
+                    logisticsScoreDetail.setStatus(NumberConstant.ONE);
+                    logisticsScoreDetail.setScore(resultScore);
+                    logisticsScoreDetail.setUpdateBy(LoginUserHolder.getUserId());
+                    logisticsScoreDetail.setUpdateTime(new Date());
+                    kwcContractLogisticsScoreDetailMapper.updateKwcContractLogisticsScoreDetail(logisticsScoreDetail);
+                    // todo tys更新司机评分 需要传参供应企业id,物流企业id,评分变动,变动原因
+                    logisticsScore.getProviderEntId();
+                    logisticsScore.getLogisticsEntId();
+                    logisticsScoreDetail.getScoreChange();
+                    logisticsScoreDetail.getAction();
+
+
+                }
+            }else{
+                throw new BusinessException("该评分已审批完成");
+            }
+        } finally {
+            RedissonUtils.unlock(lockKey);
+        }
+    }
+
+
+    /**
+     * 用户修改物流企业评分
+     *
+     * @param detailDto 物流企业评分
+     * @return 结果
+     */
+    @Override
+    public boolean insertLogisticsScoreDetailByUser(LogisticsScoreDetailAddDto detailDto,Long providerEntId)
+    {
+        //校验评分权限
+        KwcContractLogisticsScore logisticsScore = checkLogisticsScoreAuth(providerEntId, detailDto.getScoreId());
+        String lockKey = String.format(RedisConstant.LOGISTICS_SCORE_RECORD_UPDATE_KEY,detailDto.getScoreId());
+        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
+            throw new BusinessException("业务繁忙,请稍后再试!");
+        }
+        try {
+            //校验是否已存在待审核评分
+            KwcContractLogisticsScoreDetail dbScoreDetail = kwcContractLogisticsScoreDetailMapper.selectLogisticsPendingScoreDetail(detailDto.getScoreId());
+            if(dbScoreDetail != null){
+                throw new BusinessException("修改评分失败,存在待审核评分未处理");
+            }
+            //校验分数扣减是否会超过上下限
+            BigDecimal score = logisticsScore.getScore();
+            double scoreDouble = score.add(detailDto.getScoreChange()).doubleValue();
+            if (scoreDouble < 0 || scoreDouble > 100) {
+                throw new BusinessException("修改评分失败,评分不能低于0分或超过100分");
+            }
+            //用户修改评分
+            detailDto.setInfluenceBy(LoginUserHolder.getUserId());
+            detailDto.setInfluenceByName(LoginUserHolder.getUserName());
+            detailDto.setStatus(NumberConstant.ZERO);
+            detailDto.setAction("修改企业评分,原因:"+detailDto.getAction());
+            KwcContractLogisticsScoreDetail logisticsScoreDetail = buildLogisticsScoreDetail(detailDto);
+            return SqlHelper.retBool(kwcContractLogisticsScoreDetailMapper.insertKwcContractLogisticsScoreDetail(logisticsScoreDetail));
+        } finally {
+            RedissonUtils.unlock(lockKey);
+        }
+    }
+
+
+    /**
+     * 系统修改物流企业评分
+     *
+     * @param detailDto 物流企业评分
+     * @return 结果
+     */
+    @Override
+    public boolean updateLogisticsScoreBySystem(LogisticsScoreDetailFeignDto detailDto)
+    {
+        //1.根据供应商企业id和物流企业查询物流企业评分
+        KwcContractLogisticsScore logisticsScore = kwcContractLogisticsScoreMapper.selectLogisticsScoreByEntId(detailDto.getProviderEntId(),detailDto.getLogisticsEntId());
+        //1、更新企业评分
+        BigDecimal score = logisticsScore.getScore();
+        BigDecimal resultScore = score.add(detailDto.getScoreChange());
+        logisticsScore.setScore(resultScore);
+        logisticsScore.setUpdateBy(LoginUserHolder.getUserId());
+        logisticsScore.setUpdateTime(new Date());
+        kwcContractLogisticsScoreMapper.updateKwcContractLogisticsScore(logisticsScore);
+        //2.插入评分明细记录
+        LogisticsScoreDetailAddDto detailAddDto = new LogisticsScoreDetailAddDto();
+        detailAddDto.setScoreId(logisticsScore.getId());
+        detailAddDto.setInfluenceBy(detailDto.getInfluenceBy());
+        detailAddDto.setInfluenceByName(detailDto.getInfluenceByName());
+        detailAddDto.setAction(detailDto.getAction());
+        detailAddDto.setScoreChange(detailDto.getScoreChange());
+        detailAddDto.setScore(resultScore);
+        //2.设置评分状态为通过
+        detailAddDto.setStatus(NumberConstant.ONE);
+        //3.构建评分明细记录
+        KwcContractLogisticsScoreDetail logisticsScoreDetail = buildLogisticsScoreDetail(detailAddDto);
+        //4.插入数据
+        return SqlHelper.retBool(kwcContractLogisticsScoreDetailMapper.insertKwcContractLogisticsScoreDetail(logisticsScoreDetail));
+    }
+
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void resetLogisticsScore(Long scoreId, Long providerEntId)
+    {
+        //1.校验供应商企业评分权限
+        KwcContractLogisticsScore logisticsScore = checkLogisticsScoreAuth(providerEntId, scoreId);
+        String lockKey = String.format(RedisConstant.LOGISTICS_SCORE_RECORD_RESET_KEY,scoreId);
+        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
+            throw new BusinessException("业务繁忙,请稍后再试!");
+        }
+        try {
+            //2.修改企业评分为初始化分
+            logisticsScore.setScore(new BigDecimal(customConfig.getLogisticsInitScore()));
+            logisticsScore.setUpdateBy(LoginUserHolder.getUserId());
+            logisticsScore.setUpdateTime(new Date());
+            kwcContractLogisticsScoreMapper.updateKwcContractLogisticsScore(logisticsScore);
+            //3.评分明细中插入重置记录
+            KwcContractLogisticsScoreDetail resetLogisticsScoreDetail = buildResetLogisticsScoreDetail(scoreId);
+            kwcContractLogisticsScoreDetailMapper.insertKwcContractLogisticsScoreDetail(resetLogisticsScoreDetail);
+            //4.清除待审核评分
+            kwcContractLogisticsScoreDetailMapper.deleteKwcContractLogisticsScoreDetailByScoreId(logisticsScore.getId(),NumberConstant.ZERO);
+            //4.todo tys重置司机评分需要传参供应商企业id,物流企业id,重置评分,原因
+
+        } finally {
+            RedissonUtils.unlock(lockKey);
+        }
+    }
+
+
+    /**
+     * 构建重置评分记录明细
+     *
+     * @param scoreId 评分id
+     * @return 评分记录
+     */
+    private KwcContractLogisticsScoreDetail buildResetLogisticsScoreDetail(Long scoreId) {
+        KwcContractLogisticsScoreDetail logisticsScoreDetail = new KwcContractLogisticsScoreDetail();
+        long scoreDetailId = new IdWorker(1L).nextId();
+        logisticsScoreDetail.setId(scoreDetailId);
+        logisticsScoreDetail.setScoreId(scoreId);
+        logisticsScoreDetail.setInfluenceBy(LoginUserHolder.getUserId());
+        logisticsScoreDetail.setInfluenceByName(LoginUserHolder.getUserName());
+        logisticsScoreDetail.setAction("重置企业评分");
+        logisticsScoreDetail.setScore(new BigDecimal(customConfig.getLogisticsInitScore()));
+        logisticsScoreDetail.setScoreChange(null);
+        logisticsScoreDetail.setStatus(NumberConstant.ONE);
+        logisticsScoreDetail.setCreateBy(LoginUserHolder.getUserId());
+        logisticsScoreDetail.setCreateTime(new Date());
+        logisticsScoreDetail.setUpdateBy(LoginUserHolder.getUserId());
+        logisticsScoreDetail.setUpdateTime(new Date());
+        return logisticsScoreDetail;
+    }
+
+
+    private KwcContractLogisticsScoreDetail buildLogisticsScoreDetail(LogisticsScoreDetailAddDto detailDto) {
+        KwcContractLogisticsScoreDetail logisticsScoreDetail = new KwcContractLogisticsScoreDetail();
+        long scoreDetailId = new IdWorker(1L).nextId();
+        logisticsScoreDetail.setId(scoreDetailId);
+        logisticsScoreDetail.setScoreId(detailDto.getScoreId());
+        logisticsScoreDetail.setInfluenceBy(detailDto.getInfluenceBy());
+        logisticsScoreDetail.setInfluenceByName(detailDto.getInfluenceByName());
+        logisticsScoreDetail.setAction(detailDto.getAction());
+        logisticsScoreDetail.setScoreChange(detailDto.getScoreChange());
+        logisticsScoreDetail.setScore(detailDto.getScore());
+        logisticsScoreDetail.setStatus(detailDto.getStatus());
+        logisticsScoreDetail.setCreateBy(LoginUserHolder.getUserId());
+        logisticsScoreDetail.setCreateTime(new Date());
+        logisticsScoreDetail.setUpdateBy(LoginUserHolder.getUserId());
+        logisticsScoreDetail.setUpdateTime(new Date());
+        return logisticsScoreDetail;
+    }
+}

+ 30 - 17
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractLogisticsService.java

@@ -20,10 +20,7 @@ import com.sckw.contract.model.vo.res.*;
 import com.sckw.contract.repository.KwcContractLogisticsGoodsRepository;
 import com.sckw.contract.repository.KwcContractLogisticsRepository;
 import com.sckw.contract.repository.KwcContractLogisticsUnitRepository;
-import com.sckw.contract.service.CommonBusinessService;
-import com.sckw.contract.service.KwcContractLogisticsGoodsService;
-import com.sckw.contract.service.KwcContractLogisticsTrackService;
-import com.sckw.contract.service.KwcContractLogisticsUnitService;
+import com.sckw.contract.service.*;
 import com.sckw.core.common.enums.enums.DictEnum;
 import com.sckw.core.common.enums.enums.DictTypeEnum;
 import com.sckw.core.exception.BusinessException;
@@ -58,7 +55,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.RequestBody;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -93,6 +89,9 @@ public class KwcContractLogisticsService {
     @Autowired
     private CommonBusinessService commonBusinessService;
 
+    @Autowired
+    private IKwcContractLogisticsScoreService  logisticsScoreService;
+
     private final KwcContractLogisticsRepository kwcContractLogisticsRepository;
     private final KwcContractLogisticsUnitRepository kwcContractLogisticsUnitRepository;
     private final KwcContractLogisticsGoodsRepository kwcContractLogisticsGoodsRepository;
@@ -1268,7 +1267,17 @@ public class KwcContractLogisticsService {
         }else {
             saveContractLogistics.setEndTime(DateUtils.getEndOfDay(baseInfo.getEndTime()));
         }
+        List<Long> entIdList = new ArrayList<>();
+        if (Objects.nonNull(baseInfo.getProvideEntId())) {
+            entIdList.add(baseInfo.getProvideEntId());
+        }
 
+        if (Objects.nonNull(baseInfo.getPurchaseEntId())) {
+            entIdList.add(baseInfo.getPurchaseEntId());
+        }
+        Map<Long, EntCacheResDto> entCacheResDtoMap = commonBusinessService.queryEntCacheMapByIds(entIdList);
+        //校验自动派单合同的托运单位是否为供应商类型
+        checkAutoDispatchingContractEntType(baseInfo,entCacheResDtoMap);
         //校验物流企业是否存在同时段的自动派车合同
         checkAutoDispatchingContractExist(baseInfo);
 
@@ -1284,23 +1293,27 @@ public class KwcContractLogisticsService {
         //保存交易商品信息
         saveLogisticsGoods(req, saveContractLogistics.getId());
         //保存物流企业信息
-        List<Long> entIdList = new ArrayList<>();
-        if (Objects.nonNull(baseInfo.getProvideEntId())) {
-            entIdList.add(baseInfo.getProvideEntId());
-        }
-
-        if (Objects.nonNull(baseInfo.getPurchaseEntId())) {
-            entIdList.add(baseInfo.getPurchaseEntId());
-        }
         if (CollectionUtils.isEmpty(entIdList)) {
             return false;
         }
+        saveLogisticListUnit(entIdList, baseInfo, saveContractLogistics.getId(), date,entCacheResDtoMap);
 
-        saveLogisticListUnit(entIdList, baseInfo, saveContractLogistics.getId(), date);
-
+        //如果是自动派单合同需要初始化物流企业评分记录和评分记录明细
+        if(Objects.equals(Integer.parseInt(DictEnum.DISPATCHING_TYPE_2.getValue()), baseInfo.getDispatching())){
+            logisticsScoreService.initLogisticsScore(baseInfo,entCacheResDtoMap);
+        }
         return Boolean.TRUE;
     }
 
+    private void checkAutoDispatchingContractEntType(LogisticListReq.TradeBaseInfo baseInfo,Map<Long, EntCacheResDto> entCacheResDtoMap) {
+        if (Objects.equals(Integer.parseInt(DictEnum.DISPATCHING_TYPE_2.getValue()), baseInfo.getDispatching())) {
+            EntCacheResDto entCacheResDto = entCacheResDtoMap.get(baseInfo.getProvideEntId());
+            if (entCacheResDto != null && !entCacheResDto.getEntTypes().contains(String.valueOf(EntTypeEnum.SUPPLIER.getCode()))) {
+                throw new BusinessException("自动派车合同的托运单位必须为供应商");
+            }
+        }
+    }
+
     public void checkAutoDispatchingContractExist(LogisticListReq.TradeBaseInfo baseInfo) {
         List<KwcContractLogisticsUnit> units = kwcContractLogisticsUnitRepository.queryByEntIdAndEntType(baseInfo.getPurchaseEntId(), EntTypeEnum.LOGISTICS4.getCode());
         if (CollectionUtils.isNotEmpty(units)) {
@@ -1373,8 +1386,8 @@ public class KwcContractLogisticsService {
         return logisticsGoods;
     }
 
-    private void saveLogisticListUnit(List<Long> entIdList, LogisticListReq.TradeBaseInfo baseInfo, long contactId, Date date) {
-        Map<Long, EntCacheResDto> entCacheResDtoMap = commonBusinessService.queryEntCacheMapByIds(entIdList);
+    private void saveLogisticListUnit(List<Long> entIdList, LogisticListReq.TradeBaseInfo baseInfo, long contactId, Date date,Map<Long, EntCacheResDto> entCacheResDtoMap) {
+
         List<KwcContractLogisticsUnit> units = Lists.newArrayList();
         //存供应商
         if(Objects.nonNull(baseInfo.getProvideEntId())) {

+ 110 - 0
sckw-modules/sckw-contract/src/main/resources/mapper/KwcContractLogisticsScoreDetailMapper.xml

@@ -0,0 +1,110 @@
+<?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.sckw.contract.dao.KwcContractLogisticsScoreDetailMapper">
+    
+    <resultMap type="com.sckw.contract.model.entity.KwcContractLogisticsScoreDetail" id="KwcContractLogisticsScoreDetailResult">
+        <result property="id"    column="id"    />
+        <result property="scoreId"    column="score_id"    />
+        <result property="influenceBy"    column="influence_by"    />
+        <result property="influenceByName"    column="influence_by_name"    />
+        <result property="action"    column="action"    />
+        <result property="scoreChange"    column="score_change"    />
+        <result property="score"    column="score"    />
+        <result property="status"    column="status"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectKwcContractLogisticsScoreDetailVo">
+        select id, score_id, influence_by, influence_by_name, action, score_change, score, status, create_by, create_time, update_by, update_time from kwc_contract_logistics_score_detail
+    </sql>
+
+    <select id="selectKwcContractLogisticsScoreDetailList" parameterType="com.sckw.contract.model.dto.req.LogisticsScoreDetailQueryDto" resultMap="KwcContractLogisticsScoreDetailResult">
+        <include refid="selectKwcContractLogisticsScoreDetailVo"/>
+        <where>
+            and score_id in
+            <foreach collection="scoreIds" item="scoreId" open="(" separator="," close=")">
+                #{scoreId}
+            </foreach>
+            <if test="status != null">and status = #{status}</if>
+            <if test="action != null  and action != ''"> and action like concat('%', #{action}, '%')</if>
+        </where>
+        order by update_time desc
+    </select>
+
+
+    <select id="selectLogisticsPendingScoreDetail" parameterType="com.sckw.contract.model.dto.req.LogisticsScoreDetailQueryDto" resultType="com.sckw.contract.model.entity.KwcContractLogisticsScoreDetail">
+        <include refid="selectKwcContractLogisticsScoreDetailVo"/>
+        <where>
+            and score_id = #{scoreId} and status = 0
+        </where>
+        order by update_time desc
+    </select>
+    
+    <select id="selectKwcContractLogisticsScoreDetailById" parameterType="Long" resultMap="KwcContractLogisticsScoreDetailResult">
+        <include refid="selectKwcContractLogisticsScoreDetailVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertKwcContractLogisticsScoreDetail" parameterType="com.sckw.contract.model.entity.KwcContractLogisticsScoreDetail">
+        insert into kwc_contract_logistics_score_detail
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="scoreId != null">score_id,</if>
+            <if test="influenceBy != null">influence_by,</if>
+            <if test="influenceByName != null and influenceByName != ''">influence_by_name,</if>
+            <if test="action != null and action != ''">action,</if>
+            <if test="scoreChange != null">score_change,</if>
+            <if test="score != null">score,</if>
+            <if test="status != null">status,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="scoreId != null">#{scoreId},</if>
+            <if test="influenceBy != null">#{influenceBy},</if>
+            <if test="influenceByName != null and influenceByName != ''">#{influenceByName},</if>
+            <if test="action != null and action != ''">#{action},</if>
+            <if test="scoreChange != null">#{scoreChange},</if>
+            <if test="score != null">#{score},</if>
+            <if test="status != null">#{status},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateKwcContractLogisticsScoreDetail" parameterType="com.sckw.contract.model.entity.KwcContractLogisticsScoreDetail">
+        update kwc_contract_logistics_score_detail
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="score != null">score = #{score},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteKwcContractLogisticsScoreDetailById">
+        delete from kwc_contract_logistics_score_detail where id = #{id} and status = #{status}
+    </delete>
+
+    <delete id="deleteKwcContractLogisticsScoreDetailByScoreId">
+        delete from kwc_contract_logistics_score_detail where score_id = #{scoreId} and status = #{status}
+    </delete>
+
+    <delete id="deleteKwcContractLogisticsScoreDetailByIds" parameterType="String">
+        delete from kwc_contract_logistics_score_detail where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 95 - 0
sckw-modules/sckw-contract/src/main/resources/mapper/KwcContractLogisticsScoreMapper.xml

@@ -0,0 +1,95 @@
+<?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.sckw.contract.dao.KwcContractLogisticsScoreMapper">
+    
+    <resultMap type="com.sckw.contract.model.entity.KwcContractLogisticsScore" id="KwcContractLogisticsScoreResult">
+        <result property="id"    column="id"    />
+        <result property="providerEntId"    column="provider_ent_id"    />
+        <result property="logisticsEntId"    column="logistics_ent_id"    />
+        <result property="logisticsEntName"    column="logistics_ent_name"    />
+        <result property="score"    column="score"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectKwcContractLogisticsScoreVo">
+        select id, provider_ent_id, logistics_ent_id, logistics_ent_name, score, create_by, create_time, update_by, update_time from kwc_contract_logistics_score
+    </sql>
+
+    <select id="selectKwcContractLogisticsScoreList" parameterType="com.sckw.contract.model.dto.req.LogisticsScoreQueryDto" resultMap="KwcContractLogisticsScoreResult">
+        <include refid="selectKwcContractLogisticsScoreVo"/>
+        <where>  
+            provider_ent_id = #{providerEntId}
+            and logistics_ent_id in
+            <foreach collection="logisticsEntIds" item="logisticsEntId" open="(" separator="," close=")">
+                #{logisticsEntId}
+            </foreach>
+        </where>
+        order by score desc
+    </select>
+    
+    <select id="selectKwcContractLogisticsScoreById" parameterType="Long" resultMap="KwcContractLogisticsScoreResult">
+        <include refid="selectKwcContractLogisticsScoreVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectLogisticsScoreByEntId" resultMap="KwcContractLogisticsScoreResult">
+        <include refid="selectKwcContractLogisticsScoreVo"/>
+         where provider_ent_id = #{providerEntId} and logistics_ent_id = #{logisticsEntId}
+    </select>
+
+    <select id="selectLogisticsScoreByEntIdAndScoreId" resultMap="KwcContractLogisticsScoreResult">
+        <include refid="selectKwcContractLogisticsScoreVo"/>
+        where id = #{scoreId} and provider_ent_id = #{providerEntId}
+    </select>
+
+    <insert id="insertKwcContractLogisticsScore" parameterType="com.sckw.contract.model.entity.KwcContractLogisticsScore">
+        insert into kwc_contract_logistics_score
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="providerEntId != null">provider_ent_id,</if>
+            <if test="logisticsEntId != null">logistics_ent_id,</if>
+            <if test="logisticsEntName != null and logisticsEntName != ''">logistics_ent_name,</if>
+            <if test="score != null">score,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="providerEntId != null">#{providerEntId},</if>
+            <if test="logisticsEntId != null">#{logisticsEntId},</if>
+            <if test="logisticsEntName != null and logisticsEntName != ''">#{logisticsEntName},</if>
+            <if test="score != null">#{score},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateKwcContractLogisticsScore" parameterType="com.sckw.contract.model.entity.KwcContractLogisticsScore">
+        update kwc_contract_logistics_score
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="score != null">score = #{score},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteKwcContractLogisticsScoreById" parameterType="Long">
+        delete from kwc_contract_logistics_score where id = #{id}
+    </delete>
+
+    <delete id="deleteKwcContractLogisticsScoreByIds" parameterType="String">
+        delete from kwc_contract_logistics_score where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 1 - 0
sql/2025/12/01/2025_12_03_tys_alert.sql

@@ -0,0 +1 @@
+ALTER TABLE `sckw_ng_contract`.`kwc_contract_logistics` ADD COLUMN `dispatching` int NULL DEFAULT 1 COMMENT '派车方式(1手动派车、2自动派车)' AFTER `trading`;

+ 31 - 0
sql/2025/12/09/2025_12_09_tys_creat.sql

@@ -0,0 +1,31 @@
+CREATE TABLE `kwc_contract_logistics_score` (
+    `id` bigint NOT NULL COMMENT '主键',
+    `provider_ent_id` bigint NOT NULL COMMENT '供应商企业id',
+    `logistics_ent_id` bigint NOT NULL COMMENT '物流企业id',
+    `logistics_ent_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '物流企业名称',
+    `score` decimal(10,2) NOT NULL COMMENT '物流企业评分',
+    `create_by` bigint NOT NULL,
+    `create_time` datetime NOT NULL,
+    `update_by` bigint NOT NULL,
+    `update_time` datetime NOT NULL COMMENT '更新时间',
+    PRIMARY KEY (`id`) USING BTREE,
+    UNIQUE KEY `provider_logistics_id_index` (`provider_ent_id`,`logistics_ent_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='物流企业评分表';
+
+
+CREATE TABLE `kwc_contract_logistics_score_detail` (
+   `id` bigint NOT NULL COMMENT '主键',
+   `score_id` bigint NOT NULL COMMENT '评分主键id',
+   `influence_by` bigint NOT NULL COMMENT '影响人id',
+   `influence_by_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '影响人名字',
+   `action` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '行为',
+   `score_change` decimal(10,2) DEFAULT NULL COMMENT '评分变动',
+   `score` decimal(10,2) DEFAULT NULL COMMENT '变动后评分',
+   `status` int NOT NULL DEFAULT '1' COMMENT '审核状态0-待审核,1-审核通过',
+   `create_by` bigint NOT NULL,
+   `create_time` datetime NOT NULL,
+   `update_by` bigint NOT NULL,
+   `update_time` datetime NOT NULL,
+   PRIMARY KEY (`id`) USING BTREE,
+   KEY `score_id_index` (`score_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='物流企业评分明细表';