Ver código fonte

feat(auth): 添加中车电商和同济大学电商接口支持

- 新增中车电商和同济大学电商的私钥公钥配置
- 实现getAccessToken方法用于获取访问令牌
- 添加JLDXResult类型支持统一返回格式
- 新增商品分类BProductCategory对象及业务对象BProductCategoryBo
- 添加商品对外接口BProductExternal对象及业务对象BProductExternalBo
- 创建地址对象BRegion及业务对象BRegionBo
- 实现阳光公采商城订单对象BYggcOrder及业务对象BYggcOrderBo
- 完善订单对象的验证注解和业务字段定义
肖路 5 horas atrás
pai
commit
697e200485
30 arquivos alterados com 2791 adições e 181 exclusões
  1. 130 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BProductCategory.java
  2. 197 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BProductExternal.java
  3. 45 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BRegion.java
  4. 202 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BYggcOrder.java
  5. 52 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BYggcOrderTrack.java
  6. 128 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BProductCategoryBo.java
  7. 190 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BProductExternalBo.java
  8. 49 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BRegionBo.java
  9. 222 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BYggcOrderBo.java
  10. 57 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BYggcOrderTrackBo.java
  11. 12 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/GetAreaBo.java
  12. 16 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/GetProductDetailBo.java
  13. 13 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/GetSkusBo.java
  14. 196 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/SaveBYggcOrderBo.java
  15. 12 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/TokenBo.java
  16. 3 0
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/bo/ThirdpartyProductDetailBo.java
  17. 8 18
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductDetailDto.java
  18. 139 41
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductDto.java
  19. 8 12
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductPriceDto.java
  20. 2 2
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductStatusDto.java
  21. 148 13
      ruoyi-auth/src/main/java/org/dromara/auth/controller/Auth2Controller.java
  22. 59 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/jldx/JLDXResult.java
  23. 487 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/jldx/JLDXController.java
  24. 3 3
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/tongji/TongJiPullController.java
  25. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/tongji/TongJiPushController.java
  26. 379 49
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/handler/impl/TongjiPushStrategy.java
  27. 5 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductBaseAuditBo.java
  28. 0 18
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductBaseVo.java
  29. 18 3
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseAuditServiceImpl.java
  30. 10 21
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseServiceImpl.java

+ 130 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BProductCategory.java

@@ -0,0 +1,130 @@
+package org.dromara.external.api.jldx;
+
+import lombok.Data;
+
+import java.io.Serial;
+
+/**
+ * 商品分类(支持多级类目)对象 b_product_category
+ *
+ * @author Lion Li
+ * @date 2025-08-05
+ */
+@Data
+public class BProductCategory {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键,自增ID
+     */
+    private Long id;
+
+    /**
+     * 分类编号,业务唯一编码,如 CAT001
+     */
+    private String categoryNo;
+
+    /**
+     * 分类名称,如“手机”、“笔记本电脑”
+     */
+    private String categoryName;
+
+    /**
+     * 父级分类ID(字符串类型),顶级分类为 NULL 或空字符串
+     */
+    private String parentId;
+
+    /**
+     * 分类层级:1 表示一级分类,2 表示二级分类,以此类推
+     */
+    private Integer classLevel;
+
+    /**
+     * 是否显示:1=显示,0=隐藏(前端展示控制)
+     */
+    private Integer isShow;
+
+    /**
+     * 是否在GPS相关模块显示:1=显示,0=不显示
+     */
+    private Integer isShowGps;
+
+    /**
+     * 折扣率配置(可能为JSON或多个折扣规则拼接)
+     */
+    private String discountRate;
+
+    /**
+     * 拼音码,用于搜索匹配,如“sj”代表“手机”
+     */
+    private String pyCode;
+
+    /**
+     * 分类描述,用于后台管理说明或前端提示信息
+     */
+    private String classDescription;
+
+    /**
+     * 数据来源标识,如 SYSTEM, ERP, MANUAL 等
+     */
+    private String dataSource;
+
+    /**
+     * 扩展标签1,可用于前端打标或筛选
+     */
+    private String oneLable1;
+
+    /**
+     * 扩展标签2
+     */
+    private String oneLable2;
+
+    /**
+     * 扩展链接1,如跳转H5页面地址
+     */
+    private String oneLink1;
+
+    /**
+     * 扩展链接2
+     */
+    private String oneLink2;
+
+    /**
+     * 排序权重,数值越大越靠前,相同则按ID倒序
+     */
+    private Integer sort;
+
+    /**
+     * 颜色标识,如用于前端分类标签颜色显示 #FF5722
+     */
+    private String color;
+
+    /**
+     * 采购组编号,关联采购部门
+     */
+    private String purchaseNo;
+
+    /**
+     * 采购组名称
+     */
+    private String purchaseName;
+
+    /**
+     * 采购负责人编号
+     */
+    private String purchaseManagerNo;
+
+    /**
+     * 采购负责人姓名
+     */
+    private String purchaseManagerName;
+
+    /**
+     * 所属平台标识:1=自营平台,2=第三方平台等(可根据业务定义)
+     */
+    private Integer platform;
+
+
+}

+ 197 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BProductExternal.java

@@ -0,0 +1,197 @@
+package org.dromara.external.api.jldx;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+
+/**
+ * 商品对外接口对象 b_product_external
+ *
+ * @author Lion Li
+ * @date 2025-08-05
+ */
+@Data
+public class BProductExternal  {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 商品编号
+     */
+    private String sku;
+
+    /**
+    * 格式:1_12_111,三级地址
+    * */
+    private String area;
+
+    /**
+     * 商品url
+     */
+    private String url;
+
+    /**
+     * 型号
+     */
+    private String model;
+
+    /**
+     * 重量
+     */
+    private String weight;
+
+    /**
+     * 主图地址
+     */
+    private String imagePath;
+    private String images;
+
+    /**
+     * 上下架状态
+     */
+    private String state;
+
+    /**
+     * 品牌
+     */
+    private String brandName;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 产地
+     */
+    private String productArea;
+
+    /**
+     * 条形码
+     */
+    private String upc;
+
+    /**
+     * 销售单位
+     */
+    private String unit;
+
+    /**
+     * 类别
+     */
+    private String category;
+
+    /**
+     * 售后服务
+     */
+    private String service;
+
+    /**
+     * 69码
+     */
+    private String code69;
+
+    /**
+     *
+     */
+    private String attributes;
+
+    /**
+     * 详细介绍
+     */
+    private String introduction;
+
+    /**
+     * 规格参数
+     */
+    private String param;
+
+    /**
+     * 货物
+     */
+    private String ware;
+
+    /**
+     * 是否是促销商品,数值类型,“0-不是促销产品, 1-是促销产品”
+     */
+    private String saleActives;
+
+    /**
+     * 标杆供应商   【product_extend_attributes参数】
+     */
+    private String exampleEmall;
+
+    /**
+     * 标杆供应商sku【product_extend_attributes参数】
+     */
+    private String exampleSku;
+
+    /**
+     * 标杆供应商官网价/凭证价格【product_extend_attributes参数】
+     */
+    private BigDecimal examplePrice;
+
+    /**
+     * 价格凭证【product_extend_attributes参数】
+     */
+    private String priceVoucher;
+
+    /**
+     * 价格凭证类别1. 标杆供应商商品的URL,2. 图片URL 【product_extend_attributes参数】说明:price_voucher_type必填。当price_voucher_type=1时,表明有标杆供应商,则example_emall、example_sku、example_price、price_voucher必填;当price_voucher_type=2时,price_voucher、example_price必填。当price_voucher_type不传或为空,则默认值为1
+     */
+    private String priceVoucherType;
+
+    /**
+     * 质量标准(多个质量标准,用英文","分隔)【product_extend_attributes参数】
+     */
+    private String qualities;
+
+    /**
+     * 是否采购人申请的商品(true是,false否)【product_extend_attributes参数】
+     */
+    private Long isApply;
+
+    /**
+     * 编码凭证【product_extend_attributes参数】
+     */
+    private String code69File;
+
+    /**
+     * 1有国际编码 2无国际编码并且有凭证【product_extend_attributes参数】说明: code_69_type为必填项。 当code_69_type=1时,code_69选填,当code_69_type=2时,code_69_file必填。当code_69_type不传或为空,则默认值为1。
+     */
+    private String code69Type;
+
+    /**
+     * 商品库存
+     */
+    private Integer num;
+
+    /**
+     * 价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 商城售价
+     */
+    private BigDecimal mallPrice;
+
+    /**
+     * 分类id
+     */
+    private Long catalogId;
+
+    /**
+     * 国家标准地址
+     */
+    private String codes;
+
+
+}

+ 45 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BRegion.java

@@ -0,0 +1,45 @@
+package org.dromara.external.api.jldx;
+
+import lombok.Data;
+
+import java.io.Serial;
+
+/**
+ * 地址对象 b_region
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+public class BRegion {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 深度
+     */
+    private String ancestryDepth;
+
+    /**
+     * 祖籍
+     */
+    private String pccIds;
+
+    /**
+     * 祖籍名称
+     */
+    private String pccNames;
+
+
+}

+ 202 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BYggcOrder.java

@@ -0,0 +1,202 @@
+package org.dromara.external.api.jldx;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+
+/**
+ * 阳光公采商城订单对象 b_yggc_order
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+
+public class BYggcOrder{
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 自增主键
+     */
+    private Long orderId;
+
+    /**
+     * 阳光公采商城的订单单号
+     */
+    private String yggcOrder;
+
+    /**
+     * 商品SKU
+     */
+    private String sku;
+
+    /**
+     * 收货人
+     */
+    private String name;
+
+    /**
+     * 一级地址(省)
+     */
+    private Long province;
+
+    /**
+     * 二级地址(市)
+     */
+    private Long city;
+
+    /**
+     * 三级地址(区/县)
+     */
+    private Long county;
+
+    /**
+     * 详细地址
+     */
+    private String address;
+
+    /**
+     * 邮编
+     */
+    private String zip;
+
+    /**
+     * 座机号(与mobile二选一)
+     */
+    private String phone;
+
+    /**
+     * 手机号(与phone二选一)
+     */
+    private String mobile;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 备注(少于100字)
+     */
+    private String remark;
+
+    /**
+     * 采购单位名称
+     */
+    private String depName;
+
+    /**
+     * 发票抬头(个人或公司名称)
+     */
+    private String invoiceTitle;
+
+    /**
+     * 发票类型:1-普通发票;2-增值税发票;3-电子发票
+     */
+    private Integer invoiceType;
+
+    /**
+     * 纳税人识别号
+     */
+    private String invoiceOrgCode;
+
+    /**
+     * 增值税发票收票人(invoice_type=2时必填)
+     */
+    private String invoiceName;
+
+    /**
+     * 注册电话(invoice_type=2时必填)
+     */
+    private String invoicePhone;
+
+    /**
+     * 开户银行(invoice_type=2时必填)
+     */
+    private String invoiceBank;
+
+    /**
+     * 开户行账号(invoice_type=2时必填)
+     */
+    private String invoiceBankCode;
+
+    /**
+     * 注册地址(invoice_type=2时必填)
+     */
+    private String invoiceAddress;
+
+    /**
+     * 收票联系电话
+     */
+    private String invoiceMobile;
+
+    /**
+     * 收票地址
+     */
+    private String invoiceReceiptAddress;
+
+    /**
+     * 支付方式:1-货到付款;2-国库集中支付;3-在线支付;4-支票
+     */
+    private Integer payment;
+
+    /**
+     * 订单金额(含运费)
+     */
+    private BigDecimal orderPrice;
+
+    /**
+     * 运费
+     */
+    private BigDecimal freight;
+
+    /**
+     * 订单模式:1-协议价;2-团购;3-特惠;4-阶梯价
+     */
+    private Long mode;
+
+    /**
+     * 状态 0 是新建  1是妥投完成  -1是拒收 4是退换货中
+     */
+    private String state;
+
+    /**
+     * 状态 0 未确认  1 已确认
+     */
+    private String submitState;
+
+    /**
+     * 发货状态  0 未发货  1已发货(全部)  2 部分发货
+     */
+    private String deliverState;
+
+    /**
+     * 订单总价价格
+     */
+    private BigDecimal totalPrice;
+
+    /**
+     * 采购商品列表
+     */
+    private String skus;
+
+    /**
+     * 已退货的商品
+     */
+    private String returnSkus;
+
+    /**
+     * 子订单列表(拆单时必传)
+     */
+    private String corders;
+
+    /**
+     * 订单类型:1 是父订单, 2 是子订单。如果不传,则默认是父订单
+     */
+    private String type;
+
+
+}

+ 52 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/BYggcOrderTrack.java

@@ -0,0 +1,52 @@
+package org.dromara.external.api.jldx;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * 订单状态记录对象 b_yggc_order_track
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+public class BYggcOrderTrack {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 操作时间
+     */
+    private Date operateTime;
+
+    /**
+     * 状态类型
+     */
+    private String statusType;
+
+    /**
+     * 状态名称
+     */
+    private String statusName;
+
+    /**
+     * 操作人
+     */
+    private String operator;
+
+
+}

+ 128 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BProductCategoryBo.java

@@ -0,0 +1,128 @@
+package org.dromara.external.api.jldx.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+/**
+ * 商品分类(支持多级类目)业务对象 b_product_category
+ *
+ * @author Lion Li
+ * @date 2025-08-05
+ */
+@Data
+public class BProductCategoryBo {
+
+    /**
+     * 主键,自增ID
+     */
+    private Long id;
+
+    /**
+     * 分类编号,业务唯一编码,如 CAT001
+     */
+    private String categoryNo;
+
+    /**
+     * 分类名称,如“手机”、“笔记本电脑”
+     */
+    private String categoryName;
+
+    /**
+     * 父级分类ID(字符串类型),顶级分类为 NULL 或空字符串
+     */
+    private String parentId;
+
+    /**
+     * 分类层级:1 表示一级分类,2 表示二级分类,以此类推
+     */
+    private Integer classLevel;
+
+    /**
+     * 是否显示:1=显示,0=隐藏(前端展示控制)
+     */
+    private Integer isShow;
+
+    /**
+     * 是否在GPS相关模块显示:1=显示,0=不显示
+     */
+    private Integer isShowGps;
+
+    /**
+     * 折扣率配置(可能为JSON或多个折扣规则拼接)
+     */
+    private String discountRate;
+
+    /**
+     * 拼音码,用于搜索匹配,如“sj”代表“手机”
+     */
+    private String pyCode;
+
+    /**
+     * 分类描述,用于后台管理说明或前端提示信息
+     */
+    private String classDescription;
+
+    /**
+     * 数据来源标识,如 SYSTEM, ERP, MANUAL 等
+     */
+    private String dataSource;
+
+    /**
+     * 扩展标签1,可用于前端打标或筛选
+     */
+    private String oneLable1;
+
+    /**
+     * 扩展标签2
+     */
+    private String oneLable2;
+
+    /**
+     * 扩展链接1,如跳转H5页面地址
+     */
+    private String oneLink1;
+
+    /**
+     * 扩展链接2
+     */
+    private String oneLink2;
+
+    /**
+     * 排序权重,数值越大越靠前,相同则按ID倒序
+     */
+    private Integer sort;
+
+    /**
+     * 颜色标识,如用于前端分类标签颜色显示 #FF5722
+     */
+    private String color;
+
+    /**
+     * 采购组编号,关联采购部门
+     */
+    private String purchaseNo;
+
+    /**
+     * 采购组名称
+     */
+    private String purchaseName;
+
+    /**
+     * 采购负责人编号
+     */
+    private String purchaseManagerNo;
+
+    /**
+     * 采购负责人姓名
+     */
+    private String purchaseManagerName;
+
+    /**
+     * 所属平台标识:1=自营平台,2=第三方平台等(可根据业务定义)
+     */
+    private Integer platform;
+
+
+}

+ 190 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BProductExternalBo.java

@@ -0,0 +1,190 @@
+package org.dromara.external.api.jldx.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+import java.math.BigDecimal;
+
+/**
+ * 商品对外接口业务对象 b_product_external
+ *
+ * @author Lion Li
+ * @date 2025-08-05
+ */
+@Data
+public class BProductExternalBo {
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 商品编号
+     */
+    private String sku;
+
+    /**
+     * 格式:1_12_111,三级地址
+     * */
+    private String area;
+
+    /**
+     * 商品url
+     */
+    private String url;
+
+    /**
+     * 型号
+     */
+    private String model;
+
+    /**
+     * 重量
+     */
+    private String weight;
+
+    /**
+     * 主图地址
+     */
+    private String imagePath;    private String images;
+
+    /**
+     * 上下架状态
+     */
+    private String state;
+
+    /**
+     * 品牌
+     */
+    private String brandName;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 产地
+     */
+    private String productArea;
+
+    /**
+     * 条形码
+     */
+    private String upc;
+
+    /**
+     * 销售单位
+     */
+    private String unit;
+
+    /**
+     * 类别
+     */
+    private String category;
+
+    /**
+     * 售后服务
+     */
+    private String service;
+
+    /**
+     * 69码
+     */
+    private String code69;
+
+    /**
+     *
+     */
+    private String attributes;
+
+    /**
+     * 详细介绍
+     */
+    private String introduction;
+
+    /**
+     * 规格参数
+     */
+    private String param;
+
+    /**
+     * 货物
+     */
+    private String ware;
+
+    /**
+     * 是否是促销商品,数值类型,“0-不是促销产品, 1-是促销产品”
+     */
+    private String saleActives;
+
+    /**
+     * 标杆供应商   【product_extend_attributes参数】
+     */
+    private String exampleEmall;
+
+    /**
+     * 标杆供应商sku【product_extend_attributes参数】
+     */
+    private String exampleSku;
+
+    /**
+     * 标杆供应商官网价/凭证价格【product_extend_attributes参数】
+     */
+    private BigDecimal examplePrice;
+
+    /**
+     * 价格凭证【product_extend_attributes参数】
+     */
+    private String priceVoucher;
+
+    /**
+     * 价格凭证类别1. 标杆供应商商品的URL,2. 图片URL 【product_extend_attributes参数】说明:price_voucher_type必填。当price_voucher_type=1时,表明有标杆供应商,则example_emall、example_sku、example_price、price_voucher必填;当price_voucher_type=2时,price_voucher、example_price必填。当price_voucher_type不传或为空,则默认值为1
+     */
+    private String priceVoucherType;
+
+    /**
+     * 质量标准(多个质量标准,用英文","分隔)【product_extend_attributes参数】
+     */
+    private String qualities;
+
+    /**
+     * 是否采购人申请的商品(true是,false否)【product_extend_attributes参数】
+     */
+    private Long isApply;
+
+    /**
+     * 编码凭证【product_extend_attributes参数】
+     */
+    private String code69File;
+
+    /**
+     * 1有国际编码 2无国际编码并且有凭证【product_extend_attributes参数】说明: code_69_type为必填项。 当code_69_type=1时,code_69选填,当code_69_type=2时,code_69_file必填。当code_69_type不传或为空,则默认值为1。
+     */
+    private String code69Type;
+
+    /**
+     * 商品库存
+     */
+    private Integer num;
+
+    /**
+     * 价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 分类id
+     */
+    private Long catalogId;
+
+    /**
+     * 国家标准地址
+     */
+    private String codes;
+
+
+}

+ 49 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BRegionBo.java

@@ -0,0 +1,49 @@
+package org.dromara.external.api.jldx.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+
+/**
+ * 地址业务对象 b_region
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+public class BRegionBo  {
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 名称
+     */
+    @NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String name;
+
+    /**
+     * 深度
+     */
+    @NotBlank(message = "深度不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String ancestryDepth;
+
+    /**
+     * 祖籍
+     */
+    @NotBlank(message = "祖籍不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String pccIds;
+
+    /**
+     * 祖籍名称
+     */
+    @NotBlank(message = "祖籍名称不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String pccNames;
+
+
+}

+ 222 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BYggcOrderBo.java

@@ -0,0 +1,222 @@
+package org.dromara.external.api.jldx.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+
+import java.math.BigDecimal;
+
+/**
+ * 阳光公采商城订单业务对象 b_yggc_order
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+public class BYggcOrderBo {
+
+    /**
+     * 自增主键
+     */
+    private Long orderId;
+
+    /**
+     * 阳光公采商城的订单单号
+     */
+    private String yggcOrder;
+
+    /**
+     * 商品SKU
+     */
+    private String sku;
+
+    /**
+     * 收货人
+     */
+    private String name;
+
+    /**
+     * 一级地址(省)
+     */
+    private Long province;
+
+    /**
+     * 二级地址(市)
+     */
+    private Long city;
+
+    /**
+     * 三级地址(区/县)
+     */
+    private Long county;
+
+    /**
+     * 详细地址
+     */
+    private String address;
+
+    /**
+     * 邮编
+     */
+    private String zip;
+
+    /**
+     * 座机号(与mobile二选一)
+     */
+    @NotBlank(message = "座机号(与mobile二选一)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String phone;
+
+    /**
+     * 手机号(与phone二选一)
+     */
+    @NotBlank(message = "手机号(与phone二选一)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String mobile;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 备注(少于100字)
+     */
+    @NotBlank(message = "备注(少于100字)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String remark;
+
+    /**
+     * 采购单位名称
+     */
+    @NotBlank(message = "采购单位名称不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String depName;
+
+    /**
+     * 发票抬头(个人或公司名称)
+     */
+    private String invoiceTitle;
+
+    /**
+     * 发票类型:1-普通发票;2-增值税发票;3-电子发票
+     */
+    private Integer invoiceType;
+
+    /**
+     * 纳税人识别号
+     */
+    private String invoiceOrgCode;
+
+    /**
+     * 增值税发票收票人(invoice_type=2时必填)
+     */
+    @NotBlank(message = "增值税发票收票人(invoice_type=2时必填)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoiceName;
+
+    /**
+     * 注册电话(invoice_type=2时必填)
+     */
+    @NotBlank(message = "注册电话(invoice_type=2时必填)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoicePhone;
+
+    /**
+     * 开户银行(invoice_type=2时必填)
+     */
+    @NotBlank(message = "开户银行(invoice_type=2时必填)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoiceBank;
+
+    /**
+     * 开户行账号(invoice_type=2时必填)
+     */
+    @NotBlank(message = "开户行账号(invoice_type=2时必填)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoiceBankCode;
+
+    /**
+     * 注册地址(invoice_type=2时必填)
+     */
+    @NotBlank(message = "注册地址(invoice_type=2时必填)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoiceAddress;
+
+    /**
+     * 收票联系电话
+     */
+    @NotBlank(message = "收票联系电话不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoiceMobile;
+
+    /**
+     * 收票地址
+     */
+    @NotBlank(message = "收票地址不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String invoiceReceiptAddress;
+
+    /**
+     * 支付方式:1-货到付款;2-国库集中支付;3-在线支付;4-支票
+     */
+    private Integer payment;
+
+    /**
+     * 订单金额(含运费)
+     */
+    private BigDecimal orderPrice;
+
+    /**
+     * 运费
+     */
+    private BigDecimal freight;
+
+    /**
+     * 订单模式:1-协议价;2-团购;3-特惠;4-阶梯价
+     */
+    private Long mode;
+
+    /**
+     * 状态 0 是新建  1是妥投完成  -1是拒收 4是退换货中
+     */
+    @NotBlank(message = "状态 0 是新建  1是妥投完成  -1是拒收 4是退换货中不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String state;
+
+    /**
+     * 状态 0 未确认  1 已确认
+     */
+    @NotBlank(message = "状态 0 未确认  1 已确认 不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String submitState;
+
+    /**
+     * 发货状态  0 未发货  1已发货(全部)  2 部分发货
+     */
+    @NotBlank(message = "发货状态  0 未发货  1已发货(全部)  2 部分发货不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String deliverState;
+
+    /**
+     * 订单总价价格
+     */
+    @NotNull(message = "订单总价价格不能为空", groups = { AddGroup.class, EditGroup.class })
+    private BigDecimal totalPrice;
+
+    /**
+     * 采购商品列表
+     */
+    @NotBlank(message = "采购商品列表不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String skus;
+
+    /**
+     * 已退货的商品
+     */
+    @NotBlank(message = "已退货的商品不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String returnSkus;
+
+    /**
+     * 子订单列表(拆单时必传)
+     */
+    @NotBlank(message = "子订单列表(拆单时必传)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String corders;
+
+    /**
+     * 订单类型:1 是父订单, 2 是子订单。如果不传,则默认是父订单
+     */
+    @NotBlank(message = "订单类型:1 是父订单, 2 是子订单。如果不传,则默认是父订单不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String type;
+
+
+}

+ 57 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/BYggcOrderTrackBo.java

@@ -0,0 +1,57 @@
+package org.dromara.external.api.jldx.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+
+import java.util.Date;
+
+/**
+ * 订单状态记录业务对象 b_yggc_order_track
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+public class BYggcOrderTrackBo {
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    @NotNull(message = "订单id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long orderId;
+
+    /**
+     * 操作时间
+     */
+    @NotNull(message = "操作时间不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Date operateTime;
+
+    /**
+     * 状态类型
+     */
+    private String statusType;
+
+    /**
+     * 状态名称
+     */
+    @NotBlank(message = "内容不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String statusName;
+
+    /**
+     * 操作人
+     */
+    @NotBlank(message = "操作人不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String operator;
+
+
+}

+ 12 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/GetAreaBo.java

@@ -0,0 +1,12 @@
+package org.dromara.external.api.jldx.bo;
+
+import lombok.Data;
+
+/**
+ * @author
+ * @date 2025/8/12 下午6:02
+ */
+@Data
+public class GetAreaBo extends TokenBo{
+    private String id;
+}

+ 16 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/GetProductDetailBo.java

@@ -0,0 +1,16 @@
+package org.dromara.external.api.jldx.bo;
+
+import lombok.Data;
+
+/**
+ * @author
+ * @date 2025/8/12 下午5:57
+ */
+@Data
+public class GetProductDetailBo extends TokenBo {
+    private String sku;
+
+    private String skus;
+
+    private String area;
+}

+ 13 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/GetSkusBo.java

@@ -0,0 +1,13 @@
+package org.dromara.external.api.jldx.bo;
+
+import lombok.Data;
+
+/**
+ * @author
+ * @date 2025/8/12 下午5:51
+ */
+@Data
+public class GetSkusBo extends TokenBo{
+
+    private String catalog_id;
+}

+ 196 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/SaveBYggcOrderBo.java

@@ -0,0 +1,196 @@
+package org.dromara.external.api.jldx.bo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 阳光公采商城订单对象 b_yggc_order
+ *
+ * @author Lion Li
+ * @date 2025-08-07
+ */
+@Data
+public class SaveBYggcOrderBo extends TokenBo {
+
+
+    /**
+     *
+     */
+    private Long order_id;
+
+    /**
+     * 阳光公采商城的订单单号
+     */
+    private String yggc_order;
+
+    /**
+     * 商品SKU
+     */
+    private String sku;
+
+    /**
+     * 收货人
+     */
+    private String name;
+
+    /**
+     * 一级地址(省)
+     */
+    private Long province;
+
+    /**
+     * 二级地址(市)
+     */
+    private Long city;
+
+    /**
+     * 三级地址(区/县)
+     */
+    private Long county;
+
+    /**
+     * 详细地址
+     */
+    private String address;
+
+    /**
+     * 邮编
+     */
+    private String zip;
+
+    /**
+     * 座机号(与mobile二选一)
+     */
+    private String phone;
+
+    /**
+     * 手机号(与phone二选一)
+     */
+    private String mobile;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 备注(少于100字)
+     */
+    private String remark;
+
+    /**
+     * 采购单位名称
+     */
+    private String dep_name;
+
+    /**
+     * 发票抬头(个人或公司名称)
+     */
+    private String invoice_title;
+
+    /**
+     * 发票类型:1-普通发票;2-增值税发票;3-电子发票
+     */
+    private Integer invoice_type;
+
+    /**
+     * 纳税人识别号
+     */
+    private String invoice_org_code;
+
+    /**
+     * 增值税发票收票人(invoice_type=2时必填)
+     */
+    private String invoice_name;
+
+    /**
+     * 注册电话(invoice_type=2时必填)
+     */
+    private String invoice_phone;
+
+    /**
+     * 开户银行(invoice_type=2时必填)
+     */
+    private String invoice_bank;
+
+    /**
+     * 开户行账号(invoice_type=2时必填)
+     */
+    private String invoice_bank_code;
+
+    /**
+     * 注册地址(invoice_type=2时必填)
+     */
+    private String invoice_address;
+
+    /**
+     * 收票联系电话
+     */
+    private String invoice_mobile;
+
+    /**
+     * 收票地址
+     */
+    private String invoice_receipt_address;
+
+    /**
+     * 支付方式:1-货到付款;2-国库集中支付;3-在线支付;4-支票
+     */
+    private Integer payment;
+
+    /**
+     * 订单金额(含运费)
+     */
+    private BigDecimal order_price;
+
+    /**
+     * 运费
+     */
+    private BigDecimal freight;
+
+    /**
+     * 订单模式:1-协议价;2-团购;3-特惠;4-阶梯价
+     */
+    private Long mode;
+
+    /**
+     * 状态 0 是新建  1是妥投完成  -1是拒收 4是退换货中
+     */
+    private String state;
+
+    /**
+     * 状态 0 未确认  1 已确认
+     */
+    private String submit_state;
+
+    /**
+     * 发货状态  0 未发货  1已发货(全部)  2 部分发货
+     */
+    private String deliver_state;
+
+    /**
+     * 订单总价价格
+     */
+    private BigDecimal total_price;
+
+    /**
+     * 采购商品列表
+     */
+    private String skus;
+
+    /**
+     * 已退货的商品
+     */
+    private String return_skus;
+
+    /**
+     * 子订单列表(拆单时必传)
+     */
+    private String corders;
+
+    /**
+     * 订单类型:1 是父订单, 2 是子订单。如果不传,则默认是父订单
+     */
+    private String type;
+}

+ 12 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/jldx/bo/TokenBo.java

@@ -0,0 +1,12 @@
+package org.dromara.external.api.jldx.bo;
+
+import lombok.Data;
+
+/**
+ * @author
+ * @date 2025/8/12 下午5:55
+ */
+@Data
+public class TokenBo {
+    private String token;
+}

+ 3 - 0
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/bo/ThirdpartyProductDetailBo.java

@@ -1,5 +1,7 @@
 package org.dromara.external.api.thirdparty.domain.bo;
 
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
 import java.io.Serial;
@@ -19,5 +21,6 @@ public class ThirdpartyProductDetailBo implements Serializable {
     /**
      * 产品编号
      */
+    @NotBlank(message = "商品编号不能为空")
     private String productNo;
 }

+ 8 - 18
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductDetailDto.java

@@ -33,28 +33,18 @@ public class ThirdpartyProductDetailDto implements Serializable {
     private String itemName;
 
     /**
-     * 商品图片
+     * 产品图片URL
      */
-    private String photo;
+    private String productImage;
 
     /**
-     * 商品多图
-     */
-    private List<ProductImage> productImages;
+     * 商品多图,分隔
+     * */
+    private String imageUrl;
 
     /**
-     * 品详情
+     * 品详情
      */
-    private String content;
-
-    @Data
-    public static class ProductImage implements Serializable {
-        @Serial
-        private static final long serialVersionUID = 1L;
-
-        /**
-         * 图片URL
-         */
-        private String imageUrl;
-    }
+    private String pcDetail;
+
 }

+ 139 - 41
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductDto.java

@@ -5,6 +5,7 @@ import lombok.Data;
 import java.io.Serial;
 import java.io.Serializable;
 import java.math.BigDecimal;
+import java.util.List;
 
 /**
  * 商品数据
@@ -18,108 +19,205 @@ public class ThirdpartyProductDto implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
-     * 产品编号
+     * 产品名称
      */
-    private String productNo;
+    private String itemName;
 
     /**
-     * 商品主图
+     * 品牌id
      */
-    private String photo;
+    private Long brandId;
 
     /**
-     * 商品多图
+     * 品牌名称
      */
-    private String productImages;
+    private String brandName;
 
     /**
-     * 商品详情
+     * 顶级分类id
      */
-    private String content;
+    private Long topCategoryId;
 
     /**
-     * 产品名称
+     * 中级分类id
      */
-    private String itemName;
+    private Long mediumCategoryId;
+
+    /**
+     * 底层分类id
+     */
+    private Long bottomCategoryId;
+
+    /**
+     * 分类名称(底级分类)
+     */
+    private String categoryName;
+
+    /**
+     * 顶级分类名称
+     */
+    private String topCategoryName;
+
+    /**
+     * 中级分类名称
+     */
+    private String mediumCategoryName;
+
+    /**
+     * 底级分类名称
+     */
+    private String bottomCategoryName;
 
     /**
-     * 一级分类ID
+     * 规格代码
      */
-    private String cateLable;
+    private String specificationsCode;
 
     /**
-     * 二级分类ID
+     * 单位id
      */
-    private String cateLevel;
+    private String unitId;
 
     /**
-     * 三级分类ID
+     * 单位名称(如:件、箱、千克等)
      */
-    private String cateProduct;
+    private String unitName;
+
+    /**
+     * 产品图片URL
+     */
+    private String productImage;
+
+    /**
+     * 商品多图
+     * */
+    private String imageUrl;
+
 
     /**
-     * 单位名称(如:件、箱、千克等)
+     * 是否自营(1=是,0=否
      */
-    private String pdunit;
+    private Integer isSelf;
 
     /**
      * 市场价
+     * */
+    private BigDecimal marketPrice;
+
+    /**
+     * 官网价格
      */
-    private BigDecimal pdpricemarket;
+    private BigDecimal memberPrice;
+
+    /**
+     * 协议价价格
+     * */
+    private BigDecimal externalPrice;
 
     /**
-     * 平台价格
+     * 规格型号
      */
-    private BigDecimal pdpricemall;
+    private String specification;
 
     /**
-     * 供应价格
+     * UPC(S)条码
      */
-    private BigDecimal pdpricesale;
+    private String barCoding;
 
     /**
-     * 折扣率
+     * 发票名称
      */
-    private String pddiscount;
+    private String invoiceName;
 
     /**
-     * 上下架状态:3=上架,4=下架
+     * 发票规格
      */
-    private Integer pdStatus;
+    private String invoiceSpecs;
 
     /**
-     * 商品卖点
+     * 包装规格
      */
-    private String pdhotpoint;
+    private String packagingSpec;
 
     /**
-     * 起订量
+     * 参考链接
      */
-    private Integer pdsaleunit;
+    private String referenceLink;
 
     /**
-     * 品牌名称
+     * 商品重量
      */
-    private String brandName;
+    private String productWeight;
+
+    /**
+     * 重量单位
+     */
+    private String weightUnit;
+
+    /**
+     * 商品体积
+     */
+    private String productVolume;
+
+    /**
+     * 体积单位
+     */
+    private String volumeUnit;
 
     /**
-     * 售后信息
+     * 商品详情
      */
-    private String pdsaleinfo;
+    private String pcDetail;
 
     /**
-     * 商品属性
+     * 税率
      */
-    private String attributes;
+    private BigDecimal taxRate;
 
     /**
-     * 可用库存数量
+     * 币种
      */
-    private Integer availableStockNum;
+    private String currency;
 
     /**
-     * 占用库存数
+     * 最低起订
      */
-    private Integer occupyStockNum;
+    private Long minOrderQuantity;
+
+    /**
+     * 是否可定制 0:不可定制 1:可定制
+     * */
+    private String isCustomize;
+
+    /**
+     * 总库存
+     * */
+    private Long totalInventory;
+    /**
+     * 当前可用库存
+     * */
+    private Long nowInventory;
+
+    /**
+     * 商品属性值(JSON字符串)
+     */
+    private String attributesList;
+
+    /**
+     * 自定义商品属性(JSON字符串)
+     * */
+    private String diyAttributesList;
+
+    /**
+     * 税收编码id
+     *
+     * */
+    private Long taxationId;
+    /**
+     * 税收编码code
+     *
+     * */
+    private Long taxationCode;
+
 
 }

+ 8 - 12
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductPriceDto.java

@@ -33,22 +33,18 @@ public class ThirdpartyProductPriceDto implements Serializable {
     private String itemName;
 
     /**
-     * 市场价
-     */
-    private BigDecimal pdpricemarket;
+     * 市场价
+     * */
+    private BigDecimal marketPrice;
 
     /**
-     * 平台价格
+     * 官网价格
      */
-    private BigDecimal pdpricemall;
+    private BigDecimal memberPrice;
 
     /**
-     * 供应价格
-     */
-    private BigDecimal pdpricesale;
+     * 协议价价格
+     * */
+    private BigDecimal externalPrice;
 
-    /**
-     * 折扣率
-     */
-    private String pddiscount;
 }

+ 2 - 2
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/thirdparty/domain/dto/ThirdpartyProductStatusDto.java

@@ -32,7 +32,7 @@ public class ThirdpartyProductStatusDto implements Serializable {
     private String itemName;
 
     /**
-     * 产品状态3-上架4-下架
+     * 产品状态0-上架1-下架
      */
-    private Integer pdstatus;
+    private Integer productStatus;
 }

+ 148 - 13
ruoyi-auth/src/main/java/org/dromara/auth/controller/Auth2Controller.java

@@ -15,6 +15,7 @@ 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.core.domain.jldx.JLDXResult;
 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;
@@ -42,16 +43,42 @@ public class Auth2Controller {
 
     // ========== 读取yml中的真实公私钥(直接复制使用) ==========
 
-    //测试环境
-    //电商私钥
-//    private final static String DEVELOPER_PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgpQdXwMi21Mg1FhWad2AQLOwfNiDHgwhootau0YerQbagCgYIKoEcz1UBgi2hRANCAATVjJs6XRAMTZ72G6aWbgCAjfAnW0j5R9VFnHySTiF8+1mOisc3xOOr9w/Tu3hixzL5H2gVyLzHDRWkFtyeVqrX";
-//    //企采公钥
-//    private final static String DEVELOPER_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmUrB5ByAeb8jHayC7vbddqBFDIEsf1cpNO1qJttZ17xlDagVB/tBFasPr/x0+OWf2kimTKah2NGCYarymD1R5Q==";
-    //正式环境
-    //电商私钥
-    private final static String DEVELOPER_PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgQu0H97EPqkgz1YS5LkzZNmkG3mS5Er8rJ2LSoJtuOlGgCgYIKoEcz1UBgi2hRANCAARP6NYwTHpW2QTL8A2f2hpgunEpDVkJBhErBQPLqNS/Si5Q+9I9wUpCYdk1EvB5Hw6yzkE4bYk5IZM1j+/SnNFn";
-    //企采公钥
-    private final static String DEVELOPER_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE9ITEKJdH9o1K9AeQYY7zNMo/q5/cdce+9jbawURTPEpBKAx4VkB+lRkb5e5YL+Be4pPM464rPvLyfqGNJvL6uQ==";
+    //中车电商私钥
+    private final static String ZHONGCHE_DEVELOPER_PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgQu0H97EPqkgz1YS5LkzZNmkG3mS5Er8rJ2LSoJtuOlGgCgYIKoEcz1UBgi2hRANCAARP6NYwTHpW2QTL8A2f2hpgunEpDVkJBhErBQPLqNS/Si5Q+9I9wUpCYdk1EvB5Hw6yzkE4bYk5IZM1j+/SnNFn";
+    //中车企采公钥
+    private final static String ZHONGCHE_DEVELOPER_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE9ITEKJdH9o1K9AeQYY7zNMo/q5/cdce+9jbawURTPEpBKAx4VkB+lRkb5e5YL+Be4pPM464rPvLyfqGNJvL6uQ==";
+
+    //同济电商私钥
+    private final static String TONGJI_DEVELOPER_PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgQu0H97EPqkgz1YS5LkzZNmkG3mS5Er8rJ2LSoJtuOlGgCgYIKoEcz1UBgi2hRANCAARP6NYwTHpW2QTL8A2f2hpgunEpDVkJBhErBQPLqNS/Si5Q+9I9wUpCYdk1EvB5Hw6yzkE4bYk5IZM1j+/SnNFn";
+    //同济企采公钥
+    private final static String TONGJI_DEVELOPER_PUBLIC_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgQu0H97EPqkgz1YS5LkzZNmkG3mS5Er8rJ2LSoJtuOlGgCgYIKoEcz1UBgi2hRANCAARP6NYwTHpW2QTL8A2f2hpgunEpDVkJBhErBQPLqNS/Si5Q+9I9wUpCYdk1EvB5Hw6yzkE4bYk5IZM1j+/SnNFn";
+    /**
+     * 获取 Access Token
+     * @param username 用户名
+     * @param password 密码(明文,生产环境建议加密后再传)
+     * @return 包含 access_token 和 expires_at 的 JLDXResult,失败则 success=false
+     */
+    @PostMapping("/access_token")
+    public static JLDXResult getAccessToken(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);
+
+        if(Objects.equals(sign1,sign)){
+            LoginVo loginVo = IAuthStrategy.getAccessToken(username, password);
+            if(ObjectUtil.isEmpty(loginVo)){
+                return JLDXResult.fail("授权失败");
+            }
+            if(ObjectUtil.isNotEmpty(loginVo.getMsg())){
+                return JLDXResult.fail(loginVo.getMsg());
+            }
+            DateTime date = DateUtil.offsetSecond(DateUtil.date(), (int) StpUtil.getTokenTimeout(loginVo.getAccessToken()));
+            String format = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss");
+            return  JLDXResult.tokenOk(loginVo.getAccessToken(), format);
+        } else  {
+            return JLDXResult.fail("授权失败,签名不不匹配");
+        }
+    }
 
     /**
      * 获取 Access Token  ZHONGZHI
@@ -115,7 +142,115 @@ public class Auth2Controller {
         // ========== 步骤2:签名校验(核心!复用工具类,无需修改工具类) ==========
         boolean signVerifyResult = false;
         try {
-            signVerifyResult = SignParamUtils.verifyRequestSign(zcTokenBo, DEVELOPER_PUBLIC_KEY);
+            signVerifyResult = SignParamUtils.verifyRequestSign(zcTokenBo, ZHONGCHE_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:业务逻辑校验( ==========
+        //这里用的肖哥的逻辑
+        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, null); // 先填充 data,暂不填 sign
+        String respSignContent = null;
+        try {
+            respSignContent = SignParamUtils.getSignContent(successZcr);
+        } catch (JsonProcessingException e) {
+            return ZCR.fail("1001", "接口响应签名错误(验签异常)");
+        }
+        String respSign = SM2SignatureUtils.sign(respSignContent, ZHONGCHE_DEVELOPER_PRIVATE_KEY);
+        // ========== 步骤8:返回成功响应(填充最终签名) ==========
+        log.info("中车电商登录授权成功,用户名:{},accessToken:{}", username, accessToken);
+        return ZCR.ok(respData, respSign);
+
+    }
+
+    /**
+     * 获取 Access Token  ZHONGChe
+     * 注册地址:武汉市硚口区古田二路长丰村长丰乡15栋1号5室
+     * 供应商名称:优易达(武汉)有限公司
+     * 管理员手机号:18062697722
+     * 管理员名称:刘洋
+     * 电商系统域名(生产):apipre.yoe365.com
+     * 登录用户名:api_zczc_202403166035
+     * 登陆密码:brsa1odzd28xnqz4
+     * @return 包含 access_token 和 expires_at 的 ZZResult,失败则 success=false
+     */
+    @PostMapping("/tongji/access_token")
+    public ZCR getAccessTokenTongji(@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, TONGJI_DEVELOPER_PUBLIC_KEY);
         } catch (JsonProcessingException e) {
             return ZCR.fail("1001", "接口签名错误(验签异常)");
         }
@@ -181,7 +316,7 @@ public class Auth2Controller {
         } catch (JsonProcessingException e) {
             return ZCR.fail("1001", "接口响应签名错误(验签异常)");
         }
-        String respSign = SM2SignatureUtils.sign(respSignContent, DEVELOPER_PRIVATE_KEY);
+        String respSign = SM2SignatureUtils.sign(respSignContent, TONGJI_DEVELOPER_PRIVATE_KEY);
         // ========== 步骤8:返回成功响应(填充最终签名) ==========
         log.info("中车电商登录授权成功,用户名:{},accessToken:{}", username, accessToken);
         return ZCR.ok(respData, respSign);
@@ -197,7 +332,7 @@ public class Auth2Controller {
         bo.setVersion("1.0.0");
 
 
-        String sign = SignParamUtils.generateRequestSign(bo, DEVELOPER_PRIVATE_KEY);
+        String sign = SignParamUtils.generateRequestSign(bo, ZHONGCHE_DEVELOPER_PRIVATE_KEY);
         bo.setSign(sign);
 
         System.out.println("生成的签名: " + sign);

+ 59 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/jldx/JLDXResult.java

@@ -0,0 +1,59 @@
+package org.dromara.common.core.domain.jldx;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+@NoArgsConstructor
+public class JLDXResult<T> implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 成功
+     */
+    private static final boolean SUCCESS = true;
+
+    /**
+     * 失败
+     */
+    private static final boolean FAIL = false;
+
+    private Boolean success;
+    private int code;
+    private String access_token;
+    private String expires_at;
+    private String desc;
+    private T result;
+
+    public static <T> JLDXResult<T> tokenOk(String accessToken, String expires_at) {
+        return restResult( SUCCESS,accessToken,expires_at, "",null);
+    }
+
+    public static <T> JLDXResult<T> ok(T result) {
+        return restResult( SUCCESS,"","", "",result);
+    }
+
+    public static <T> JLDXResult<T> ok(String msg, T result) {
+        return restResult( SUCCESS,"","", msg,result);
+    }
+
+    public static <T> JLDXResult<T> fail(String msg) {
+        return restResult( FAIL, "","",msg,null);
+    }
+
+
+
+    private static <T> JLDXResult<T> restResult(boolean success, String accessToken, String expires_at, String desc, T result) {
+        JLDXResult JLDXResult = new JLDXResult();
+        JLDXResult.setResult( result);
+        JLDXResult.setSuccess(success);
+        JLDXResult.setAccess_token(accessToken);
+        JLDXResult.setExpires_at(expires_at);
+        JLDXResult.setDesc(desc);
+        return JLDXResult;
+    }
+}

+ 487 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/jldx/JLDXController.java

@@ -0,0 +1,487 @@
+package org.dromara.external.controller.jldx;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.compress.utils.Lists;
+import org.dromara.common.core.domain.jldx.JLDXResult;
+import org.dromara.external.api.jldx.*;
+import org.dromara.external.api.jldx.bo.*;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 对外接口
+ *
+ * @author
+ * @date 2025/8/5 下午6:31
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping(value = "/api")
+public class JLDXController {
+
+
+    /**
+     * 查询商品对外接口列表
+     */
+    @PostMapping(value = "product/get_pools")
+    public JLDXResult get_pools(TokenBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        List<BProductCategory> list = new ArrayList<>();
+        List<Map<String, Object>> maps = list.stream().map(item -> {
+            Map<String, Object> map = new HashMap<>();
+            map.put("id", item.getId());
+            map.put("name", item.getCategoryName());
+            return map;
+        }).toList();
+        return JLDXResult.ok(maps);
+    }
+    /**
+    * 获取商品SKU
+    * */
+    @PostMapping(value = "product/skus")
+    public JLDXResult productSkus(GetSkusBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getCatalog_id())){
+            return JLDXResult.fail("catalog_id不能为空");
+        }
+        List<BProductExternal> bProductExternals = new ArrayList<>();
+        List<String> skus = bProductExternals.stream().map(item -> item.getSku()).toList();
+        return JLDXResult.ok(skus);
+    }
+    /**
+     * 商品详情接口
+     * */
+    @PostMapping(value = "product/detail")
+    public JLDXResult productDetail(GetProductDetailBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSku())){
+            return JLDXResult.fail("sku不能为空");
+        }
+        BProductExternal sku = new BProductExternal();
+        if(ObjectUtil.isEmpty(sku)){
+            return JLDXResult.fail("商品不存在");
+        }
+        Map<String, Object> map = BeanUtil.beanToMap(sku, true, false);
+        map.put("code_69",sku.getCode69());
+        map.put("code_69_file",sku.getCode69File());
+        map.put("code_69_type",sku.getCode69Type());
+        return JLDXResult.ok(map);
+    }
+    /**
+    * 获取商品标准信息(新增)
+    * */
+    @PostMapping(value = "product/product_quality", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public JLDXResult productQuality(GetProductDetailBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSkus())){
+            return JLDXResult.fail("skus不能为空");
+        }
+        String[] skusSplit = bo.getSkus().split(",");
+        if(ObjectUtil.isEmpty(skusSplit)){
+            return JLDXResult.fail("skus不能为空");
+        }
+        List<BProductExternal> bProductExternals = new ArrayList<>();
+        List<Map<String, Object>> maps = bProductExternals.stream().map(item -> {
+            Map<String, Object> map = new HashMap<>();
+            map.put("sku", item.getSku());
+            map.put("codes",ObjectUtil.isEmpty(item.getQualities())? Lists.newArrayList() : JSONUtil.parseArray(item.getQualities()));
+            return map;
+        }).toList();
+        return JLDXResult.ok(maps);
+    }
+
+    /**
+     * 上下架状态接口
+     * */
+    @PostMapping(value = "product/shelf_states")
+    public JLDXResult shelf_states(GetProductDetailBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSku())){
+            return JLDXResult.fail("sku不能为空");
+        }
+        String[] skusSplit = bo.getSku().split(",");
+        if(ObjectUtil.isEmpty(skusSplit)){
+            return JLDXResult.fail("sku不能为空");
+        }
+        List<BProductExternal> bProductExternals = new ArrayList<>();
+        List<Map<String, Object>> maps = bProductExternals.stream().map(item -> {
+            Map<String, Object> map = new HashMap<>();
+            map.put("sku", item.getSku());
+            map.put("state",item.getState());
+            return map;
+        }).toList();
+        return JLDXResult.ok(maps);
+    }
+
+    /**
+    * 图片接口
+    * */
+    @PostMapping(value = "product/images")
+    public JLDXResult images(GetProductDetailBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSku())){
+            return JLDXResult.fail("sku不能为空");
+        }
+        String[] skusSplit = bo.getSku().split(",");
+        if(ObjectUtil.isEmpty(skusSplit)){
+            return JLDXResult.fail("sku不能为空");
+        }
+        List<BProductExternal> bProductExternals = new ArrayList<>();
+        List<Map<String, Object>> maps = bProductExternals.stream().map(item -> {
+            Map<String, Object> map = new HashMap<>();
+            map.put("sku", item.getSku());
+            String[] split = item.getImages().split(",");
+            List<Map<String, Object>> images = Arrays.stream(split).map(image -> {
+                Map<String, Object> imagePath = new HashMap<>();
+                imagePath.put("path", image);
+                imagePath.put("order", Arrays.asList(split).indexOf(image));
+                return imagePath;
+            }).toList();
+            map.put("images",ObjectUtil.isEmpty(images)?Lists.newArrayList():images);
+            return map;
+        }).toList();
+        return JLDXResult.ok(maps);
+    }
+    /**
+    * 获取一级地址
+    * */
+    @PostMapping(value = "area/provinces")
+    public JLDXResult areaProvinces(GetAreaBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        List<BRegion> bRegions = new ArrayList<>();
+        if(ObjectUtil.isEmpty(bRegions)){
+            return JLDXResult.ok(new HashMap<String, Long>());
+        }
+        Map<String, Long> map = bRegions.stream().collect(Collectors.toMap(BRegion::getName, BRegion::getId));
+        return JLDXResult.ok(map);
+    }
+    /**
+     * 获取二级地址
+     * */
+    @PostMapping(value = "area/cities")
+    public JLDXResult areaCities(GetAreaBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getId())){
+            return JLDXResult.fail("id不能为空");
+        }
+        List<BRegion> bRegions = new ArrayList<>();
+        if(ObjectUtil.isEmpty(bRegions)){
+            return JLDXResult.ok(new HashMap<String, Long>());
+        }
+        Map<String, Long> map = bRegions.stream().collect(Collectors.toMap(BRegion::getName, BRegion::getId));
+        return JLDXResult.ok(map);
+    }
+    /**
+     * 获取三级地址
+     * */
+    @PostMapping(value = "area/getCounty")
+    public JLDXResult areaGetCounty(GetAreaBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getId())){
+            return JLDXResult.fail("id不能为空");
+        }
+        List<BRegion> bRegions = new ArrayList<>();
+        if(ObjectUtil.isEmpty(bRegions)){
+            return JLDXResult.ok(new HashMap<String, Long>());
+        }
+        Map<String, Long> map = bRegions.stream().collect(Collectors.toMap(BRegion::getName, BRegion::getId));
+        return JLDXResult.ok(map);
+    }
+
+
+    /**
+     * 价格接口
+     * */
+    @PostMapping(value = "product/prices")
+    public JLDXResult prices(GetProductDetailBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSku())){
+            return JLDXResult.fail("sku不能为空");
+        }
+        String[] skusSplit = bo.getSku().split(",");
+        if(ObjectUtil.isEmpty(skusSplit)){
+            return JLDXResult.fail("sku不能为空");
+        }
+        List<BProductExternal> bProductExternals = new ArrayList<>();
+        List<Map<String, Object>> maps = bProductExternals.stream().map(item -> {
+            Map<String, Object> map = new HashMap<>();
+            map.put("sku", item.getSku());
+            map.put("price",item.getPrice());
+            map.put("mall_price",item.getMallPrice());
+            return map;
+        }).toList();
+        return JLDXResult.ok(maps);
+    }
+    /**
+    * 库存接口
+    * */
+    @PostMapping(value = "product/stocks")
+    public JLDXResult productStocks(GetProductDetailBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSku())){
+            return JLDXResult.fail("sku不能为空");
+        }
+        if(ObjectUtil.isEmpty(bo.getArea())){
+            return JLDXResult.fail("area不能为空");
+        }
+        String[] skusSplit = bo.getSku().split(",");
+        if(ObjectUtil.isEmpty(skusSplit)){
+            return JLDXResult.fail("sku不能为空");
+        }
+        List<BProductExternal> bProductExternals = new ArrayList<>();
+        if(ObjectUtil.isEmpty(bProductExternals)){
+            List<Map<String, Object>> maps = Arrays.stream(skusSplit).map(item -> {
+                Map<String, Object> map = new HashMap<>();
+                map.put("sku", item);
+                map.put("area", bo.getArea());
+                map.put("num", 0);
+                map.put("desc", "无货");
+                return map;
+            }).toList();
+            return JLDXResult.ok(maps);
+        }else {
+            List<Map<String, Object>> maps = bProductExternals.stream().map(item -> {
+                Map<String, Object> map = new HashMap<>();
+                map.put("sku", item.getSku());
+                map.put("area", bo.getArea());
+                map.put("num",item.getNum());
+                if(ObjectUtil.isNotEmpty(item.getNum())&&item.getNum()>0){
+                    map.put("desc","有货");
+                }else {
+                    map.put("desc","无货");
+                }
+                return map;
+            }).toList();
+            return JLDXResult.ok(maps);
+        }
+    }
+    /**
+    * 预下单接口
+    * */
+    @PostMapping(value = "order/submit")
+    public JLDXResult orderSubmit(SaveBYggcOrderBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getSku())){
+            return JLDXResult.fail("sku不能为空");
+        }
+        List<Map> skus = JSONUtil.toList(bo.getSku(), Map.class);
+        if(ObjectUtil.isEmpty(skus)){
+            return JLDXResult.fail("sku不能为空");
+        }
+
+        for (Map map : skus) {
+            BProductExternal one = new BProductExternal();
+            if(ObjectUtil.isEmpty(one)){
+                return JLDXResult.fail("商品不存在");
+            }
+            if( one.getNum() - (Integer) map.get("num") <= 0){
+                return JLDXResult.fail("库存不足");
+            }
+//            bProductExternalService.update(Wrappers.lambdaUpdate(BProductExternal.class)
+//                .eq(BProductExternal::getId, one.getId())
+//                .set(BProductExternal::getNum, one.getNum() - (Integer) map.get("num"))
+//            );
+        }
+
+        BYggcOrder bYggcOrder = BeanUtil.toBean(bo, BYggcOrder.class);
+//        boolean save = byggcOrderService.save(bYggcOrder);
+//        if(!save){
+//            return JLDXResult.fail("下单失败");
+//        }
+//        BYggcOrderTrack byggcOrderTrack = new BYggcOrderTrack();
+//        byggcOrderTrack.setOrderId(bYggcOrder.getOrderId());
+//        byggcOrderTrack.setStatusType("发货");
+//        byggcOrderTrack.setOperateTime(DateUtil.date());
+//        byggcOrderTrack.setOperator("客户");
+//        byggcOrderTrack.setStatusName("订单已提交");
+//        byggcOrderTrackService.save(byggcOrderTrack);
+        Map<Object, Object> map = new HashMap<>();
+        map.put("mall_order_id",bYggcOrder.getOrderId());
+        map.put("sku",bYggcOrder.getSku());
+        map.put("order_price",bYggcOrder.getOrderPrice());
+        map.put("freight",bYggcOrder.getFreight());
+        return JLDXResult.ok(map);
+    }
+    /**
+    * 确认订单接口
+    * */
+    @PostMapping(value = "order/confirm")
+    public JLDXResult orderConfirm(SaveBYggcOrderBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getOrder_id())){
+            return JLDXResult.fail("order_id不能为空");
+        }
+//        byggcOrderService.update(Wrappers.lambdaUpdate(BYggcOrder.class)
+//            .set(BYggcOrder::getSubmitState, "1")
+//            .eq(BYggcOrder::getOrderId, bo.getOrder_id())
+//        );
+//        BYggcOrderTrack byggcOrderTrack = new BYggcOrderTrack();
+//        byggcOrderTrack.setOrderId((Long) bo.getOrder_id());
+//        byggcOrderTrack.setStatusType("发货");
+//        byggcOrderTrack.setOperator("系统");
+//        byggcOrderTrack.setOperateTime(DateUtil.date());
+//        byggcOrderTrack.setStatusName("订单已确认");
+//        byggcOrderTrackService.save(byggcOrderTrack);
+        return JLDXResult.ok(null);
+    }
+    /**
+    * 取消订单接口
+    * */
+    @PostMapping(value = "order/cancel")
+    public JLDXResult orderCancel(SaveBYggcOrderBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getOrder_id())){
+            return JLDXResult.fail("order_id不能为空");
+        }
+        //查询订单
+        BYggcOrder bYggcOrder = new BYggcOrder();
+        if(ObjectUtil.isEmpty(bYggcOrder)){
+            return JLDXResult.fail("订单不存在");
+        }
+        List<Map> maps = JSONUtil.toList(bYggcOrder.getSku(), Map.class);
+        //回滚库存
+        for (Map map : maps) {
+            BProductExternal one = new BProductExternal();
+            if(ObjectUtil.isEmpty(one)){
+                return JLDXResult.fail("商品不存在");
+            }
+//            bProductExternalService.update(Wrappers.lambdaUpdate(BProductExternal.class)
+//                .eq(BProductExternal::getId, one.getId())
+//                .set(BProductExternal::getNum, one.getNum() + (Integer) map.get("num"))
+//            );
+        }
+
+//        BYggcOrderTrack byggcOrderTrack = new BYggcOrderTrack();
+//        byggcOrderTrack.setOrderId( bo.getOrder_id());
+//        byggcOrderTrack.setStatusType("发货");
+//        byggcOrderTrack.setOperator("客户");
+//        byggcOrderTrack.setOperateTime(DateUtil.date());
+//        byggcOrderTrack.setStatusName("订单已取消");
+//        byggcOrderTrackService.save(byggcOrderTrack);
+        return JLDXResult.ok(null);
+    }
+
+    /**
+    * 查询订单信息接口
+    * */
+    @PostMapping(value = "order/select")
+    public JLDXResult orderSelect(SaveBYggcOrderBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getOrder_id())){
+            return JLDXResult.fail("order_id不能为空");
+        }
+        BYggcOrder bYggcOrder = new BYggcOrder();
+        Map<String, Object> map = new HashMap<>();
+        map.put("order_id",bYggcOrder.getOrderId());
+        map.put("skus",bYggcOrder.getSku());
+        map.put("state",bYggcOrder.getState());
+        map.put("submit_state",bYggcOrder.getSubmitState());
+        map.put("deliver_state",bYggcOrder.getDeliverState());
+        map.put("total_price",bYggcOrder.getTotalPrice());
+        map.put("return_skus",bYggcOrder.getReturnSkus());
+        map.put("corders",bYggcOrder.getCorders());
+        map.put("type",bYggcOrder.getType());
+        return JLDXResult.ok(map);
+    }
+
+    /**
+    * 订单状态流程
+    * */
+    @PostMapping(value = "order/track")
+    public JLDXResult orderTrack(SaveBYggcOrderBo bo) {
+        JLDXResult JLDXResult = this.checkToken(bo.getToken());
+        if(ObjectUtil.isNotEmpty(JLDXResult)){
+            return JLDXResult;
+        }
+        if(ObjectUtil.isEmpty(bo.getOrder_id())){
+            return JLDXResult.fail("order_id不能为空");
+        }
+        List<BYggcOrderTrack> bYggcOrderTracks = new ArrayList<>();
+        List<Map<Object, Object>> maps = bYggcOrderTracks.stream().map(item -> {
+            Map<Object, Object> map = new HashMap<>();
+            map.put("content", "您的" + item.getStatusName());
+            map.put("operator", item.getOperator());
+            map.put("operate_time", item.getOperateTime());
+            return map;
+        }).toList();
+        Map<Object, Object> map = new HashMap<>();
+        map.put("order_id",bo.getOrder_id());
+        map.put("track",maps);
+        return JLDXResult.ok(map);
+    }
+
+
+    /**
+    * 校验token
+    * */
+    private JLDXResult checkToken(String token){
+        if(ObjectUtil.isEmpty(token)){
+            return JLDXResult.fail("token不能为空");
+        }
+        if(StpUtil.getTokenTimeout(token) == -2l){
+            return JLDXResult.fail("token_expired");
+        }
+        return null;
+    }
+
+
+
+}

+ 3 - 3
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/tongji/TongJiPullController.java

@@ -53,14 +53,14 @@ public class TongJiPullController {
     // 同济提供的配置(替换为真实值)
     private static final String CLIENT_ID = "KFZnKGiDsJ7";
     private static final String PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgQu0H97EPqkgz1YS5LkzZNmkG3mS5Er8rJ2LSoJtuOlGgCgYIKoEcz1UBgi2hRANCAARP6NYwTHpW2QTL8A2f2hpgunEpDVkJBhErBQPLqNS/Si5Q+9I9wUpCYdk1EvB5Hw6yzkE4bYk5IZM1j+/SnNFn"; // 电商平台私钥
-    private static final String ZC_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE9ITEKJdH9o1K9AeQYY7zNMo/q5/cdce+9jbawURTPEpBKAx4VkB+lRkb5e5YL+Be4pPM464rPvLyfqGNJvL6uQ=="; // 同济公钥
+    private static final String TJ_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE9ITEKJdH9o1K9AeQYY7zNMo/q5/cdce+9jbawURTPEpBKAx4VkB+lRkb5e5YL+Be4pPM464rPvLyfqGNJvL6uQ=="; // 同济公钥
     //测试环境
     // 同济地区查询接口地址(替换为真实域名)
 //    private static final String AREA_QUERY_URL = "https://supply-test.crrcgo.cc/mallapi/";
 //    // 同济提供的配置(替换为真实值)
 //    private static final String CLIENT_ID = "KFZAVuIyC56";
 //    private static final String PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgpQdXwMi21Mg1FhWad2AQLOwfNiDHgwhootau0YerQbagCgYIKoEcz1UBgi2hRANCAATVjJs6XRAMTZ72G6aWbgCAjfAnW0j5R9VFnHySTiF8+1mOisc3xOOr9w/Tu3hixzL5H2gVyLzHDRWkFtyeVqrX"; // 电商平台私钥
-//    private static final String ZC_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1YybOl0QDE2e9humlm4AgI3wJ1tI+UfVRZx8kk4hfPtZjorHN8Tjq/cP07t4Yscy+R9oFci8xw0VpBbcnlaq1w=="; // 同济公钥
+//    private static final String TJ_PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1YybOl0QDE2e9humlm4AgI3wJ1tI+UfVRZx8kk4hfPtZjorHN8Tjq/cP07t4Yscy+R9oFci8xw0VpBbcnlaq1w=="; // 同济公钥
     //企采公钥
     private static final String VERSION = "1.0.0";
 
@@ -101,7 +101,7 @@ public class TongJiPullController {
             return SM2SignatureUtils.verify(
                 signContent,
                 responseDto.getSign(),
-                ZC_PUBLIC_KEY
+                TJ_PUBLIC_KEY
             );
         } catch (Exception e) {
             log.error("通用签名校验 - 校验响应签名异常", e);

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/tongji/TongJiController.java → ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/tongji/TongJiPushController.java

@@ -57,7 +57,7 @@ import static org.dromara.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
 @RequiredArgsConstructor
 @RestController
 @RequestMapping("/tongji/api/mall")
-public class TongJiController {
+public class TongJiPushController {
     private final String key = GLOBAL_REDIS_KEY+"external:zhongche:token:";
     private final String CLIENT_ID = "KFZnKGiDsJ7";
     private final String VERSION = "1.0.0";

+ 379 - 49
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/handler/impl/TongjiPushStrategy.java

@@ -1,17 +1,39 @@
 package org.dromara.external.handler.impl;
 
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.dromara.external.api.zhongche.domain.vo.GoodsImageUpdateVo;
-import org.dromara.external.api.zhongche.domain.vo.GoodsPriceUpdateVo;
-import org.dromara.external.api.zhongche.domain.vo.GoodsStatusUpdateVo;
-import org.dromara.external.api.zhongche.domain.vo.GoodsUpdateVo;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.exception.api.ZhongcheException;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.external.api.zhongche.domain.GoodsImageUpdateItem;
+import org.dromara.external.api.zhongche.domain.GoodsImportItem;
+import org.dromara.external.api.zhongche.domain.GoodsPropertiesUpdateItem;
+import org.dromara.external.api.zhongche.domain.GoodsStatusUpdateItem;
+import org.dromara.external.api.zhongche.domain.bo.*;
+import org.dromara.external.api.zhongche.domain.vo.*;
+import org.dromara.external.controller.tongji.TongJiPullController;
 import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.domain.ExternalProductCategory;
+import org.dromara.external.domain.ExternalPushPoolLog;
+import org.dromara.external.domain.vo.ExternalProductVo;
 import org.dromara.external.handler.ProductPushStrategy;
+import org.dromara.external.mapper.ExternalProductMapper;
+import org.dromara.external.service.IExternalProductCategoryService;
+import org.dromara.external.service.IExternalPushPoolLogService;
+import org.dromara.product.api.RemoteProductService;
 import org.dromara.product.api.domain.ProductVo;
+import org.dromara.product.api.domain.zhongche.dto.ProductAggregateDto;
 import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
 
-import java.util.List;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * @author
@@ -21,69 +43,377 @@ import java.util.List;
 @RequiredArgsConstructor
 @Slf4j
 public class TongjiPushStrategy  implements ProductPushStrategy {
-    /**
-     * 推送商品
-     *
-     * @param itemId
-     * @param products
-     */
+
+    private final String username = "20240316001";
+
+    @DubboReference
+    private final RemoteProductService remoteProductService;
+
+    private final TongJiPullController tongJiPullController;
+
+    private final ExternalProductMapper externalProductMapper;
+
+    private final IExternalProductCategoryService externalProductCategoryService;
+
+    private final IExternalPushPoolLogService externalPushPoolLogService;
+
+    private final ObjectMapper objectMapper;
+
     @Override
-    public void push(Long itemId, List<ExternalProduct> products) {
+    public void push( Long itemId,List<ExternalProduct> products) {
+        List<ExternalProductVo> productVoList = new ArrayList<>();
+        for (ExternalProduct product : products) {
+            ExternalProductVo vo = BeanUtil.toBean(product, ExternalProductVo.class);
+            productVoList.add(vo);
+        }
+        productVoList.forEach(item -> {
+            ExternalProductVo externalProductVo = BeanUtil.toBean(item, ExternalProductVo.class);
+            ProductVo productDetail = remoteProductService.getProductDetail(item.getProductId());
+            BeanUtil.copyProperties(productDetail, item);
+            item.setId(externalProductVo.getId());
+            item.setProductStatus(externalProductVo.getProductStatus());
+            item.setMemberPrice(productDetail.getMemberPrice());
+            item.setProductImage(productDetail.getImageUrl());
+        });
+
+        // 收集所有 externalCategoryId
+        Set<Long> categoryIds = productVoList.stream()
+            .map(ExternalProductVo::getExternalCategoryId)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+        if (!categoryIds.isEmpty()) {
+            List<ExternalProductCategory> categoryList =
+                externalProductCategoryService.listByIds(categoryIds);
+
+            // 转成 Map <id, name>
+            Map<Long, ExternalProductCategory> categoryMap = categoryList.stream()
+                .collect(Collectors.toMap(
+                    ExternalProductCategory::getId,
+                    Function.identity()
+
+                ));
+
+            // 回填分类名称
+            productVoList.forEach(item -> {
+                ExternalProductCategory externalProductCategory =
+                    categoryMap.get(item.getExternalCategoryId());
+                item.setStandardCatalogName(externalProductCategory.getCategoryName());
+                item.setExternalCategoryNo(externalProductCategory.getCategoryNo());
+            });
+
+            List<Long> productIds = productVoList.stream()
+                .map(ExternalProductVo::getProductId)
+                .filter(Objects::nonNull) // 过滤空 ID,避免远程调用报错
+                .collect(Collectors.toList());
+            //远程调用获取 ProductAggregateDto 列表
+            final Map<Long, ProductAggregateDto> productAggregateMap = new HashMap<>();
+
+            if (!CollectionUtils.isEmpty(productIds)) {
+                List<ProductAggregateDto> productAggregateList =
+                    remoteProductService.getProductInfo(productIds);
+
+                if (!CollectionUtils.isEmpty(productAggregateList)) {
+                    productAggregateMap.putAll(
+                        productAggregateList.stream()
+                            .collect(Collectors.toMap(
+                                ProductAggregateDto::getProductId,
+                                dto -> dto,
+                                (existing, replacement) -> existing
+                            ))
+                    );
+                }
+            }
+
+            List<GoodsImportItem> batchGoods = new ArrayList<>();
+            productVoList.forEach(item -> {
+                GoodsImportItem goodsImportItem = new GoodsImportItem();
+                goodsImportItem.setGoodsId(item.getProductNo());
+                goodsImportItem.setCatalogId(item.getBottomCategoryId().toString());
+                goodsImportItem.setCatalogName(item.getCategoryName());
+                goodsImportItem.setStandardCatalogId(item.getExternalCategoryNo());
+                goodsImportItem.setStandardCatalogName(item.getStandardCatalogName());
+                //这里有英文有中文混合,需要处理
+                String brandName = item.getBrandName();
+                if (isChinese(brandName)) {
+                    goodsImportItem.setBrandName(brandName);
+                } else if (isEnglish(brandName)) {
+                    goodsImportItem.setBrandNameEn(brandName);
+                }
+                goodsImportItem.setName(item.getItemName());
+                goodsImportItem.setDsPrice(item.getMarketPrice());
+                goodsImportItem.setPrice(item.getExternalPrice());
+                //第三方价格
+                goodsImportItem.setThirdPrice(item.getExternalPrice());
+                goodsImportItem.setUnit(item.getUnitName());
+                //TODO 库存
+//            goodsImportItem.setStock(productAggregateMap.get(item.getProductId()).getStock());
+                goodsImportItem.setStock(999);
+                //链接
+                goodsImportItem.setGoodsUrl(productAggregateMap.get(item.getProductId()).getGoodsUrl());
+                goodsImportItem.setThirdUrl(productAggregateMap.get(item.getProductId()).getThirdUrl());
+                //图片
+                String rawImageStr = item.getProductImage();
+                List<String> imageList = new ArrayList<>();
+                if (StringUtils.isNotBlank(rawImageStr)) {
+                    String[] imagePaths = rawImageStr.split(",");
+                    for (String path : imagePaths) {
+                        String trimedPath = path.trim();
+                        if (StringUtils.isNotBlank(trimedPath)) {
+                            imageList.add(trimedPath);
+                        }
+                    }
+                }
+                String barImgUrlsJson;
+                try {
+                    barImgUrlsJson = objectMapper.writeValueAsString(imageList);
+                } catch (JsonProcessingException e) {
+                    barImgUrlsJson = "[]";
+                }
+                goodsImportItem.setBarImgUrls(barImgUrlsJson);
+                //TODO 商品描述
+                goodsImportItem.setDescription(productAggregateMap.get(item.getProductId()).getDescription());
 
+                //TODO 商品规格  默认 颜色:白色
+//            if (StringUtils.isNotBlank(productAggregateMap.get(item.getProductId()).getDiyAttributesList())) {
+//                String diyAttributesList = productAggregateMap.get(item.getProductId()).getDiyAttributesList();
+//                List<Map> list = JSONUtil.toList(diyAttributesList, Map.class);
+//                //格式为[{attributeKey:"",attributeValue:""}]转换成 [{key:value}]
+//                List<Map<String, String>> map = list.stream().map(e -> {
+//                    Map<String, String> result = new HashMap<>();
+//                    result.put(e.get("attributeKey").toString(), e.get("attributeValue").toString());
+//                    return result;
+//                }).collect(Collectors.toList());
+//                goodsImportItem.setProperties(JSONUtil.toJsonStr(map));
+//            }else{
+                goodsImportItem.setProperties("{\"保质期\":\"12个月\"}");
+//            }
+
+                //TODO 是否自营
+                goodsImportItem.setIsSelfOperated(1);
+                //税率
+                goodsImportItem.setTax( new BigDecimal("0.13"));
+                //TODO 税收编码   默认填 1
+                goodsImportItem.setTaxCode("107022301");
+                batchGoods.add(goodsImportItem);
+            });
+            GoodsImportBo bo = new GoodsImportBo();
+            bo.setAccount(username);
+            bo.setGoods(batchGoods);
+            GoodsImportVo goodsImportVo = new GoodsImportVo();
+
+            try {
+                goodsImportVo = tongJiPullController.egoodsImport(bo);
+                if (goodsImportVo.getResult() == 1) {
+                    externalProductMapper.update(
+                        Wrappers.lambdaUpdate(ExternalProduct.class)
+                            .set(ExternalProduct::getPushStatus, 1)
+                            .in(ExternalProduct::getId, productIds)
+                            .eq(ExternalProduct::getItemId, itemId)
+                    );
+                }else {
+                    externalProductMapper.update(
+                        Wrappers.lambdaUpdate(ExternalProduct.class)
+                            .set(ExternalProduct::getConnectStatus, 1)
+                            .set(ExternalProduct::getPushStatus, 2)
+                            .set(ExternalProduct::getRemark, goodsImportVo.getMessage())
+                            .in(ExternalProduct::getId, productIds)
+                            .eq(ExternalProduct::getItemId, itemId)
+                    );
+                    for (Long productId : productIds) {
+                        ExternalPushPoolLog externalPushPoolLog = new ExternalPushPoolLog();
+                        externalPushPoolLog.setProductId(productId);
+                        externalPushPoolLog.setItemId(itemId);
+                        externalPushPoolLog.setPushStatus("1");
+                        externalPushPoolLog.setRemark(goodsImportVo.getMessage());
+                        externalPushPoolLogService.save(externalPushPoolLog);
+                    }
+                }
+            } catch (ZhongcheException e) {
+                externalProductMapper.update(
+                    Wrappers.lambdaUpdate(ExternalProduct.class)
+                        .set(ExternalProduct::getConnectStatus, 1)
+                        .set(ExternalProduct::getPushStatus, 2)
+                        .set(ExternalProduct::getRemark, e.getMessage())
+                        .in(ExternalProduct::getId, productIds)
+                        .eq(ExternalProduct::getItemId, itemId)
+                );
+                for (Long productId : productIds) {
+                    ExternalPushPoolLog externalPushPoolLog = new ExternalPushPoolLog();
+                    externalPushPoolLog.setItemId(itemId);
+                    externalPushPoolLog.setProductId(productId);
+                    externalPushPoolLog.setPushStatus("1");
+                    externalPushPoolLog.setReason(e.getMessage());
+                    externalPushPoolLogService.save(externalPushPoolLog);
+                }
+                throw e;
+            }
+        }
     }
 
-    /**
-     * 商品价格变更
-     *
-     * @param itemId
-     * @param products
-     */
     @Override
-    public GoodsPriceUpdateVo updatePrice(Long itemId, List<ProductVo> products) {
-        return null;
+    public GoodsPriceUpdateVo updatePrice(Long itemId,List<ProductVo> products) {
+        GoodsImportBo bo =  new GoodsImportBo();
+        bo.setAccount(username);
+        List<ExternalProductVo> externalProductVos = externalProductMapper.selectVoList(Wrappers.lambdaQuery(ExternalProduct.class).eq(ExternalProduct::getItemId, itemId));
+        Map<String, BigDecimal> decimalMap = externalProductVos.stream().collect(Collectors.toMap(ExternalProductVo::getProductNo, ExternalProductVo::getExternalPrice));
+        bo.setGoods(products.stream().map(item ->{
+            GoodsImportItem goodsImportItem = new GoodsImportItem();
+            goodsImportItem.setGoodsId(item.getProductNo());
+            goodsImportItem.setDsPrice(item.getMarketPrice());
+            goodsImportItem.setPrice(decimalMap.get(item.getProductNo()));
+            return goodsImportItem;
+        }).toList());
+        return tongJiPullController.egoodsPriceUpdate(bo);
     }
 
-    /**
-     * 商品上下架状态变更
-     *
-     * @param productNos
-     * @param status
-     */
     @Override
     public GoodsStatusUpdateVo updateStatus(List<String> productNos, Integer status) {
-        return null;
+        GoodsStatusUpdateBo goodsStatusUpdateBo = new GoodsStatusUpdateBo();
+        goodsStatusUpdateBo.setAccount(username);
+        goodsStatusUpdateBo.setGoods(productNos.stream().map(productNo -> {
+            GoodsStatusUpdateItem item = new GoodsStatusUpdateItem();
+            item.setGoodsId(productNo);
+            item.setStatus(status);
+            return item;
+        }).collect(Collectors.toList()));
+        return tongJiPullController.egoodsStatusUpdate(goodsStatusUpdateBo);
     }
 
-    /**
-     * 商品图片变更
-     *
-     * @param itemId
-     * @param products
-     */
     @Override
-    public GoodsImageUpdateVo updateImages(Long itemId, List<ProductVo> products) {
-        return null;
+    public GoodsImageUpdateVo updateImages(Long itemId,List<ProductVo> products) {
+        try {
+            GoodsImageUpdateBo bo = new GoodsImageUpdateBo();
+            bo.setAccount(username);
+            bo.setGoods(products.stream().map(item -> {
+                GoodsImageUpdateItem goodsImageUpdateItem = new GoodsImageUpdateItem();
+                goodsImageUpdateItem.setBarImgUrls(item.getImageUrl());
+                goodsImageUpdateItem.setGoodsId(item.getProductNo());
+                return goodsImageUpdateItem;
+            }).toList());
+            return tongJiPullController.egoodsImgsUpdate(bo);
+        }catch (ZhongcheException e){
+            for (ProductVo productVo : products) {
+                ExternalPushPoolLog externalPushPoolLog = new ExternalPushPoolLog();
+                externalPushPoolLog.setItemId(itemId);
+                externalPushPoolLog.setProductId(productVo.getId());
+                externalPushPoolLog.setPushStatus("1");
+                externalPushPoolLog.setReason(e.getMessage());
+                externalPushPoolLogService.save(externalPushPoolLog);
+            }
+            throw e;
+        }
     }
 
+    @Override
+    public GoodsUpdateVo updateProperties(Long itemId,List<ProductVo> products) {
+        try {
+            GoodsPropertiesUpdateBo bo = new GoodsPropertiesUpdateBo();
+            bo.setAccount(username);
+            bo.setGoods(products.stream().map(item ->{
+                GoodsPropertiesUpdateItem goodsImageUpdateItem = new GoodsPropertiesUpdateItem();
+                goodsImageUpdateItem.setProperties("{\"保质期\":\"12个月\"}");
+                goodsImageUpdateItem.setGoodsId(item.getProductNo());
+                return goodsImageUpdateItem;
+            }).toList());
+            return tongJiPullController.egoodsPropertiesUpdate(bo);
+        }catch (ZhongcheException e){
+            for (ProductVo productVo : products) {
+                ExternalPushPoolLog externalPushPoolLog = new ExternalPushPoolLog();
+                externalPushPoolLog.setItemId(itemId);
+                externalPushPoolLog.setProductId(productVo.getId());
+                externalPushPoolLog.setPushStatus("1");
+                externalPushPoolLog.setReason(e.getMessage());
+                externalPushPoolLogService.save(externalPushPoolLog);
+            }
+            throw e;
+        }
+    }
+
+    @Override
+    public GoodsUpdateVo updateDetail(Long itemId,List<ProductVo> products) {
+        try {
+            GoodsDetailBo bo = new GoodsDetailBo();
+            bo.setAccount(username);
+            bo.setGoods(products.stream().map(item ->{
+                GoodsDetailUpdateBo goodsImageUpdateItem = new GoodsDetailUpdateBo();
+                goodsImageUpdateItem.setBrandName(item.getBrandName());
+                goodsImageUpdateItem.setDescription(item.getPcDetail());
+                goodsImageUpdateItem.setUpc(item.getBarCoding());
+                goodsImageUpdateItem.setMoq(BigDecimal.valueOf(item.getMinOrderQuantity()));
+                goodsImageUpdateItem.setIsSelfOperated(1);
+                goodsImageUpdateItem.setGoodsUrl("https://item.xiaoluwebsite.xyz/item?productNo="+item.getProductNo());
+                goodsImageUpdateItem.setThirdUrl(item.getReferenceLink());
+                goodsImageUpdateItem.setTaxCode("107022301");
+                goodsImageUpdateItem.setTax(BigDecimal.valueOf(0.13));
+                goodsImageUpdateItem.setUnit(item.getUnitName());
+                goodsImageUpdateItem.setStandardCatalogId("1374013891398471680");
+                goodsImageUpdateItem.setStandardCatalogName("福利套餐");
+                goodsImageUpdateItem.setGoodsId(item.getProductNo());
+                goodsImageUpdateItem.setTax(BigDecimal.valueOf(0.13));
+                return goodsImageUpdateItem;
+            }).toList());
+            return tongJiPullController.egoodsDetailUpdate(bo);
+        }catch (ZhongcheException e){
+            for (ProductVo productVo : products) {
+                ExternalPushPoolLog externalPushPoolLog = new ExternalPushPoolLog();
+                externalPushPoolLog.setItemId(itemId);
+                externalPushPoolLog.setProductId(productVo.getId());
+                externalPushPoolLog.setPushStatus("1");
+                externalPushPoolLog.setReason(e.getMessage());
+                externalPushPoolLogService.save(externalPushPoolLog);
+            }
+            throw e;
+        }
+    }
+
+    // --------------------- 核心判断方法 ---------------------
     /**
-     * 商品规格信息变更
-     *
-     * @param itemId
-     * @param products
+     * 判断字符串是否包含中文汉字(核心判断逻辑)
+     * @param str 待判断字符串
+     * @return true=包含中文,false=不包含
      */
-    @Override
-    public GoodsUpdateVo updateProperties(Long itemId, List<ProductVo> products) {
-        return null;
+    private boolean isChinese(String str) {
+        // 匹配任意中文字符(Unicode 中文编码范围)
+        return str.matches(".*[\\u4e00-\\u9fa5]+.*");
     }
 
     /**
-     * 商品详情信息变更
-     *
-     * @param itemId
-     * @param products
+     * 判断字符串是否为纯英文(字母、数字、空格、常见标点)
+     * @param str 待判断字符串
+     * @return true=纯英文/数字,false=包含其他字符
      */
-    @Override
-    public GoodsUpdateVo updateDetail(Long itemId, List<ProductVo> products) {
-        return null;
+    private boolean isEnglish(String str) {
+        // 匹配字母、数字、空格、横线、点、下划线(可根据业务扩展)
+        return str.matches("[a-zA-Z0-9 \\-\\.\\_]+");
     }
+
+    /*public static void main(String[] args) {
+        String username = "admin";
+        List<GoodsImportItem> batchGoods = new ArrayList<>();
+        GoodsImportItem item = new GoodsImportItem();
+        item.setGoodsId("362031");
+        item.setCatalogId("13012");
+        item.setCatalogName("原装墨盒");
+        item.setStandardCatalogId("1750717233748832257");
+        item.setStandardCatalogName("铁圈装订机耗材");
+        item.setBrandName("得力");
+        item.setName("得力");
+        item.setDsPrice(new BigDecimal(41));
+        item.setPrice(new BigDecimal(34));
+        item.setUnit("个");
+        item.setStock(100);
+        item.setBarImgUrls("[\"https://img1.com\",\"https://img2.com\"]");
+        item.setDescription("得力商品");
+        item.setProperties("{\"颜色\":\"红色\",\"尺寸\":\"XL\",\"材质\":\"棉|涤纶\"}");
+        item.setIsSelfOperated(1);
+        item.setTax(new BigDecimal(0.05));
+        item.setTaxCode("123456");
+        batchGoods.add(item);
+        GoodsImportBo bo = new GoodsImportBo();
+        bo.setAccount(username);
+        bo.setGoods(batchGoods);
+        tongJiPullController tongJiPullController = new tongJiPullController();
+        GoodsImportVo resp = tongJiPullController.egoodsImport(bo);
+        System.out.println(resp);
+    }*/
 }

+ 5 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductBaseAuditBo.java

@@ -122,4 +122,9 @@ public class ProductBaseAuditBo extends BaseEntity {
      * 底层分类id
      */
     private Long bottomCategoryId;
+
+    /**
+     * 查询类型  1=供应商查询,2=伙伴商查询
+     * */
+    private Integer queryType;
 }

+ 0 - 18
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductBaseVo.java

@@ -366,24 +366,6 @@ public class ProductBaseVo implements Serializable {
     @ExcelProperty(value = "免费安装")
     private String freeInstallation;
 
-    /**
-     * 中档价
-     */
-    @ExcelProperty(value = "中档价")
-    private BigDecimal midRangePrice;
-
-    /**
-     * 平档价
-     */
-    @ExcelProperty(value = "平档价")
-    private BigDecimal standardPrice;
-
-    /**
-     * 套证价
-     */
-    @ExcelProperty(value = "套证价")
-    private BigDecimal certificatePrice;
-
 
     /**
      * 最高采购价

+ 18 - 3
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseAuditServiceImpl.java

@@ -129,7 +129,6 @@ public class ProductBaseAuditServiceImpl extends ServiceImpl<ProductBaseAuditMap
     private LambdaQueryWrapper<ProductBaseAudit> buildQueryWrapper(ProductBaseAuditBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<ProductBaseAudit> lqw = Wrappers.lambdaQuery();
-        lqw.orderByAsc(ProductBaseAudit::getId);
         lqw.eq(bo.getProductId() != null, ProductBaseAudit::getProductId, bo.getProductId());
         lqw.eq(bo.getAuditStatus() != null, ProductBaseAudit::getAuditStatus, bo.getAuditStatus());
         lqw.eq(StringUtils.isNotBlank(bo.getAuditReason()), ProductBaseAudit::getAuditReason, bo.getAuditReason());
@@ -138,7 +137,7 @@ public class ProductBaseAuditServiceImpl extends ServiceImpl<ProductBaseAuditMap
         lqw.eq(StringUtils.isNotBlank(bo.getProductData()), ProductBaseAudit::getProductData, bo.getProductData());
         lqw.eq(bo.getType() != null, ProductBaseAudit::getType, bo.getType());
         lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), ProductBaseAudit::getPlatformCode, bo.getPlatformCode());
-        
+        lqw.orderByDesc(ProductBaseAudit::getCreateTime);
         // 对 productData JSON 字段进行查询
         // 产品编号
         if (StringUtils.isNotBlank(bo.getProductNo())) {
@@ -168,7 +167,19 @@ public class ProductBaseAuditServiceImpl extends ServiceImpl<ProductBaseAuditMap
         if (bo.getBottomCategoryId() != null) {
             lqw.apply("JSON_EXTRACT(product_data, '$.bottomCategoryId') = {0}", bo.getBottomCategoryId());
         }
-        
+        if(ObjectUtil.isNotEmpty(bo.getQueryType())){
+            lqw.eq(bo.getQueryType()==1,ProductBaseAudit::getCreateByType,1);
+            lqw.eq(bo.getQueryType()==1,ProductBaseAudit::getCreateById,LoginHelper.getLoginUser().getSupplierId());
+            lqw.eq(bo.getQueryType()==2,ProductBaseAudit::getCreateByType,2);
+            lqw.eq(bo.getQueryType()==2,ProductBaseAudit::getCreateById,LoginHelper.getLoginUser().getPartnerId());
+        }
+//        if(ObjectUtil.isNotEmpty(bo.getQueryType())){
+//            lqw.apply(bo.getQueryType()==1,"JSON_EXTRACT(product_data, '$.createByType') = {0}", 1);
+//            lqw.apply(bo.getQueryType()==1,"JSON_EXTRACT(product_data, '$.createById') = {0}", LoginHelper.getLoginUser().getSupplierId());
+//            lqw.apply(bo.getQueryType()==2,"JSON_EXTRACT(product_data, '$.createByType') = {0}", 2);
+//            lqw.apply(bo.getQueryType()==2,"JSON_EXTRACT(product_data, '$.createById') = {0}", LoginHelper.getLoginUser().getPartnerId());
+//        }
+
         return lqw;
     }
 
@@ -298,8 +309,12 @@ public class ProductBaseAuditServiceImpl extends ServiceImpl<ProductBaseAuditMap
             // type=0: 提交审核
             if (ObjectUtil.isEmpty(productId)) {
                 // 没有productId,说明是新增商品,需要还原数据后调用商品新增
+                productBaseVo.setCreateByType(auditRecord.getCreateByType());
+                productBaseVo.setCreateById(auditRecord.getCreateById());
                 handleNewProduct(productBaseVo);
             } else {
+                productBaseVo.setCreateByType(auditRecord.getCreateByType());
+                productBaseVo.setCreateById(auditRecord.getCreateById());
                 // 有productId,说明是编辑商品,需要还原数据后调用商品编辑
                 handleEditProduct(productBaseVo, productId);
             }

+ 10 - 21
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseServiceImpl.java

@@ -452,10 +452,13 @@ public class ProductBaseServiceImpl extends ServiceImpl<ProductBaseMapper, Produ
         if (ObjectUtil.isNotEmpty(bo.getCategoryIds())){
             productBaseVoLambdaEsQueryWrapper.in(ProductBaseVo::getBottomCategoryId, bo.getCategoryIds().split(","));
         }
-//        productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==1,ProductBaseVo::getCreateByType,1);
-//        productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==1,ProductBaseVo::getCreateById,LoginHelper.getLoginUser().getSupplierId());
-//        productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==2,ProductBaseVo::getCreateByType,2);
-//        productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==2,ProductBaseVo::getCreateById,LoginHelper.getLoginUser().getPartnerId());
+        if(ObjectUtil.isNotEmpty(bo.getQueryType())){
+            productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==1,ProductBaseVo::getCreateByType,1);
+            productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==1,ProductBaseVo::getCreateById,LoginHelper.getLoginUser().getSupplierId());
+            productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==2,ProductBaseVo::getCreateByType,2);
+            productBaseVoLambdaEsQueryWrapper.eq(bo.getQueryType()==2,ProductBaseVo::getCreateById,LoginHelper.getLoginUser().getPartnerId());
+        }
+
         return productBaseVoLambdaEsQueryWrapper;
     }
 
@@ -600,23 +603,9 @@ public class ProductBaseServiceImpl extends ServiceImpl<ProductBaseMapper, Produ
             ProductBase productBase = MapstructUtils.convert(bo, ProductBase.class);
             validEntityBeforeSave(productBase);
             //查询最大productNo生成productNo
-            if(ObjectUtil.isEmpty(productBase.getProductNo())){
-                ProductBase one = baseMapper.selectOne(Wrappers.lambdaQuery(ProductBase.class).orderByDesc(ProductBase::getProductNo).last("limit 1"));
-                if (one == null) {
-                    productBase.setProductNo("0000000001");
-                }else {
-                    productBase.setProductNo(NumberGeneratorUtil.generateNumber(one.getProductNo()));
-                }
-            }else {
-                //校验编号不能重复
-                ProductBase one = baseMapper.selectOne(Wrappers.lambdaQuery(ProductBase.class)
-                    .eq(ProductBase::getProductNo, productBase.getProductNo())
-                    .last("limit 1")
-                );
-                if (one != null) {
-                    throw new ServiceException("编号已存在");
-                }
-            }
+            ProductBase one = baseMapper.selectOne(Wrappers.lambdaQuery(ProductBase.class).orderByDesc(ProductBase::getProductNo).last("limit 1"));
+            String string = NumberGeneratorUtil.generateNumber(one.getProductNo());
+            productBase.setProductNo(string);
 
             // 设置默认值
             setDefaultValues(productBase);