Просмотр исходного кода

Merge remote-tracking branch 'origin/master' into master

肖路 2 месяцев назад
Родитель
Сommit
d626d8326b
95 измененных файлов с 4848 добавлено и 925 удалено
  1. 6 0
      pom.xml
  2. 1 0
      ruoyi-api/pom.xml
  3. 25 0
      ruoyi-api/ruoyi-api-bill/pom.xml
  4. 8 0
      ruoyi-api/ruoyi-api-bill/src/main/java/org/dromara/bill/api/RemoteBillService.java
  5. 6 0
      ruoyi-api/ruoyi-api-bom/pom.xml
  6. 14 0
      ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/RemotePartnerPreparedService.java
  7. 18 0
      ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/domain/dto/PartnerPreparedDTO.java
  8. 4 2
      ruoyi-api/ruoyi-api-external/pom.xml
  9. 1 1
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/GoodsImportItem.java
  10. 11 40
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/ZCR.java
  11. 19 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/DeliveryTrackBo.java
  12. 5 1
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/MessageBo.java
  13. 1 1
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/ZhongCheOrderDeliverBo.java
  14. 6 6
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/CatalogsVo.java
  15. 15 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/GoodsStockVo.java
  16. 5 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/MessageVo.java
  17. 19 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/ZCLoginBusinessRespVo.java
  18. 1 1
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/ZhongCheOrderDeliverVo.java
  19. 5 0
      ruoyi-api/ruoyi-api-order/pom.xml
  20. 22 0
      ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/RemoteExternalOrderService.java
  21. 21 1
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductService.java
  22. 13 0
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductShoppingCartService.java
  23. 46 0
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/domain/zhongche/dto/ProductAggregateDto.java
  24. 16 0
      ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteComLogisticsCompanyService.java
  25. 123 2
      ruoyi-auth/src/main/java/org/dromara/auth/controller/Auth2Controller.java
  26. 128 0
      ruoyi-auth/src/main/java/org/dromara/auth/util/SM2SignatureUtils.java
  27. 111 0
      ruoyi-auth/src/main/java/org/dromara/auth/util/SignParamUtils.java
  28. 94 0
      ruoyi-auth/src/main/java/org/dromara/auth/util/ZCApiUtils.java
  29. 4 2
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/zhongche/domain/DeliveryTrack.java
  30. 3 4
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/zhongche/vo/ZhongCheTrackVo.java
  31. 6 0
      ruoyi-modules/ruoyi-bill/pom.xml
  32. 18 0
      ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/dubbo/RemoteBillServiceImpl.java
  33. 0 1
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/SupplierInfoController.java
  34. 75 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemotePartnerPreparedServiceImpl.java
  35. 54 0
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/enums/PartnerPreparedStatusEnum.java
  36. 1 3
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ISupplierInfoService.java
  37. 8 8
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierContactServiceImpl.java
  38. 105 94
      ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierInfoServiceImpl.java
  39. 2 0
      ruoyi-modules/ruoyi-external/pom.xml
  40. 2 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductController.java
  41. 288 450
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/ZhongChePullController.java
  42. 503 257
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/ZhongChePushController.java
  43. 40 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/MallMessageDispatcher.java
  44. 18 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/MallMessageHandler.java
  45. 154 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/AccountActiveMessageHandler.java
  46. 45 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/AfterSaleApplyMessageHandler.java
  47. 41 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/AfterSaleCancelMessageHandler.java
  48. 33 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillAbnormalPassMessageHandler.java
  49. 34 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillConfirmMessageHandler.java
  50. 33 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillCreateMessageHandler.java
  51. 34 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillFinishMessageHandler.java
  52. 35 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillModifyMessageHandler.java
  53. 35 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillRejctPassMessageHandler.java
  54. 41 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillRuleCreateMessageHandler.java
  55. 34 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillWaitInvoiceMessageHandler.java
  56. 52 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsAuditPassMessageHandler.java
  57. 54 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsAuditRejectMessageHandler.java
  58. 71 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsImportBlockMessageHandler.java
  59. 52 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsOffShelfMessageHandler.java
  60. 52 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsOnShelfFailMessageHandler.java
  61. 54 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsWaitAuditMessageHandler.java
  62. 122 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/InvoiceApplyMessageHandler.java
  63. 41 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderCancelApplyMessageHandler.java
  64. 44 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderCancelMessageHandler.java
  65. 39 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderCreateMessageHandler.java
  66. 40 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderReceiveConfirmMessageHandler.java
  67. 40 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/PrepareCancelMessageHandler.java
  68. 40 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/PrepareConfirmMessageHandler.java
  69. 49 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/SettlementCreateMessageHandler.java
  70. 55 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/StockLockMessageHandler.java
  71. 46 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/StockUnlockMessageHandler.java
  72. 10 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductVo.java
  73. 108 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/enums/MallMessageTypeEnum.java
  74. 5 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductService.java
  75. 68 3
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductServiceImpl.java
  76. 128 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/util/SM2SignatureUtils.java
  77. 109 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/util/SignParamUtils.java
  78. 93 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/util/ZCApiUtils.java
  79. 192 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/dubbo/RemoteExternalOrderServiceImpl.java
  80. 34 0
      ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/enums/PackStatusEnum.java
  81. 3 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductCategoryController.java
  82. 106 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductInventoryLockController.java
  83. 1 1
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductBase.java
  84. 57 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductInventoryLock.java
  85. 44 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductInventoryLockBo.java
  86. 56 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductInventoryLockVo.java
  87. 294 47
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductServiceImpl.java
  88. 39 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductShoppingCartServiceImpl.java
  89. 15 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductInventoryLockMapper.java
  90. 70 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductInventoryLockService.java
  91. 2 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductWarehouseInventoryService.java
  92. 135 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductInventoryLockServiceImpl.java
  93. 6 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductWarehouseInventoryServiceImpl.java
  94. 7 0
      ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductInventoryLockMapper.xml
  95. 25 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteComLogisticsCompanyServiceImpl.java

+ 6 - 0
pom.xml

@@ -144,6 +144,12 @@
     <dependencyManagement>
         <dependencies>
 
+            <dependency>
+                <groupId>org.bouncycastle</groupId>
+                <artifactId>bcprov-jdk18on</artifactId>
+                <version>1.78.1</version>
+            </dependency>
+
             <!-- SpringCloud 微服务 -->
             <dependency>
                 <groupId>org.springframework.cloud</groupId>

+ 1 - 0
ruoyi-api/pom.xml

@@ -17,6 +17,7 @@
         <module>ruoyi-api-external</module>
         <module>ruoyi-api-order</module>
         <module>ruoyi-api-customer</module>
+        <module>ruoyi-api-bill</module>
     </modules>
 
     <artifactId>ruoyi-api</artifactId>

+ 25 - 0
ruoyi-api/ruoyi-api-bill/pom.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-api</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>ruoyi-api-bill</artifactId>
+
+    <dependencies>
+
+        <!-- RuoYi Common Core-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+
+    </dependencies>
+
+</project>

+ 8 - 0
ruoyi-api/ruoyi-api-bill/src/main/java/org/dromara/bill/api/RemoteBillService.java

@@ -0,0 +1,8 @@
+package org.dromara.bill.api;
+
+/**
+ * author
+ * 时间:2026/2/4,16:52
+ */
+public interface RemoteBillService {
+}

+ 6 - 0
ruoyi-api/ruoyi-api-bom/pom.xml

@@ -21,6 +21,12 @@
     <dependencyManagement>
         <dependencies>
 
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-api-bill</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
             <dependency>
                 <groupId>org.dromara</groupId>
                 <artifactId>ruoyi-api-customer</artifactId>

+ 14 - 0
ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/RemotePartnerPreparedService.java

@@ -0,0 +1,14 @@
+package org.dromara.customer.api;
+
+import org.dromara.customer.api.domain.dto.PartnerPreparedDTO;
+
+/**
+ * author
+ * 时间:2026/2/3,17:49
+ */
+public interface RemotePartnerPreparedService {
+
+    PartnerPreparedDTO updatePartnerPreparedById(String id);
+
+    PartnerPreparedDTO cancelPartnerPreparedById(String prepareOrderNo, String cancelReason);
+}

+ 18 - 0
ruoyi-api/ruoyi-api-customer/src/main/java/org/dromara/customer/api/domain/dto/PartnerPreparedDTO.java

@@ -0,0 +1,18 @@
+package org.dromara.customer.api.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * author
+ * 时间:2026/2/3,17:51
+ */
+@Data
+public class PartnerPreparedDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private boolean flag;
+
+    private String message;
+}

+ 4 - 2
ruoyi-api/ruoyi-api-external/pom.xml

@@ -26,11 +26,13 @@
 
         <dependency>
             <groupId>org.bouncycastle</groupId>
-            <artifactId>bcprov-jdk15on</artifactId>
-            <version>1.70</version>
+            <artifactId>bcprov-jdk18on</artifactId>
+            <version>1.78.1</version>
         </dependency>
 
 
+
+
     </dependencies>
 
 </project>

+ 1 - 1
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/GoodsImportItem.java

@@ -87,7 +87,7 @@ public class GoodsImportItem {
      * 商品轮播图,JSON格式数组,其中第一张为主图
      * 示例:["imgUrl1","imgUrl2"]
      */
-    private List<String> barImgUrls;
+    private String barImgUrls;
     /**
      * 商品介绍
      */

+ 11 - 40
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/ZCR.java

@@ -12,7 +12,7 @@ import java.io.Serializable;
  */
 @Data
 @NoArgsConstructor
-public class ZCR<T> implements Serializable {
+public class ZCR implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
     /**
@@ -32,65 +32,36 @@ public class ZCR<T> implements Serializable {
     /**
      * 业务响应参数    N
      */
-    private T data;
+    private String data;
 
     /**
      * 签名    Y
      */
     private String sign;
 
-    /**
-     * token
-     */
-    private String accessToken;
 
-    /**
-     * 有效期  访问令牌有效期,单位秒,建议24小时 24小时返回值为
-     * 24*60*60 = 86400
-     */
-    private Integer expiresIn;
 
-    public static <T> ZCR<T> tokenOk(String accessToken, Integer expiresIn) {
-        return resetRToken(SUCCESS, "",null,"", accessToken,expiresIn);
+    public static  ZCR ok(String data,String sign) {
+        return resetR(SUCCESS, null, data, sign);
     }
 
-
-
-    public static <T> ZCR<T> ok(T data,String sign) {
-        return resetR(SUCCESS, "", data, sign);
-    }
-
-    public static <T> ZCR<T> ok(T data) {
-        return resetR(SUCCESS, "", data, "" );
+    public static  ZCR ok(String data) {
+        return resetR(SUCCESS, null, data, null );
     }
-    public static <T> ZCR<T> ok(String respMsg, T data,String sign) {
+    public static  ZCR ok(String respMsg, String data,String sign) {
         return resetR(SUCCESS, respMsg, data, sign);
     }
 
-    public static <T> ZCR<T> fail(String code, String msg) {
-        return resetR(code, msg,null,"");
-    }
-
-    public static <T> ZCR<T> resetR(String respCode, String respMsg, T data, String sign) {
-        ZCR ZCR = new ZCR<>();
-        ZCR.setRespCode(respCode);
-        ZCR.setRespMsg(respMsg);
-        ZCR.setData(data);
-        ZCR.setSign(sign);
-        return ZCR;
+    public static  ZCR fail(String code, String msg) {
+        return resetR(code, msg,null,null);
     }
 
-    public static <T> ZCR<T> resetRToken(String respCode, String respMsg, T data, String sign, String accessToken, Integer expiresIn) {
-        ZCR ZCR = new ZCR<>();
+    public static  ZCR resetR(String respCode, String respMsg, String data, String sign) {
+        ZCR ZCR = new ZCR();
         ZCR.setRespCode(respCode);
         ZCR.setRespMsg(respMsg);
         ZCR.setData(data);
         ZCR.setSign(sign);
-        ZCR.setAccessToken(accessToken);
-        ZCR.setExpiresIn(expiresIn);
         return ZCR;
     }
-
-
-
 }

+ 19 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/DeliveryTrackBo.java

@@ -0,0 +1,19 @@
+package org.dromara.external.api.zhongche.domain.bo;
+
+import lombok.Data;
+
+/**
+ * 物流查询请求 - 业务参数根节点
+ */
+@Data
+public class DeliveryTrackBo {
+    /**
+     * 中车电子商城发货单编号(必填,长度20)
+     */
+    private String outgoingCode;
+
+    /**
+     * 运单类型(必填,长度5;0=订单,1=换新单)
+     */
+    private String waybillType;
+}

+ 5 - 1
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/MessageBo.java

@@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.util.Map;
+
 /**
  * 消息监听接口的业务请求参数
  * (对应请求体中 data 字段 Base64 解码后的内容)
@@ -23,9 +25,11 @@ public class MessageBo {
     /**
      * 消息内容,格式为json对象
      */
-    private Object content;
+    private Map<String, Object> content;
     /**
      * 推送时间,格式YYYYMMDDHHMMSS
      */
     private String time;
+
+    private String accountName;
 }

+ 1 - 1
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/OrderDeliverBo.java → ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/bo/ZhongCheOrderDeliverBo.java

@@ -14,7 +14,7 @@ import java.util.List;
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class OrderDeliverBo {
+public class ZhongCheOrderDeliverBo {
     /**
      * 中车电子商城订单号
      * 必填

+ 6 - 6
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/CatalogsVo.java

@@ -3,15 +3,15 @@ package org.dromara.external.api.zhongche.domain.vo;
 import lombok.Data;
 import org.dromara.external.api.zhongche.domain.Catalog;
 
-import java.io.Serializable;
 import java.util.List;
 
+/**
+ * 品目查询业务响应(对应文档 4.2.6.1 + 4.2.6 业务参数)
+ */
 @Data
-public class CatalogsVo implements Serializable {
-    private static final long serialVersionUID = 1L;
-
+public class CatalogsVo {
     /**
-     * 电商品目列表(必填)
+     * 电商品目列表(文档参数名:catalogs,必填,List类型)
      */
-    private List<Catalog> catalogs;
+    private List<Catalog> catalogs; // 对应文档 4.2.6.1 的参数 2(catalogs)
 }

+ 15 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/GoodsStockVo.java

@@ -0,0 +1,15 @@
+package org.dromara.external.api.zhongche.domain.vo;
+
+import lombok.Data;
+import org.dromara.external.api.zhongche.domain.Stocks;
+
+import java.util.List;
+
+/**
+ * author
+ * 时间:2026/2/2,17:49
+ */
+@Data
+public class GoodsStockVo {
+    private List<Stocks> stocks;
+}

+ 5 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/MessageVo.java

@@ -12,6 +12,11 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor
 @AllArgsConstructor
 public class MessageVo {
+
+    public MessageVo(String result) {
+        this.result = result;
+    }
+
     /**
      * 结果:0-失败 1-成功
      */

+ 19 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/ZCLoginBusinessRespVo.java

@@ -0,0 +1,19 @@
+package org.dromara.external.api.zhongche.domain.vo;
+
+import lombok.Data;
+
+/**
+ * 中车登录业务响应参数(data字段编码前对应的实体)
+ */
+@Data
+public class ZCLoginBusinessRespVo {
+    /**
+     * 访问令牌,用于业务接口调用  Y
+     */
+    private String accessToken;
+
+    /**
+     * 访问令牌有效期,单位秒  Y
+     */
+    private Integer expiresIn;
+}

+ 1 - 1
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/OrderDeliverVo.java → ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/ZhongCheOrderDeliverVo.java

@@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class OrderDeliverVo {
+public class ZhongCheOrderDeliverVo {
     /**
      * 发货单编号
      * 必填

+ 5 - 0
ruoyi-api/ruoyi-api-order/pom.xml

@@ -23,6 +23,11 @@
             <artifactId>ruoyi-common-core</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-external</artifactId>
+        </dependency>
+
 
     </dependencies>
 

+ 22 - 0
ruoyi-api/ruoyi-api-order/src/main/java/org/dromara/product/api/RemoteExternalOrderService.java

@@ -1,9 +1,13 @@
 package org.dromara.product.api;
 
+import org.dromara.common.core.domain.zhongche.domain.DeliveryTrack;
+import org.dromara.common.core.domain.zhongche.vo.ZhongCheTrackVo;
 import org.dromara.product.api.domain.dto.OrderNoDto;
 import org.dromara.product.api.domain.dto.OrderNoticeDto;
 import org.dromara.product.api.domain.dto.OrderPushDto;
 
+import java.util.List;
+
 /**
  * @author
  * @date 2025/12/30 下午7:09
@@ -32,4 +36,22 @@ public interface RemoteExternalOrderService {
     String getOrderNo(String ZCorderNo);
 
 
+    //查询物流单号物流公司
+    ZhongCheTrackVo queryLogisticsTrack(String outgoingCode, String waybillType);
+
+    //获取物流轨迹
+    List<DeliveryTrack> queryDeliverTrack(String logisticsCompanyCode,String logisticNo ,String phone);
+
+    //获取退货订单号
+    String getReturnOrderNo(String ZCorderNo);
+
+    //取消订单
+    boolean cancelOrder(String orderNo ,String cancelReason);
+
+    //确认收获消息
+    boolean confirmReceive(String orderNo , String outgoingCode);
+
+    //取消售后订单
+    boolean cancelReturnOrder(String afterSaleNo, String cancelReason);
+
 }

+ 21 - 1
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductService.java

@@ -8,6 +8,7 @@ import org.dromara.product.api.domain.ProductVo;
 import org.dromara.product.api.domain.SiteProductRemoteBo;
 import org.dromara.product.api.domain.SiteProductRemoteResult;
 import org.dromara.product.api.domain.SiteProductRemoteVo;
+import org.dromara.product.api.domain.zhongche.dto.ProductAggregateDto;
 import org.dromara.product.api.domain.zhongche.dto.StocksResultDto;
 import org.dromara.product.api.domain.RemoteProductBrand;
 
@@ -70,7 +71,7 @@ public interface RemoteProductService {
 
     StocksResultDto queryProductStock(Map<String, Integer> goods, String areaId);
 
-    List<Prices> queryProductPrice(List<String> goodsIds);
+    Map<String, Prices> queryProductPrice(List<String> goodsIds);
 
     /**
      * 分页查询站点产品列表(供远程调用)
@@ -80,4 +81,23 @@ public interface RemoteProductService {
      */
     SiteProductRemoteResult querySiteProductPage(SiteProductRemoteBo bo);
 
+    /**
+     * zhongche获取商品信息
+     */
+    List<ProductAggregateDto> getProductInfo(List<Long> productIds);
+
+
+    /**
+     * 库存锁定
+     */
+    //锁定库存
+    boolean lockShoppingCart(Long productId, Long count,String accountName);
+
+    //解定库存
+    boolean unlockShoppingCart(Long productId, String accountName);
+    /**
+     * 库存解定
+     */
+
+
 }

+ 13 - 0
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductShoppingCartService.java

@@ -0,0 +1,13 @@
+package org.dromara.product.api;
+
+/**
+ * author
+ * 时间:2026/2/4,17:33
+ */
+public interface RemoteProductShoppingCartService {
+    //锁定购物车 就是 加入购物车
+    boolean lockShoppingCart(Long productId, Long count);
+
+    //解顶购物车 就是 删除购物车
+    boolean unlockShoppingCart(Long productId, Long count);
+}

+ 46 - 0
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/domain/zhongche/dto/ProductAggregateDto.java

@@ -0,0 +1,46 @@
+package org.dromara.product.api.domain.zhongche.dto;
+
+import lombok.Data;
+
+import javax.lang.model.element.NestingKind;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * author
+ * 时间:2026/2/4,13:38
+ */
+@Data
+public class ProductAggregateDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long productId;
+
+    private String BrandName;
+
+    private String BrandNameEn;
+
+    private String productName;
+
+    private String name;
+
+    private BigDecimal dsPrice;
+
+    private BigDecimal price;
+
+    private String unit;
+
+    private Integer stock;
+
+    private String barImgUrls;
+
+    private String description;
+
+    private String properties;
+
+    private Integer isSelfOperated;
+
+    private BigDecimal tax;
+
+    private String taxCode;
+}

+ 16 - 0
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteComLogisticsCompanyService.java

@@ -0,0 +1,16 @@
+package org.dromara.system.api;
+
+import org.dromara.common.core.domain.zhongche.domain.DeliveryTrack;
+import org.dromara.common.core.validate.enumd.EnumPattern;
+
+import java.util.List;
+
+/**
+ * author
+ * 时间:2026/2/2,19:12
+ */
+public interface RemoteComLogisticsCompanyService {
+    String selectLogisticsCompanyNameById(Long ids);
+
+
+}

+ 123 - 2
ruoyi-auth/src/main/java/org/dromara/auth/controller/Auth2Controller.java

@@ -10,18 +10,31 @@ import cn.hutool.crypto.SecureUtil;
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.annotation.PostConstruct;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.auth.domain.vo.LoginVo;
 import org.dromara.auth.service.IAuthStrategy;
+import org.dromara.auth.util.SM2SignatureUtils;
+import org.dromara.auth.util.SignParamUtils;
+import org.dromara.auth.util.ZCApiUtils;
 import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.external.api.zhongche.domain.ZCR;
+import org.dromara.external.api.zhongche.domain.bo.UserLoginBo;
+import org.dromara.external.api.zhongche.domain.bo.ZCTokenBo;
+import org.dromara.external.api.zhongche.domain.vo.ZCLoginBusinessRespVo;
 import org.dromara.external.api.zhongzhi.domain.Result;
+import org.springframework.beans.factory.annotation.Value;
 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;
 
 import java.time.Duration;
 import java.time.format.DateTimeFormatter;
+import java.util.Base64;
 import java.util.Map;
 import java.util.Objects;
 
@@ -38,15 +51,23 @@ import static org.dromara.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
 @RequestMapping("/auth2")
 public class Auth2Controller {
 
+    private final ObjectMapper objectMapper;
+
+    // ========== 读取yml中的真实公私钥(直接复制使用) ==========
+
+    private final String DEVELOPER_PRIVATE_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1YybOl0QDE2e9humlm4AgI3wJ1tI+UfVRZx8kk4hfPtZjorHN8Tjq/cP07t4Yscy+R9oFci8xw0VpBbcnlaq1w=="; // 电商提供的私钥
+
+    private final String DEVELOPER_PUBLIC_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgpQdXwMi21Mg1FhWad2AQLOwfNiDHgwhootau0YerQbagCgYIKoEcz1UBgi2hRANCAATVjJs6XRAMTZ72G6aWbgCAjfAnW0j5R9VFnHySTiF8+1mOisc3xOOr9w/Tu3hixzL5H2gVyLzHDRWkFtyeVqrX";  // 电商提供的公钥
+
 
     /**
-     * 获取 Access Token
+     * 获取 Access Token  ZHONGZHI
      * @param username 用户名
      * @param password 密码(明文,生产环境建议加密后再传)
      * @return 包含 access_token 和 expires_at 的 Result,失败则 success=false
      */
     @PostMapping("/zhongzhi/access_token")
-    public Result getAccessToken(String timestamp, String username, String password, String sign) {
+    public Result getAccessTokenZhongZhi(String timestamp, String username, String password, String sign) {
         // 2. 生成 sign = MD5(username + password + timestamp + password).toLowerCase()
         String signStr = username + password + timestamp + password;
         String sign1 = SecureUtil.md5(signStr).toLowerCase();
@@ -66,6 +87,106 @@ public class Auth2Controller {
             return Result.fail(5004,"签名错误,请检查后重试");
         }
     }
+    /**
+     * 获取 Access Token  ZHONGChe
+     * @return 包含 access_token 和 expires_at 的 Result,失败则 success=false
+     */
+    @PostMapping("/zhongche/access_token")
+    public ZCR getAccessTokenZhongChe(@RequestBody ZCTokenBo zcTokenBo) {
+        if (zcTokenBo == null) {
+            return ZCR.fail("1001", "请求参数不能为空");
+        }
+        if (zcTokenBo.getVersion() == null || zcTokenBo.getVersion().trim().isEmpty()) {
+            return ZCR.fail("1001", "接口版本version不能为空");
+        }
+        if (zcTokenBo.getTimestamp() == null || zcTokenBo.getTimestamp().trim().isEmpty()) {
+            return ZCR.fail("1001", "时间戳timestamp不能为空");
+        }
+        if (zcTokenBo.getClientId() == null || zcTokenBo.getClientId().trim().isEmpty()) {
+            return ZCR.fail("1001", "开发者id clientId不能为空");
+        }
+        if (zcTokenBo.getData() == null || zcTokenBo.getData().trim().isEmpty()) {
+            return ZCR.fail("1001", "业务请求参数data不能为空");
+        }
+        if (zcTokenBo.getSign() == null || zcTokenBo.getSign().trim().isEmpty()) {
+            return ZCR.fail("1001", "签名sign不能为空");
+        }
+        //sign值校验
+        // ========== 步骤2:签名校验(核心!复用工具类,无需修改工具类) ==========
+        boolean signVerifyResult = false;
+        try {
+            signVerifyResult = SignParamUtils.verifyRequestSign(zcTokenBo, DEVELOPER_PUBLIC_KEY);
+        } catch (JsonProcessingException e) {
+            return ZCR.fail("1001", "接口签名错误(验签异常)");
+        }
+
+        if (!signVerifyResult) {
+            try {
+                log.error("中车电商接口验签失败,请求参数:{}", objectMapper.writeValueAsString(zcTokenBo));
+            } catch (JsonProcessingException e) {
+                return ZCR.fail("1001", "接口签名错误(验签异常)");
+            }
+            return ZCR.fail("2002", "接口签名错误(验签失败)");
+        }
+
+        // ========== 步骤3:解码data字段,获取username和password(复用 ZCApiUtils 更简洁) ==========
+        UserLoginBo userLoginBo = null;
+        try {
+            userLoginBo = ZCApiUtils.base64JsonToObject(zcTokenBo.getData(), UserLoginBo.class);
+        } catch (JsonProcessingException e) {
+            return ZCR.fail("1001", "账号密码解析异常");
+        }
+        // 校验业务参数非空
+        if (userLoginBo.getUsername() == null || userLoginBo.getUsername().trim().isEmpty()) {
+            return ZCR.fail("1007", "账户名称username不能为空");
+        }
+        if (userLoginBo.getPassword() == null || userLoginBo.getPassword().trim().isEmpty()) {
+            return ZCR.fail("1008", "账户密码password不能为空");
+        }
+
+        // ========== 步骤4:业务逻辑校验( ==========
+        //TODO 这里用的肖哥的逻辑 待完成吧
+        String username = userLoginBo.getUsername();
+        String password = userLoginBo.getPassword();
+        LoginVo loginVo = IAuthStrategy.getAccessToken(username, password);
+
+        if(ObjectUtil.isEmpty(loginVo)){
+            return ZCR.fail("1001","授权失败");
+        }
+        if(ObjectUtil.isNotEmpty(loginVo.getMsg())){
+            return ZCR.fail(loginVo.getCode().toString(),loginVo.getMsg());
+        }
+
+        // ========== 步骤5:封装业务响应参数(accessToken + expiresIn) ==========
+        String accessToken = loginVo.getAccessToken();
+        // 获取令牌有效期(秒),与 zhongzhi 逻辑一致
+        Integer expiresIn = (int) StpUtil.getTokenTimeout(accessToken);
+        ZCLoginBusinessRespVo loginBusinessRespBo = new ZCLoginBusinessRespVo();
+        loginBusinessRespBo.setAccessToken(accessToken);
+        loginBusinessRespBo.setExpiresIn(expiresIn);
+
+        // ========== 步骤6:封装响应 data 字段(Base64 编码,复用 ZCApiUtils) ==========
+        String respData = null;
+        try {
+            respData = ZCApiUtils.objectToBase64Json(loginBusinessRespBo);
+        } catch (JsonProcessingException e) {
+            return ZCR.fail("1001", "接口响应数据编码异常");
+        }
+
+        // ========== 步骤7:生成响应签名(正常响应必须返回 sign,复用工具类) ==========
+        ZCR successZcr = ZCR.ok(respData, ""); // 先填充 data,暂不填 sign
+        String respSignContent = null;
+        try {
+            respSignContent = SignParamUtils.getSignContent(successZcr);
+        } catch (JsonProcessingException e) {
+            return ZCR.fail("1001", "接口响应签名错误(验签异常)");
+        }
+        String respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        // ========== 步骤8:返回成功响应(填充最终签名) ==========
+        log.info("中车电商登录授权成功,用户名:{},accessToken:{}", username, accessToken);
+        return ZCR.ok(respData, respSign);
+
+    }
 
 
 

+ 128 - 0
ruoyi-auth/src/main/java/org/dromara/auth/util/SM2SignatureUtils.java

@@ -0,0 +1,128 @@
+package org.dromara.auth.util;
+
+import org.bouncycastle.asn1.gm.GMNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.signers.SM2Signer;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Base64;
+
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.security.Security;
+
+/**
+ * 国密 SM2withSM3 签名工具类
+ * 注意:开发者私钥/公钥需由电商平台提供,此处提供生成示例(实际使用平台分配的密钥)
+ */
+public class SM2SignatureUtils {
+    // 注册 BouncyCastle 安全提供者
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+    // SM2 曲线参数(固定,国密标准)
+    private static final X9ECParameters SM2_CURVE_PARAMS = GMNamedCurves.getByName("sm2p256v1");
+    private static final ECDomainParameters EC_DOMAIN_PARAMETERS = new ECDomainParameters(
+            SM2_CURVE_PARAMS.getCurve(),
+            SM2_CURVE_PARAMS.getG(),
+            SM2_CURVE_PARAMS.getN(),
+            SM2_CURVE_PARAMS.getH()
+    );
+
+    /**
+     * 生成 SM2 密钥对(仅用于测试,实际使用电商平台提供的开发者私钥/公钥)
+     * @return 密钥对(私钥在前,公钥在后,均为 Base64 编码)
+     */
+    public static String[] generateSM2KeyPair() {
+        ECKeyPairGenerator generator = new ECKeyPairGenerator();
+        ECKeyGenerationParameters genParams = new ECKeyGenerationParameters(EC_DOMAIN_PARAMETERS, new SecureRandom());
+        generator.init(genParams);
+
+        AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();
+        ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters) keyPair.getPrivate();
+        ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters) keyPair.getPublic();
+
+        // 转换为 Base64 编码字符串
+        String privateKeyBase64 = Base64.toBase64String(privateKeyParams.getD().toByteArray());
+        String publicKeyBase64 = Base64.toBase64String(publicKeyParams.getQ().getEncoded(false));
+
+        return new String[]{privateKeyBase64, publicKeyBase64};
+    }
+
+    /**
+     * SM2withSM3 签名(私钥签名,生成待提交的 sign 字段)
+     * @param content 待签名字符串(筛选排序后的 JSON 字符串)
+     * @param privateKeyBase64 开发者私钥(Base64 编码,平台提供)
+     * @return 签名结果(Base64 编码,可直接赋值给 sign 字段)
+     */
+    public static String sign(String content, String privateKeyBase64) {
+        if (content == null || content.trim().isEmpty() || privateKeyBase64 == null || privateKeyBase64.trim().isEmpty()) {
+            throw new IllegalArgumentException("待签名字符串和私钥不能为空");
+        }
+
+        try {
+            // 1. 解码私钥
+            byte[] privateKeyBytes = Base64.decode(privateKeyBase64);
+            ECPrivateKeyParameters privateKeyParams = new ECPrivateKeyParameters(
+                    new java.math.BigInteger(1, privateKeyBytes),
+                    EC_DOMAIN_PARAMETERS
+            );
+
+            // 2. 初始化 SM2 签名器
+            SM2Signer signer = new SM2Signer();
+            signer.init(true, privateKeyParams);
+
+            // 3. 传入待签名内容(UTF-8 编码)
+            byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
+            signer.update(contentBytes, 0, contentBytes.length);
+
+            // 4. 生成签名并进行 Base64 编码
+            byte[] signatureBytes = signer.generateSignature();
+            return Base64.toBase64String(signatureBytes);
+        } catch (Exception e) {
+            throw new RuntimeException("SM2 签名失败:" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * SM2withSM3 验签(公钥校验,验证请求传入的 sign 是否合法)
+     * @param content 待签名字符串(与签名时一致的 JSON 字符串)
+     * @param signBase64 请求传入的 sign 字段(Base64 编码)
+     * @param publicKeyBase64 开发者公钥(Base64 编码,平台提供)
+     * @return true=验签通过,false=验签失败
+     */
+    public static boolean verify(String content, String signBase64, String publicKeyBase64) {
+        if (content == null || content.trim().isEmpty() || signBase64 == null || signBase64.trim().isEmpty()
+                || publicKeyBase64 == null || publicKeyBase64.trim().isEmpty()) {
+            throw new IllegalArgumentException("待签名字符串、签名和公钥不能为空");
+        }
+
+        try {
+            // 1. 解码公钥和签名
+            byte[] publicKeyBytes = Base64.decode(publicKeyBase64);
+            byte[] signatureBytes = Base64.decode(signBase64);
+
+            // 2. 构建公钥参数
+            org.bouncycastle.math.ec.ECPoint ecPoint = SM2_CURVE_PARAMS.getCurve().decodePoint(publicKeyBytes);
+            ECPublicKeyParameters publicKeyParams = new ECPublicKeyParameters(ecPoint, EC_DOMAIN_PARAMETERS);
+
+            // 3. 初始化 SM2 签名器
+            SM2Signer signer = new SM2Signer();
+            signer.init(false, publicKeyParams);
+
+            // 4. 传入待签名内容并验签
+            byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
+            signer.update(contentBytes, 0, contentBytes.length);
+
+            return signer.verifySignature(signatureBytes);
+        } catch (Exception e) {
+            throw new RuntimeException("SM2 验签失败:" + e.getMessage(), e);
+        }
+    }
+}

+ 111 - 0
ruoyi-auth/src/main/java/org/dromara/auth/util/SignParamUtils.java

@@ -0,0 +1,111 @@
+package org.dromara.auth.util;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.dromara.external.api.zhongche.domain.bo.ZCTokenBo;
+
+import java.lang.reflect.Field;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * 签名参数处理工具类(筛选、排序、拼接JSON)
+ */
+public class SignParamUtils {
+    /**
+     * JSON 转换工具(保持与 ZCApiUtils 一致)
+     */
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    /**
+     * 处理签名参数(核心方法)
+     * @param paramObj 请求/响应参数实体(如 ZCTokenBo、ZCR)
+     * @return 待签名字符串(筛选排序后的 JSON 字符串)
+     * @throws JsonProcessingException JSON 转换异常
+     */
+    public static String getSignContent(Object paramObj) throws JsonProcessingException {
+        if (paramObj == null) {
+            throw new IllegalArgumentException("参数实体不能为空");
+        }
+
+        // 步骤 1:反射获取参数实体的所有字段(键值对)
+        Map<String, Object> paramMap = new HashMap<>();
+        Field[] fields = paramObj.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            field.setAccessible(true); // 允许访问私有字段
+            String fieldName = field.getName();
+            Object fieldValue = null;
+
+            try {
+                fieldValue = field.get(paramObj);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException("获取字段值失败:" + fieldName, e);
+            }
+
+            // 步骤 2:筛选字段(剔除 sign、剔除 null 值、剔除字节数组)
+            if ("sign".equals(fieldName)) {
+                continue; // 剔除 sign 字段
+            }
+            if (fieldValue == null) {
+                continue; // 剔除 null 值
+            }
+            if (fieldValue instanceof byte[]) {
+                continue; // 剔除字节类型字段(当前场景无,预留)
+            }
+
+            // 符合条件的字段存入 Map
+            paramMap.put(fieldName, fieldValue);
+        }
+
+        // 步骤 3:按字段名(键)ASCII 码升序排序
+        Map<String, Object> sortedParamMap = new TreeMap<>(new Comparator<String>() {
+            @Override
+            public int compare(String key1, String key2) {
+                // 按 ASCII 码升序排序(逐个字符对比)
+                return key1.compareTo(key2);
+            }
+        });
+        sortedParamMap.putAll(paramMap);
+
+        // 步骤 4:拼接为 JSON 字符串(待签名字符串)
+        return OBJECT_MAPPER.writeValueAsString(sortedParamMap);
+    }
+
+    /**
+     * 快捷方法:生成请求签名(ZCTokenBo → 待签名内容 → SM2 签名)
+     * @param zcTokenBo 请求参数实体
+     * @param privateKeyBase64 开发者私钥(Base64 编码)
+     * @return 签名结果(Base64 编码,可赋值给 sign 字段)
+     * @throws JsonProcessingException JSON 转换异常
+     */
+    public static String generateRequestSign(ZCTokenBo zcTokenBo, String privateKeyBase64) throws JsonProcessingException {
+        // 生成待签名字符串
+        String signContent = getSignContent(zcTokenBo);
+        // SM2 签名并返回
+        return SM2SignatureUtils.sign(signContent, privateKeyBase64);
+    }
+
+    /**
+     * 快捷方法:验证请求签名(ZCTokenBo → 待签名内容 → 校验 sign 是否合法)
+     * @param zcTokenBo 请求参数实体
+     * @param publicKeyBase64 开发者公钥(Base64 编码)
+     * @return true=验签通过,false=验签失败
+     * @throws JsonProcessingException JSON 转换异常
+     */
+    public static boolean verifyRequestSign(ZCTokenBo zcTokenBo, String publicKeyBase64) throws JsonProcessingException {
+        // 提取请求传入的 sign
+        String requestSign = zcTokenBo.getSign();
+        if (requestSign == null || requestSign.trim().isEmpty()) {
+            return false;
+        }
+
+        // 生成待签名字符串(与签名时一致)
+        String signContent = getSignContent(zcTokenBo);
+
+        // SM2 验签
+        return SM2SignatureUtils.verify(signContent, requestSign, publicKeyBase64);
+    }
+}

+ 94 - 0
ruoyi-auth/src/main/java/org/dromara/auth/util/ZCApiUtils.java

@@ -0,0 +1,94 @@
+package org.dromara.auth.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.Base64;
+
+/**
+ * 中车接口工具类(Base64 + JSON 转换)
+ */
+public class ZCApiUtils {
+    /**
+     * JSON 转换工具(Jackson)
+     */
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    /**
+     * Base64 解码(字符串 → 原始字符串)
+     * @param base64Str Base64编码字符串
+     * @return 解码后的原始字符串
+     */
+    public static String base64Decode(String base64Str) {
+        if (base64Str == null || base64Str.trim().isEmpty()) {
+            throw new IllegalArgumentException("Base64编码字符串不能为空");
+        }
+        byte[] decodeBytes = Base64.getDecoder().decode(base64Str);
+        return new String(decodeBytes);
+    }
+
+    /**
+     * Base64 编码(原始字符串 → Base64编码字符串)
+     * @param rawStr 原始字符串
+     * @return Base64编码字符串
+     */
+    public static String base64Encode(String rawStr) {
+        if (rawStr == null || rawStr.trim().isEmpty()) {
+            throw new IllegalArgumentException("原始字符串不能为空");
+        }
+        byte[] encodeBytes = rawStr.getBytes();
+        return Base64.getEncoder().encodeToString(encodeBytes);
+    }
+
+    /**
+     * JSON 字符串 → Java 对象
+     * @param jsonStr JSON字符串
+     * @param clazz 目标对象类型
+     * @param <T> 泛型
+     * @return 目标Java对象
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static <T> T jsonToObject(String jsonStr, Class<T> clazz) throws JsonProcessingException {
+        if (jsonStr == null || jsonStr.trim().isEmpty()) {
+            throw new IllegalArgumentException("JSON字符串不能为空");
+        }
+        return OBJECT_MAPPER.readValue(jsonStr, clazz);
+    }
+
+    /**
+     * Java 对象 → JSON 字符串
+     * @param obj Java对象
+     * @return JSON字符串
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static String objectToJson(Object obj) throws JsonProcessingException {
+        if (obj == null) {
+            throw new IllegalArgumentException("Java对象不能为空");
+        }
+        return OBJECT_MAPPER.writeValueAsString(obj);
+    }
+
+    /**
+     * 快捷方法:Java对象 → Base64编码的JSON字符串(响应data字段专用)
+     * @param obj Java对象
+     * @return Base64编码的JSON字符串
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static String objectToBase64Json(Object obj) throws JsonProcessingException {
+        String jsonStr = objectToJson(obj);
+        return base64Encode(jsonStr);
+    }
+
+    /**
+     * 快捷方法:Base64编码的JSON字符串 → Java对象(请求data字段专用)
+     * @param base64Json Base64编码的JSON字符串
+     * @param clazz 目标对象类型
+     * @param <T> 泛型
+     * @return 目标Java对象
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static <T> T base64JsonToObject(String base64Json, Class<T> clazz) throws JsonProcessingException {
+        String jsonStr = base64Decode(base64Json);
+        return jsonToObject(jsonStr, clazz);
+    }
+}

+ 4 - 2
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/DeliveryTrack.java → ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/zhongche/domain/DeliveryTrack.java

@@ -1,14 +1,16 @@
-package org.dromara.external.api.zhongche.domain;
+package org.dromara.common.core.domain.zhongche.domain;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
+
 // 1. 物流信息详情 (deliveryTrack 列表项)
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class DeliveryTrack {
+public class DeliveryTrack implements Serializable {
     /**
      * 物流详情
      * 必填

+ 3 - 4
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongche/domain/vo/TrackVo.java → ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/zhongche/vo/ZhongCheTrackVo.java

@@ -1,17 +1,16 @@
-package org.dromara.external.api.zhongche.domain.vo;
+package org.dromara.common.core.domain.zhongche.vo;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.dromara.external.api.zhongche.domain.DeliveryTrack;
+import org.dromara.common.core.domain.zhongche.domain.DeliveryTrack;
 
 import java.util.List;
 
-
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
-public class TrackVo {
+public class ZhongCheTrackVo {
     /**
      * 物流单号
      * 非必填

+ 6 - 0
ruoyi-modules/ruoyi-bill/pom.xml

@@ -21,6 +21,11 @@
             <artifactId>ruoyi-api-customer</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-api-bill</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-common-nacos</artifactId>
@@ -124,6 +129,7 @@
             <artifactId>ruoyi-api-product</artifactId>
         </dependency>
 
+
     </dependencies>
 
     <build>

+ 18 - 0
ruoyi-modules/ruoyi-bill/src/main/java/org/dromara/bill/dubbo/RemoteBillServiceImpl.java

@@ -0,0 +1,18 @@
+package org.dromara.bill.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.bill.api.RemoteBillService;
+import org.springframework.stereotype.Service;
+
+/**
+ * author
+ * 时间:2026/2/4,16:52
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@DubboService
+public class RemoteBillServiceImpl implements RemoteBillService {
+}

+ 0 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/SupplierInfoController.java

@@ -202,7 +202,6 @@ public class SupplierInfoController extends BaseController {
     @RepeatSubmit()
     @PutMapping("/edit")
     @Transactional(rollbackFor = Exception.class)
-
     public R<Void> srmEdit(@RequestBody SupplierInfoBo bo) throws JsonProcessingException {
         return toAjax(supplierInfoService.srmUpdateByBo(bo));
     }

+ 75 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/dubbo/RemotePartnerPreparedServiceImpl.java

@@ -0,0 +1,75 @@
+package org.dromara.customer.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.customer.api.RemotePartnerPreparedService;
+import org.dromara.customer.api.domain.dto.PartnerPreparedDTO;
+import org.dromara.customer.domain.PartnerPrepared;
+import org.dromara.customer.enums.PartnerPreparedStatusEnum;
+import org.dromara.customer.service.IPartnerPreparedService;
+import org.springframework.stereotype.Service;
+
+/**
+ * author
+ * 时间:2026/2/3,17:53
+ */
+@Service
+@RequiredArgsConstructor
+@DubboService
+public class RemotePartnerPreparedServiceImpl implements RemotePartnerPreparedService {
+
+    private final IPartnerPreparedService partnerPreparedService;
+    @Override
+    public PartnerPreparedDTO updatePartnerPreparedById(String id) {
+        PartnerPreparedDTO partnerPreparedDTO = new PartnerPreparedDTO();
+        PartnerPrepared one = partnerPreparedService.lambdaQuery().eq(PartnerPrepared::getPreparedNo, id).one();
+        if (one == null){
+            partnerPreparedDTO.setFlag(false);
+            partnerPreparedDTO.setMessage("未找到该数据");
+        }
+        //这里状态不知道 没有eq判断状态 如果需要的话
+        boolean update = partnerPreparedService.lambdaUpdate().set(PartnerPrepared::getPreparedStatus, PartnerPreparedStatusEnum.PREPARED_TIME)
+            .eq(PartnerPrepared::getId, one.getId())
+            .update();
+        if (update){
+            partnerPreparedDTO.setFlag(true);
+            partnerPreparedDTO.setMessage("修改成功");
+        }else {
+            partnerPreparedDTO.setFlag(false);
+            partnerPreparedDTO.setMessage("修改失败");
+        }
+
+        return partnerPreparedDTO;
+    }
+
+    @Override
+    public PartnerPreparedDTO cancelPartnerPreparedById(String prepareOrderNo, String cancelReason) {
+        PartnerPreparedDTO partnerPreparedDTO = new PartnerPreparedDTO();
+        PartnerPrepared one = partnerPreparedService.lambdaQuery().eq(PartnerPrepared::getPreparedNo, prepareOrderNo).one();
+        if (one == null){
+            partnerPreparedDTO.setFlag(false);
+            partnerPreparedDTO.setMessage("未找到该数据");
+        }
+
+        boolean update = partnerPreparedService.lambdaUpdate()
+            .set(PartnerPrepared::getPreparedStatus, PartnerPreparedStatusEnum.PREPARED_TIME.getCode())
+            .set(PartnerPrepared::getReject, cancelReason)
+            .eq(PartnerPrepared::getId, one.getId())
+            .in(
+                PartnerPrepared::getPreparedStatus,
+                PartnerPreparedStatusEnum.PREPARED_APPROVE.getCode(),
+                PartnerPreparedStatusEnum.PREPARED_TIME.getCode(),
+                PartnerPreparedStatusEnum.PREPARED_FINISH.getCode()
+            )
+            .update();
+
+        if (update){
+            partnerPreparedDTO.setFlag(true);
+            partnerPreparedDTO.setMessage("修改成功");
+        }else {
+            partnerPreparedDTO.setFlag(false);
+            partnerPreparedDTO.setMessage("修改失败");
+        }
+        return partnerPreparedDTO;
+    }
+}

+ 54 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/enums/PartnerPreparedStatusEnum.java

@@ -0,0 +1,54 @@
+package org.dromara.customer.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * author
+ * 时间:2026/2/3,17:39
+ */
+@Getter
+@AllArgsConstructor
+public enum PartnerPreparedStatusEnum {
+    // 枚举项:状态码, 展示文案
+    PREPARED_APPROVE(0, "待审核"),
+    PREPARED_PASS(1, "已通过"),
+    PREPARED_UNPASS(2, "已驳回"),
+    PREPARED_TIME(3,"待备货"),
+    PREPARED_FINISH(4, "备货完成");
+
+
+
+    // 状态码
+    private final Integer code;
+    // 前端/业务展示的文案
+    private final String displayName;
+
+    /**
+     * 核心方法:根据状态码获取展示文案
+     * @param code 数据库中的数字值(0/1/2)
+     * @return 展示文案,无匹配时返回"未知状态"
+     */
+    public static String getDisplayNameByCode(Integer code) {
+        // 空值校验,避免空指针
+        if (code == null) {
+            return "未知状态";
+        }
+        // 遍历枚举匹配状态码(修正枚举类型为当前类)
+        for (PartnerPreparedStatusEnum status : values()) {
+            if (status.code.equals(code)) {
+                return status.displayName;
+            }
+        }
+        return "未知状态";
+    }
+
+    // getter方法(便于单独获取码值/文案)
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+}

+ 1 - 3
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ISupplierInfoService.java

@@ -41,7 +41,6 @@ public interface ISupplierInfoService extends IService<SupplierInfo>{
      * @return 供应商信息分页列表
      */
     TableDataInfo<SupplierInfoVo> queryPageList(SupplierInfoBo bo, PageQuery pageQuery);
-
     /**
      * 获取供应商信息列表
      *
@@ -54,7 +53,6 @@ public interface ISupplierInfoService extends IService<SupplierInfo>{
 
     /**
      * 获取供应商审核列表
-     *
      * @param bo
      * @param pageQuery
      * @return
@@ -103,7 +101,7 @@ public interface ISupplierInfoService extends IService<SupplierInfo>{
 
     Long getSupplierStatus(Long id);
 
-    boolean srmUpdateByBo(SupplierInfoBo bo);
+    boolean srmUpdateByBo(SupplierInfoBo bo) throws JsonProcessingException;
 
     /*根据ids查询供应商名称*/
     Map<Long, String> selectSupplierNameByIds(Set<Long> ids);

+ 8 - 8
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierContactServiceImpl.java

@@ -165,8 +165,15 @@ public class SupplierContactServiceImpl  extends ServiceImpl<SupplierContactMapp
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean insertByBo(SupplierContactBo bo) {
+        //首先判断是否是待审核状态
+        //1.如果是待审核 得记录联系人 不能登录  user是不能登录的 status = 1 停用
+
+        //2.如果是正式供应商  能登录  user是能登录的 status = 0 正常
+
+        //3.如果是停用的供应商  不能登录  user是不能登录的 status = 1 停用
+
+        //4.如果是待修改审核  能登录  user是能登录的 status = 0
         SupplierContact add = MapstructUtils.convert(bo, SupplierContact.class);
-        validEntityBeforeSave(add);
         RemoteUserBo remoteUserBo = new RemoteUserBo();
         remoteUserBo.setNickName(bo.getUserName());
         remoteUserBo.setUserName(bo.getPhone());
@@ -201,7 +208,6 @@ public class SupplierContactServiceImpl  extends ServiceImpl<SupplierContactMapp
     @Transactional(rollbackFor = Exception.class)
     public Boolean updateByBo(SupplierContactBo bo) {
         SupplierContact update = MapstructUtils.convert(bo, SupplierContact.class);
-        validEntityBeforeSave(update);
         if (update.getUserId() != null){
             RemoteUserBo remoteUserBo = new RemoteUserBo();
             remoteUserBo.setNickName(bo.getUserName());
@@ -218,12 +224,6 @@ public class SupplierContactServiceImpl  extends ServiceImpl<SupplierContactMapp
         return baseMapper.updateById(update) > 0;
     }
 
-    /**
-     * 保存前的数据校验
-     */
-    private void validEntityBeforeSave(SupplierContact entity){
-        //TODO 做一些数据校验,如唯一约束
-    }
 
     /**
      * 校验并批量删除联系人信息

+ 105 - 94
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SupplierInfoServiceImpl.java

@@ -82,10 +82,12 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
 
     private final ISupplierInfoTemporaryService supplierInfoTemporaryService;
 
+    private final ObjectMapper objectMapper;
+
     /**
      *
-    * 供应商联系人信息
-    * */
+     * 供应商联系人信息
+     * */
     private final SupplierContactMapper supplierContactMapper;
 
     @DubboReference
@@ -104,6 +106,8 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
     private final RemoteSupplierTypeService remoteSupplierTypeService;
 
 
+
+
     /**
      * 新增供应商信息
      *
@@ -144,7 +148,6 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
             return;
         }
         try {
-            ObjectMapper objectMapper = new ObjectMapper();
             // 解析JSON到SupplierBusinessInfo对象
             SupplierBusinessInfo businessInfo = objectMapper.readValue(otherCustomersJson, SupplierBusinessInfo.class);
 
@@ -254,7 +257,6 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
                 // 无区域数据,直接更新主表即可
                 return baseMapper.updateById(supplierInfoVo) > 0;
             }
-            ObjectMapper objectMapper = new ObjectMapper();
             try {
                 // 1. 解析JSON字符串为 TableDataInfo<SupplyAreaVo>(和存储时的类型一致)
                 // 注意:泛型解析需要用 TypeReference 明确类型,否则会解析为 LinkedHashMap
@@ -349,6 +351,88 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
         return baseMapper.updateById(update) > 0;
     }
 
+    @Override
+    public boolean srmUpdateByBo(SupplierInfoBo bo) throws JsonProcessingException {
+        Long id = bo.getId();
+        SupplierInfo supplierInfo = baseMapper.selectById(id);
+        //如果是待审核和审核不通过 随便改
+        if (bo.getSupplyStatus() == SupplierStatusEnum.PENDING_REVIEW.getCode() || bo.getSupplyStatus() == SupplierStatusEnum.REVIEW_FAILED.getCode()){
+            SupplierInfo update = MapstructUtils.convert(bo, SupplierInfo.class);
+            return baseMapper.updateById(update) > 0;
+        }
+        //如果是启用状态,就变成待修改审核状态
+        if (supplierInfo.getSupplyStatus() == SupplierStatusEnum.OFFICIAL_SUPPLIER.getCode()){
+            SupplierInfoTemporary supplierInfoTemporary = supplierInfoTemporaryService.querBySupplierId(id);
+            if (supplierInfoTemporary == null){
+                supplierInfoTemporary = new SupplierInfoTemporary();
+                BeanUtils.copyProperties(supplierInfo, supplierInfoTemporary,"id");
+                supplierInfoTemporary.setSupplierId(id);
+                //通过传参在set临时表
+                //查询供应地址 存入  areaListJson  为了回显
+                SupplyAreaBo supplyAreaBo = new SupplyAreaBo();
+                supplyAreaBo.setSupplierId(bo.getId());
+                PageQuery pageQuery = new PageQuery();
+                TableDataInfo<SupplyAreaVo> supplyAreaVoTableDataInfo = supplyAreaService.queryPageList(supplyAreaBo, pageQuery);
+                String areaListJson = objectMapper.writeValueAsString(supplyAreaVoTableDataInfo);
+                supplierInfoTemporary.setAreaListJson(areaListJson);
+                supplierInfoTemporary.setSupplyStatus(SupplierStatusEnum.REVIEW_UPDATED.getCode());
+                boolean save = supplierInfoTemporaryService.save(supplierInfoTemporary);
+                if (save == false){
+                    throw new RuntimeException("保存供应商待审核数据失败");
+                }
+
+            }
+            //一共三个地方
+            boolean flag =false;
+            //1.简称
+            if (bo.getShortName() != null && StringUtils.isNotBlank(bo.getShortName())){
+                supplierInfoTemporary.setShortName(bo.getShortName());
+                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
+            }
+            //2.供货品牌
+            if (bo.getOperatingBrand() != null && StringUtils.isNotBlank(bo.getOperatingBrand())){
+                supplierInfoTemporary.setOperatingBrand(bo.getOperatingBrand());
+                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
+            }
+            //3.供货类目
+            if (bo.getOperatingCategory() != null && StringUtils.isNotBlank(bo.getOperatingCategory())){
+                supplierInfoTemporary.setOperatingCategory(bo.getOperatingCategory());
+                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
+            }
+
+            supplierInfo.setSupplyStatus(SupplierStatusEnum.REVIEW_UPDATED.getCode());
+            boolean update =baseMapper.updateById(supplierInfo) > 0;
+            return update && flag;
+        }
+        //如果是待审核状态,依旧是待修改审核状态
+        if (supplierInfo.getSupplyStatus() == SupplierStatusEnum.REVIEW_UPDATED.getCode()){
+            SupplierInfoTemporary supplierInfoTemporary = supplierInfoTemporaryService.querBySupplierId(id);
+            //一共三个地方
+            boolean flag =false;
+            //1.简称
+            if (bo.getShortName() != null && StringUtils.isNotBlank(bo.getShortName())){
+                supplierInfoTemporary.setShortName(bo.getShortName());
+                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
+            }
+            //2.供货品牌
+            if (bo.getOperatingBrand() != null && StringUtils.isNotBlank(bo.getOperatingBrand())){
+                supplierInfoTemporary.setOperatingBrand(bo.getOperatingBrand());
+                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
+            }
+            //3.供货类目
+            if (bo.getOperatingCategory() != null && StringUtils.isNotBlank(bo.getOperatingCategory())){
+                supplierInfoTemporary.setOperatingCategory(bo.getOperatingCategory());
+                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
+            }
+            return flag;
+        }
+        // 停用呢  不能修改了
+        if (supplierInfo.getSupplyStatus() == SupplierStatusEnum.DISABLED.getCode()){
+            throw new RuntimeException("供应商已停用,不能修改");
+        }
+        return false;
+    }
+
     /**
      * 校验并批量删除供应商信息信息
      *
@@ -413,19 +497,18 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
     public TableDataInfo<SupplierInfoVo> getSupplierInformation(SupplierInfoBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<SupplierInfo> lqw = new LambdaQueryWrapper<>();
         // 1. 基础分页查询
-        if (bo.getSupplyStatus() == null) {
+        if (bo.getSupplyStatus() == null){
             //正式供应商
             lqw.eq(SupplierInfo::getSupplyStatus, 1L);
-        } else {
-            lqw.eq(SupplierInfo::getSupplyStatus, bo.getSupplyStatus());
+        }else {
+            lqw.eq(SupplierInfo::getSupplyStatus,bo.getSupplyStatus());
         }
 
-
         // 2. 添加品牌条件
-        if (bo.getOperatingBrand() != null && StringUtils.isNotBlank(bo.getOperatingBrand())) {
-            if (StringUtils.isNotBlank(bo.getOperatingBrand())) {
+        if (bo.getOperatingBrand()!= null && StringUtils.isNotBlank(bo.getOperatingBrand())){
+            if (StringUtils.isNotBlank(bo.getOperatingBrand())){
                 Long productBrandIdByName = remoteProductService.getProductBrandIdByName(bo.getOperatingBrand());
-                if (productBrandIdByName != null) {
+                if (productBrandIdByName != null){
                     lqw.like(SupplierInfo::getOperatingBrand, productBrandIdByName);
                 }
             }
@@ -635,13 +718,12 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
         if (bo.getSupplyStatus() == null) {
             List<Long> status = Arrays.asList(0L, 4L);
             lqw.in(SupplierInfo::getSupplyStatus, status);
-        } else {
-            lqw.eq(SupplierInfo::getSupplyStatus, bo.getSupplyStatus());
+        }else {
+            lqw.eq(SupplierInfo::getSupplyStatus,bo.getSupplyStatus());
         }
-
         // 2.添加品牌条件
-        if (bo.getOperatingBrand() != null && StringUtils.isNotBlank(bo.getOperatingBrand())) {
-            if (StringUtils.isNotBlank(bo.getOperatingBrand())) {
+        if (bo.getOperatingBrand()!= null && StringUtils.isNotBlank(bo.getOperatingBrand())){
+            if (StringUtils.isNotBlank(bo.getOperatingBrand())){
                 Long productBrandIdByName = remoteProductService.getProductBrandIdByName(bo.getOperatingBrand());
                 if (productBrandIdByName != null){
                     lqw.like(SupplierInfo::getOperatingBrand, productBrandIdByName);
@@ -671,8 +753,6 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
                 lqw.in(SupplierInfo::getId, -1L);
             }
         }
-
-
         // 2. 基础分页查询
         Page<SupplierInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
         List<SupplierInfoVo> supplierVos = result.getRecords();
@@ -733,9 +813,9 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
         lqw.eq(StringUtils.isNotBlank(bo.getSupplierName()), SupplierInfo::getEnterpriseName, bo.getSupplierName());
 
         //可供应品牌
-        if (StringUtils.isNotBlank(bo.getSupplyBrand())) {
+        if (StringUtils.isNotBlank(bo.getSupplyBrand())){
             Long productBrandIdByName = remoteProductService.getProductBrandIdByName(bo.getSupplyBrand());
-            if (productBrandIdByName != null) {
+            if (productBrandIdByName != null){
                 lqw.like(SupplierInfo::getOperatingBrand, productBrandIdByName);
             }
         }
@@ -743,10 +823,10 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
         if (StringUtils.isNotBlank(bo.getProvince()) || StringUtils.isNotBlank(bo.getCity())) {
             // 查询符合条件的供应商ID列表
             List<Long> supplierIds = supplyAreaService.getSupplierIdsByArea(bo.getProvince(), bo.getCity());
-            if (supplierIds != null && !supplierIds.isEmpty()) {
+            if (supplierIds != null &&!supplierIds.isEmpty()) {
                 lqw.in(SupplierInfo::getId, supplierIds);
 
-            } else {
+            }else {
                 lqw.in(SupplierInfo::getId, -1L);
 
             }
@@ -756,9 +836,9 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
         if (StringUtils.isNotBlank(bo.getBrandName())) {
             // 通过SupplierAuthorizeService查询符合条件的供应商ID
             List<Long> supplierIdsByBrand = commonSupplierAuthorizeMapper.getSupplierIdsByBrandName(bo.getBrandName());
-            if (supplierIdsByBrand != null && !supplierIdsByBrand.isEmpty()) {
+            if (supplierIdsByBrand!=null &&!supplierIdsByBrand.isEmpty()) {
                 lqw.in(SupplierInfo::getId, supplierIdsByBrand);
-            } else {
+            }else {
                 lqw.in(SupplierInfo::getId, -1L);
 
             }
@@ -814,75 +894,6 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
         return supplierInfoVo1.getSupplyStatus();
     }
 
-    @Override
-    public boolean srmUpdateByBo(SupplierInfoBo bo) {
-        Long id = bo.getId();
-        SupplierInfo supplierInfo = baseMapper.selectById(id);
-        //如果是待审核 随便改
-        if (bo.getSupplyStatus() == SupplierStatusEnum.PENDING_REVIEW.getCode()){
-            SupplierInfo update = MapstructUtils.convert(bo, SupplierInfo.class);
-            return baseMapper.updateById(update) > 0;
-        }
-        //如果是启用状态,就变成待修改审核状态
-        if (supplierInfo.getSupplyStatus() == SupplierStatusEnum.OFFICIAL_SUPPLIER.getCode()){
-            SupplierInfoTemporary supplierInfoTemporary = supplierInfoTemporaryService.querBySupplierId(id);
-            if (supplierInfoTemporary == null){
-                BeanUtils.copyProperties(bo, supplierInfoTemporary,"id");
-                supplierInfoTemporary.setSupplierId(id);
-                supplierInfoTemporary.setSupplyStatus(SupplierStatusEnum.REVIEW_UPDATED.getCode());
-                boolean save = supplierInfoTemporaryService.save(supplierInfoTemporary);
-                if (save == false){
-                    throw new RuntimeException("保存供应商待审核数据失败");
-                }
-            }
-            //一共三个地方
-            boolean flag =false;
-            //1.简称
-            if (bo.getShortName() != null && StringUtils.isNotBlank(bo.getShortName())){
-                supplierInfoTemporary.setShortName(bo.getShortName());
-                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
-            }
-            //2.供货品牌
-            if (bo.getOperatingBrand() != null && StringUtils.isNotBlank(bo.getOperatingBrand())){
-                supplierInfoTemporary.setOperatingBrand(bo.getOperatingBrand());
-                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
-            }
-            //3.供货类目
-            if (bo.getOperatingCategory() != null && StringUtils.isNotBlank(bo.getOperatingCategory())){
-                supplierInfoTemporary.setOperatingCategory(bo.getOperatingCategory());
-                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
-            }
-
-            supplierInfo.setSupplyStatus(SupplierStatusEnum.REVIEW_UPDATED.getCode());
-            boolean update =baseMapper.updateById(supplierInfo) > 0;
-            return update && flag;
-        }
-        //如果是待审核状态,就变成待修改审核状态
-        if (supplierInfo.getSupplyStatus() == SupplierStatusEnum.REVIEW_UPDATED.getCode()){
-            SupplierInfoTemporary supplierInfoTemporary = supplierInfoTemporaryService.querBySupplierId(id);
-            //一共三个地方
-            boolean flag =false;
-            //1.简称
-            if (bo.getShortName() != null && StringUtils.isNotBlank(bo.getShortName())){
-                supplierInfoTemporary.setShortName(bo.getShortName());
-                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
-            }
-            //2.供货品牌
-            if (bo.getOperatingBrand() != null && StringUtils.isNotBlank(bo.getOperatingBrand())){
-                supplierInfoTemporary.setOperatingBrand(bo.getOperatingBrand());
-                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
-            }
-            //3.供货类目
-            if (bo.getOperatingCategory() != null && StringUtils.isNotBlank(bo.getOperatingCategory())){
-                supplierInfoTemporary.setOperatingCategory(bo.getOperatingCategory());
-                flag = supplierInfoTemporaryService.updateById(supplierInfoTemporary);
-            }
-            return flag;
-        }
-        return false;
-    }
-
-
     @Override
     public Map<Long, String> selectSupplierNameByIds(Set<Long> ids) {
         if (ids == null || ids.isEmpty()) {
@@ -930,7 +941,6 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
     }
 
     // ========== 3. 数据转换 - 映射构建方法 ==========
-
     /**
      * 构建品牌ID→名称映射表
      */
@@ -1555,6 +1565,7 @@ public class SupplierInfoServiceImpl  extends ServiceImpl<SupplierInfoMapper, Su
     }*/
 
 
+
     /**
      * 处理采购员和产品经理信息和品牌和供应商类型
      */

+ 2 - 0
ruoyi-modules/ruoyi-external/pom.xml

@@ -100,6 +100,7 @@
             <artifactId>ruoyi-api-system</artifactId>
         </dependency>
 
+
         <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>ruoyi-api-resource</artifactId>
@@ -128,6 +129,7 @@
             <artifactId>mssql-jdbc</artifactId>
             <version>9.4.0.jre11</version>
         </dependency>
+
     </dependencies>
 
     <build>

+ 2 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductController.java

@@ -131,4 +131,6 @@ public class ExternalProductController extends BaseController {
     }
 
 
+
+
 }

+ 288 - 450
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/ZhongChePullController.java

@@ -3,10 +3,13 @@ package org.dromara.external.controller.zhongche;
 import cn.hutool.core.codec.Base64;
 import cn.hutool.core.date.DateUtil;
 
+import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.dromara.external.api.zhongche.domain.*;
 import org.dromara.external.api.zhongche.domain.aftersale.bo.*;
 import org.dromara.external.api.zhongche.domain.aftersale.vo.*;
@@ -21,6 +24,9 @@ import org.dromara.external.api.zhongche.domain.settlement.vo.SettlementDetailVo
 import org.dromara.external.api.zhongche.domain.settlement.vo.SettlementPaymentDetailVo;
 import org.dromara.external.api.zhongche.domain.vo.*;
 import org.dromara.external.util.SM2SignUtil;
+import org.dromara.external.util.SM2SignatureUtils;
+import org.dromara.external.util.SignParamUtils;
+import org.dromara.external.util.ZCApiUtils;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -28,11 +34,13 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.nio.charset.StandardCharsets;
+import java.util.List;
 
 /**
  * 中车拉取接口
  * 时间:2026/1/5,19:03
  */
+@Slf4j
 @Validated
 @RequiredArgsConstructor
 @RestController
@@ -40,278 +48,299 @@ import java.nio.charset.StandardCharsets;
 public class ZhongChePullController {
 
     // 中车地区查询接口地址(替换为真实域名)
-    private static final String AREA_QUERY_URL = "https://{中车域名}";
-
+    private static final String AREA_QUERY_URL = "https://supply-test.crrcgo.cc/mallapi/";
     // 中车提供的配置(替换为真实值)
-    private static final String CLIENT_ID = "KFZiA6EknYf";
-    private static final String ACCESS_TOKEN = "1261127442808451075";
-    private static final String PRIVATE_KEY = "你的私钥(16进制)"; // 电商平台私钥
-    private static final String ZC_PUBLIC_KEY = "中车公钥(16进制)"; // 中车公钥
-    private static final String VERSION = "1.0";
+    private static final String CLIENT_ID = "KFZAVuIyC56";
+    private static final String PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgpQdXwMi21Mg1FhWad2AQLOwfNiDHgwhootau0YerQbagCgYIKoEcz1UBgi2hRANCAATVjJs6XRAMTZ72G6aWbgCAjfAnW0j5R9VFnHySTiF8+1mOisc3xOOr9w/Tu3hixzL5H2gVyLzHDRWkFtyeVqrX"; // 电商平台私钥
+    private static final String ZC_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmUrB5ByAeb8jHayC7vbddqBFDIEsf1cpNO1qJttZ17xlDagVB/tBFasPr/x0+OWf2kimTKah2NGCYarymD1R5Q==\n"; // 中车公钥
+    private static final String VERSION = "1.0.0";
 
-    private final SM2SignUtil sm2SignUtil;
 
     //5	中车电子商城提供服务
     //5.1	基础数据服务
 
     //5.1.1	地区查询
     @PostMapping("/area/query")
-    public ZCR<AreaVo> areaQuery(@RequestBody AreaQueryBo bo) {
-        //获取response.body
-        ZCR<String> responseDto = doZcPost("/api/area/query", bo);
-        //TODO 2 签名校验
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
+    public AreaVo areaQuery(@RequestBody AreaQueryBo bo) {
+        // 1. 校验业务请求参数(自身先校验,避免无效调用电商平台)
+        //1 省级,2市级,3县级, 4区级
+        //父级地址id	当查询省级时填0
+        if (bo.getLevel() == null || !List.of(1, 2, 3, 4).contains(bo.getLevel())) {
+            throw new RuntimeException("级次(level)必填,且仅支持1/2/3/4");
         }
-        //解析业务响应参数
-        ZCR<AreaVo> zcr = parseZcResponse(responseDto, AreaVo.class);
-        return zcr;
+        if (StrUtil.isBlank(bo.getPid())) {
+            throw new RuntimeException("父级地址id(pid)不能为空");
+        }
+        //获取response.body
+        ZCR responseDto = doZcPost("/api/area/query", bo);
+        // 4. 复用工具类解析响应
+        return parseZcResponse(responseDto, AreaVo.class);
     }
 
-    private Boolean verifyResponseSign(ZCR<String> responseDto) {
-        String sign = responseDto.getSign();
-        if (sign == null){
+    private Boolean verifyResponseSign(ZCR responseDto) {
+        // 1. 空值防护
+        if (responseDto == null || responseDto.getSign() == null || responseDto.getSign().trim().isEmpty()) {
+            log.warn("通用签名校验 - 电商平台响应签名为空");
+            return false;
+        }
+
+        try {
+            // 2. 生成响应签名原文(复用 SignParamUtils.getSignContent,剔除 sign 字段)
+            String signContent = SignParamUtils.getSignContent(responseDto);
+
+            // 3. SM2 验签(复用 SM2SignatureUtils.verify,传入电商平台公钥)
+            return SM2SignatureUtils.verify(
+                signContent,
+                responseDto.getSign(),
+                ZC_PUBLIC_KEY
+            );
+        } catch (Exception e) {
+            log.error("通用签名校验 - 校验响应签名异常", e);
             return false;
         }
-        return true;
     }
 
 
-    private <B> ZCR<String> doZcPost(String apiPath, B bo) {
-        // 1. 业务参数 -> JSON -> Base64
-        String bizJson = JSONUtil.toJsonStr(bo);
-        String dataBase64 = Base64.encode(bizJson, StandardCharsets.UTF_8);
+    private <B> ZCR doZcPost(String apiPath, B bo) {
+        // 1.BO → JSON
+        String bizJson;
+        try {
+            bizJson = ZCApiUtils.objectToJson(bo);
+        } catch (JsonProcessingException e) {
+            return ZCR.fail("5000", "业务参数转换失败:" + e.getMessage());
+        }
 
-        // 2. 构建 token 请求体
-        ZCTokenBo zcTokenBo = getZcTokenBo(dataBase64);
-        String requestJson = JSONUtil.toJsonStr(zcTokenBo);
+        // 2. JSON→ Base64
+        String dataBase64;
+        try {
+            // 注意:你的 ZCApiUtils.base64Encode 内部用 getBytes(),默认是系统编码,补充 UTF-8 编码保证一致性
+            dataBase64 = ZCApiUtils.base64Encode(bizJson);
+        } catch (IllegalArgumentException e) {
+            log.error("通用请求 - 业务 JSON Base64 编码失败", e);
+            return ZCR.fail("5000", "业务参数编码失败:" + e.getMessage());
+        }
 
-        // 3. HTTP POST
+        //TODO 3. 构建 ZCTokenBo 请求体
+        ZCTokenBo zcTokenBo = getZcTokenBo(dataBase64);
+        // 4. 生成请求签名
+        String requestSign;
+        try {
+            requestSign = SignParamUtils.generateRequestSign(zcTokenBo, PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("通用请求 - 生成请求签名失败", e);
+            return ZCR.fail("5000", "生成请求签名失败:" + e.getMessage());
+        }
+        zcTokenBo.setSign(requestSign);
+        // 5. ZCTokenBo → JSON 字符串
+        String requestJson;
+        try {
+            requestJson = ZCApiUtils.objectToJson(zcTokenBo);
+        } catch (JsonProcessingException e) {
+            log.error("通用请求 - ZCTokenBo 转换 JSON 失败", e);
+            return ZCR.fail("5000", "请求体转换失败:" + e.getMessage());
+        }
+
+        // 6. 发送 HTTP POST 请求(保持 hutool HTTP 工具,保证稳定性)
+        String fullUrl = AREA_QUERY_URL + apiPath;
         HttpResponse httpResponse = HttpRequest
-            .post(AREA_QUERY_URL + apiPath)
+            .post(fullUrl)
             .charset(StandardCharsets.UTF_8)
+            .contentType("application/json")
             .body(requestJson)
             .timeout(60000)
             .execute();
 
-        // 4. 响应体转 DTO
+        // 7. 校验 HTTP 响应状态
+        if (!httpResponse.isOk()) {
+            log.error("通用请求 - 电商平台接口调用失败,接口路径:{},HTTP 状态码:{}", apiPath, httpResponse.getStatus());
+            return ZCR.fail("5000", "电商平台接口调用失败,HTTP 响应异常");
+        }
+
+        // 8. 响应体 → ZCR(复用 ZCApiUtils 转换 JSON)
         String responseBody = httpResponse.body();
-        ZCR<String> responseDto = JSONUtil.toBean(responseBody, ZCR.class);
+        ZCR responseDto;
+        try {
+            responseDto = ZCApiUtils.jsonToObject(responseBody, ZCR.class);
+        } catch (JsonProcessingException e) {
+            log.error("通用请求 - 响应体转换 ZCR 失败", e);
+            return ZCR.fail("5000", "响应体解析失败:" + e.getMessage());
+        }
 
-        // 5. 响应码校验
+        // 9. 响应码校验
         if (!"0".equals(responseDto.getRespCode())) {
             return ZCR.fail(responseDto.getRespCode(), responseDto.getRespMsg());
         }
 
+        // 10. 响应签名校验(中车强要求)
+        if (!verifyResponseSign(responseDto)) {
+            log.error("通用请求 - 响应签名校验失败,apiPath={}", apiPath);
+            return ZCR.fail("5001", "响应签名验证失败");
+        }
+
         return responseDto;
     }
 
+    //TODO 怎么获取TOKEN
     private ZCTokenBo getZcTokenBo(String data) {
         ZCTokenBo zcTokenBo = new ZCTokenBo();
         zcTokenBo.setVersion(VERSION);
         zcTokenBo.setTimestamp(DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss"));
-        zcTokenBo.setAccessToken(ACCESS_TOKEN);
+        zcTokenBo.setAccessToken(null);
         zcTokenBo.setClientId(CLIENT_ID);
         zcTokenBo.setData(data);
-        zcTokenBo.setSign("");
+        zcTokenBo.setSign(null);
         return zcTokenBo;
     }
 
 
-    //5.2 商品服务
-
-    //TODO 5.2.1	商品导入
+    //5.2.1	商品导入
     @PostMapping("/egoods/import")
-    public ZCR<GoodsImportVo> egoodsImport(@RequestBody GoodsImportBo bo) {
-
-        ZCR<String> responseDto = doZcPost("/api/egoods/import", bo);
-        //TODO 6.2 签名校验
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
+    public GoodsImportVo egoodsImport(@RequestBody GoodsImportBo bo) {
+        ZCR responseDto = doZcPost("/api/egoods/import", bo);
         //解析业务响应参数
-        ZCR<GoodsImportVo> zcr = parseZcResponse(responseDto, GoodsImportVo.class);
+        GoodsImportVo zcr = parseZcResponse(responseDto, GoodsImportVo.class);
         return zcr;
-
     }
-    private <V> ZCR<V> parseZcResponse(ZCR<String> responseDto, Class<V> voClass) {
-        // Base64 解码 data
-        String respBizJson = Base64.decodeStr(
-            responseDto.getData(),
-            StandardCharsets.UTF_8
-        );
+    private <V> V parseZcResponse(ZCR responseDto, Class<V> voClass) {
+        // 1. 基础校验
+        if (responseDto == null) {
+            throw new RuntimeException("中车响应为空");
+        }
+
+        if (!"0".equals(responseDto.getRespCode())) {
+            throw new RuntimeException(
+                "中车接口返回失败:" + responseDto.getRespCode() + " - " + responseDto.getRespMsg()
+            );
+        }
+
+        if (StrUtil.isBlank(responseDto.getData())) {
+            throw new RuntimeException("中车响应 data 为空");
+        }
+
+        try {
+            // 2. Base64 → JSON
+            String bizJson = ZCApiUtils.base64Decode(responseDto.getData());
 
-        // JSON → VO
-        V vo = JSONUtil.toBean(respBizJson, voClass);
+            // 3. JSON → VO(Jackson 自动处理嵌套对象 / List)
+            return ZCApiUtils.jsonToObject(bizJson, voClass);
 
-        return ZCR.ok(vo);
+        } catch (Exception e) {
+            log.error("解析中车响应失败,response={}", responseDto, e);
+            throw new RuntimeException("解析中车响应失败", e);
+        }
     }
 
 
     //TODO 5.2.2	商品价格变更
     @PostMapping("/egoods/price/update")
-    public ZCR<GoodsPriceUpdateVo> egoodsPriceUpdate(@RequestBody GoodsImportBo bo) {
-
-        ZCR<String> responseDto = doZcPost("/api/egoods/price/update", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsPriceUpdateVo> zcr = parseZcResponse(responseDto, GoodsPriceUpdateVo.class);
+    public GoodsPriceUpdateVo egoodsPriceUpdate(@RequestBody GoodsImportBo bo) {
+        ZCR responseDto = doZcPost("/api/egoods/price/update", bo);
+        GoodsPriceUpdateVo zcr = parseZcResponse(responseDto, GoodsPriceUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.2.3	商品上下架状态变更
     @PostMapping("/egoods/status/update")
-    public ZCR<GoodsStatusUpdateVo> egoodsStatusUpdate(@RequestBody GoodsStatusUpdateBo bo) {
+    public GoodsStatusUpdateVo egoodsStatusUpdate(@RequestBody GoodsStatusUpdateBo bo) {
 
-        ZCR<String> responseDto = doZcPost("/api/egoods/status/update", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsStatusUpdateVo> zcr = parseZcResponse(responseDto, GoodsStatusUpdateVo.class);
+        ZCR responseDto = doZcPost("/api/egoods/status/update", bo);
+        GoodsStatusUpdateVo zcr = parseZcResponse(responseDto, GoodsStatusUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.2.4	商品图片变更
     @PostMapping("/egoods/imgs/update")
-    public ZCR<GoodsImageUpdateVo> egoodsImgsUpdate(@RequestBody GoodsImageUpdateBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/egoods/imgs/update", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsImageUpdateVo> zcr = parseZcResponse(responseDto, GoodsImageUpdateVo.class);
+    public GoodsImageUpdateVo egoodsImgsUpdate(@RequestBody GoodsImageUpdateBo bo) {
+        ZCR responseDto = doZcPost("/api/egoods/imgs/update", bo);
+        GoodsImageUpdateVo zcr = parseZcResponse(responseDto, GoodsImageUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.2.5	商品规格信息变更
     @PostMapping("/egoods/properties/update")
-    public ZCR<GoodsUpdateVo> egoodsPropertiesUpdate(@RequestBody GoodsPropertiesUpdateBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/egoods/properties/update", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo egoodsPropertiesUpdate(@RequestBody GoodsPropertiesUpdateBo bo) {
+        ZCR responseDto = doZcPost("/api/egoods/properties/update", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.2.6	商品详情信息变更
     @PostMapping("/egoods/detail/update")
-    public ZCR<GoodsUpdateVo> egoodsDetailUpdate(@RequestBody GoodsDetailBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/egoods/detail/update", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo egoodsDetailUpdate(@RequestBody GoodsDetailBo bo) {
+        ZCR responseDto = doZcPost("/api/egoods/detail/update", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
     //5.3	订单服务
 
-    //TODO 5.3.1	查询订单详情
+    // 5.3.1	查询订单详情
     @PostMapping("/mall/order/detail")
-    public ZCR<OrderDetailVo> mallOrderDetail(@RequestBody OrderDetailBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/detail", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<OrderDetailVo> zcr = parseZcResponse(responseDto, OrderDetailVo.class);
-        return zcr;
+    public OrderDetailVo mallOrderDetail(@RequestBody OrderDetailBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/detail", bo);
+        OrderDetailVo orderDetailVo = parseZcResponse(responseDto, OrderDetailVo.class);
+        return orderDetailVo;
     }
 
     //TODO 5.3.2	接单
     @PostMapping("/mall/order/confirm")
-    public ZCR<GoodsUpdateVo> mallOrderConfirm(@RequestBody OrderConfirmBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/confirm", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallOrderConfirm(@RequestBody OrderConfirmBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/confirm", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.3.3	同步商品协商发货时间
     @PostMapping("/mall/order/goods/append")
-    public ZCR<GoodsUpdateVo> mallOrderGoodsAppend(@RequestBody OrderGoodsAppendBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/goods/append", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallOrderGoodsAppend(@RequestBody OrderGoodsAppendBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/goods/append", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.3.4	拒单
     @PostMapping("/mall/order/reject")
-    public ZCR<GoodsUpdateVo> mallOrderReject(@RequestBody OrderRejectBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/reject", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallOrderReject(@RequestBody OrderRejectBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/reject", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.3.5	发货
     @PostMapping("/mall/order/deliver/goods")
-    public ZCR<OrderDeliverVo> mallOrderDeliverGoods(@RequestBody OrderDeliverBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/deliver/goods", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<OrderDeliverVo> zcr = parseZcResponse(responseDto, OrderDeliverVo.class);
+    public ZhongCheOrderDeliverVo mallOrderDeliverGoods(@RequestBody ZhongCheOrderDeliverBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/deliver/goods", bo);
+
+        ZhongCheOrderDeliverVo zcr = parseZcResponse(responseDto, ZhongCheOrderDeliverVo.class);
         return zcr;
 
     }
 
     //TODO 5.3.6	查询待处理订单列表
     @PostMapping("/mall/order/pending/list")
-    public ZCR<PendingOrderListVo> mallOrderPendingList(@RequestBody ZCTokenBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/pending/list", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<PendingOrderListVo> zcr = parseZcResponse(responseDto, PendingOrderListVo.class);
+    public PendingOrderListVo mallOrderPendingList(@RequestBody ZCTokenBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/pending/list", bo);
+        PendingOrderListVo zcr = parseZcResponse(responseDto, PendingOrderListVo.class);
         return zcr;
     }
 
     //TODO 5.3.7	妥投通知
     @PostMapping("/mall/order/delivered/notice")
-    public ZCR<GoodsUpdateVo> mallOrderDeliveredNotice(@RequestBody OrderDeliveredNoticeBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/delivered/notice", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallOrderDeliveredNotice(@RequestBody OrderDeliveredNoticeBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/delivered/notice", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
     //TODO 5.3.8	查询发货单信息
     @PostMapping("/mall/order/query/outgoing")
-    public ZCR<OutgoingVo> mallOrderQueryOutgoing(@RequestBody OutgoingQueryBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/query/outgoing", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<OutgoingVo> zcr = parseZcResponse(responseDto, OutgoingVo.class);
+    public OutgoingVo mallOrderQueryOutgoing(@RequestBody OutgoingQueryBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/query/outgoing", bo);
+        OutgoingVo zcr = parseZcResponse(responseDto, OutgoingVo.class);
         return zcr;
     }
 
-    //TODO 5.3.12	审核订单取消
+    //TODO 5.3.11	审核订单取消
     /*
         //请求业务参数
         OrderCancelAuditBo orderCancelAuditBo = new OrderCancelAuditBo();
@@ -319,21 +348,12 @@ public class ZhongChePullController {
         GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
      */
     @PostMapping("/mall/order/cancel/audit/judge")
-    public ZCR<GoodsUpdateVo> mallOrderCancelAuditJudge(@RequestBody OrderCancelAuditBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/order/cancel/audit/judge", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallOrderCancelAuditJudge(@RequestBody OrderCancelAuditBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/order/cancel/audit/judge", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
-
-
-
-    //5.4	售后服务
-
-    //TODO 5.4.1	查询售后单详情
+    //5.4.1	查询售后单详情
     /*
         //请求业务参数
         AfterSaleDetailBo afterSaleDetailBo = new AfterSaleDetailBo();
@@ -346,383 +366,201 @@ public class ZhongChePullController {
         AfterSaleReturn afterSaleReturn = new AfterSaleReturn();
      */
     @PostMapping("/mall/aftersale/detail")
-    public ZCR<AfterSaleDetailVo> mallAftersaleDetail(@RequestBody AfterSaleDetailBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/detail", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<AfterSaleDetailVo> zcr = parseZcResponse(responseDto, AfterSaleDetailVo.class);
+    public AfterSaleDetailVo mallAftersaleDetail(@RequestBody AfterSaleDetailBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/detail", bo);
+        AfterSaleDetailVo zcr = parseZcResponse(responseDto, AfterSaleDetailVo.class);
         return zcr;
     }
 
-    //TODO 5.4.2	接受售后
+    //5.4.2	接受售后
     @PostMapping("/mall/aftersale/confirm")
-    public ZCR<GoodsUpdateVo> mallAftersaleConfirm(@RequestBody AfterSaleConfirmBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/confirm", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallAftersaleConfirm(@RequestBody AfterSaleConfirmBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/confirm", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
-    //TODO 5.4.3	拒绝售后
+    //5.4.3	拒绝售后
     @PostMapping("/mall/aftersale/reject")
-    public ZCR<GoodsUpdateVo> mallAftersaleReject(@RequestBody AfterSaleRejectBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/reject", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallAftersaleReject(@RequestBody AfterSaleRejectBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/reject", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
-    //TODO 5.4.4	确认收到退货
+    //5.4.4	确认收到退货
     @PostMapping("/mall/aftersale/return/goods/received")
-    public ZCR<GoodsUpdateVo> mallAftersaleReturnGoodsReceived(@RequestBody AfterSaleReturnReceivedBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/return/goods/received", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallAftersaleReturnGoodsReceived(@RequestBody AfterSaleReturnReceivedBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/return/goods/received", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
-    //TODO 5.4.5	换货新品发货
+    //5.4.5	换货新品发货
     @PostMapping("/mall/aftersale/deliver/goods")
-    public ZCR<AfterSaleDeliverGoodsVo> mallAftersaleDeliverGoods(@RequestBody AfterSaleDeliverGoodsBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/deliver/goods", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<AfterSaleDeliverGoodsVo> zcr = parseZcResponse(responseDto, AfterSaleDeliverGoodsVo.class);
+    public AfterSaleDeliverGoodsVo mallAftersaleDeliverGoods(@RequestBody AfterSaleDeliverGoodsBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/deliver/goods", bo);
+        AfterSaleDeliverGoodsVo zcr = parseZcResponse(responseDto, AfterSaleDeliverGoodsVo.class);
         return zcr;
     }
 
     //TODO 5.4.6	查询待处理售后单列表
     @PostMapping("/mall/aftersale/pending/list")
-    public ZCR<AfterSalePendingListVo> mallAftersalePendingList(@RequestBody AfterSalePendingListBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/pending/list", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<AfterSalePendingListVo> zcr = parseZcResponse(responseDto, AfterSalePendingListVo.class);
+    public AfterSalePendingListVo mallAftersalePendingList(@RequestBody AfterSalePendingListBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/pending/list", bo);
+        AfterSalePendingListVo zcr = parseZcResponse(responseDto, AfterSalePendingListVo.class);
         return zcr;
     }
 
-    //TODO 5.4.7	查询换货新品发货单信息
+    //5.4.7	查询换货新品发货单信息
     @PostMapping("/mall/aftersale/query/outgoing")
-    public ZCR<AfterSaleQueryOutgoingVo> mallAftersaleQueryOutgoing(@RequestBody AfterSaleQueryOutgoingBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/query/outgoing", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<AfterSaleQueryOutgoingVo> zcr = parseZcResponse(responseDto, AfterSaleQueryOutgoingVo.class);
+    public AfterSaleQueryOutgoingVo mallAftersaleQueryOutgoing(@RequestBody AfterSaleQueryOutgoingBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/query/outgoing", bo);
+        AfterSaleQueryOutgoingVo zcr = parseZcResponse(responseDto, AfterSaleQueryOutgoingVo.class);
         return zcr;
     }
 
-    //TODO 5.4.8	线下售后
+    //5.4.8	线下售后
     @PostMapping("/mall/aftersale/offline/create")
-    public ZCR<AfterSaleOfflineCreateVo> mallAftersaleOfflineCreate(@RequestBody AfterSaleOfflineCreateBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/offline/create", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<AfterSaleOfflineCreateVo> zcr = parseZcResponse(responseDto, AfterSaleOfflineCreateVo.class);
+    public AfterSaleOfflineCreateVo mallAftersaleOfflineCreate(@RequestBody AfterSaleOfflineCreateBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/offline/create", bo);
+        AfterSaleOfflineCreateVo zcr = parseZcResponse(responseDto, AfterSaleOfflineCreateVo.class);
         return zcr;
     }
 
-    //TODO 5.4.9	确认退款
+    //5.4.9	确认退款
     @PostMapping("/mall/aftersale/refund")
-    public ZCR<GoodsUpdateVo> mallAftersaleRefund(@RequestBody AfterSaleRefundBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/aftersale/refund", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallAftersaleRefund(@RequestBody AfterSaleRefundBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/aftersale/refund", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
-    //5.7	开票服务
 
-    //TODO 5.7.1	查询开票信息
-    /*
-        //请求业务参数
-        InvoiceApplyDetailBo invoiceApplyDetailBo = new InvoiceApplyDetailBo();
-        //响应业务参数
-        InvoiceApplyDetailVo invoiceApplyDetailVo = new InvoiceApplyDetailVo();
-        InvoiceReceiver invoiceReceiver = new InvoiceReceiver();
-     */
+    //5.7.1	查询开票信息
     @PostMapping("/mall/invoice/apply/detail")
-    public ZCR<InvoiceApplyDetailVo> mallInvoiceApplyDetail(@RequestBody InvoiceApplyDetailBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/apply/detail", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<InvoiceApplyDetailVo> zcr = parseZcResponse(responseDto, InvoiceApplyDetailVo.class);
+    public InvoiceApplyDetailVo mallInvoiceApplyDetail(@RequestBody InvoiceApplyDetailBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/apply/detail", bo);
+        InvoiceApplyDetailVo zcr = parseZcResponse(responseDto, InvoiceApplyDetailVo.class);
         return zcr;
 
     }
 
-    //TODO 5.7.2	查询开票申请订单列表
-    /*
-        //请求业务参数
-        InvoiceApplyOrdersBo invoiceApplyOrdersBo = new InvoiceApplyOrdersBo();
-        //响应业务参数
-        InvoiceApplyOrdersVo invoiceApplyOrdersVo = new InvoiceApplyOrdersVo();
-        InvoiceOrder invoiceOrder = new InvoiceOrder();
-     */
+    //5.7.2	查询开票申请订单列表
     @PostMapping("/mall/invoice/apply/orders")
-    public ZCR<InvoiceApplyOrdersVo> mallInvoiceApplyOrders(@RequestBody InvoiceApplyOrdersBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/apply/orders", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<InvoiceApplyOrdersVo> zcr = parseZcResponse(responseDto, InvoiceApplyOrdersVo.class);
+    public InvoiceApplyOrdersVo mallInvoiceApplyOrders(@RequestBody InvoiceApplyOrdersBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/apply/orders", bo);
+        InvoiceApplyOrdersVo zcr = parseZcResponse(responseDto, InvoiceApplyOrdersVo.class);
         return zcr;
 
     }
 
-    //TODO 5.7.3    拒绝开票
-
+    //5.7.3    拒绝开票
     @PostMapping("/mall/invoice/apply/reject")
-    public ZCR<GoodsUpdateVo> mallInvoiceApplyReject(@RequestBody InvoiceApplyRejectBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/apply/reject", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallInvoiceApplyReject(@RequestBody InvoiceApplyRejectBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/apply/reject", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
-    //TODO 5.7.4	电商同步开票信息
-    /*
-        //请求业务参数
-        InvoiceSyncInvoiceInfosBo invoiceSyncInvoiceInfosBo = new InvoiceSyncInvoiceInfosBo();
-        InvoiceInfo invoiceInfo = new InvoiceInfo();
-        //响应业务参数
-        GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
-     */
+    //5.7.4	电商同步开票信息
     @PostMapping("/mall/invoice/sync/invoiceinfos")
-    public ZCR<GoodsUpdateVo> mallInvoiceSyncInvoiceInfos(@RequestBody InvoiceSyncInvoiceInfosBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/sync/invoiceinfos", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallInvoiceSyncInvoiceInfos(@RequestBody InvoiceSyncInvoiceInfosBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/sync/invoiceinfos", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
-
     }
 
-    //TODO 5.7.5 同步纸质发票邮寄信息
-    /*
-        //请求业务参数
-        InvoiceSyncWaybillBo invoiceSyncWaybillBo = new InvoiceSyncWaybillBo();
-        //响应业务参数
-        GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
-     */
+    //5.7.5 同步纸质发票邮寄信息
+
     @PostMapping("/mall/invoice/sync/waybill")
-    public ZCR<GoodsUpdateVo> mallInvoiceSyncWaybill(@RequestBody InvoiceSyncWaybillBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/sync/waybill", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallInvoiceSyncWaybill(@RequestBody InvoiceSyncWaybillBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/sync/waybill", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
     }
 
-    //TODO 5.7.6 发票妥投通知
-    /*
-        //请求业务参数
-        InvoiceDeliveredNoticeBo invoiceDeliveredNoticeBo = new InvoiceDeliveredNoticeBo();
-        //响应业务参数
-        GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
-     */
+    //5.7.6 发票妥投通知
     @PostMapping("/mall/invoice/delivered/notice")
-    public ZCR<GoodsUpdateVo> mallInvoiceDeliveredNotice(@RequestBody InvoiceDeliveredNoticeBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/delivered/notice", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallInvoiceDeliveredNotice(@RequestBody InvoiceDeliveredNoticeBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/delivered/notice", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
-
-
     }
 
-    //TODO 5.7.7	查询待开票申请单列表
-    /*
-        //请求业务参数
-        InvoiceApplyWaitlistBo invoiceApplyWaitListBo = new InvoiceApplyWaitlistBo();
-
-        //响应业务参数
-        WaitInvoiceApply waitInvoiceApply = new WaitInvoiceApply();
-        InvoiceApplyWaitlistVo invoiceApplyWaitlistVo = new InvoiceApplyWaitlistVo();
-     */
+    //5.7.7	查询待开票申请单列表
     @PostMapping("/mall/invoice/apply/waitlist")
-    public ZCR<InvoiceApplyWaitlistVo> mallInvoiceApplyWaitList(@RequestBody InvoiceApplyWaitlistBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/apply/waitlist", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<InvoiceApplyWaitlistVo> zcr = parseZcResponse(responseDto, InvoiceApplyWaitlistVo.class);
+    public InvoiceApplyWaitlistVo mallInvoiceApplyWaitList(@RequestBody InvoiceApplyWaitlistBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/apply/waitlist", bo);
+        InvoiceApplyWaitlistVo zcr = parseZcResponse(responseDto, InvoiceApplyWaitlistVo.class);
         return zcr;
-
-
     }
 
-    //TODO 5.7.8	电商同意退票
-    /*
-        //请求业务参数
-        InvoiceRefundAgreeBo invoiceRefundAgreeBo = new InvoiceRefundAgreeBo();
-        //响应业务参数
-        GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
-     */
+    //5.7.8	电商同意退票
     @PostMapping("/mall/invoice/refund/agree")
-    public ZCR<GoodsUpdateVo> mallInvoiceRefundAgree(@RequestBody InvoiceRefundAgreeBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/refund/agree", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallInvoiceRefundAgree(@RequestBody InvoiceRefundAgreeBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/refund/agree", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
-
     }
 
-    //TODO 5.7.9	电商确认完成退票
-    /*
-        //请求业务参数
-        InvoiceRefundFinishBo invoiceRefundFinishBo = new InvoiceRefundFinishBo();
-        //响应业务参数
-        GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
-     */
+    //5.7.9	电商确认完成退票
+
     @PostMapping("/mall/invoice/refund/finish")
-    public ZCR<GoodsUpdateVo> mallInvoiceRefundFinish(@RequestBody InvoiceRefundFinishBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/refund/finish", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
+    public GoodsUpdateVo mallInvoiceRefundFinish(@RequestBody InvoiceRefundFinishBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/refund/finish", bo);
+        GoodsUpdateVo zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
         return zcr;
-
     }
 
-    //TODO 5.7.10 电商拒绝退票申请
-    /*
-        //请求业务参数
-        InvoiceRefundRejectBo invoiceRefundRejectBo = new InvoiceRefundRejectBo();
-        //响应业务参数
-        GoodsUpdateVo goodsUpdateVo = new GoodsUpdateVo();
-     */
+    //5.7.10 电商拒绝退票申请
     @PostMapping("/mall/invoice/refund/reject")
-    public ZCR<GoodsUpdateVo> mallInvoiceRefundReject(@RequestBody InvoiceRefundRejectBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/invoice/refund/reject", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
-        return zcr;
-
+    public GoodsUpdateVo mallInvoiceRefundReject(@RequestBody InvoiceRefundRejectBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/invoice/refund/reject", bo);
+        GoodsUpdateVo goodsUpdateVo = parseZcResponse(responseDto, GoodsUpdateVo.class);
+        return goodsUpdateVo;
     }
 
-    //5.9 结算服务
-
-    //TODO 5.9.1	查询结算单详情
+    //5.9.1	查询结算单详情
     @PostMapping("/mall/settlement/detail")
-    public ZCR<SettlementDetailVo> mallSettlementDetail(@RequestBody SettlementDetailBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/settlement/detail", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<SettlementDetailVo> zcr = parseZcResponse(responseDto, SettlementDetailVo.class);
-        return zcr;
-
+    public SettlementDetailVo mallSettlementDetail(@RequestBody SettlementDetailBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/settlement/detail", bo);
+        SettlementDetailVo settlementDetailVo = parseZcResponse(responseDto, SettlementDetailVo.class);
+        return settlementDetailVo;
     }
 
-    //TODO 5.9.2	查询结算单订单列表
+    //5.9.2	查询结算单订单列表
     @PostMapping("/mall/settlement/apply/orders")
-    public ZCR<SettlementApplyOrdersVo> mallSettlementApplyOrders(@RequestBody SettlementApplyOrdersBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/settlement/apply/orders", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<SettlementApplyOrdersVo> zcr = parseZcResponse(responseDto, SettlementApplyOrdersVo.class);
-        return zcr;
-
+    public SettlementApplyOrdersVo mallSettlementApplyOrders(@RequestBody SettlementApplyOrdersBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/settlement/apply/orders", bo);
+        SettlementApplyOrdersVo settlementApplyOrdersVo = parseZcResponse(responseDto, SettlementApplyOrdersVo.class);
+        return settlementApplyOrdersVo;
     }
 
 
-    //TODO 5.9.3	结算单确认结算
+    //5.9.3	结算单确认结算
     @PostMapping("/mall/settlement/confirm")
-    public ZCR<GoodsUpdateVo> mallSettlementConfirm(@RequestBody SettlementConfirmBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/settlement/confirm", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
-        return zcr;
-
-
+    public GoodsUpdateVo mallSettlementConfirm(@RequestBody SettlementConfirmBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/settlement/confirm", bo);
+        GoodsUpdateVo goodsUpdateVo = parseZcResponse(responseDto, GoodsUpdateVo.class);
+        return goodsUpdateVo;
     }
 
-    //TODO 5.9.4	结算单付款详情
+    //5.9.4	结算单付款详情
     @PostMapping("/mall/settlement/payment/detail")
-    public ZCR<SettlementPaymentDetailVo> mallSettlementPaymentDetail( @RequestBody SettlementPaymentDetailBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/settlement/payment/detail", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<SettlementPaymentDetailVo> zcr = parseZcResponse(responseDto, SettlementPaymentDetailVo.class);
-        return zcr;
+    public SettlementPaymentDetailVo mallSettlementPaymentDetail( @RequestBody SettlementPaymentDetailBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/settlement/payment/detail", bo);
+        SettlementPaymentDetailVo settlementPaymentDetailVo = parseZcResponse(responseDto, SettlementPaymentDetailVo.class);
+        return settlementPaymentDetailVo;
 
     }
 
-    //TODO 5.9.5	结算单确认收款
+    //5.9.5	结算单确认收款
     @PostMapping("/mall/settlement/confirm/payment")
-    public ZCR<GoodsUpdateVo> mallSettlementConfirmPayment( @RequestBody SettlementConfirmPaymentBo bo) {
-        ZCR<String> responseDto = doZcPost("/api/mall/settlement/confirm/payment", bo);
-        Boolean aBoolean = verifyResponseSign(responseDto);
-        if (!aBoolean){
-            return ZCR.fail("5001", "响应签名验证失败");
-        }
-        ZCR<GoodsUpdateVo> zcr = parseZcResponse(responseDto, GoodsUpdateVo.class);
-        return zcr;
+    public GoodsUpdateVo mallSettlementConfirmPayment( @RequestBody SettlementConfirmPaymentBo bo) {
+        ZCR responseDto = doZcPost("/api/mall/settlement/confirm/payment", bo);
+        GoodsUpdateVo goodsUpdateVo = parseZcResponse(responseDto, GoodsUpdateVo.class);
+        return goodsUpdateVo;
     }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
 }

+ 503 - 257
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/ZhongChePushController.java

@@ -1,36 +1,42 @@
 package org.dromara.external.controller.zhongche;
 
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.codec.Base64;
-import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.domain.zhongche.domain.Goods;
 import org.dromara.common.core.domain.zhongche.domain.Prices;
 import org.dromara.common.core.domain.zhongche.vo.PricesVo;
-import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.core.domain.zhongche.vo.ZhongCheTrackVo;
 import org.dromara.external.api.zhongche.domain.*;
 import org.dromara.external.api.zhongche.domain.bo.AreaStockBo;
 import org.dromara.external.api.zhongche.domain.bo.*;
 import org.dromara.external.api.zhongche.domain.vo.*;
 import org.dromara.external.api.zhongche.domain.Catalog;
-import org.dromara.external.service.IExternalProductCategoryService;
-import org.dromara.external.util.SM2SignUtil;
+import org.dromara.external.controller.zhongche.handle.MallMessageDispatcher;
+import org.dromara.external.util.SM2SignatureUtils;
+import org.dromara.external.util.SignParamUtils;
 import org.dromara.product.api.RemoteExternalOrderService;
 import org.dromara.product.api.RemoteProductService;
 import org.dromara.product.api.domain.ProductCategoryRemoteVo;
+import org.dromara.product.api.domain.zhongche.dto.StocksResult;
 import org.dromara.product.api.domain.zhongche.dto.StocksResultDto;
+import org.springframework.beans.BeanUtils;
 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;
 
+import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static org.dromara.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
@@ -39,14 +45,15 @@ import static org.dromara.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
  * 中车推送接口
  * 时间:2026/1/5,19:03
  */
+@Slf4j
 @Validated
 @RequiredArgsConstructor
 @RestController
 @RequestMapping("/api/mall/auth")
 public class ZhongChePushController {
-    private final String url = "";
     private final String key = GLOBAL_REDIS_KEY+"external:zhongche:token:";
-    private final String CLIENT_ID = "ZC_CLIENT_ID";
+    private final String CLIENT_ID = "KFZAVuIyC56";
+    private final String VERSION = "1.0.0";
 
     @DubboReference
     private final RemoteProductService remoteProductService;
@@ -54,9 +61,11 @@ public class ZhongChePushController {
     @DubboReference
     private final RemoteExternalOrderService remoteOrderService;
 
-    private final IExternalProductCategoryService externalProductCategoryService;
+    private final MallMessageDispatcher mallMessageDispatcher;
 
-    private final SM2SignUtil sm2SignUtil;
+    private final String DEVELOPER_PRIVATE_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1YybOl0QDE2e9humlm4AgI3wJ1tI+UfVRZx8kk4hfPtZjorHN8Tjq/cP07t4Yscy+R9oFci8xw0VpBbcnlaq1w=="; // 电商提供的私钥
+
+    private final String DEVELOPER_PUBLIC_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgpQdXwMi21Mg1FhWad2AQLOwfNiDHgwhootau0YerQbagCgYIKoEcz1UBgi2hRANCAATVjJs6XRAMTZ72G6aWbgCAjfAnW0j5R9VFnHySTiF8+1mOisc3xOOr9w/Tu3hixzL5H2gVyLzHDRWkFtyeVqrX";  // 电商提供的公钥
 
 
 
@@ -71,43 +80,52 @@ public class ZhongChePushController {
 
     // 获取品目列表
     @PostMapping("/catalog/query")
-    public ZCR<String> catelogQuery(@RequestBody ZCTokenBo zcTokenBo) {
-            //TODO  1. 公共请求参数校验
-            ZCR<Void> checkResult = checkPublicParams(zcTokenBo);
-            if (!"0".equals(checkResult.getRespCode())) {
-                // 校验失败,直接返回错误响应
-                return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
-            }
-            // 2.业务参数校验
-            String bizJson = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
-            if (!"{}".equals(bizJson.trim())){
-                return ZCR.fail("5007", "业务参数data格式错误,需为空JSON的Base64编码");
-            }
-
-            // TODO 3. AccessToken有效性校验
-            if (!checkAccessTokenValid(zcTokenBo.getAccessToken())) {
-                return ZCR.fail("5007", "accessToken无效或已过期");
-            }
-
-            // 4. 核心业务:查询品目列表并转换为文档要求的结构
-            List<Catalog> catalogVoList = remoteProductService.queryList()
-                .stream()
-                .map(this::convertToCatalogVo)
-                .collect(Collectors.toList());
-
-            // 5. 构造响应业务参数并Base64编码(放入ZCR的data字段)
-            CatalogsVo catalogVo = new CatalogsVo();
-            catalogVo.setCatalogs(catalogVoList);
-
-            // 业务参数→JSON→Base64编码
-            String respBizJson = JSONUtil.toJsonStr(catalogVo);
-            String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
-
-            //TODO 6. 生成响应签名(复用你的ZCR的sign字段)
-            String respSign = "";
-
-            // 7. 封装最终响应(严格复用你的ZCR.resetR)
-            return ZCR.ok(respDataBase64,respSign);
+    public ZCR catelogQuery(@RequestBody ZCTokenBo zcTokenBo) {
+        //  1. 公共请求参数校验
+        ZCR checkResult = checkPublicParams(zcTokenBo);
+        if (!"0".equals(checkResult.getRespCode())) {
+            // 校验失败,直接返回错误响应
+            return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
+        }
+        // 2.业务参数校验
+        String bizJson = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+        if (!"{}".equals(bizJson.trim())){
+            return ZCR.fail("5007", "业务参数data格式错误,需为空JSON的Base64编码");
+        }
+        //3. AccessToken有效性校验
+        ZCR zcr = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!zcr.getRespCode().equals("0")){
+            return zcr;
+        }
+        // 4. 核心业务:查询品目列表并转换为文档要求的结构  TODO这里标准品目没有做
+        List<Catalog> catalogVoList = remoteProductService.queryList()
+            .stream()
+            .map(this::convertToCatalogVo)
+            .collect(Collectors.toList());
+        // 5. 构造响应业务参数并Base64编码(放入ZCR的data字段)
+        CatalogsVo catalogVo = new CatalogsVo();
+        catalogVo.setCatalogs(catalogVoList);
+        // 业务参数→JSON→Base64编码
+        String respBizJson = JSONUtil.toJsonStr(catalogVo);
+        String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
+        // 6. 生成响应签名(核心:复用工具类,完成SM2withSM3签名,补全TODO)
+        String respSign = "";
+        try {
+            // 步骤6.1:封装空签名的成功响应实体(用于生成待签名字符串)
+            ZCR successZcr = ZCR.ok(respDataBase64, "");
+            // 步骤6.2:生成待签名字符串(筛选、排序、拼接JSON,严格贴合文档)
+            String respSignContent = SignParamUtils.getSignContent(successZcr);
+            // 步骤6.3:用电商私钥生成SM2签名(Base64编码,直接赋值给sign)
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (JsonProcessingException e) {
+            log.error("中车电商品目查询接口 - 待签名字符串生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5009", "接口响应签名生成异常(JSON转换失败)");
+        } catch (Exception e) {
+            log.error("中车电商品目查询接口 - 响应签名生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5010", "接口响应签名生成失败,请稍后重试");
+        }
+        // 7. 封装最终响应(严格复用你的ZCR.resetR)
+        return ZCR.ok(respDataBase64,respSign);
     }
 
     /**
@@ -116,7 +134,7 @@ public class ZhongChePushController {
     private Catalog convertToCatalogVo(ProductCategoryRemoteVo category) {
         Catalog catalog = new Catalog();
         // 以下字段映射需根据你的实体实际字段调整
-        catalog.setId(category.getCategoryNo());          // 品目id
+        catalog.setId(category.getId().toString());          // 品目id
         catalog.setPid(category.getParentId().toString());   // 父id
         catalog.setName(category.getCategoryName());      // 品目名称
         catalog.setLevel(category.getClassLevel().toString()); // 品目级次
@@ -150,77 +168,100 @@ public class ZhongChePushController {
      * @return
      */
     @PostMapping("/egoods/stock/query")
-    public ZCR<String> egoodsStockQuery(@RequestBody ZCTokenBo zcTokenBo) {
-            //TODO  1. 公共请求参数校验
-            ZCR<Void> checkResult = checkPublicParams(zcTokenBo);
-            if (!"0".equals(checkResult.getRespCode())) {
-                return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
+    public ZCR egoodsStockQuery(@RequestBody ZCTokenBo zcTokenBo) {
+
+        //1. 公共请求参数校验
+        ZCR checkResult = checkPublicParams(zcTokenBo);
+        if (!"0".equals(checkResult.getRespCode())) {
+            return checkResult;
+        }
+        //2. AccessToken有效性校验
+        ZCR zcr = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!zcr.getRespCode().equals("0")){
+            return zcr;
+        }
+        //  3. 业务参数解析
+        AreaStockBo areaStockBo;
+        try {
+            // 解码data字段(Base64→JSON→业务BO)
+            String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+            if (StrUtil.isBlank(decodedData)) {
+                return ZCR.fail("5011", "业务参数data不能为空");
             }
-            // TODO 2. AccessToken有效性校验
-            if (!checkAccessTokenValid(zcTokenBo.getAccessToken())) {
-                return ZCR.fail("5007", "accessToken无效或已过期");
+            areaStockBo = JSONUtil.toBean(decodedData, AreaStockBo.class);
+            if (areaStockBo == null) {
+                return ZCR.fail("5012", "业务参数data格式错误,无法解析");
             }
-            //  3. 业务参数解析
-            AreaStockBo areaStockBo;
-            try {
-                // 解码data字段(Base64→JSON→业务BO)
-                String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
-                areaStockBo = JSONUtil.toBean(decodedData, AreaStockBo.class);
-            } catch (Exception e) {
-                return ZCR.fail("5007", "业务参数data解析失败:" + e.getMessage());
+            // 3.3 业务参数必填项校验
+            if (areaStockBo.getGoods() == null || areaStockBo.getGoods().isEmpty()) {
+                return ZCR.fail("5013", "商品信息列表goods不能为空");
             }
-            //  4. 业务参数校验
-            String validateMsg = validateBizParams(areaStockBo);
-            if (StrUtil.isNotBlank(validateMsg)) {
-                return ZCR.fail("5007", validateMsg);
+            if (areaStockBo.getGoods().size() > 50) {
+                return ZCR.fail("5014", "商品信息列表goods最多支持50条");
             }
-            // 5.核心业务:库存查询
-            String areaId = areaStockBo.getAreaId();
-            Map<String, Integer> collect = areaStockBo.getGoods().stream()
-                .collect(Collectors.toMap(Goods::getGoodsId,
-                    Goods::getGoodsNum));
-            StocksResultDto stocksResultDto = remoteProductService.queryProductStock(collect,areaId);
-
-            // 6. 构造响应业务参数
-            // JSON→Base64编码(响应data字段值)
-            String respBizJson = JSONUtil.toJsonStr(stocksResultDto);
-            String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
-            // 6. 生成响应签名
-            String respSign = "";
-
-            // 7. 封装最终响应
-            return ZCR.ok(respDataBase64, respSign);
-    }
-    private String validateBizParams(AreaStockBo areaStockBo) {
-        // 1. goods列表校验
-        if (CollUtil.isEmpty(areaStockBo.getGoods())) {
-            return "商品信息goods列表不能为空";
+            // 3.4 单个商品信息校验(避免无效数据)
+            for (Goods goods : areaStockBo.getGoods()) {
+                if (StrUtil.isBlank(goods.getGoodsId()) || goods.getGoodsNum() == null || goods.getGoodsNum() <= 0) {
+                    return ZCR.fail("5015", "商品sku(goodsId)不能为空,所需库存(goodsNum)必须为正整数");
+                }
+            }
+        } catch (Exception e) {
+            return ZCR.fail("5007", "业务参数data解析失败:" + e.getMessage());
         }
-        if (areaStockBo.getGoods().size() > 50) {
-            return "商品信息goods列表最多支持50个商品";
+
+        GoodsStockVo goodsStockVo = new GoodsStockVo();
+        // 4. 核心业务:查询商品库存(封装业务逻辑,映射文档返回格式)
+        List<Stocks> stockRespList = queryGoodsStock(areaStockBo);
+        goodsStockVo.setStocks(stockRespList);
+        // 7. 业务参数→JSON→Base64编码(响应data字段要求)
+        String respBizJson = JSONUtil.toJsonStr(goodsStockVo);
+        String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
+
+        // 8. 生成响应签名(贴合签名机制,复用工具类)
+        String respSign = "";
+        try {
+            ZCR successZcr = ZCR.ok(respDataBase64, "");
+            String respSignContent = SignParamUtils.getSignContent(successZcr);
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("响应签名生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5017", "接口响应签名生成失败");
         }
 
-        // 2. 遍历校验每个商品
-        for (int i = 0; i < areaStockBo.getGoods().size(); i++) {
-            Goods goods = areaStockBo.getGoods().get(i);
-            if (StrUtil.isBlank(goods.getGoodsId())) {
-                return "第" + (i + 1) + "个商品的goodsId(商品sku)不能为空";
-            }
-            if (goods.getGoodsNum() == null || goods.getGoodsNum() <= 0) {
-                return "第" + (i + 1) + "个商品的goodsNum(所需库存)必须大于0";
-            }
+        // 9. 封装最终响应(符合文档要求)
+        return ZCR.ok(respDataBase64, respSign);
+    }
+
+    /**
+     * 核心业务:查询商品库存,映射文档返回格式(包含库存状态、剩余数量等规则)
+     */
+    private List<Stocks> queryGoodsStock(AreaStockBo bo) {
+        String areaId = bo.getAreaId() == null ? "" : bo.getAreaId();
+
+        Map<String, Integer> goodsMap = new HashMap<>();
+        for (Goods goodsReq : bo.getGoods()) {
+            String goodsId = goodsReq.getGoodsId();
+            Integer goodsNum = goodsReq.getGoodsNum();
+            goodsMap.put(goodsId, goodsNum); // 对应Dubbo服务要求:key=商品ID,value=所需库存
         }
 
-        //TODO 3. areaId校验(虚拟库存可不填,有地区库存则必填)
-        //
-        /*boolean isVirtualStock = false; // 假设从配置获取:是否虚拟库存
-        if (!isVirtualStock && StrUtil.isBlank(areaStockBo.getAreaId())) {
-            return "非虚拟库存模式下,地区id areaId不能为空";
-        }*/
+        // 3. 调用Dubbo服务,获取库存结果(你的remoteProductService)
+        StocksResultDto stocksResultDto = remoteProductService.queryProductStock(goodsMap, areaId);
+
+        List<Stocks> goodsStockRespList = new ArrayList<>();
+        if (stocksResultDto == null || stocksResultDto.getStocks() == null || stocksResultDto.getStocks().isEmpty()) {
+            // 无库存数据返回,遍历入参商品,按「未查询到」处理
+            for (StocksResult stocksResult : stocksResultDto.getStocks()) {
+                Stocks stocks =new Stocks();
+                BeanUtils.copyProperties(stocksResult, stocks);
+                goodsStockRespList.add(stocks);
+            }
+        }
 
-        return null; // 校验通过
+        return goodsStockRespList;
     }
 
+
     //TODO 查询商品价格
     /*
         //请求业务参数
@@ -230,91 +271,174 @@ public class ZhongChePushController {
         PricesVo pricesVo = new PricesVo();
      */
     @PostMapping("/egoods/price/query")
-    public ZCR<String> egoodsPriceQuery(@RequestBody ZCTokenBo zcTokenBo) {
-            //TODO  1. 公共请求参数校验
-            ZCR<Void> checkResult = checkPublicParams(zcTokenBo);
-            if (!"0".equals(checkResult.getRespCode())) {
-                return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
-            }
+    public ZCR egoodsPriceQuery(@RequestBody ZCTokenBo zcTokenBo) {
+        //1. 公共请求参数校验
+        ZCR checkResult = checkPublicParams(zcTokenBo);
+        if (!"0".equals(checkResult.getRespCode())) {
+            return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
+        }
+        //2. AccessToken有效性校验
+        ZCR zcr = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!zcr.getRespCode().equals("0")){
+            return zcr;
+        }
+        // 3. 业务参数解析
+        GoodsPrieceBo goods;
+        List<String> goodsIdList;
+        // 解码data字段(Base64→JSON→业务BO)
+        String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+        if (StrUtil.isBlank(decodedData)) {
+            return ZCR.fail("5021", "业务参数data不能为空");
+        }
+        goods = JSONUtil.toBean(decodedData, GoodsPrieceBo.class);
+        if (goods == null || StrUtil.isBlank(goods.getGoodsIds())) {
+            return ZCR.fail("5022", "商品sku(goodsIds)不能为空");
+        }
+        // 3.3 分割商品sku,转换为列表(多个用,分隔)
+        goodsIdList = Arrays.stream(goods.getGoodsIds().split(","))
+            .map(String::trim)
+            .filter(StrUtil::isNotBlank)
+            .collect(Collectors.toList());
+        if (goodsIdList.isEmpty()) {
+            return ZCR.fail("5023", "商品sku(goodsIds)格式错误,有效sku不能为空");
+        }
+        // 4. 核心业务:调用Dubbo服务查询商品价格(适配你的业务逻辑)
+        PricesVo pricesVo = queryGoodsPrice(goodsIdList);
 
-            // TODO 2. AccessToken有效性校验
-            if (!checkAccessTokenValid(zcTokenBo.getAccessToken())) {
-                return ZCR.fail("5007", "accessToken无效或已过期");
-            }
+        // 5. 构造响应业务参数并Base64编码(符合文档data字段要求)
+        String respBizJson = JSONUtil.toJsonStr(pricesVo);
+        String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
 
-            // 3. 业务参数解析
-            GoodsPrieceBo goods;
-            // 解码data字段(Base64→JSON→业务BO)
-            String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
-            goods = JSONUtil.toBean(decodedData, GoodsPrieceBo.class);
+        // 6. 生成响应签名(复用工具类,贴合签名机制)
+        String respSign = "";
+        try {
+            ZCR successZcr = ZCR.ok(respDataBase64, "");
+            String respSignContent = SignParamUtils.getSignContent(successZcr);
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("商品价格查询 - 响应签名生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5025", "接口响应签名生成失败");
+        }
+        // 7. 封装最终响应(符合文档要求)
+        return ZCR.ok(respDataBase64, respSign);
+    }
 
-            // 4. 业务参数校验
-            String validateMsg = validateGoodsPriceParams(goods);
-            if (StrUtil.isNotBlank(validateMsg)) {
-                return ZCR.fail("5007", validateMsg);
+    /**
+     * 核心业务:查询商品价格,映射文档返回格式
+     */
+    private PricesVo queryGoodsPrice(List<String> goodsIdList) {
+        // 1. 初始化响应结果
+        PricesVo pricesVo = new PricesVo();
+        pricesVo.setPrices(new ArrayList<>());
+
+        // 2. 调用Dubbo服务查询商品价格(替换为你的真实Dubbo服务方法)
+        // 示例:假设你的Dubbo服务提供了查询商品价格的方法
+        Map<String, Prices> priceMap = remoteProductService.queryProductPrice(goodsIdList);
+
+        // 3. 遍历商品sku,封装价格信息(贴合文档规则)
+        for (String goodsId : goodsIdList) {
+            Prices priceResp = new Prices();
+            priceResp.setGoodsId(goodsId);
+
+            // 3.1 获取Dubbo查询结果,判断是否查询到
+            Prices productPrice = priceMap.get(goodsId);
+            if (productPrice == null) {
+                // 未查询到,按文档规则赋值-1(BigDecimal类型)
+                priceResp.setDsPrice(new BigDecimal(-1));
+                priceResp.setPrice(new BigDecimal(-1));
+                priceResp.setTaxFreePrice(null);
+                priceResp.setTax(null);
+                priceResp.setTaxCode("");
+                pricesVo.getPrices().add(priceResp);
+                continue;
             }
-            // 5. 查询商品价格
-            List<String> goodsIds = List.of(goods.toString().split(","));
-            List<Prices> prices = remoteProductService.queryProductPrice(goodsIds);
 
+            // 3.2 填充查询到的价格信息(保证精度,最多精确到分)
+            // 电商价格(dsPrice)
+            BigDecimal dsPrice = productPrice.getDsPrice() == null ? new BigDecimal(-1) : productPrice.getDsPrice();
+            priceResp.setDsPrice(dsPrice); // 保留2位小数,四舍五入
+
+            // 协议价格(price)
+            BigDecimal protocolPrice = productPrice.getPrice() == null ? new BigDecimal(-1) : productPrice.getPrice();
+            priceResp.setPrice(protocolPrice);
+            priceResp.setTaxFreePrice(null);
+            priceResp.setTax(productPrice.getTax());
+            // 税收编码(非必填)
+            priceResp.setTaxCode(null);
+
+            // 3.3 添加到响应列表
+            pricesVo.getPrices().add(priceResp);
+        }
 
-            // 6. 构造响应业务参数
-            // 封装响应根对象(包含prices列表)
-            PricesVo pricesVo = new PricesVo();
-            pricesVo.setPrices(prices);
-            System.out.println(pricesVo);
+        return pricesVo;
+    }
 
-            // JSON→Base64编码(响应data字段值)
-            String respBizJson = JSONUtil.toJsonStr(pricesVo);
-            String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
+    // 4.5查询物流信息(物流信息尚未实现)
+    @PostMapping("/get/track")
+    public ZCR getTrack(@RequestBody ZCTokenBo zcTokenBo) {
+        // 1. 公共请求参数校验(含签名、版本、clientId等,复用已有逻辑)
+        ZCR checkResult = checkPublicParams(zcTokenBo);
+        if (!"0".equals(checkResult.getRespCode())) {
+            return checkResult;
+        }
 
-            //  7. 生成响应签名
-            Map<String, String> map = new HashMap<>();
-            map.put("respCode", "0");
-            map.put("data", respBizJson);
-            String respSign = JsonUtils.toJsonString(map);
+        //2. AccessToken有效性校验
+        ZCR zcr = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!zcr.getRespCode().equals("0")){
+            return zcr;
+        }
 
-            //8. 封装最终响应
-            return ZCR.ok(respDataBase64, respSign);
-    }
-    /**
-     * 业务参数校验(匹配4.4.4.1文档规则)
-     */
-    private String validateGoodsPriceParams(GoodsPrieceBo goods) {
-        // 1. goodsIds非空校验
-        if (StrUtil.isBlank(goods.getGoodsIds())) {
-            return "商品sku(goodsIds)不能为空";
-        }
-
-        // 2. 拆分goodsIds并校验格式/数量
-        String[] goodsIdArray = goods.getGoodsIds().split(",");
-        if (goodsIdArray.length == 0) {
-            return "商品sku(goodsIds)格式错误,多个sku需用英文逗号分隔";
-        }
-        // 3. 校验每个sku非空
-        for (int i = 0; i < goodsIdArray.length; i++) {
-            String goodsId = goodsIdArray[i].trim();
-            if (StrUtil.isBlank(goodsId)) {
-                return "第" + (i + 1) + "个商品sku为空,请检查goodsId格式";
+        // 3. 业务参数解析与校验(贴合文档要求)
+        DeliveryTrackBo bizReq;
+        try {
+            // 3.1 Base64解码data字段
+            String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+            if (StrUtil.isBlank(decodedData)) {
+                return ZCR.fail("5031", "业务参数data不能为空");
+            }
+
+            // 3.2 JSON转业务请求实体
+            bizReq = JSONUtil.toBean(decodedData, DeliveryTrackBo.class);
+            if (bizReq == null) {
+                return ZCR.fail("5032", "业务参数data格式错误,无法解析");
+            }
+            // 3.3 业务参数必填项校验
+            if (StrUtil.isBlank(bizReq.getOutgoingCode()) || bizReq.getOutgoingCode().length() > 20) {
+                return ZCR.fail("5033", "发货单编号(outgoingCode)不能为空,且长度不超过20");
+            }
+            if (StrUtil.isBlank(bizReq.getWaybillType()) || !List.of("0", "1").contains(bizReq.getWaybillType())) {
+                return ZCR.fail("5034", "运单类型(waybillType)必填,且仅支持0(订单)、1(换新单)");
             }
+        } catch (Exception e) {
+            log.error("物流查询 - 业务参数解析/校验失败,data:{}", zcTokenBo.getData(), e);
+            return ZCR.fail("5035", "业务参数data解析失败:" + e.getMessage());
         }
-        return null; // 校验通过
-    }
 
-    //TODO 4.5查询物流信息(物流信息尚未实现)
-    @PostMapping("/get/track")
-    public ZCR<TrackVo> getTrack(@RequestBody ZCTokenBo zcTokenBo) {
-        //请求业务参数
-        DeliveryTrack deliveryTrack = new DeliveryTrack();
+        //******4. 核心业务:调用Dubbo服务查询物流信息   我们没有换新单 所以第二个参数先抛弃掉
+        ZhongCheTrackVo trackVo = remoteOrderService.queryLogisticsTrack(bizReq.getOutgoingCode(), bizReq.getWaybillType());
+        if (trackVo == null){
+            return ZCR.fail("5035", "物流信息为空");
+        }
+        // 6. 业务参数→JSON→Base64编码(符合文档data字段要求)
+        String respBizJson = JSONUtil.toJsonStr(trackVo);
+        String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
 
-        //响应业务参数
-        TrackVo trackVo = new TrackVo();
-        DeliveryTrack deliveryTrack1 = new DeliveryTrack();
+        // 7. 生成响应签名(复用工具类,贴合签名机制)
+        String respSign = "";
+        try {
+            ZCR successZcr = ZCR.ok(respDataBase64, "");
+            String respSignContent = SignParamUtils.getSignContent(successZcr);
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("物流查询 - 响应签名生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5036", "接口响应签名生成失败");
+        }
 
-        return null;
+        // 8. 封装最终响应(符合文档要求)
+        return ZCR.ok(respDataBase64, respSign);
     }
 
-    //TODO 4.6 查询电商平台订单号
+    //4.6 查询电商平台订单号
     /*
         //请求业务参数
         MallOrderNoQueryBo mallOrderNoQueryBo = new MallOrderNoQueryBo();
@@ -323,87 +447,209 @@ public class ZhongChePushController {
         MallOrderNoVo mallOrderNoVo = new MallOrderNoVo();
      */
     @PostMapping("/get/mallOrderNo")
-    public ZCR<String> getMallOrderNo(@RequestBody ZCTokenBo zcTokenBo) {
+    public ZCR getMallOrderNo(@RequestBody ZCTokenBo zcTokenBo) {
         //1. 公共请求参数校验
-        ZCR<Void> checkResult = checkPublicParams(zcTokenBo);
+        ZCR checkResult = checkPublicParams(zcTokenBo);
         if (!"0".equals(checkResult.getRespCode())) {
             return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
         }
-
-        // TODO 2. AccessToken有效性校验
-        if (!checkAccessTokenValid(zcTokenBo.getAccessToken())) {
-            return ZCR.fail("5007", "accessToken无效或已过期");
+        // 2. 请求签名校验(必须)
+        boolean verifyResult;
+        try {
+            verifyResult = SignParamUtils.verifyRequestSign(
+                zcTokenBo,
+                DEVELOPER_PUBLIC_KEY   // 中车给你的公钥
+            );
+        } catch (Exception e) {
+            log.error("查询电商订单号 - 请求验签异常", e);
+            return ZCR.fail("5005", "请求签名校验异常");
         }
 
-        //2. 业务参数解析(Base64→JSON→BO)
+        if (!verifyResult) {
+            return ZCR.fail("5006", "请求签名校验失败");
+        }
+        //3. AccessToken 有效性校验
+        ZCR zcr = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!zcr.getRespCode().equals("0")){
+            return zcr;
+        }
+        // 4. 业务参数解析(Base64 → JSON → BO)
         MallOrderNoQueryBo orderNoQueryBo;
-
-        // 解码data字段(核心:Base64解码为JSON字符串)
-        String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
-        // JSON转业务BO(你已创建的MallOrderNoQueryBo)
-        orderNoQueryBo = JSONUtil.toBean(decodedData, MallOrderNoQueryBo.class);
-
-        //3. 业务参数校验
-        String validateMsg = validateOrderParams(orderNoQueryBo);
-        if (StrUtil.isNotBlank(validateMsg)) {
-            return ZCR.fail("5007", validateMsg);
+        try {
+            String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+            orderNoQueryBo = JSONUtil.toBean(decodedData, MallOrderNoQueryBo.class);
+        } catch (Exception e) {
+            log.error("查询电商订单号 - 业务参数解析失败,data={}", zcTokenBo.getData(), e);
+            return ZCR.fail("5008", "业务参数解析失败");
         }
 
-        //5.查询电商订单号
+        // 5. 查询电商平台订单号(你的内部逻辑)
         String orderNo = orderNoQueryBo.getOrderNo();
-        String mallOrderNo = remoteOrderService.getOrderNo(orderNo);
-        // 6. 构造响应业务参数
+        String mallOrderNo;
+        try {
+            mallOrderNo = remoteOrderService.getOrderNo(orderNo);
+        } catch (Exception e) {
+            log.error("查询电商订单号 - 查询失败,orderNo={}", orderNo, e);
+            return ZCR.fail("5010", "查询电商订单号失败");
+        }
+        // 6. 构造业务响应 data(VO → JSON → Base64)
         MallOrderNoVo orderNoVo = new MallOrderNoVo();
         orderNoVo.setMallOrderNo(mallOrderNo);
-        // VO→JSON→Base64编码(响应的data字段值)
+
         String respBizJson = JSONUtil.toJsonStr(orderNoVo);
         String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
-        //7. 生成响应签名
-        String respSign = "";
-        //8. 封装最终响应
-        return ZCR.ok(respDataBase64, respSign);
-    }
-    private String validateOrderParams(MallOrderNoQueryBo orderNoQueryBo) {
-        // 1. orderNo非空校验
-        if (StrUtil.isBlank(orderNoQueryBo.getOrderNo())) {
-            return "中车电子商城订单编号(orderNo)不能为空";
-        }
 
-        // 2. orderNo长度校验(≤20)
-        if (orderNoQueryBo.getOrderNo().length() > 20) {
-            return "中车电子商城订单编号(orderNo)长度不能超过20位";
+        // 7. 生成响应签名
+        ZCR resp = ZCR.ok(respDataBase64);
+        String respSign;
+        try {
+            String respSignContent = SignParamUtils.getSignContent(resp);
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("查询电商订单号 - 响应签名生成失败,业务JSON={}", respBizJson, e);
+            return ZCR.fail("5036", "接口响应签名生成失败");
         }
 
-        return null; // 校验通过
+        // 9. 回填 sign 并返回
+        resp.setSign(respSign);
+        return resp;
     }
 
-    //TODO 4.7 查询电商平台售后单号
+    //4.7 查询电商平台售后单号
     @PostMapping("/get/mallAfterSaleNo")
-    public ZCR<MallAfterSaleNoVo> getMallAfterSaleNo(@RequestBody ZCTokenBo zcTokenBo) {
-        //请求业务参数
-        MallAfterSaleNoQueryBo mallAfterSaleNoQueryBo = new MallAfterSaleNoQueryBo();
+    public ZCR getMallAfterSaleNo(@RequestBody ZCTokenBo zcTokenBo) {
+        // 1. 公共请求参数校验
+        ZCR checkResult = checkPublicParams(zcTokenBo);
+        if (!"0".equals(checkResult.getRespCode())) {
+            return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
+        }
 
-        //响应业务参数
-        MallAfterSaleNoVo mallAfterSaleNoVo = new MallAfterSaleNoVo();
+        //2. AccessToken 有效性校验
+        ZCR zcr = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!zcr.getRespCode().equals("0")){
+            return zcr;
+        }
 
-        return null;
+        // 3. 业务参数解析(Base64 → JSON → BO)
+        MallAfterSaleNoQueryBo queryBo;
+        try {
+            String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+            queryBo = JSONUtil.toBean(decodedData, MallAfterSaleNoQueryBo.class);
+        } catch (Exception e) {
+            log.error("售后单号查询 - 业务参数解析失败", e);
+            return ZCR.fail("5007", "业务参数解析失败");
+        }
+
+        // 4. 业务参数校验
+        if (queryBo == null || StrUtil.isBlank(queryBo.getAfterSaleNo())) {
+            return ZCR.fail("5007", "afterSaleNo不能为空");
+        }
+
+        // 5. 查询电商平台售后单号(内部逻辑你自己实现)
+        String afterSaleNo = queryBo.getAfterSaleNo();
+        String mallAfterSaleNo = remoteOrderService.getReturnOrderNo(afterSaleNo);
+
+        if (StrUtil.isBlank(mallAfterSaleNo)) {
+            return ZCR.fail("5004", "未查询到对应的电商平台售后单号");
+        }
+
+        // 6. 构造响应业务参数
+        MallAfterSaleNoVo vo = new MallAfterSaleNoVo();
+        vo.setMallAfterSaleNo(mallAfterSaleNo);
+
+        String respBizJson = JSONUtil.toJsonStr(vo);
+        String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
+
+        // 7. 生成响应签名(关键补全点)
+        String respSign;
+        try {
+            // 先构造不带 sign 的响应对象
+            ZCR successZcr = ZCR.ok(respDataBase64);
+
+            // 按平台规则生成待签名字符串
+            String respSignContent = SignParamUtils.getSignContent(successZcr);
+
+            // 使用【电商私钥】进行 SM2 签名
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("售后单号查询 - 响应签名生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5036", "接口响应签名生成失败");
+        }
+
+        // 8. 返回最终响应
+        return ZCR.ok(respDataBase64, respSign);
     }
 
     //TODO 4.8 消息监听     消息类型枚举没做
     @PostMapping("/message/listening")
-    public ZCR<MessageVo> listener(@RequestBody ZCTokenBo zcTokenBo) {
-        //请求业务参数
-        MessageBo messageBo = new MessageBo();
+    public ZCR listener(@RequestBody ZCTokenBo zcTokenBo) {
+        // 1. 公共请求参数校验
+        ZCR checkResult = checkPublicParams(zcTokenBo);
+        if (!"0".equals(checkResult.getRespCode())) {
+            return ZCR.fail(checkResult.getRespCode(), checkResult.getRespMsg());
+        }
 
-        //响应业务参数
-        MessageVo messageVo = new MessageVo();
+        // 2. accessToken 校验
+        ZCR tokenCheck = checkAccessTokenValid(zcTokenBo.getAccessToken());
+        if (!"0".equals(tokenCheck.getRespCode())) {
+            return tokenCheck;
+        }
+        //TODO 假设解析出电商用户名
+        String accountName = "123456";
+        // 3. 业务参数解析
+        MessageBo messageBo;
+        try {
+            String decodedData = Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+            messageBo = JSONUtil.toBean(decodedData, MessageBo.class);
+            messageBo.setAccountName(accountName);
+        } catch (Exception e) {
+            log.error("消息监听 - 业务参数解析失败", e);
+            return ZCR.fail("5007", "业务参数解析失败");
+        }
+        // 4. 业务参数必填校验
+        if (messageBo == null
+            || StrUtil.isBlank(messageBo.getId())
+            || StrUtil.isBlank(messageBo.getType())
+            || messageBo.getContent() == null
+            || StrUtil.isBlank(messageBo.getTime())) {
+            return ZCR.fail("5007", "消息业务参数不完整");
+        }
+
+        // 5. 按消息类型处理业务
+        MessageVo messageVo;
+        try {
+            messageVo = mallMessageDispatcher.dispatch(messageBo);
+        } catch (Exception e) {
+            log.error("消息处理异常,messageId={}", messageBo.getId(), e);
+            return ZCR.fail("5007", "消息处理失败");
+        }
+        // 防御式兜底
+        if (messageVo == null) {
+            messageVo = new MessageVo("0", "消息处理无返回结果");
+        }
+
+        String respBizJson = JSONUtil.toJsonStr(messageVo);
+        String respDataBase64 = Base64.encode(respBizJson, StandardCharsets.UTF_8);
+
+        // 7. 生成响应签名(和 4.7 一模一样)
+        String respSign;
+        try {
+            ZCR successZcr = ZCR.ok(respDataBase64);
+            String respSignContent = SignParamUtils.getSignContent(successZcr);
+            respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        } catch (Exception e) {
+            log.error("消息监听 - 响应签名生成失败,业务JSON:{}", respBizJson, e);
+            return ZCR.fail("5036", "接口响应签名生成失败");
+        }
+
+        // 8. 返回响应
+        return ZCR.ok(respDataBase64, respSign);
 
-        return null;
     }
 
     //TODO 4.9 非必接模块接入校验
     @PostMapping("/notRequireApi/check")
-    public ZCR<ModuleCheckVo> notRequireApiCheck(@RequestBody ZCTokenBo zcTokenBo) {
+    public ZCR notRequireApiCheck(@RequestBody ZCTokenBo zcTokenBo) {
         //请求业务参数
         ModuleCheckBo moduleCheckBo = new ModuleCheckBo();
 
@@ -415,7 +661,7 @@ public class ZhongChePushController {
 
     //TODO 4.10 	查询运费
     @PostMapping("egoods/getfreight")
-    public ZCR<FreightVo> getFreight(@RequestBody ZCTokenBo zcTokenBo) {
+    public ZCR getFreight(@RequestBody ZCTokenBo zcTokenBo) {
         //请求业务参数
         AreaStockBo areaStock = new AreaStockBo();
 
@@ -429,7 +675,7 @@ public class ZhongChePushController {
     /**
      * 校验公共请求参数(基于你的ZCTokenBo)
      */
-    private ZCR<Void> checkPublicParams(ZCTokenBo zcTokenBo) {
+    private ZCR checkPublicParams(ZCTokenBo zcTokenBo) {
         // 1. 必填项非空校验(严格按文档4.2.4)
         if (StrUtil.isBlank(zcTokenBo.getVersion())) {
             return ZCR.fail("5007", "接口版本version不能为空");
@@ -447,32 +693,36 @@ public class ZhongChePushController {
             return ZCR.fail("5007", "签名sign不能为空");
         }
 
-        // 2. TODO 版本校验(固定1.0.0)
-        /*if (!"1.0.0".equals(zcTokenBo.getVersion())) {
+        // 2.版本校验(固定1.0.0)
+        if (!VERSION.equals(zcTokenBo.getVersion())) {
             return ZCR.fail("1008", "仅支持接口版本1.0.0");
-        }*/
+        }
 
         // 3. 时间戳格式校验(14位)
-        if (zcTokenBo.getTimestamp().length() != 14) {
-            return ZCR.fail("5007", "时间戳格式错误,需为14位YYYYMMDDHHMMSS");
+        if (!ReUtil.isMatch("\\d{14}", zcTokenBo.getTimestamp())) {
+            return ZCR.fail("5007", "时间戳格式错误,需为14位数字YYYYMMDDHHMMSS");
         }
-        if (zcTokenBo.getClientId() !=CLIENT_ID){
+        // 4. clientId 校验
+        if (!CLIENT_ID.equals(zcTokenBo.getClientId())){
             return ZCR.fail("5007", "clientId错误");
         }
 
-        // 4.TODO  签名校验(验证中车请求的签名)
-        /*try {
-            boolean signValid = sm2SignUtil.sm2Verify(
-                JSONUtil.toJsonStr(SM2SignUtil.beanToFilteredMap(zcTokenBo)).getBytes(),
-                zcTokenBo.getSign(),
-                "中车提供的公钥(16进制)" // 替换为真实公钥
-            );
+        //
+        // 5. 签名校验
+        try {
+            // 防御性 Base64 校验
+            Base64.decodeStr(zcTokenBo.getData(), StandardCharsets.UTF_8);
+            // 调用 SignParamUtils 验证请求签名,直接复用之前的逻辑
+            boolean signValid = SignParamUtils.verifyRequestSign(zcTokenBo, DEVELOPER_PUBLIC_KEY);
             if (!signValid) {
-                return ZCR.fail("1010", "签名验证失败");
+                // 验签失败,返回错误响应
+                return ZCR.fail("5007", "接口签名错误(验签失败)");
             }
         } catch (Exception e) {
-            return ZCR.fail("1011", "签名校验异常:" + e.getMessage());
-        }*/
+            // 捕获验签过程中的异常(如JSON转换、Base64解码、SM2算法异常等)
+            log.error("中车电商接口签名校验异常,请求参数:{}", JSONUtil.toJsonStr(zcTokenBo), e);
+            return ZCR.fail("5007", "接口签名校验异常,请稍后重试");
+        }
 
         // 校验通过
         return ZCR.ok(null);
@@ -481,20 +731,16 @@ public class ZhongChePushController {
 
 
     /**
-     * 校验AccessToken有效性(替换为你的真实逻辑)
+     * 校验AccessToken有效性
      */
-    private boolean checkAccessTokenValid(String accessToken) {
-        // 临时占位,需替换
-        return true;
+    private ZCR checkAccessTokenValid(String accessToken) {
+        if(ObjectUtil.isEmpty(accessToken)){
+            return ZCR.fail("5006","token不能为空");
+        }
+        if(StpUtil.getTokenTimeout(accessToken) == -2l){
+            return ZCR.fail("5005","token_expired");
+        }
+        return ZCR.ok( null);
     }
 
-
-
-    /**
-     * 生成响应签名(按中车签名规则)
-     */
-    private String generateRespSign(String respDataBase64, String clientId){
-        // 临时占位,需替换
-        return "";
-    }
 }

+ 40 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/MallMessageDispatcher.java

@@ -0,0 +1,40 @@
+package org.dromara.external.controller.zhongche.handle;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+@Slf4j
+public class MallMessageDispatcher {
+
+    private final Map<MallMessageTypeEnum, MallMessageHandler> handlerMap = new HashMap<>();
+
+    public MallMessageDispatcher(List<MallMessageHandler> handlers) {
+        for (MallMessageHandler handler : handlers) {
+            handlerMap.put(handler.supportType(), handler);
+        }
+    }
+
+    public MessageVo dispatch(MessageBo messageBo) {
+        MallMessageTypeEnum type = MallMessageTypeEnum.of(messageBo.getType());
+        if (type == null) {
+            log.warn("未知消息类型:{}", messageBo.getType());
+            return new MessageVo("0", "未知消息类型");
+        }
+
+        MallMessageHandler handler = handlerMap.get(type);
+        if (handler == null) {
+            log.warn("未找到消息处理器,type={}", type);
+            return new MessageVo("0", "未找到消息处理器");
+        }
+
+        return handler.handle(messageBo);
+    }
+}

+ 18 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/MallMessageHandler.java

@@ -0,0 +1,18 @@
+package org.dromara.external.controller.zhongche.handle;
+
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.enums.MallMessageTypeEnum;
+
+public interface MallMessageHandler {
+
+    /**
+     * 当前处理器支持的消息类型
+     */
+    MallMessageTypeEnum supportType();
+
+    /**
+     * 处理消息
+     */
+    MessageVo handle(MessageBo messageBo);
+}

+ 154 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/AccountActiveMessageHandler.java

@@ -0,0 +1,154 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.GoodsImportItem;
+import org.dromara.external.api.zhongche.domain.aftersale.bo.AfterSaleDetailBo;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.GoodsImportBo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.GoodsImportVo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.domain.vo.ExternalProductVo;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.dromara.product.api.RemoteProductService;
+import org.dromara.product.api.domain.zhongche.dto.ProductAggregateDto;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * author
+ * 时间:2026/2/3,19:30
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class AccountActiveMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+
+    private final IExternalProductService externalProductService;
+
+    private final RemoteProductService remoteProductService;
+
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ACCOUNT_ACTIVE;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+        String username = String.valueOf(content.get("username"));
+        List<ExternalProductVo> allProductList = externalProductService.getAllProductList();
+        if (CollUtil.isEmpty(allProductList)) {
+            log.info("商品导入:无可导入商品,username={}", username);
+            return new MessageVo("0","无可导入商品");
+        }
+
+        List<Long> productIds = allProductList.stream()
+                .map(ExternalProductVo::getProductId)
+                .toList();
+
+        List<ProductAggregateDto> productInfo = remoteProductService.getProductInfo(productIds);
+
+
+        Map<Long, ExternalProductVo> externalMap = allProductList.stream()
+                .collect(Collectors.toMap(
+                        ExternalProductVo::getProductId,
+                        Function.identity(),
+                        (a, b) -> a
+                ));
+
+        List<GoodsImportItem> goodsList = productInfo.stream().map(p -> {
+            GoodsImportItem item = new GoodsImportItem();
+
+            ExternalProductVo ext = externalMap.get(p.getProductId());
+
+            // ===== 商品唯一标识 =====
+            item.setGoodsId(p.getProductId().toString());
+
+            // ===== 品目(只能来自 ExternalProductVo)=====
+            item.setCatalogId(ext.getCategoryId().toString());
+            item.setCatalogName(ext.getCategoryName());
+            item.setStandardCatalogId(ext.getExternalCategoryId().toString());
+            item.setStandardCatalogName(ext.getStandardCatalogName());
+
+            // ===== 商品基础 =====
+            item.setName(p.getName());
+            item.setUnit(p.getUnit());
+            item.setStock(p.getStock());
+
+            // ===== 价格 =====
+            item.setDsPrice(p.getDsPrice());
+            item.setPrice(p.getPrice());
+
+            // ===== 税 =====
+            item.setTax(p.getTax());
+            item.setTaxCode(p.getTaxCode());
+
+            // ===== 品牌 =====
+            if (p.getBrandName() != null){
+                item.setBrandName(p.getBrandName());
+            }else {
+                item.setBrandNameEn(p.getBrandNameEn());
+            }
+
+            // ===== 图片 / 描述 / 规格 =====
+            item.setBarImgUrls(p.getBarImgUrls());
+            item.setDescription(p.getDescription());
+            item.setProperties(p.getProperties());
+
+            // ===== 自营 =====
+            item.setIsSelfOperated(p.getIsSelfOperated());
+
+            return item;
+        }).toList();
+
+        int size = goodsList.size();
+
+        for (int i = 0; i < size; i += 50) {
+            int end = Math.min(i + 50, size);
+            List<GoodsImportItem> batchGoods = goodsList.subList(i, end);
+
+            GoodsImportBo bo = new GoodsImportBo();
+            bo.setAccount(username);
+            bo.setGoods(batchGoods);
+            GoodsImportVo resp = zhongChePullController.egoodsImport(bo);
+            // ===== 结果校验 =====
+            if (resp == null) {
+                log.error("商品导入失败,batch={}~{},中车无响应", i, end);
+                return new MessageVo("0", "商品导入失败:中车无响应");
+            }
+
+            if (resp.getResult() == 0) {
+                log.error("商品导入失败,batch={}~{},原因={}",
+                        i, end,
+                        resp.getMessage()
+                );
+                return new MessageVo("0", "商品导入失败:" + resp.getMessage());
+            }
+            // ===== 本批次推送成功,更新推送状态 =====
+            List<Long> pushedProductIds = batchGoods.stream()
+                .map(item -> Long.valueOf(item.getGoodsId()))
+                .toList();
+
+            externalProductService.lambdaUpdate()
+                .in(ExternalProduct::getProductId, pushedProductIds)
+                .set(ExternalProduct::getPushStatus, 1L)
+                .update();
+        }
+
+        return new MessageVo("1","商品导入成功");
+    }
+}

+ 45 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/AfterSaleApplyMessageHandler.java

@@ -0,0 +1,45 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.bo.AfterSaleDetailBo;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.ZhongChePushController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * author
+ * 时间:2026/2/3,19:00
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class AfterSaleApplyMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.AFTER_SALE_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String afterSaleNo = (String) messageBo.getContent().get("afterSaleNo");
+        AfterSaleDetailBo bo = new AfterSaleDetailBo();
+        bo.setAfterSaleNo(afterSaleNo);
+        AfterSaleDetailVo afterSaleDetailVo = zhongChePullController.mallAftersaleDetail(bo);
+
+
+        if (afterSaleDetailVo != null){
+            return new MessageVo("1");
+        }
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 41 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/AfterSaleCancelMessageHandler.java

@@ -0,0 +1,41 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:08
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class AfterSaleCancelMessageHandler implements MallMessageHandler {
+
+
+    private final RemoteExternalOrderService remoteExternalOrderService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.AFTER_SALE_CANCEL;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String afterSaleNo = (String) messageBo.getContent().get("afterSaleNo");
+        String cancelReason = (String) messageBo.getContent().get("cancelReason");
+
+        boolean b = remoteExternalOrderService.cancelReturnOrder(afterSaleNo, cancelReason);
+
+        if (b){
+            return new MessageVo("1");
+        }
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 33 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillAbnormalPassMessageHandler.java

@@ -0,0 +1,33 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:47
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillAbnormalPassMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ABNORMAL_PASS;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String abnormalId = (String) messageBo.getContent().get("abnormalId");
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 34 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillConfirmMessageHandler.java

@@ -0,0 +1,34 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:39
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillConfirmMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.AFTER_SALE_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String billId = (String) messageBo.getContent().get("billId");
+        String remark = (String) messageBo.getContent().get("remark");
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 33 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillCreateMessageHandler.java

@@ -0,0 +1,33 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:43
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillCreateMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.BILL_CREATE;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String billId = (String) messageBo.getContent().get("billId");
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 34 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillFinishMessageHandler.java

@@ -0,0 +1,34 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:45
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillFinishMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.BILL_FINISH;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String billId = (String) messageBo.getContent().get("billId");
+
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 35 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillModifyMessageHandler.java

@@ -0,0 +1,35 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:40
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillModifyMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.AFTER_SALE_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String billId = (String) messageBo.getContent().get("billId");
+        String purchaserRemark = (String) messageBo.getContent().get("purchaserRemark");
+
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 35 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillRejctPassMessageHandler.java

@@ -0,0 +1,35 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:49
+ */
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillRejctPassMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ABNORMAL_REJECT;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String abnormalId = (String) messageBo.getContent().get("abnormalId");
+
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 41 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillRuleCreateMessageHandler.java

@@ -0,0 +1,41 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.bo.AfterSaleDetailBo;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:32
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillRuleCreateMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.AFTER_SALE_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String billRuleNo = (String) messageBo.getContent().get("billRuleNo");
+        String billCycle = (String) messageBo.getContent().get("billCycle");
+        String billDay = (String) messageBo.getContent().get("billDay");
+        //格式:2020-09-29 21:20:58
+        String firstStartTime = (String) messageBo.getContent().get("firstStartTime");
+        boolean cashIncluded = (boolean) messageBo.getContent().get("cashIncluded");
+        String orderCompleteDay = (String) messageBo.getContent().get("orderCompleteDay");
+        String ruleStatus = (String) messageBo.getContent().get("ruleStatus");
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 34 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/BillWaitInvoiceMessageHandler.java

@@ -0,0 +1,34 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.aftersale.vo.AfterSaleDetailVo;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,19:42
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class BillWaitInvoiceMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.AFTER_SALE_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String batchNo = (String) messageBo.getContent().get("batchNo");
+
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 52 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsAuditPassMessageHandler.java

@@ -0,0 +1,52 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,19:48
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class GoodsAuditPassMessageHandler implements MallMessageHandler {
+
+    private final IExternalProductService externalProductService;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.GOODS_AUDIT_PASS;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+
+        String goodsIdsStr = (String) content.get("goodsIds");
+
+        if (StrUtil.isBlank(goodsIdsStr)) {
+            return new MessageVo("0", "goodsIds为空");
+        }
+
+
+        // 更新
+        boolean update = externalProductService.lambdaUpdate()
+            .eq(ExternalProduct::getProductId, Long.parseLong(goodsIdsStr))
+            .set(ExternalProduct::getPushStatus, 1L)
+            .update();
+
+        return update
+            ? new MessageVo("1", "处理成功")
+            : new MessageVo("0", "处理失败");
+    }
+}

+ 54 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsAuditRejectMessageHandler.java

@@ -0,0 +1,54 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,19:50
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class GoodsAuditRejectMessageHandler implements MallMessageHandler {
+
+    private final IExternalProductService externalProductService;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.GOODS_AUDIT_REJECT;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+
+        String goodsIdsStr = (String) content.get("goodsIds");
+        String auditMsg = (String) content.get("auditMsg");
+
+        if (StrUtil.isBlank(goodsIdsStr)) {
+            return new MessageVo("0", "goodsIds为空");
+        }
+
+
+        // 更新
+        boolean update = externalProductService.lambdaUpdate()
+            .eq(ExternalProduct::getProductId, Long.parseLong(goodsIdsStr))
+            .set(ExternalProduct::getPushStatus, 2L)
+            .set(ExternalProduct::getRemark, auditMsg)
+            .update();
+
+        return update
+            ? new MessageVo("1", "处理成功")
+            : new MessageVo("0", "处理失败");
+    }
+}

+ 71 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsImportBlockMessageHandler.java

@@ -0,0 +1,71 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+/**
+ * author
+ * 时间:2026/2/4,19:34
+ */
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class GoodsImportBlockMessageHandler implements MallMessageHandler {
+
+    private final IExternalProductService externalProductService;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.GOODS_IMPORT_BLOCK;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+
+        String goodsIdsStr = (String) content.get("goodsIds");
+        String msg = (String) content.get("msg");
+
+        if (StrUtil.isBlank(goodsIdsStr)) {
+            return new MessageVo("0", "goodsIds为空");
+        }
+
+        // sku1,sku2,sku3
+        List<String> goodsIds = StrUtil.split(goodsIdsStr, ",");
+
+        if (CollUtil.isEmpty(goodsIds)) {
+            return new MessageVo("0", "goodsIds解析失败");
+        }
+
+        // 转成 Long productId(你的系统里 sku = productId)
+        List<Long> productIds = goodsIds.stream()
+            .map(Long::valueOf)
+            .toList();
+
+        // 更新为“拦截状态”
+        boolean update = externalProductService.lambdaUpdate()
+            .in(ExternalProduct::getProductId, productIds)
+            .set(ExternalProduct::getPushStatus, 2L)
+            .set(ExternalProduct::getRemark, msg)
+            .update();
+
+        log.info("商品导入拦截处理完成,productIds={}, msg={}", productIds, msg);
+
+        return update
+            ? new MessageVo("1", "拦截处理成功")
+            : new MessageVo("0", "拦截处理失败");
+    }
+}

+ 52 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsOffShelfMessageHandler.java

@@ -0,0 +1,52 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,19:56
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class GoodsOffShelfMessageHandler implements MallMessageHandler {
+
+    private final IExternalProductService externalProductService;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.GOODS_AUDIT_PASS;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+        String goodsIdsStr = (String) content.get("goodsIds");
+        String reason = (String) content.get("reason");
+        if (StrUtil.isBlank(goodsIdsStr)) {
+            return new MessageVo("0", "goodsIds为空");
+        }
+
+
+        // 更新下架
+        boolean update = externalProductService.lambdaUpdate()
+            .eq(ExternalProduct::getProductId, Long.parseLong(goodsIdsStr))
+            .set(ExternalProduct::getProductStatus, 0L)
+            .set(ExternalProduct::getRemark, reason)
+            .update();
+
+        return update
+            ? new MessageVo("1", "处理成功")
+            : new MessageVo("0", "处理失败");
+    }
+}

+ 52 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsOnShelfFailMessageHandler.java

@@ -0,0 +1,52 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,19:53
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class GoodsOnShelfFailMessageHandler implements MallMessageHandler {
+
+    private final IExternalProductService externalProductService;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.GOODS_AUDIT_PASS;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+        String goodsIdsStr = (String) content.get("goodsIds");
+        String message = (String) content.get("message");
+        if (StrUtil.isBlank(goodsIdsStr)) {
+            return new MessageVo("0", "goodsIds为空");
+        }
+
+
+        // 更新下架
+        boolean update = externalProductService.lambdaUpdate()
+            .eq(ExternalProduct::getProductId, Long.parseLong(goodsIdsStr))
+            .set(ExternalProduct::getProductStatus, 0L)
+            .set(ExternalProduct::getRemark, message)
+            .update();
+
+        return update
+            ? new MessageVo("1", "处理成功")
+            : new MessageVo("0", "处理失败");
+    }
+}

+ 54 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/GoodsWaitAuditMessageHandler.java

@@ -0,0 +1,54 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.external.service.IExternalProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,19:45
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class GoodsWaitAuditMessageHandler implements MallMessageHandler {
+
+    private final IExternalProductService externalProductService;
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.GOODS_WAIT_AUDIT;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+
+        String goodsIdsStr = (String) content.get("goodsIds");
+
+        if (StrUtil.isBlank(goodsIdsStr)) {
+            return new MessageVo("0", "goodsIds为空");
+        }
+
+
+        // 更新
+        boolean update = externalProductService.lambdaUpdate()
+            .eq(ExternalProduct::getProductId, Long.parseLong(goodsIdsStr))
+            .set(ExternalProduct::getPushStatus, 0L)
+            .update();
+
+        return update
+            ? new MessageVo("1", "处理成功")
+            : new MessageVo("0", "处理失败");
+    }
+}

+ 122 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/InvoiceApplyMessageHandler.java

@@ -0,0 +1,122 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.invoice.bo.InvoiceApplyDetailBo;
+import org.dromara.external.api.zhongche.domain.invoice.bo.InvoiceApplyOrdersBo;
+import org.dromara.external.api.zhongche.domain.invoice.domain.InvoiceOrder;
+import org.dromara.external.api.zhongche.domain.invoice.vo.InvoiceApplyDetailVo;
+import org.dromara.external.api.zhongche.domain.invoice.vo.InvoiceApplyOrdersVo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,15:17
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class InvoiceApplyMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+
+
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.INVOICE_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+        String applyNo = String.valueOf(content.get("applyNo"));
+
+        if (StrUtil.isBlank(applyNo)) {
+            return new MessageVo("0", "缺少开票申请编号");
+        }
+        try {
+            // 1、查询开票申请详情
+            InvoiceApplyDetailBo bo = new InvoiceApplyDetailBo(applyNo);
+            bo.setApplyNo(applyNo);
+            InvoiceApplyDetailVo invoiceApplyDetailVo = zhongChePullController.mallInvoiceApplyDetail(bo);
+
+            if (invoiceApplyDetailVo == null) {
+                return new MessageVo("0", "未查询到开票申请详情");
+            }
+
+            //TODO解析TOKEN 获取电商账号
+            //先假设一个电商账号 123456
+            // 2️、 查询开票申请订单列表(分页)
+            String account = "123456";
+            List<InvoiceOrder> invoiceOrders = queryAllInvoiceOrders(account, applyNo);
+
+            if (CollUtil.isEmpty(invoiceOrders)) {
+                return new MessageVo("0", "开票申请无订单数据");
+            }
+
+            // 3、 和本地数据核对
+            //boolean checkResult = remoteExternalOrderService.checkInvoiceData(invoiceApplyDetailVo, invoiceOrders);
+
+            /*if (!checkResult) {
+                return new MessageVo("0", "开票数据校验不通过");
+            }*/
+
+            // 4、更新本地开票申请状态
+            //invoiceService.saveOrUpdateInvoice(invoiceApplyDetailVo, invoiceOrders);
+
+            return new MessageVo("1", "开票申请处理成功");
+
+        } catch (Exception e) {
+            log.error("处理开票申请消息失败,applyNo={}", applyNo, e);
+            return new MessageVo("0", "系统异常");
+        }
+
+    }
+
+    private List<InvoiceOrder> queryAllInvoiceOrders(String account, String applyNo) {
+
+        List<InvoiceOrder> result = new ArrayList<>();
+
+        int current = 1;
+        int size = 50; // 文档最大 50
+
+        while (true) {
+            InvoiceApplyOrdersBo bo = new InvoiceApplyOrdersBo();
+            bo.setCurrent(current);
+            bo.setSize(size);
+            bo.setAccount(account);
+            bo.setApplyNo(applyNo);
+
+            InvoiceApplyOrdersVo resp =
+                zhongChePullController.mallInvoiceApplyOrders(bo);
+
+            if (resp == null || CollUtil.isEmpty(resp.getInvoiceOrders())) {
+                break;
+            }
+
+            result.addAll(resp.getInvoiceOrders());
+
+            // 已经到最后一页
+            if (current >= resp.getPages()) {
+                break;
+            }
+            current++;
+        }
+
+        return result;
+    }
+}

+ 41 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderCancelApplyMessageHandler.java

@@ -0,0 +1,41 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,18:50
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class OrderCancelApplyMessageHandler implements MallMessageHandler {
+
+
+    private final RemoteExternalOrderService remoteExternalOrderService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ORDER_CANCEL_APPLY;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String orderNo = (String) messageBo.getContent().get("orderNo");
+        String cancelReason = (String) messageBo.getContent().get("cancelReason");
+
+        boolean b = remoteExternalOrderService.cancelOrder(orderNo, cancelReason);
+
+        if (b){
+            return new MessageVo("1");
+        }
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 44 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderCancelMessageHandler.java

@@ -0,0 +1,44 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.bo.OrderDetailBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.api.zhongche.domain.vo.OrderDetailVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,15:41
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class OrderCancelMessageHandler implements MallMessageHandler {
+
+
+    private final RemoteExternalOrderService remoteExternalOrderService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ORDER_CANCEL;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String orderNo = (String) messageBo.getContent().get("orderNo");
+        String cancelReason = (String) messageBo.getContent().get("cancelReason");
+
+        boolean b = remoteExternalOrderService.cancelOrder(orderNo, cancelReason);
+
+        if (b){
+            return new MessageVo("1");
+        }
+        return new MessageVo("0","取消订单失败");
+    }
+}

+ 39 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderCreateMessageHandler.java

@@ -0,0 +1,39 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.bo.OrderDetailBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.api.zhongche.domain.vo.OrderDetailVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class OrderCreateMessageHandler implements MallMessageHandler {
+
+    private final ZhongChePullController zhongChePullController;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ORDER_CREATE;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String orderNo = (String) messageBo.getContent().get("orderNo");
+        log.info("处理新订单消息,orderNo={}", orderNo);
+        OrderDetailBo orderDetailBo = new OrderDetailBo();
+        orderDetailBo.setOrderNo(orderNo);
+        OrderDetailVo orderDetailVo = zhongChePullController.mallOrderDetail(orderDetailBo);
+        if (orderDetailVo != null){
+            return new MessageVo("1");
+        }
+
+        return new MessageVo("0","获取订单详情失败");
+    }
+}

+ 40 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/OrderReceiveConfirmMessageHandler.java

@@ -0,0 +1,40 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,16:06
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class OrderReceiveConfirmMessageHandler implements MallMessageHandler {
+
+    private final RemoteExternalOrderService remoteExternalOrderService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.ORDER_RECEIVE_CONFIRM;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String orderNo = (String) messageBo.getContent().get("orderNo");
+        String outgoingCode = (String) messageBo.getContent().get("outgoingCode");
+
+        boolean b = remoteExternalOrderService.cancelOrder(orderNo, outgoingCode);
+
+        if (b){
+            return new MessageVo("1");
+        }
+        return new MessageVo("0","确认收获失败");
+    }
+}

+ 40 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/PrepareCancelMessageHandler.java

@@ -0,0 +1,40 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.customer.api.RemotePartnerPreparedService;
+import org.dromara.customer.api.domain.dto.PartnerPreparedDTO;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,18:15
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class PrepareCancelMessageHandler implements MallMessageHandler {
+
+    private final RemotePartnerPreparedService remotePartnerPreparedService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.PREPARE_CANCEL;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String prepareOrderNo = (String) messageBo.getContent().get("prepareOrderNo");
+        String cancelReason = (String) messageBo.getContent().get("cancelReason");
+        PartnerPreparedDTO partnerPreparedDTO = remotePartnerPreparedService.cancelPartnerPreparedById(prepareOrderNo,cancelReason);
+        if (partnerPreparedDTO.isFlag()){
+            return new MessageVo("1");
+        }
+
+        return new MessageVo("0",partnerPreparedDTO.getMessage());
+    }
+}

+ 40 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/PrepareConfirmMessageHandler.java

@@ -0,0 +1,40 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.customer.api.RemotePartnerPreparedService;
+import org.dromara.customer.api.domain.dto.PartnerPreparedDTO;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+
+/**
+ * author
+ * 时间:2026/2/3,17:32
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class PrepareConfirmMessageHandler  implements MallMessageHandler {
+
+    private final RemotePartnerPreparedService remotePartnerPreparedService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.PREPARE_CONFIRM;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String prepareOrderNo = (String) messageBo.getContent().get("prepareOrderNo");
+        PartnerPreparedDTO partnerPreparedDTO = remotePartnerPreparedService.updatePartnerPreparedById(prepareOrderNo);
+        if (partnerPreparedDTO.isFlag()){
+            return new MessageVo("1");
+        }
+
+        return new MessageVo("0",partnerPreparedDTO.getMessage());
+    }
+}

+ 49 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/SettlementCreateMessageHandler.java

@@ -0,0 +1,49 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.settlement.bo.SettlementDetailBo;
+import org.dromara.external.api.zhongche.domain.settlement.vo.SettlementDetailVo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * author
+ * 时间:2026/2/5,9:24
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class SettlementCreateMessageHandler implements MallMessageHandler {
+
+    private final RemoteExternalOrderService remoteExternalOrderService;
+
+    private final ZhongChePullController zhongChePullController;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.SETTLEMENT_CREATE;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        String applyNo = (String) messageBo.getContent().get("applyNo");
+        SettlementDetailBo bo = new SettlementDetailBo();
+        bo.setApplyNo(applyNo);
+        SettlementDetailVo settlementDetailVo = zhongChePullController.mallSettlementDetail(bo);
+
+
+        //boolean b = remoteExternalOrderService.cancelOrder(orderNo, outgoingCode);
+
+       /* if (b){
+            return new MessageVo("1");
+        }*/
+        return new MessageVo("0","确认收获失败");
+    }
+}

+ 55 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/StockLockMessageHandler.java

@@ -0,0 +1,55 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.invoice.bo.InvoiceApplyDetailBo;
+import org.dromara.external.api.zhongche.domain.invoice.domain.InvoiceOrder;
+import org.dromara.external.api.zhongche.domain.invoice.vo.InvoiceApplyDetailVo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.ZhongChePullController;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteExternalOrderService;
+import org.dromara.product.api.RemoteProductService;
+import org.dromara.product.api.RemoteProductShoppingCartService;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,17:28
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class StockLockMessageHandler implements MallMessageHandler {
+
+    private final RemoteProductService remoteProductService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.STOCK_LOCK;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+        String accountName = messageBo.getAccountName();
+        String goodsId = String.valueOf(content.get("goodsId"));
+        String goodsNum = String.valueOf(content.get("goodsNum"));
+        if (StrUtil.isBlank(goodsId) || StrUtil.isBlank(goodsNum)) {
+            return new MessageVo("0", "缺少商品编号或商品数量");
+        }
+        boolean b = remoteProductService.lockShoppingCart(Long.valueOf(goodsId), Long.parseLong(goodsNum), accountName);
+        if (b){
+            return new MessageVo("1");
+        } else {
+            return new MessageVo("0", "锁定失败");
+        }
+    }
+}

+ 46 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongche/handle/impl/StockUnlockMessageHandler.java

@@ -0,0 +1,46 @@
+package org.dromara.external.controller.zhongche.handle.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.api.zhongche.domain.bo.MessageBo;
+import org.dromara.external.api.zhongche.domain.vo.MessageVo;
+import org.dromara.external.controller.zhongche.handle.MallMessageHandler;
+import org.dromara.external.enums.MallMessageTypeEnum;
+import org.dromara.product.api.RemoteProductService;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * author
+ * 时间:2026/2/4,19:02
+ */
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class StockUnlockMessageHandler implements MallMessageHandler {
+
+    private final RemoteProductService remoteProductService;
+
+    @Override
+    public MallMessageTypeEnum supportType() {
+        return MallMessageTypeEnum.STOCK_LOCK;
+    }
+
+    @Override
+    public MessageVo handle(MessageBo messageBo) {
+        Map<String, Object> content = (Map<String, Object>) messageBo.getContent();
+        String accountName = messageBo.getAccountName();
+        String goodsId = String.valueOf(content.get("goodsId"));
+        if (StrUtil.isBlank(goodsId)) {
+            return new MessageVo("0", "缺少商品编号");
+        }
+        boolean b = remoteProductService.unlockShoppingCart(Long.valueOf(goodsId), accountName);
+        if (b){
+            return new MessageVo("1");
+        } else {
+            return new MessageVo("0", "解定失败");
+        }
+    }
+}

+ 10 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductVo.java

@@ -53,12 +53,22 @@ public class ExternalProductVo implements Serializable {
     @ExcelProperty(value = "分类id")
     private Long categoryId;
 
+    /**
+     * 电商品目名称
+     */
+    private String catalogName;
+
     /**
      * 外部分类id
      */
     @ExcelProperty(value = "外部分类id")
     private Long externalCategoryId;
 
+    /**
+     * 第三方品目名称
+     */
+    private String standardCatalogName;
+
     /**
      * 推送状态 0未推送,1已推送
      */

+ 108 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/enums/MallMessageTypeEnum.java

@@ -0,0 +1,108 @@
+package org.dromara.external.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum MallMessageTypeEnum {
+
+    /* ======================= 订单 ======================= */
+    ORDER_CREATE("2001", "订单", "新订单消息"),
+    ORDER_CANCEL("2002", "订单", "取消订单消息"),
+    ORDER_RECEIVE_CONFIRM("2003", "订单", "确认收货消息"),
+    //TODO 没有预购单
+    ORDER_PRE_CONFIRM("2004", "订单", "确认预购单"),
+    //TODO 胡哥说没有混合支付订单
+    ORDER_PAY_NOTICE("2005", "订单", "订单支付信息通知"),
+
+    /* ======================= 备货单 ======================= */
+    //TODO 废弃
+    PREPARE_CREATE("2006", "备货单", "新备货单消息"),
+    PREPARE_CONFIRM("2007", "备货单", "确认备货单消息"),
+    PREPARE_CANCEL("2008", "备货单", "取消备货单消息"),
+
+    /* ======================= 订单取消申请 ======================= */
+    //TODO 跟2002功能重复
+    ORDER_CANCEL_APPLY("2009", "订单", "取消订单申请消息"),
+    /* ======================= 售后 ======================= */
+    AFTER_SALE_APPLY("2101", "售后单", "申请售后消息"),
+    AFTER_SALE_CANCEL("2102", "售后单", "取消售后消息"),
+    //没注释
+    AFTER_SALE_DELIVER("2103", "售后单", "退货发运消息"),
+    //没注释
+    AFTER_SALE_RECEIVE_CONFIRM("2104", "售后单", "确认收货"),
+    //胡歌说都是信用支付不是现金支付
+    AFTER_SALE_REFUND_NOTICE("2105", "售后单", "售后退款信息通知"),
+
+    /* ======================= 账户 ======================= */
+    //TODO 没做
+    ACCOUNT_ACTIVE("2201", "账户", "电商账户已生效"),
+    //没做常老师说不需要
+    ACCOUNT_NOTICE("2202", "账户", "通知公告信息"),
+
+    /* ======================= 对账 ======================= */
+    //废弃
+    BILL_RULE_CREATE("2301", "对账", "生成对账规则消息"),
+    //废弃
+    BILL_CONFIRM("2302", "对账", "采购确认账单"),
+    //废弃
+    BILL_MODIFY("2303", "对账", "采购修改账单"),
+    //废弃
+    BILL_WAIT_INVOICE("2304", "对账", "待开票订单消息"),
+    //废弃
+    BILL_CREATE("2305", "对账", "采购生成对账单消息"),
+    //废弃
+    BILL_FINISH("2306", "对账", "采购完成对账单消息"),
+    //废弃
+    ABNORMAL_PASS("2307", "对账", "异议单审核通过消息"),
+    //废弃
+    ABNORMAL_REJECT("2308", "对账", "异议单审核不通过消息"),
+
+    /* ======================= 开票 ======================= */
+    //TODO 交接不好
+    INVOICE_APPLY("2401", "开票", "开票申请消息"),
+    INVOICE_CONFIRM("2402", "开票", "采购确认收票消息"),
+    INVOICE_REFUND_APPLY("2403", "开票", "退票申请消息"),
+    INVOICE_RETURN("2405", "开票", "采购邮寄退票消息"),
+
+    /* ======================= 库存 ======================= */
+    STOCK_LOCK("2501", "购物车", "库存锁定消息"),
+    STOCK_UNLOCK("2502", "购物车", "库存解定消息"),
+
+    /* ======================= 商品 ======================= */
+    GOODS_IMPORT_BLOCK("2601", "商品", "商品导入拦截消息"),
+    GOODS_WAIT_AUDIT("2602", "商品", "商品待审核消息"),
+    GOODS_AUDIT_PASS("2603", "商品", "商品审核通过消息"),
+    GOODS_AUDIT_REJECT("2604", "商品", "商品审核不通过消息"),
+    GOODS_ON_SHELF_FAIL("2605", "商品", "商品上架失败消息"),
+    GOODS_OFF_SHELF("2606", "商品", "采购主动下架商品消息"),
+
+    /* ======================= 结算 ======================= */
+    //TODO
+    SETTLEMENT_CREATE("2701", "结算", "采购生成结算单消息"),
+    //TODO
+    SETTLEMENT_PAYED("2702", "结算", "采购结算单已付款消息"),
+    //新的文档已经没有了
+    SETTLEMENT_INVOICE_RETURN("2703", "结算", "采购结算单开票退回消息");
+
+    private final String code;
+    private final String module;
+    private final String desc;
+
+    /**
+     * 根据 type 查枚举
+     */
+    public static MallMessageTypeEnum of(String code) {
+        if (code == null) {
+            return null;
+        }
+        for (MallMessageTypeEnum type : values()) {
+            if (type.code.equals(code)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}

+ 5 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductService.java

@@ -92,4 +92,9 @@ public interface IExternalProductService extends IService<ExternalProduct>{
      * @return 是否审核成功
      */
     Boolean shelfReview(ExternalProductBo bo);
+
+    /**
+     * 获取所有商品列表
+     */
+    List<ExternalProductVo> getAllProductList();
 }

+ 68 - 3
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductServiceImpl.java

@@ -13,6 +13,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.external.domain.ExternalProductCategory;
+import org.dromara.external.service.IExternalProductBrandService;
+import org.dromara.external.service.IExternalProductCategoryService;
 import org.dromara.product.api.RemoteProductService;
 import org.dromara.product.api.domain.ProductVo;
 import org.springframework.stereotype.Service;
@@ -22,9 +25,8 @@ import org.dromara.external.domain.ExternalProduct;
 import org.dromara.external.mapper.ExternalProductMapper;
 import org.dromara.external.service.IExternalProductService;
 
-import java.util.List;
-import java.util.Map;
-import java.util.Collection;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 对外部推送商品Service业务层处理
@@ -42,6 +44,9 @@ public class ExternalProductServiceImpl  extends ServiceImpl<ExternalProductMapp
     @DubboReference
     private RemoteProductService remoteProductService;
 
+    private final IExternalProductBrandService externalProductBrandService;
+
+    private final IExternalProductCategoryService externalProductCategoryService;
     /**
      * 查询对外部推送商品
      *
@@ -193,4 +198,64 @@ public class ExternalProductServiceImpl  extends ServiceImpl<ExternalProductMapp
             .eq(ExternalProduct::getId, bo.getId())
         )>0;
     }
+
+    @Override
+    public List<ExternalProductVo> getAllProductList() {
+        List<ExternalProductVo> externalProductVos = baseMapper.selectVoList(new LambdaQueryWrapper<ExternalProduct>().eq(ExternalProduct::getPushStatus, 0));
+        if (CollUtil.isEmpty(externalProductVos)) {
+            return externalProductVos;
+        }
+        // 2. 收集所有分类 id(两个字段一起)
+        Set<Long> categoryIds = new HashSet<>();
+        for (ExternalProductVo vo : externalProductVos) {
+            if (vo.getCategoryId() != null) {
+                categoryIds.add(vo.getCategoryId());
+            }
+            if (vo.getExternalCategoryId() != null) {
+                categoryIds.add(vo.getExternalCategoryId());
+            }
+        }
+
+        if (CollUtil.isEmpty(categoryIds)) {
+            return externalProductVos;
+        }
+
+        // 3. 一次性查询分类表
+        List<ExternalProductCategory> categoryList =
+            externalProductCategoryService.lambdaQuery()
+                .in(ExternalProductCategory::getProductCategoryId, categoryIds)
+                .list();
+
+        // 4. 转 Map:id -> 分类名称
+        Map<Long, String> categoryNameMap =
+            categoryList.stream()
+                .collect(Collectors.toMap(
+                    ExternalProductCategory::getProductCategoryId,
+                    ExternalProductCategory::getCategoryName,
+                    (a, b) -> a
+                ));
+
+        // 5. 回填分类名称
+        for (ExternalProductVo vo : externalProductVos) {
+
+            // 电商品目名称
+            if (vo.getCategoryId() != null) {
+                vo.setCatalogName(categoryNameMap.get(vo.getCategoryId()));
+            }
+
+            // 第三方品目名称
+            if (vo.getExternalCategoryId() != null) {
+                vo.setStandardCatalogName(categoryNameMap.get(vo.getExternalCategoryId()));
+            }
+        }
+
+        //查询所有商品信息
+        List<Long> productIds = externalProductVos.stream()
+            .map(ExternalProductVo::getProductId)
+            .toList();
+
+
+
+        return externalProductVos;
+    }
 }

+ 128 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/util/SM2SignatureUtils.java

@@ -0,0 +1,128 @@
+package org.dromara.external.util;
+
+import org.bouncycastle.asn1.gm.GMNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.signers.SM2Signer;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Base64;
+
+import java.security.SecureRandom;
+import java.security.Security;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 国密 SM2withSM3 签名工具类
+ * 注意:开发者私钥/公钥需由电商平台提供,此处提供生成示例(实际使用平台分配的密钥)
+ */
+public class SM2SignatureUtils {
+    // 注册 BouncyCastle 安全提供者
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+    // SM2 曲线参数(固定,国密标准)
+    private static final X9ECParameters SM2_CURVE_PARAMS = GMNamedCurves.getByName("sm2p256v1");
+    private static final ECDomainParameters EC_DOMAIN_PARAMETERS = new ECDomainParameters(
+            SM2_CURVE_PARAMS.getCurve(),
+            SM2_CURVE_PARAMS.getG(),
+            SM2_CURVE_PARAMS.getN(),
+            SM2_CURVE_PARAMS.getH()
+    );
+
+    /**
+     * 生成 SM2 密钥对(仅用于测试,实际使用电商平台提供的开发者私钥/公钥)
+     * @return 密钥对(私钥在前,公钥在后,均为 Base64 编码)
+     */
+    public static String[] generateSM2KeyPair() {
+        ECKeyPairGenerator generator = new ECKeyPairGenerator();
+        ECKeyGenerationParameters genParams = new ECKeyGenerationParameters(EC_DOMAIN_PARAMETERS, new SecureRandom());
+        generator.init(genParams);
+
+        AsymmetricCipherKeyPair keyPair = generator.generateKeyPair();
+        ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters) keyPair.getPrivate();
+        ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters) keyPair.getPublic();
+
+        // 转换为 Base64 编码字符串
+        String privateKeyBase64 = Base64.toBase64String(privateKeyParams.getD().toByteArray());
+        String publicKeyBase64 = Base64.toBase64String(publicKeyParams.getQ().getEncoded(false));
+
+        return new String[]{privateKeyBase64, publicKeyBase64};
+    }
+
+    /**
+     * SM2withSM3 签名(私钥签名,生成待提交的 sign 字段)
+     * @param content 待签名字符串(筛选排序后的 JSON 字符串)
+     * @param privateKeyBase64 开发者私钥(Base64 编码,平台提供)
+     * @return 签名结果(Base64 编码,可直接赋值给 sign 字段)
+     */
+    public static String sign(String content, String privateKeyBase64) {
+        if (content == null || content.trim().isEmpty() || privateKeyBase64 == null || privateKeyBase64.trim().isEmpty()) {
+            throw new IllegalArgumentException("待签名字符串和私钥不能为空");
+        }
+
+        try {
+            // 1. 解码私钥
+            byte[] privateKeyBytes = Base64.decode(privateKeyBase64);
+            ECPrivateKeyParameters privateKeyParams = new ECPrivateKeyParameters(
+                    new java.math.BigInteger(1, privateKeyBytes),
+                    EC_DOMAIN_PARAMETERS
+            );
+
+            // 2. 初始化 SM2 签名器
+            SM2Signer signer = new SM2Signer();
+            signer.init(true, privateKeyParams);
+
+            // 3. 传入待签名内容(UTF-8 编码)
+            byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
+            signer.update(contentBytes, 0, contentBytes.length);
+
+            // 4. 生成签名并进行 Base64 编码
+            byte[] signatureBytes = signer.generateSignature();
+            return Base64.toBase64String(signatureBytes);
+        } catch (Exception e) {
+            throw new RuntimeException("SM2 签名失败:" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * SM2withSM3 验签(公钥校验,验证请求传入的 sign 是否合法)
+     * @param content 待签名字符串(与签名时一致的 JSON 字符串)
+     * @param signBase64 请求传入的 sign 字段(Base64 编码)
+     * @param publicKeyBase64 开发者公钥(Base64 编码,平台提供)
+     * @return true=验签通过,false=验签失败
+     */
+    public static boolean verify(String content, String signBase64, String publicKeyBase64) {
+        if (content == null || content.trim().isEmpty() || signBase64 == null || signBase64.trim().isEmpty()
+                || publicKeyBase64 == null || publicKeyBase64.trim().isEmpty()) {
+            throw new IllegalArgumentException("待签名字符串、签名和公钥不能为空");
+        }
+
+        try {
+            // 1. 解码公钥和签名
+            byte[] publicKeyBytes = Base64.decode(publicKeyBase64);
+            byte[] signatureBytes = Base64.decode(signBase64);
+
+            // 2. 构建公钥参数
+            org.bouncycastle.math.ec.ECPoint ecPoint = SM2_CURVE_PARAMS.getCurve().decodePoint(publicKeyBytes);
+            ECPublicKeyParameters publicKeyParams = new ECPublicKeyParameters(ecPoint, EC_DOMAIN_PARAMETERS);
+
+            // 3. 初始化 SM2 签名器
+            SM2Signer signer = new SM2Signer();
+            signer.init(false, publicKeyParams);
+
+            // 4. 传入待签名内容并验签
+            byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
+            signer.update(contentBytes, 0, contentBytes.length);
+
+            return signer.verifySignature(signatureBytes);
+        } catch (Exception e) {
+            throw new RuntimeException("SM2 验签失败:" + e.getMessage(), e);
+        }
+    }
+}

+ 109 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/util/SignParamUtils.java

@@ -0,0 +1,109 @@
+package org.dromara.external.util;
+
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.dromara.external.api.zhongche.domain.bo.ZCTokenBo;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * 签名参数处理工具类(筛选、排序、拼接JSON)
+ */
+public class SignParamUtils {
+    /**
+     * JSON 转换工具(保持与 ZCApiUtils 一致)
+     */
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    /**
+     * 处理签名参数(核心方法)
+     * @param paramObj 请求/响应参数实体(如 ZCTokenBo、ZCR)
+     * @return 待签名字符串(筛选排序后的 JSON 字符串)
+     * @throws JsonProcessingException JSON 转换异常
+     */
+    public static String getSignContent(Object paramObj) throws JsonProcessingException {
+        if (paramObj == null) {
+            throw new IllegalArgumentException("参数实体不能为空");
+        }
+
+        // 步骤 1:反射获取参数实体的所有字段(键值对)
+        Map<String, Object> paramMap = new HashMap<>();
+        Field[] fields = paramObj.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            field.setAccessible(true); // 允许访问私有字段
+            String fieldName = field.getName();
+            Object fieldValue = null;
+
+            try {
+                fieldValue = field.get(paramObj);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException("获取字段值失败:" + fieldName, e);
+            }
+
+            // 步骤 2:筛选字段(剔除 sign、剔除 null 值、剔除字节数组)
+            if ("sign".equals(fieldName)) {
+                continue; // 剔除 sign 字段
+            }
+            if (fieldValue == null) {
+                continue; // 剔除 null 值
+            }
+            if (fieldValue instanceof byte[]) {
+                continue; // 剔除字节类型字段(当前场景无,预留)
+            }
+
+            // 符合条件的字段存入 Map
+            paramMap.put(fieldName, fieldValue);
+        }
+
+        // 步骤 3:按字段名(键)ASCII 码升序排序
+        Map<String, Object> sortedParamMap = new TreeMap<>(new Comparator<String>() {
+            @Override
+            public int compare(String key1, String key2) {
+                // 按 ASCII 码升序排序(逐个字符对比)
+                return key1.compareTo(key2);
+            }
+        });
+        sortedParamMap.putAll(paramMap);
+
+        // 步骤 4:拼接为 JSON 字符串(待签名字符串)
+        return OBJECT_MAPPER.writeValueAsString(sortedParamMap);
+    }
+
+    /**
+     * 快捷方法:生成请求签名(ZCTokenBo → 待签名内容 → SM2 签名)
+     * @param zcTokenBo 请求参数实体
+     * @param privateKeyBase64 开发者私钥(Base64 编码)
+     * @return 签名结果(Base64 编码,可赋值给 sign 字段)
+     * @throws JsonProcessingException JSON 转换异常
+     */
+    public static String generateRequestSign(ZCTokenBo zcTokenBo, String privateKeyBase64) throws JsonProcessingException {
+        // 生成待签名字符串
+        String signContent = getSignContent(zcTokenBo);
+        // SM2 签名并返回
+        return SM2SignatureUtils.sign(signContent, privateKeyBase64);
+    }
+
+    /**
+     * 快捷方法:验证请求签名(ZCTokenBo → 待签名内容 → 校验 sign 是否合法)
+     * @param zcTokenBo 请求参数实体
+     * @param publicKeyBase64 开发者公钥(Base64 编码)
+     * @return true=验签通过,false=验签失败
+     * @throws JsonProcessingException JSON 转换异常
+     */
+    public static boolean verifyRequestSign(ZCTokenBo zcTokenBo, String publicKeyBase64) throws JsonProcessingException {
+        // 提取请求传入的 sign
+        String requestSign = zcTokenBo.getSign();
+        if (requestSign == null || requestSign.trim().isEmpty()) {
+            return false;
+        }
+
+        // 生成待签名字符串(与签名时一致)
+        String signContent = getSignContent(zcTokenBo);
+
+        // SM2 验签
+        return SM2SignatureUtils.verify(signContent, requestSign, publicKeyBase64);
+    }
+}

+ 93 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/util/ZCApiUtils.java

@@ -0,0 +1,93 @@
+package org.dromara.external.util;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Base64;
+
+/**
+ * 中车接口工具类(Base64 + JSON 转换)
+ */
+public class ZCApiUtils {
+    /**
+     * JSON 转换工具(Jackson)
+     */
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    /**
+     * Base64 解码(字符串 → 原始字符串)
+     * @param base64Str Base64编码字符串
+     * @return 解码后的原始字符串
+     */
+    public static String base64Decode(String base64Str) {
+        if (base64Str == null || base64Str.trim().isEmpty()) {
+            throw new IllegalArgumentException("Base64编码字符串不能为空");
+        }
+        byte[] decodeBytes = Base64.getDecoder().decode(base64Str);
+        return new String(decodeBytes);
+    }
+
+    /**
+     * Base64 编码(原始字符串 → Base64编码字符串)
+     * @param rawStr 原始字符串
+     * @return Base64编码字符串
+     */
+    public static String base64Encode(String rawStr) {
+        if (rawStr == null || rawStr.trim().isEmpty()) {
+            throw new IllegalArgumentException("原始字符串不能为空");
+        }
+        byte[] encodeBytes = rawStr.getBytes();
+        return Base64.getEncoder().encodeToString(encodeBytes);
+    }
+
+    /**
+     * JSON 字符串 → Java 对象
+     * @param jsonStr JSON字符串
+     * @param clazz 目标对象类型
+     * @param <T> 泛型
+     * @return 目标Java对象
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static <T> T jsonToObject(String jsonStr, Class<T> clazz) throws JsonProcessingException {
+        if (jsonStr == null || jsonStr.trim().isEmpty()) {
+            throw new IllegalArgumentException("JSON字符串不能为空");
+        }
+        return OBJECT_MAPPER.readValue(jsonStr, clazz);
+    }
+
+    /**
+     * Java 对象 → JSON 字符串
+     * @param obj Java对象
+     * @return JSON字符串
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static String objectToJson(Object obj) throws JsonProcessingException {
+        if (obj == null) {
+            throw new IllegalArgumentException("Java对象不能为空");
+        }
+        return OBJECT_MAPPER.writeValueAsString(obj);
+    }
+
+    /**
+     * 快捷方法:Java对象 → Base64编码的JSON字符串(响应data字段专用)
+     * @param obj Java对象
+     * @return Base64编码的JSON字符串
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static String objectToBase64Json(Object obj) throws JsonProcessingException {
+        String jsonStr = objectToJson(obj);
+        return base64Encode(jsonStr);
+    }
+
+    /**
+     * 快捷方法:Base64编码的JSON字符串 → Java对象(请求data字段专用)
+     * @param base64Json Base64编码的JSON字符串
+     * @param clazz 目标对象类型
+     * @param <T> 泛型
+     * @return 目标Java对象
+     * @throws JsonProcessingException JSON转换异常
+     */
+    public static <T> T base64JsonToObject(String base64Json, Class<T> clazz) throws JsonProcessingException {
+        String jsonStr = base64Decode(base64Json);
+        return jsonToObject(jsonStr, clazz);
+    }
+}

+ 192 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/dubbo/RemoteExternalOrderServiceImpl.java

@@ -3,16 +3,38 @@ package org.dromara.order.dubbo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.domain.zhongche.domain.DeliveryTrack;
+import org.dromara.common.core.domain.zhongche.vo.ZhongCheTrackVo;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.domain.zhongche.vo.ZhongCheTrackVo;
+import org.dromara.order.domain.OrderDeliver;
 import org.dromara.order.domain.OrderMain;
+import org.dromara.order.domain.OrderReturn;
 import org.dromara.order.domain.bo.OrderProductBo;
+import org.dromara.order.enums.PackStatusEnum;
+import org.dromara.order.service.IOrderDeliverService;
 import org.dromara.order.service.IOrderMainService;
 import org.dromara.order.service.IOrderProductService;
+import org.dromara.order.service.IOrderReturnService;
+import org.dromara.order.utils.kd100.Kd100Util;
+import org.dromara.order.utils.kd100.domain.QueryTrackDTO;
+import org.dromara.order.utils.kd100.domain.TrackData;
+import org.dromara.order.utils.kd100.domain.TrackVO;
 import org.dromara.product.api.RemoteExternalOrderService;
 import org.dromara.product.api.domain.dto.OrderNoDto;
 import org.dromara.product.api.domain.dto.OrderNoticeDto;
 import org.dromara.product.api.domain.dto.OrderPushDto;
+import org.dromara.system.api.RemoteComLogisticsCompanyService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @author
@@ -28,6 +50,20 @@ public class RemoteExternalOrderServiceImpl implements RemoteExternalOrderServic
 
      private final IOrderMainService orderMainService;
 
+     private final IOrderDeliverService orderDeliverService;
+
+     @DubboReference
+     private final RemoteComLogisticsCompanyService remoteComLogisticsCompanyService;
+
+     private final IOrderReturnService orderReturnService;
+
+    // 通用正则:匹配 快递员 + 任意分隔符(无/冒号/空格) + 姓名 + (手机号)
+    // 正则说明:
+    // 快递员      :固定匹配关键字
+    // [::\\s]*   :匹配0个或多个 全角冒号/半角冒号/任意空格(兼容无分隔符的情况)
+    // ([^()]+)    :匹配任意不含括号的字符(提取姓名,排除后面的手机号括号部分)
+    // \\(         :匹配左括号(作为姓名结束标识)
+    private static final Pattern COURIER_PATTERN = Pattern.compile("快递员[::\\s]*([^()]+)\\(");
     /**
      * 推送订单
      *
@@ -78,4 +114,160 @@ public class RemoteExternalOrderServiceImpl implements RemoteExternalOrderServic
         return orderMain.getOrderNo();
 
     }
+
+    @Override
+    public ZhongCheTrackVo queryLogisticsTrack(String outgoingCode, String waybillType) {
+        //目前忽略第二个参数
+        OrderDeliver one = orderDeliverService.lambdaQuery()
+            .eq(OrderDeliver::getDeliverCode, outgoingCode)
+            .last("limit 1")
+            .one();
+        // 新增:空值防护(查询不到发货单直接返回null,避免空指针)
+        if (one == null) {
+            log.warn("物流查询 - 未查询到发货单,outgoingCode:{}", outgoingCode);
+            return null;
+        }
+
+        String name = remoteComLogisticsCompanyService.selectLogisticsCompanyNameById(one.getLogisticsCompanyId());
+        List<DeliveryTrack> deliveryTracks = queryDeliverTrack(one.getLogisticsCompanyCode(), one.getLogisticNo(), one.getConsigneePhone());
+        ZhongCheTrackVo trackVo = new ZhongCheTrackVo();
+        trackVo.setExpressCompanyName(name);
+        trackVo.setDeliveryTrack(deliveryTracks);
+        trackVo.setExpressCode(one.getLogisticNo());
+        return trackVo;
+    }
+
+    @Override
+    public List<DeliveryTrack> queryDeliverTrack(String logisticsCompanyCode, String logisticNo, String consigneePhone) {
+        // 1. 参数校验
+        if (!StringUtils.isNotBlank(logisticsCompanyCode)) {
+            log.warn("物流单号不能为空,bo={}", logisticsCompanyCode);
+            throw new IllegalArgumentException("物流单号不能为空");
+        }
+        List<DeliveryTrack> deliveryTracks = new ArrayList<>();
+
+        // 2. 构建查询 DTO
+        QueryTrackDTO dto = QueryTrackDTO.builder()
+            .com(logisticsCompanyCode)
+            .num(logisticNo)
+            .phone(consigneePhone)
+            .build();
+        // 3. 调用物流查询
+        try {
+            log.info("开始查询物流信息,单号: {}, 公司代码: {}", dto.getNum(), dto.getCom());
+            TrackVO trackVO = Kd100Util.queryTrack(dto);
+            List<TrackData> data = trackVO.getData();
+            for (TrackData trackData : data) {
+                DeliveryTrack deliveryTrack = new DeliveryTrack();
+                deliveryTrack.setExpressDetail(trackData.getContext());
+                deliveryTrack.setExpressTime(trackData.getFtime());
+                //操作员怎么设置
+                // 核心:提取快递员姓名并设置到 optName
+                String courierName = extractCourierName(trackData.getContext());
+                deliveryTrack.setOptName(courierName);
+                deliveryTracks.add(deliveryTrack);
+            }
+            return deliveryTracks;
+        } catch (Exception e) {
+            log.error("查询物流信息失败,dto={}", dto, e);
+            return null;
+        }
+    }
+
+    /**
+     * 获取退货单编号
+     * @param ZCorderNo
+     * @return
+     */
+    @Override
+    public String getReturnOrderNo(String ZCorderNo) {
+        OrderReturn one = orderReturnService.lambdaQuery()
+            .eq(OrderReturn::getReturnNo, ZCorderNo)
+            .select(OrderReturn::getReturnNo)
+            .one();
+
+        return one.getReturnNo();
+    }
+
+    @Override
+    public boolean cancelOrder(String orderNo, String cancelReason) {
+        boolean update = orderMainService.lambdaUpdate()
+            .eq(OrderMain::getOrderNo, orderNo)
+            .eq(OrderMain::getOrderStatus, "2")
+            .set(OrderMain::getOrderStatus, "7")
+            .set(OrderMain::getCancelReason, cancelReason)
+            .update();
+        return update;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean confirmReceive(String orderNo ,String outgoingCode) {
+        boolean updated = orderDeliverService.lambdaUpdate()
+            .eq(OrderDeliver::getOrderCode, orderNo)
+            .eq(OrderDeliver::getDeliverCode, outgoingCode)
+            //这里可以加一个幂等性判断但是目前好像没有包裹状态 胡哥还没完成
+            .set(OrderDeliver::getLogisticPackStatus, PackStatusEnum.PACK_STATUS_RECEIVED)
+            .update();
+
+        if (!updated) {
+            log.warn("确认收货失败,未找到发货单,orderNo={}, outgoingCode={}", orderNo, outgoingCode);
+            return false;
+        }
+        // 2. 判断该订单下是否还有【未收货】的发货单
+        long notReceivedCount = orderDeliverService.lambdaQuery()
+            .eq(OrderDeliver::getOrderCode, orderNo)
+            .ne(OrderDeliver::getLogisticPackStatus, PackStatusEnum.PACK_STATUS_RECEIVED)
+            .count();
+
+        // 3. 如果全部已收货 → 更新订单主表为【已完成】
+        if (notReceivedCount == 0) {
+            orderMainService.lambdaUpdate()
+                .eq(OrderMain::getOrderNo, orderNo)
+                .set(OrderMain::getOrderStatus, "5")
+                .update();
+
+            log.info("订单全部收货完成,orderNo={},订单状态更新为已完成", orderNo);
+        }
+
+        return true;
+
+    }
+
+    @Override
+    public boolean cancelReturnOrder(String afterSaleNo, String cancelReason) {
+        //要求是待处理状态 目前没有 就拿待处理状态先写
+        boolean update = orderReturnService.lambdaUpdate()
+            .eq(OrderReturn::getReturnNo, afterSaleNo)
+            .eq(OrderReturn::getReturnStatus, "0")
+            .set(OrderReturn::getReturnStatus, "4")
+            .set(OrderReturn::getReturnReason, cancelReason)
+            .update();
+
+        return update;
+    }
+
+    /**
+     * 从物流描述中提取快递员姓名
+     * @param context 物流描述字符串
+     * @return 快递员姓名(提取不到返回 "未知")
+     */
+    private String extractCourierName(String context) {
+        // 1. 先判断上下文是否为空,避免空指针
+        if (StringUtils.isBlank(context)) {
+            return "";
+        }
+
+        // 2. 使用正则表达式匹配快递员姓名
+        Matcher matcher = COURIER_PATTERN.matcher(context);
+        if (matcher.find()) {
+            // 提取姓名并去除前后空格(处理姓名前后的冗余空格)
+            String courierName = StringUtils.trim(matcher.group(1));
+            // 避免提取到空字符串(极端情况)
+            return StringUtils.isNotBlank(courierName) ? courierName : "";
+        }
+
+        // 3. 没有匹配到 "快递员" 关键字,返回默认值
+        return "";
+    }
 }

+ 34 - 0
ruoyi-modules/ruoyi-order/src/main/java/org/dromara/order/enums/PackStatusEnum.java

@@ -0,0 +1,34 @@
+package org.dromara.order.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * author
+ * 时间:2026/2/3,16:03
+ */
+@Getter
+@AllArgsConstructor
+public enum PackStatusEnum {
+
+    PACK_STATUS_WAIT_PACK("0", "待打包"),
+    PACK_STATUS_RECEIVED("1", "已收货");
+
+    private final String code;
+    private final String desc;
+
+    /**
+     * 根据 type 查枚举
+     */
+    public static PackStatusEnum of(String code) {
+        if (code == null) {
+            return null;
+        }
+        for (PackStatusEnum type : values()) {
+            if (type.code.equals(code)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}

+ 3 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductCategoryController.java

@@ -59,6 +59,9 @@ public class ProductCategoryController extends BaseController {
         ProductCategoryBo bo = new ProductCategoryBo();
         bo.setClassLevel(1L);
         List<ProductCategoryVo> productCategoryVos = productCategoryService.queryList(bo);
+        if (productCategoryVos == null){
+            throw new RuntimeException("商品类目为空");
+        }
         return R.ok(productCategoryVos);
     }
 

+ 106 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductInventoryLockController.java

@@ -0,0 +1,106 @@
+package org.dromara.product.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.product.domain.vo.ProductInventoryLockVo;
+import org.dromara.product.domain.bo.ProductInventoryLockBo;
+import org.dromara.product.service.IProductInventoryLockService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 库存锁定记录
+ * 前端访问路由地址为:/product/inventoryLock
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/inventoryLock")
+public class ProductInventoryLockController extends BaseController {
+
+    private final IProductInventoryLockService productInventoryLockService;
+
+    /**
+     * 查询库存锁定记录列表
+     */
+    //@SaCheckPermission("product:inventoryLock:list")
+    @GetMapping("/list")
+    public TableDataInfo<ProductInventoryLockVo> list(ProductInventoryLockBo bo, PageQuery pageQuery) {
+        return productInventoryLockService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 导出库存锁定记录列表
+     */
+    //@SaCheckPermission("product:inventoryLock:export")
+    @Log(title = "库存锁定记录", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(ProductInventoryLockBo bo, HttpServletResponse response) {
+        List<ProductInventoryLockVo> list = productInventoryLockService.queryList(bo);
+        ExcelUtil.exportExcel(list, "库存锁定记录", ProductInventoryLockVo.class, response);
+    }
+
+    /**
+     * 获取库存锁定记录详细信息
+     *
+     * @param id 主键
+     */
+    //@SaCheckPermission("product:inventoryLock:query")
+    @GetMapping("/{id}")
+    public R<ProductInventoryLockVo> getInfo(@NotNull(message = "主键不能为空")
+                                     @PathVariable("id") Long id) {
+        return R.ok(productInventoryLockService.queryById(id));
+    }
+
+    /**
+     * 新增库存锁定记录
+     */
+    //@SaCheckPermission("product:inventoryLock:add")
+    @Log(title = "库存锁定记录", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody ProductInventoryLockBo bo) {
+        return toAjax(productInventoryLockService.insertByBo(bo));
+    }
+
+    /**
+     * 修改库存锁定记录
+     */
+    //@SaCheckPermission("product:inventoryLock:edit")
+    @Log(title = "库存锁定记录", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ProductInventoryLockBo bo) {
+        return toAjax(productInventoryLockService.updateByBo(bo));
+    }
+
+    /**
+     * 删除库存锁定记录
+     *
+     * @param ids 主键串
+     */
+    //@SaCheckPermission("product:inventoryLock:remove")
+    @Log(title = "库存锁定记录", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "主键不能为空")
+                          @PathVariable("ids") Long[] ids) {
+        return toAjax(productInventoryLockService.deleteWithValidByIds(List.of(ids), true));
+    }
+}

+ 1 - 1
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductBase.java

@@ -62,7 +62,7 @@ public class ProductBase extends TenantEntity {
     /**
      * 单位id
      */
-    private String unitId;
+    private Long unitId;
 
     /**
      * 产品图片URL

+ 57 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductInventoryLock.java

@@ -0,0 +1,57 @@
+package org.dromara.product.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 库存锁定记录对象 product_inventory_lock
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("product_inventory_lock")
+public class ProductInventoryLock extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 关联 product_base.id
+     */
+    private Long productId;
+
+    /**
+     * 本次锁定库存量
+     */
+    private Long inventory;
+
+    /**
+     * 电商名称
+     */
+    private String accountName;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 44 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductInventoryLockBo.java

@@ -0,0 +1,44 @@
+package org.dromara.product.domain.bo;
+
+import org.dromara.product.domain.ProductInventoryLock;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 库存锁定记录业务对象 product_inventory_lock
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ProductInventoryLock.class, reverseConvertGenerate = false)
+public class ProductInventoryLockBo extends BaseEntity {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 关联 product_base.id
+     */
+    private Long productId;
+
+    /**
+     * 本次锁定库存量
+     */
+    private Long inventory;
+
+    /**
+     * 电商名称
+     */
+    private String accountName;
+
+
+}

+ 56 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductInventoryLockVo.java

@@ -0,0 +1,56 @@
+package org.dromara.product.domain.vo;
+
+import org.dromara.product.domain.ProductInventoryLock;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 库存锁定记录视图对象 product_inventory_lock
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ProductInventoryLock.class)
+public class ProductInventoryLockVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ExcelProperty(value = "id")
+    private Long id;
+
+    /**
+     * 关联 product_base.id
+     */
+    @ExcelProperty(value = "关联 product_base.id")
+    private Long productId;
+
+    /**
+     * 本次锁定库存量
+     */
+    @ExcelProperty(value = "本次锁定库存量")
+    private Long inventory;
+
+    /**
+     * 电商名称
+     */
+    @ExcelProperty(value = "电商名称")
+    private String accountName;
+
+
+}

+ 294 - 47
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductServiceImpl.java

@@ -1,13 +1,18 @@
 package org.dromara.product.dubbo;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.descriptive.summary.Product;
 import org.apache.dubbo.config.annotation.DubboService;
+import org.apache.seata.common.metadata.namingserver.Unit;
 import org.dromara.common.core.domain.zhongche.domain.Prices;
 import org.dromara.product.api.RemoteProductService;
 import org.dromara.product.api.domain.ProductCategoryRemoteVo;
@@ -16,29 +21,26 @@ import org.dromara.product.api.domain.ProductVo;
 import org.dromara.product.api.domain.SiteProductRemoteBo;
 import org.dromara.product.api.domain.SiteProductRemoteResult;
 import org.dromara.product.api.domain.SiteProductRemoteVo;
+import org.dromara.product.api.domain.zhongche.dto.ProductAggregateDto;
 import org.dromara.product.api.domain.zhongche.dto.StocksResult;
 import org.dromara.product.api.domain.zhongche.dto.StocksResultDto;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.product.domain.*;
 import org.dromara.product.domain.bo.SiteProductBo;
-import org.dromara.product.domain.vo.SiteProductVo;
-import org.dromara.product.domain.ProductPriceInventory;
+import org.dromara.product.domain.vo.*;
 import org.dromara.product.domain.bo.ProductCategoryBo;
 import org.dromara.product.api.domain.RemoteProductBrand;
-import org.dromara.product.domain.ProductBrand;
 import org.dromara.product.domain.bo.ProductBaseBo;
 import org.dromara.product.domain.bo.ProductChangeLogBo;
-import org.dromara.product.domain.vo.ProductBaseVo;
-import org.dromara.product.domain.vo.ProductCategoryVo;
-import org.dromara.product.domain.vo.ProductChangeLogVo;
-import org.dromara.product.service.IProductBaseService;
-import org.dromara.product.service.IProductCategoryService;
-import org.dromara.product.service.IProductBrandService;
-import org.dromara.product.service.IProductChangeLogService;
-import org.dromara.product.service.IProductPriceInventoryService;
+import org.dromara.product.service.*;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -62,6 +64,16 @@ public class RemoteProductServiceImpl implements RemoteProductService {
 
     private final IProductPriceInventoryService productPriceInventoryService;
 
+    private final IProductWarehouseInventoryService productWarehouseInventoryService;
+
+    private final IProductUnitService productUnitService;
+
+    private final IProductExtendService productExtendService;
+
+    private final IProductClassificationService productClassificationService;
+
+    private final IProductInventoryLockService productInventoryLockService;
+
     /**
      * 获取商品详情
      *
@@ -165,59 +177,124 @@ public class RemoteProductServiceImpl implements RemoteProductService {
 
     @Override
     public StocksResultDto queryProductStock(Map<String, Integer> goods, String areaId) {
-        List<String> goodsIds = goods.keySet().stream()
-            .collect(Collectors.toList());
+        // 1. 入参防护:避免goods为null导致后续异常
+        if (goods == null || goods.isEmpty()) {
+            return new StocksResultDto();
+        }
+
+        // 2. 提取商品ID列表,准备查询库存
+        List<String> goodsIds = goods.keySet().stream().collect(Collectors.toList());
 
-        List<ProductPriceInventory> productPriceInventories= productPriceInventoryService.queryProductStock(goodsIds);
+        // 3. 调用服务查询库存数据
+        List<ProductWarehouseInventory> productWarehouseInventories = productWarehouseInventoryService.queryProductStock(goodsIds);
 
+        // 4. 初始化返回结果(提前初始化列表,避免后续多次判断null)
         StocksResultDto stocksResultDto = new StocksResultDto();
-        productPriceInventories.forEach(productPriceInventory -> {
-            StocksResult stocksResult= new StocksResult();
-            stocksResult.setGoodsId(productPriceInventory.getProductId().toString());
-            stocksResult.setAreaId(areaId);
-            stocksResult.setStockState("1");
-            stocksResult.setStockStateDesc("有货");
-
-            //TODO 支持无库存下单商品返回(-999)
-            //当值为-1时,为未查询到。
-            //stockState=1或stockState=2时,入参goodsNum<50,该值为实际库存。
-            //入参50<=goodsNum<=100时,该值为-1。
-            //入参goodsNum>100,该值等于goodsNum。(这种情况并未返回真实库存)
-            long nowInventory   = productPriceInventory.getNowInventory()+productPriceInventory.getVirtualInventory();
-            Integer goodsNum = goods.get(productPriceInventory.getProductId().toString());
-            if (goodsNum<50){
-                stocksResult.setRemainNum((int)nowInventory);
-            }else if(goodsNum<=100){
-                stocksResult.setRemainNum(-1);
-            }else if (goodsNum>100){
-                stocksResult.setRemainNum(goodsNum);
-            }
-            //DateTime now = DateTime.now();
-            //DateTime after15Days = DateUtil.offsetDay(now, 15);
-            //stocksResult.setEstimatedShippingTime("");
-            if (stocksResultDto.getStocks() == null) {
-                stocksResultDto.setStocks(new ArrayList<>());
+
+        stocksResultDto.setStocks(new ArrayList<>());
+
+        // 5. 遍历查询结果,封装返回数据
+        productWarehouseInventories.forEach(productWarehouseInventorie -> {
+            // 5.1 提取商品核心信息
+            String productIdStr = productWarehouseInventorie.getProductId().toString();
+            Integer goodsNum = goods.get(productIdStr); // 入参的所需库存数量
+            //可用库存
+            Long nowInventory = productWarehouseInventorie.getNowInventory();
+
+            // 5.2 初始化单个商品库存结果
+            StocksResult stocksResult = new StocksResult();
+            stocksResult.setGoodsId(productIdStr);
+            stocksResult.setAreaId(areaId == null ? "" : areaId); // 地区id为空时赋值空字符串,保证格式统一
+
+            if (nowInventory > 0){
+                //有货
+                stocksResult.setStockState("1");
+                stocksResult.setStockStateDesc("下单立即发货");
+                if (goodsNum < 50){
+                    stocksResult.setRemainNum(nowInventory.intValue());
+                }else if (goodsNum <= 100){
+                    stocksResult.setRemainNum(-1);
+                }else {
+                    stocksResult.setRemainNum(goodsNum);
+                }
+            }else {
+                //无货
+                stocksResult.setStockState("5");
+                stocksResult.setStockStateDesc("无货");
+                stocksResult.setRemainNum(-999);
             }
+            // 5.6 添加到结果列表(已提前初始化,无需判断null)
             stocksResultDto.getStocks().add(stocksResult);
         });
 
+        // 6. 补充:处理「未查询到库存」的商品(即 goods 中有,但 productPriceInventories 中没有的商品)
+        // 提取已查询到的商品ID
+        Set<String> queriedGoodsIds = productWarehouseInventories.stream()
+            .map(p -> p.getProductId().toString())
+            .collect(Collectors.toSet());
+        // 遍历入参goods,补充未查询到的商品,返回 remainNum=-1
+        goods.keySet().stream()
+            .filter(goodsId -> !queriedGoodsIds.contains(goodsId))
+            .forEach(goodsId -> {
+                StocksResult noStockResult = new StocksResult();
+                noStockResult.setGoodsId(goodsId);
+                noStockResult.setAreaId(areaId == null ? "" : areaId);
+                noStockResult.setStockState(""); // 未查询到,库存状态为空
+                noStockResult.setStockStateDesc("未查询到商品库存");
+                noStockResult.setRemainNum(-1); // 文档规定:未查询到返回 -1
+                stocksResultDto.getStocks().add(noStockResult);
+            });
+
         return stocksResultDto;
     }
 
     @Override
-    public List<Prices> queryProductPrice(List<String> goodsIds) {
+    public Map<String, Prices> queryProductPrice(List<String> goodsIds) {
+        // 1. 入参防护:避免goodsIds为null/空,返回空Map
+        if (goodsIds == null || goodsIds.isEmpty()) {
+            return new HashMap<>();
+        }
         List<ProductPriceInventory> productPriceInventories= productPriceInventoryService.queryProductPrice(goodsIds);
-        return productPriceInventories.stream().map(productPriceInventory -> {
+        // 3. 初始化返回Map(key=商品sku,value=价格信息,方便快速查找)
+        Map<String, Prices> priceMap = new HashMap<>();
+
+        // 4. 遍历查询结果,封装Prices(贴合文档要求)
+        productPriceInventories.forEach(productPriceInventory -> {
+            // 4.1 提取商品sku(转换为字符串,保证与入参格式一致)
+            String goodsId = productPriceInventory.getProductId().toString();
             Prices prices = new Prices();
-            prices.setGoodsId(productPriceInventory.getProductId().toString());
-            prices.setPrice(productPriceInventory.getMemberPrice());
-            prices.setDsPrice(productPriceInventory.getMarketPrice());
+
+            // 4.2 填充必填字段
+            prices.setGoodsId(goodsId);
+
+            // 4.3 电商价格(dsPrice=市场价):处理null,保留2位小数,未查询到(此处是有数据,null则赋值-1)
+            BigDecimal marketPrice = productPriceInventory.getMarketPrice();
+
+            // 4.4 协议价格(price=会员价):处理null,保留2位小数,未查询到赋值-1
+            BigDecimal memberPrice = productPriceInventory.getMemberPrice();
+
+            // 4.5 填充非必填字段(文档允许为null/空,按当前逻辑赋值)
             prices.setTaxFreePrice(null);
             prices.setTax(productPriceInventory.getTaxRate());
             prices.setTaxCode(null);
-            return prices;
-        }).collect(Collectors.toList());
+            // 4.6 放入Map中
+            priceMap.put(goodsId, prices);
+        });
+        // 5. 补充:处理「入参有但查询结果无」的商品,按文档规则赋值-1
+        for (String goodsId : goodsIds) {
+            if (!priceMap.containsKey(goodsId)) {
+                Prices noPriceResult = new Prices();
+                noPriceResult.setGoodsId(goodsId);
+                noPriceResult.setDsPrice(new BigDecimal(-1).setScale(2, RoundingMode.HALF_UP));
+                noPriceResult.setPrice(new BigDecimal(-1).setScale(2, RoundingMode.HALF_UP));
+                noPriceResult.setTaxFreePrice(null);
+                noPriceResult.setTax(null);
+                noPriceResult.setTaxCode(null);
+                priceMap.put(goodsId, noPriceResult);
+            }
+        }
 
+        return priceMap;
     }
 
     /**
@@ -253,5 +330,175 @@ public class RemoteProductServiceImpl implements RemoteProductService {
         return result;
     }
 
+    @Override
+    public List<ProductAggregateDto> getProductInfo(List<Long> productIds) {
+        if (CollUtil.isEmpty(productIds)) {
+            return Collections.emptyList();
+        }
+        // 1. 查商品基础表
+        List<ProductBase> productList = productBaseService.list(new LambdaQueryWrapper<ProductBase>().in(ProductBase::getId, productIds));
+        if (CollUtil.isEmpty(productList)) {
+            return Collections.emptyList();
+        }
+        // 2. 查商品价格库存表
+        List<ProductPriceInventory> priceInventoryList = productPriceInventoryService.list(new LambdaQueryWrapper<ProductPriceInventory>().in(ProductPriceInventory::getProductId, productIds));
+        Map<Long, ProductPriceInventory> priceInventoryMap =
+            priceInventoryList.stream()
+                .collect(Collectors.toMap(
+                    ProductPriceInventory::getProductId,
+                    Function.identity(),
+                    (a, b) -> a
+                ));
+        // 3.查询品牌中文或英文名称
+        // 3. 品牌信息(重点)
+        Set<Long> brandIds = productList.stream()
+            .map(ProductBase::getBrandId)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+
+        Map<Long, ProductBrand> brandMap = Collections.emptyMap();
+        if (CollUtil.isNotEmpty(brandIds)) {
+            brandMap = productBrandService.list(
+                    new LambdaQueryWrapper<ProductBrand>()
+                        .in(ProductBrand::getId, brandIds)
+                ).stream()
+                .collect(Collectors.toMap(
+                    ProductBrand::getId,
+                    Function.identity()
+                ));
+        }
+        // 4. 组装聚合 DTO
+        Map<Long, ProductBrand> finalBrandMap = brandMap;
+
+        //5.查询单位名称
+        List<Long> unitIds = productList.stream()
+            .map(ProductBase::getUnitId)
+            .filter(Objects::nonNull)
+            .distinct()
+            .toList();
+
+        List<ProductUnit> unitList = productUnitService.list(new LambdaQueryWrapper<ProductUnit>().in(ProductUnit::getId, unitIds));
+        Map<Long, String> unitNameMap = unitList.stream()
+            .collect(Collectors.toMap(
+                ProductUnit::getId,
+                ProductUnit::getUnitName,
+                (a, b) -> a
+            ));
+
+        //6.查询商品描述
+        List<ProductExtend> extendList = productExtendService.list(
+            new LambdaQueryWrapper<ProductExtend>()
+                .in(ProductExtend::getProductId, productIds)
+        );
+
+        Map<Long, String> productDescMap = extendList.stream()
+            .collect(Collectors.toMap(
+                ProductExtend::getProductId,
+                ProductExtend::getProductDescription,
+                (a, b) -> a
+            ));
+
+        //7.查询商品规格
+        List<ProductClassification> productClassificationList = productClassificationService.list(
+            new LambdaQueryWrapper<ProductClassification>()
+                .in(ProductClassification::getProductId, productIds)
+        );
+
+        Map<Long, String> productClassificationMap = productClassificationList.stream()
+            .collect(Collectors.toMap(
+                ProductClassification::getProductId,
+                ProductClassification::getAttributesList,
+                (a, b) -> a
+            ));
+
+
+        // 5. 组装
+        return productList.stream().map(p -> {
+            //TODO 税收编码 写一个伪数据   商品规格没有 就写一个伪数据
+            ProductAggregateDto vo = new ProductAggregateDto();
+            vo.setProductId(p.getId());
+            vo.setName(p.getItemName());
+            vo.setDsPrice(priceInventoryMap.get(p.getId()).getMarketPrice());
+            vo.setPrice(priceInventoryMap.get(p.getId()).getMemberPrice());
+            vo.setStock(priceInventoryMap.get(p.getId()).getTotalInventory().intValue());
+            vo.setUnit(unitNameMap.get(p.getUnitId()));
+            vo.setTax(priceInventoryMap.get(p.getId()).getTaxRate());
+
+            //作json处理
+            String productImage = p.getProductImage();
+            if (StrUtil.isNotBlank(productImage)) {
+                List<String> imgList = Arrays.stream(productImage.split(","))
+                    .filter(StrUtil::isNotBlank)
+                    .toList();
+
+                vo.setBarImgUrls(JSONUtil.toJsonStr(imgList));
+            }
+            //作json处理
+            vo.setProperties(
+                Optional.ofNullable(productClassificationMap.get(p.getId()))
+                    .orElse("{\"1\":\"1kg\",\"2\":\"1cm\",\"3\":\"100\"}")
+            );
+
+            vo.setIsSelfOperated(p.getIsSelf());
+
+            // 商品描述
+            vo.setDescription(productDescMap.get(p.getId()));
+            vo.setTaxCode("123456");
+
+            // ===== 品牌名称规则处理 =====
+            ProductBrand brand = finalBrandMap.get(p.getBrandId());
+            if (brand != null) {
+                if (StrUtil.isNotBlank(brand.getBrandName())) {
+                    vo.setBrandName(brand.getBrandName());
+                } else if (StrUtil.isNotBlank(brand.getBrandEnglishName())){
+                    vo.setBrandNameEn(brand.getBrandEnglishName());
+                }else {
+                    vo.setBrandName(p.getItemName());
+                }
+
+            }
+            return vo;
+        }).toList();
+    }
+
+    @Override
+    @Transactional
+    public boolean lockShoppingCart(Long productId, Long count,String accountName) {
+        // 1. 减库存
+        boolean success = productPriceInventoryService.lambdaUpdate()
+            .eq(ProductPriceInventory::getProductId, productId)
+            .ge(ProductPriceInventory::getTotalInventory, count) // 库存必须足够
+            .setSql("total_inventory = total_inventory - " + count)
+            .update();
+
+        ProductInventoryLock lock = new ProductInventoryLock();
+        lock.setProductId(productId);
+        lock.setInventory(count);
+        lock.setAccountName(accountName);
+        success = success && productInventoryLockService.save(lock);
+        return success;
+    }
+
+    @Override
+    @Transactional
+    public boolean unlockShoppingCart(Long productId, String accountName) {
+        ProductInventoryLock lock =
+            productInventoryLockService.lambdaQuery()
+                .eq(ProductInventoryLock::getProductId, productId)
+                .eq(ProductInventoryLock::getAccountName, accountName)
+                .one();
+        if (lock == null) {
+            // 没有锁定记录,直接返回成功
+            return true;
+        }
+
+        boolean update = productPriceInventoryService.lambdaUpdate()
+            .eq(ProductPriceInventory::getProductId, productId)
+            .setSql("total_inventory = total_inventory + " + lock.getInventory())
+            .update();
+
+        return update;
+    }
+
 
 }

+ 39 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductShoppingCartServiceImpl.java

@@ -0,0 +1,39 @@
+package org.dromara.product.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.product.api.RemoteProductShoppingCartService;
+import org.dromara.product.domain.bo.ProductShoppingCartBo;
+import org.dromara.product.service.IProductShoppingCartService;
+import org.springframework.stereotype.Service;
+
+/**
+ * author
+ * 时间:2026/2/4,17:35
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@DubboService
+public class RemoteProductShoppingCartServiceImpl implements RemoteProductShoppingCartService {
+
+    private final IProductShoppingCartService productShoppingCartService;
+    @Override
+    public boolean lockShoppingCart(Long productId, Long count) {
+        ProductShoppingCartBo productShoppingCartBo = new ProductShoppingCartBo();
+        productShoppingCartBo.setProductId(productId);
+        productShoppingCartBo.setProductNum(count);
+        //加入购物车
+        Boolean b = productShoppingCartService.insertByBo(new ProductShoppingCartBo());
+        if (b) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean unlockShoppingCart(Long productId, Long count) {
+        return false;
+    }
+}

+ 15 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductInventoryLockMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.product.mapper;
+
+import org.dromara.product.domain.ProductInventoryLock;
+import org.dromara.product.domain.vo.ProductInventoryLockVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 库存锁定记录Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+public interface ProductInventoryLockMapper extends BaseMapperPlus<ProductInventoryLock, ProductInventoryLockVo> {
+
+}

+ 70 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductInventoryLockService.java

@@ -0,0 +1,70 @@
+package org.dromara.product.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.product.domain.ProductInventoryLock;
+import org.dromara.product.domain.vo.ProductInventoryLockVo;
+import org.dromara.product.domain.bo.ProductInventoryLockBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 库存锁定记录Service接口
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+public interface IProductInventoryLockService extends IService<ProductInventoryLock>{
+
+    /**
+     * 查询库存锁定记录
+     *
+     * @param id 主键
+     * @return 库存锁定记录
+     */
+    ProductInventoryLockVo queryById(Long id);
+
+    /**
+     * 分页查询库存锁定记录列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 库存锁定记录分页列表
+     */
+    TableDataInfo<ProductInventoryLockVo> queryPageList(ProductInventoryLockBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的库存锁定记录列表
+     *
+     * @param bo 查询条件
+     * @return 库存锁定记录列表
+     */
+    List<ProductInventoryLockVo> queryList(ProductInventoryLockBo bo);
+
+    /**
+     * 新增库存锁定记录
+     *
+     * @param bo 库存锁定记录
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(ProductInventoryLockBo bo);
+
+    /**
+     * 修改库存锁定记录
+     *
+     * @param bo 库存锁定记录
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(ProductInventoryLockBo bo);
+
+    /**
+     * 校验并批量删除库存锁定记录信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 2 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductWarehouseInventoryService.java

@@ -67,4 +67,6 @@ public interface IProductWarehouseInventoryService extends IService<ProductWareh
      * @return 是否删除成功
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    List<ProductWarehouseInventory> queryProductStock(List<String> goodsIds);
 }

+ 135 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductInventoryLockServiceImpl.java

@@ -0,0 +1,135 @@
+package org.dromara.product.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.product.domain.bo.ProductInventoryLockBo;
+import org.dromara.product.domain.vo.ProductInventoryLockVo;
+import org.dromara.product.domain.ProductInventoryLock;
+import org.dromara.product.mapper.ProductInventoryLockMapper;
+import org.dromara.product.service.IProductInventoryLockService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 库存锁定记录Service业务层处理
+ *
+ * @author LionLi
+ * @date 2026-02-04
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ProductInventoryLockServiceImpl  extends ServiceImpl<ProductInventoryLockMapper, ProductInventoryLock> implements IProductInventoryLockService {
+
+    private final ProductInventoryLockMapper baseMapper;
+
+    /**
+     * 查询库存锁定记录
+     *
+     * @param id 主键
+     * @return 库存锁定记录
+     */
+    @Override
+    public ProductInventoryLockVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 分页查询库存锁定记录列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 库存锁定记录分页列表
+     */
+    @Override
+    public TableDataInfo<ProductInventoryLockVo> queryPageList(ProductInventoryLockBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<ProductInventoryLock> lqw = buildQueryWrapper(bo);
+        Page<ProductInventoryLockVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 查询符合条件的库存锁定记录列表
+     *
+     * @param bo 查询条件
+     * @return 库存锁定记录列表
+     */
+    @Override
+    public List<ProductInventoryLockVo> queryList(ProductInventoryLockBo bo) {
+        LambdaQueryWrapper<ProductInventoryLock> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<ProductInventoryLock> buildQueryWrapper(ProductInventoryLockBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<ProductInventoryLock> lqw = Wrappers.lambdaQuery();
+        lqw.orderByAsc(ProductInventoryLock::getId);
+        lqw.eq(bo.getProductId() != null, ProductInventoryLock::getProductId, bo.getProductId());
+        lqw.eq(bo.getInventory() != null, ProductInventoryLock::getInventory, bo.getInventory());
+        lqw.like(StringUtils.isNotBlank(bo.getAccountName()), ProductInventoryLock::getAccountName, bo.getAccountName());
+        return lqw;
+    }
+
+    /**
+     * 新增库存锁定记录
+     *
+     * @param bo 库存锁定记录
+     * @return 是否新增成功
+     */
+    @Override
+    public Boolean insertByBo(ProductInventoryLockBo bo) {
+        ProductInventoryLock add = MapstructUtils.convert(bo, ProductInventoryLock.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 修改库存锁定记录
+     *
+     * @param bo 库存锁定记录
+     * @return 是否修改成功
+     */
+    @Override
+    public Boolean updateByBo(ProductInventoryLockBo bo) {
+        ProductInventoryLock update = MapstructUtils.convert(bo, ProductInventoryLock.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 保存前的数据校验
+     */
+    private void validEntityBeforeSave(ProductInventoryLock entity){
+        //TODO 做一些数据校验,如唯一约束
+    }
+
+    /**
+     * 校验并批量删除库存锁定记录信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 做一些业务上的校验,判断是否需要校验
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}

+ 6 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductWarehouseInventoryServiceImpl.java

@@ -137,4 +137,10 @@ public class ProductWarehouseInventoryServiceImpl  extends ServiceImpl<ProductWa
         }
         return baseMapper.deleteByIds(ids) > 0;
     }
+
+    @Override
+    public List<ProductWarehouseInventory> queryProductStock(List<String> goodsIds) {
+        List<ProductWarehouseInventory> productWarehouseInventories = baseMapper.selectList(new LambdaQueryWrapper<ProductWarehouseInventory>().in(ProductWarehouseInventory::getProductId, goodsIds));
+        return productWarehouseInventories;
+    }
 }

+ 7 - 0
ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductInventoryLockMapper.xml

@@ -0,0 +1,7 @@
+<?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="org.dromara.product.mapper.ProductInventoryLockMapper">
+
+</mapper>

+ 25 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteComLogisticsCompanyServiceImpl.java

@@ -0,0 +1,25 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.system.api.RemoteComLogisticsCompanyService;
+import org.dromara.system.domain.ComLogisticsCompany;
+import org.dromara.system.service.IComLogisticsCompanyService;
+import org.springframework.stereotype.Service;
+
+/**
+ * author
+ * 时间:2026/2/2,19:13
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteComLogisticsCompanyServiceImpl implements RemoteComLogisticsCompanyService {
+
+    private final IComLogisticsCompanyService comLogisticsCompanyService;
+    @Override
+    public String selectLogisticsCompanyNameById(Long ids) {
+        ComLogisticsCompany one = comLogisticsCompanyService.lambdaQuery().eq(ComLogisticsCompany::getId, ids).select(ComLogisticsCompany::getLogisticsName).one();
+        return one == null ? "" : one.getLogisticsName();
+    }
+}