Ver código fonte

feat(external): 添加外部商品推送功能并配置elasticsearch

- 新增ExternalProduct实体、BO、VO及相关映射器
- 实现外部商品推送状态管理功能
- 配置elasticsearch连接参数和认证信息
- 更新外部产品品牌信息查询逻辑,集成远程服务调用
- 调整外部产品分类相关注释和命名
- 优化docker compose配置文件挂载路径
- 修复第三方品牌信息显示逻辑,添加远程品牌名称映射
肖路 4 meses atrás
pai
commit
744f85164c
92 arquivos alterados com 2754 adições e 415 exclusões
  1. 1 1
      ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongzhi/domain/vo/ZhongzhiExternalProductVo.java
  2. 6 0
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductService.java
  3. 9 9
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/domain/ProductVo.java
  4. 128 0
      ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/domain/RemoteProductBrand.java
  5. 14 0
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
  6. 3 3
      ruoyi-example/ruoyi-demo/src/main/resources/application.yml
  7. 7 7
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalItemController.java
  8. 7 7
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductBrandController.java
  9. 19 19
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductCategoryController.java
  10. 106 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductChangeLogController.java
  11. 106 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductController.java
  12. 7 7
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalPushPoolLogController.java
  13. 1 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongzhi/ZhongZhiPullController.java
  14. 4 9
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongzhi/ZhongZhiPushController.java
  15. 2 2
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalItem.java
  16. 67 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProduct.java
  17. 1 9
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProductBrand.java
  18. 2 2
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProductCategory.java
  19. 84 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProductChangeLog.java
  20. 8 8
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalPushPoolLog.java
  21. 9 9
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalItemBo.java
  22. 65 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductBo.java
  23. 1 3
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductBrandBo.java
  24. 2 2
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductCategoryBo.java
  25. 80 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductChangeLogBo.java
  26. 11 9
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalPushPoolLogBo.java
  27. 3 3
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalItemVo.java
  28. 8 80
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductBrandVo.java
  29. 2 2
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductCategoryVo.java
  30. 90 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductChangeLogVo.java
  31. 74 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductVo.java
  32. 10 8
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalPushPoolLogVo.java
  33. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalItemMapper.java
  34. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductBrandMapper.java
  35. 2 2
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductCategoryMapper.java
  36. 15 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductChangeLogMapper.java
  37. 15 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductMapper.java
  38. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalPushPoolLogMapper.java
  39. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalItemService.java
  40. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductBrandService.java
  41. 13 13
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductCategoryService.java
  42. 70 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductChangeLogService.java
  43. 70 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductService.java
  44. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalPushPoolLogService.java
  45. 1 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalItemServiceImpl.java
  46. 25 2
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductBrandServiceImpl.java
  47. 13 13
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductCategoryServiceImpl.java
  48. 137 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductChangeLogServiceImpl.java
  49. 138 0
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductServiceImpl.java
  50. 3 1
      ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalPushPoolLogServiceImpl.java
  51. 7 0
      ruoyi-modules/ruoyi-external/src/main/resources/mapper/external/ExternalProductChangeLogMapper.xml
  52. 7 0
      ruoyi-modules/ruoyi-external/src/main/resources/mapper/external/ExternalProductMapper.xml
  53. 5 0
      ruoyi-modules/ruoyi-product/pom.xml
  54. 30 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductBaseController.java
  55. 31 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductPoolLinkController.java
  56. 14 9
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductBase.java
  57. 4 1
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductExtend.java
  58. 14 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductPool.java
  59. 22 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductPoolLink.java
  60. 2 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductAttributesBo.java
  61. 33 9
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductBaseBo.java
  62. 14 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductPoolBo.java
  63. 22 4
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductPoolLinkBo.java
  64. 3 3
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/SiteProductBo.java
  65. 6 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductAttributesVo.java
  66. 39 11
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductBaseVo.java
  67. 2 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductBrandVo.java
  68. 33 1
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductPoolLinkVo.java
  69. 32 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductPoolVo.java
  70. 3 3
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/SiteProductVo.java
  71. 35 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/StatusCountVo.java
  72. 20 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductServiceImpl.java
  73. 13 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/esmapper/ProductBrandEsMapper.java
  74. 13 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/esmapper/ProductEsMapper.java
  75. 12 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductAttributesMapper.java
  76. 43 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductBaseMapper.java
  77. 5 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductPoolMapper.java
  78. 17 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductBaseService.java
  79. 21 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductPoolLinkService.java
  80. 4 2
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductAttributesServiceImpl.java
  81. 392 78
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseServiceImpl.java
  82. 58 3
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBrandServiceImpl.java
  83. 1 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductCategoryServiceImpl.java
  84. 52 0
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductPoolLinkServiceImpl.java
  85. 19 1
      ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductPoolServiceImpl.java
  86. 45 0
      ruoyi-modules/ruoyi-product/src/main/resources/application.yml
  87. 63 0
      ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductAttributesMapper.xml
  88. 85 0
      ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductBaseMapper.xml
  89. 27 2
      ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductPoolLinkMapper.xml
  90. 11 0
      ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductPoolMapper.xml
  91. 0 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
  92. 50 50
      script/docker/docker-compose.yml

+ 1 - 1
ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongzhi/domain/vo/ExternalProductVo.java → ruoyi-api/ruoyi-api-external/src/main/java/org/dromara/external/api/zhongzhi/domain/vo/ZhongzhiExternalProductVo.java

@@ -9,7 +9,7 @@ import java.util.List;
 
 @Data
 @Builder
-public class ExternalProductVo {
+public class ZhongzhiExternalProductVo {
     private String sku;
     private String url;
     private String model;

+ 6 - 0
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/RemoteProductService.java

@@ -2,6 +2,7 @@ package org.dromara.product.api;
 
 import org.dromara.product.api.domain.ProductChangeLogApiVo;
 import org.dromara.product.api.domain.ProductVo;
+import org.dromara.product.api.domain.RemoteProductBrand;
 
 import java.util.List;
 
@@ -35,4 +36,9 @@ public interface RemoteProductService {
     List<ProductChangeLogApiVo> getProductChangeLogs(Long itemId,String type);
 
     void delMessagePool(Long messageId);
+
+    /**
+    * 根据品牌id获取单个品牌
+    * */
+    RemoteProductBrand getProductByBrandId(Long brandId);
 }

+ 9 - 9
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/domain/ProductVo.java

@@ -86,28 +86,28 @@ public class ProductVo implements Serializable {
     /**
      * 是否自营(1=是,0=否)
      */
-    private String isSelf;
+    private Integer isSelf;
 
     /**
      * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
      */
 
-    private String productReviewStatus;
+    private Integer productReviewStatus;
 
     /**
      * 首页推荐:1=推荐,0=不推荐
      */
-    private String homeRecommended;
+    private Integer homeRecommended;
 
     /**
      * 分类推荐:1=推荐,0=不推荐
      */
-    private String categoryRecommendation;
+    private Integer categoryRecommendation;
 
     /**
      * 购物车推荐:1=推荐,0=不推荐
      */
-    private String cartRecommendation;
+    private Integer cartRecommendation;
 
     /**
      * 推荐产品顺序
@@ -117,17 +117,17 @@ public class ProductVo implements Serializable {
     /**
      * 是否热门:1=是,0=否
      */
-    private String isPopular;
+    private Integer isPopular;
 
     /**
      * 是否新品:1=是,0=否
      */
-    private String isNew;
+    private Integer isNew;
 
     /**
-     * 商品状态:1=上架,0=下架等
+     * 商品状态:1=上架,0=下架 2 上架中
      */
-    private String productStatus;
+    Integer productStatus;
 
     /**
      * 数据来源

+ 128 - 0
ruoyi-api/ruoyi-api-product/src/main/java/org/dromara/product/api/domain/RemoteProductBrand.java

@@ -0,0 +1,128 @@
+package org.dromara.product.api.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 产品品牌信息对象 product_brand
+ *
+ * @author LionLi
+ * @date 2025-12-11
+ */
+@Data
+public class RemoteProductBrand implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 品牌编号(唯一标识)
+     */
+    private String brandNo;
+
+    /**
+     * 品牌中文名称
+     */
+    private String brandName;
+
+    /**
+     * 品牌首字母缩写(如拼音首字母)
+     */
+    private String brandInitials;
+
+    /**
+     * 品牌英文名称
+     */
+    private String brandEnglishName;
+
+    /**
+     * 推荐值(数值越大越靠前)
+     */
+    private Long recommendValue;
+
+    /**
+     * 品牌Logo图片路径或URL
+     */
+    private String brandLogo;
+
+    /**
+     * 品牌标题(用于展示)
+     */
+    private String brandTitle;
+
+    /**
+     * 品牌大图(横幅/封面图)
+     */
+    private String brandBigImage;
+
+    /**
+     * 品牌故事(简介文本)
+     */
+    private String brandStory;
+
+    /**
+     * 是否显示(1=显示,0=隐藏)
+     */
+    private Long isShow;
+
+    /**
+     * 品牌注册人
+     */
+    private String brandRegistrant;
+
+    /**
+     * 许可证编号
+     */
+    private String license;
+
+    /**
+     * 注册证书编号
+     */
+    private String registrationCertificate;
+
+    /**
+     * 证书/许可过期时间
+     */
+    private Date expireTime;
+
+    /**
+     * 品牌描述(较长文本)
+     */
+    private String brandDescribe;
+
+    /**
+     * 展示位置(如首页、分类页等)
+     */
+    private String position;
+
+    /**
+     * 关注度/收藏数(默认为0)
+     */
+    private Long care;
+
+    /**
+     * 数据来源
+     */
+    private String dataSource;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 14 - 0
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java

@@ -48,6 +48,20 @@ public class PageQuery implements Serializable {
      */
     private String isAsc;
 
+    /**
+    * 第一个id
+    * */
+    private Long firstSeenId;
+    /**
+    * 最后一个id
+    * */
+    private Long lastSeenId;
+
+    /**
+    * 翻页方式 0:向上翻页 1:向下翻页
+    * */
+    private Integer way;
+
     /**
      * 当前记录起始索引 默认值
      */

+ 3 - 3
ruoyi-example/ruoyi-demo/src/main/resources/application.yml

@@ -80,14 +80,14 @@ easy-es:
   # 兼容模式
   compatible: true
   # es连接地址+端口 格式必须为ip:port,如果是集群则可用逗号隔开
-  address : localhost:9200
+  address : 119.97.180.88:9200
   # 默认为http
   schema: http
   # 注意ES建议使用账号认证 不使用会报警告日志
   #如果无账号密码则可不配置此行
-  #username:
+  username: elastic
   #如果无账号密码则可不配置此行
-  #password:
+  password: kRhwhe4Mf4pyPYHN
   # 心跳策略时间 单位:ms
   keep-alive-millis: 18000
   # 连接超时时间 单位:ms

+ 7 - 7
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalItemController.java

@@ -27,7 +27,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
  * 前端访问路由地址为:/external/item
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Validated
 @RequiredArgsConstructor
@@ -40,7 +40,7 @@ public class ExternalItemController extends BaseController {
     /**
      * 查询第三方对接项目管理列表
      */
-    @SaCheckPermission("external:item:list")
+    //@SaCheckPermission("external:item:list")
     @GetMapping("/list")
     public TableDataInfo<ExternalItemVo> list(ExternalItemBo bo, PageQuery pageQuery) {
         return externalItemService.queryPageList(bo, pageQuery);
@@ -49,7 +49,7 @@ public class ExternalItemController extends BaseController {
     /**
      * 导出第三方对接项目管理列表
      */
-    @SaCheckPermission("external:item:export")
+    //@SaCheckPermission("external:item:export")
     @Log(title = "第三方对接项目管理", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(ExternalItemBo bo, HttpServletResponse response) {
@@ -62,7 +62,7 @@ public class ExternalItemController extends BaseController {
      *
      * @param id 主键
      */
-    @SaCheckPermission("external:item:query")
+    //@SaCheckPermission("external:item:query")
     @GetMapping("/{id}")
     public R<ExternalItemVo> getInfo(@NotNull(message = "主键不能为空")
                                      @PathVariable("id") Long id) {
@@ -72,7 +72,7 @@ public class ExternalItemController extends BaseController {
     /**
      * 新增第三方对接项目管理
      */
-    @SaCheckPermission("external:item:add")
+    //@SaCheckPermission("external:item:add")
     @Log(title = "第三方对接项目管理", businessType = BusinessType.INSERT)
     @RepeatSubmit()
     @PostMapping()
@@ -83,7 +83,7 @@ public class ExternalItemController extends BaseController {
     /**
      * 修改第三方对接项目管理
      */
-    @SaCheckPermission("external:item:edit")
+    //@SaCheckPermission("external:item:edit")
     @Log(title = "第三方对接项目管理", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PutMapping()
@@ -96,7 +96,7 @@ public class ExternalItemController extends BaseController {
      *
      * @param ids 主键串
      */
-    @SaCheckPermission("external:item:remove")
+    //@SaCheckPermission("external:item:remove")
     @Log(title = "第三方对接项目管理", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public R<Void> remove(@NotEmpty(message = "主键不能为空")

+ 7 - 7
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductBrandController.java

@@ -27,7 +27,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
  * 前端访问路由地址为:/external/productBrand
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Validated
 @RequiredArgsConstructor
@@ -40,7 +40,7 @@ public class ExternalProductBrandController extends BaseController {
     /**
      * 查询第三方产品品牌信息列表
      */
-    @SaCheckPermission("external:productBrand:list")
+    //@SaCheckPermission("external:productBrand:list")
     @GetMapping("/list")
     public TableDataInfo<ExternalProductBrandVo> list(ExternalProductBrandBo bo, PageQuery pageQuery) {
         return externalProductBrandService.queryPageList(bo, pageQuery);
@@ -49,7 +49,7 @@ public class ExternalProductBrandController extends BaseController {
     /**
      * 导出第三方产品品牌信息列表
      */
-    @SaCheckPermission("external:productBrand:export")
+    //@SaCheckPermission("external:productBrand:export")
     @Log(title = "第三方产品品牌信息", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(ExternalProductBrandBo bo, HttpServletResponse response) {
@@ -62,7 +62,7 @@ public class ExternalProductBrandController extends BaseController {
      *
      * @param id 主键
      */
-    @SaCheckPermission("external:productBrand:query")
+    //@SaCheckPermission("external:productBrand:query")
     @GetMapping("/{id}")
     public R<ExternalProductBrandVo> getInfo(@NotNull(message = "主键不能为空")
                                      @PathVariable("id") Long id) {
@@ -72,7 +72,7 @@ public class ExternalProductBrandController extends BaseController {
     /**
      * 新增第三方产品品牌信息
      */
-    @SaCheckPermission("external:productBrand:add")
+    //@SaCheckPermission("external:productBrand:add")
     @Log(title = "第三方产品品牌信息", businessType = BusinessType.INSERT)
     @RepeatSubmit()
     @PostMapping()
@@ -83,7 +83,7 @@ public class ExternalProductBrandController extends BaseController {
     /**
      * 修改第三方产品品牌信息
      */
-    @SaCheckPermission("external:productBrand:edit")
+    //@SaCheckPermission("external:productBrand:edit")
     @Log(title = "第三方产品品牌信息", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PutMapping()
@@ -96,7 +96,7 @@ public class ExternalProductBrandController extends BaseController {
      *
      * @param ids 主键串
      */
-    @SaCheckPermission("external:productBrand:remove")
+    //@SaCheckPermission("external:productBrand:remove")
     @Log(title = "第三方产品品牌信息", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public R<Void> remove(@NotEmpty(message = "主键不能为空")

+ 19 - 19
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductCategoryController.java

@@ -23,11 +23,11 @@ import org.dromara.external.service.IExternalProductCategoryService;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 
 /**
- * 第三方产品分类
+ * 产品分类
  * 前端访问路由地址为:/external/productCategory
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Validated
 @RequiredArgsConstructor
@@ -38,31 +38,31 @@ public class ExternalProductCategoryController extends BaseController {
     private final IExternalProductCategoryService externalProductCategoryService;
 
     /**
-     * 查询第三方产品分类列表
+     * 查询产品分类列表
      */
-    @SaCheckPermission("external:productCategory:list")
+    //@SaCheckPermission("external:productCategory:list")
     @GetMapping("/list")
     public TableDataInfo<ExternalProductCategoryVo> list(ExternalProductCategoryBo bo, PageQuery pageQuery) {
         return externalProductCategoryService.queryPageList(bo, pageQuery);
     }
 
     /**
-     * 导出第三方产品分类列表
+     * 导出产品分类列表
      */
-    @SaCheckPermission("external:productCategory:export")
-    @Log(title = "第三方产品分类", businessType = BusinessType.EXPORT)
+    //@SaCheckPermission("external:productCategory:export")
+    @Log(title = "产品分类", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(ExternalProductCategoryBo bo, HttpServletResponse response) {
         List<ExternalProductCategoryVo> list = externalProductCategoryService.queryList(bo);
-        ExcelUtil.exportExcel(list, "第三方产品分类", ExternalProductCategoryVo.class, response);
+        ExcelUtil.exportExcel(list, "产品分类", ExternalProductCategoryVo.class, response);
     }
 
     /**
-     * 获取第三方产品分类详细信息
+     * 获取产品分类详细信息
      *
      * @param id 主键
      */
-    @SaCheckPermission("external:productCategory:query")
+    //@SaCheckPermission("external:productCategory:query")
     @GetMapping("/{id}")
     public R<ExternalProductCategoryVo> getInfo(@NotNull(message = "主键不能为空")
                                      @PathVariable("id") Long id) {
@@ -70,10 +70,10 @@ public class ExternalProductCategoryController extends BaseController {
     }
 
     /**
-     * 新增第三方产品分类
+     * 新增产品分类
      */
-    @SaCheckPermission("external:productCategory:add")
-    @Log(title = "第三方产品分类", businessType = BusinessType.INSERT)
+    //@SaCheckPermission("external:productCategory:add")
+    @Log(title = "产品分类", businessType = BusinessType.INSERT)
     @RepeatSubmit()
     @PostMapping()
     public R<Void> add(@Validated(AddGroup.class) @RequestBody ExternalProductCategoryBo bo) {
@@ -81,10 +81,10 @@ public class ExternalProductCategoryController extends BaseController {
     }
 
     /**
-     * 修改第三方产品分类
+     * 修改产品分类
      */
-    @SaCheckPermission("external:productCategory:edit")
-    @Log(title = "第三方产品分类", businessType = BusinessType.UPDATE)
+    //@SaCheckPermission("external:productCategory:edit")
+    @Log(title = "产品分类", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PutMapping()
     public R<Void> edit(@Validated(EditGroup.class) @RequestBody ExternalProductCategoryBo bo) {
@@ -92,12 +92,12 @@ public class ExternalProductCategoryController extends BaseController {
     }
 
     /**
-     * 删除第三方产品分类
+     * 删除产品分类
      *
      * @param ids 主键串
      */
-    @SaCheckPermission("external:productCategory:remove")
-    @Log(title = "第三方产品分类", businessType = BusinessType.DELETE)
+    //@SaCheckPermission("external:productCategory:remove")
+    @Log(title = "产品分类", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public R<Void> remove(@NotEmpty(message = "主键不能为空")
                           @PathVariable("ids") Long[] ids) {

+ 106 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalProductChangeLogController.java

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

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

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

+ 7 - 7
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/ExternalPushPoolLogController.java

@@ -27,7 +27,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
  * 前端访问路由地址为:/external/pushPoolLog
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 @Validated
 @RequiredArgsConstructor
@@ -40,7 +40,7 @@ public class ExternalPushPoolLogController extends BaseController {
     /**
      * 查询商品池推送记录列表
      */
-    @SaCheckPermission("external:pushPoolLog:list")
+    //@SaCheckPermission("external:pushPoolLog:list")
     @GetMapping("/list")
     public TableDataInfo<ExternalPushPoolLogVo> list(ExternalPushPoolLogBo bo, PageQuery pageQuery) {
         return externalPushPoolLogService.queryPageList(bo, pageQuery);
@@ -49,7 +49,7 @@ public class ExternalPushPoolLogController extends BaseController {
     /**
      * 导出商品池推送记录列表
      */
-    @SaCheckPermission("external:pushPoolLog:export")
+    //@SaCheckPermission("external:pushPoolLog:export")
     @Log(title = "商品池推送记录", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(ExternalPushPoolLogBo bo, HttpServletResponse response) {
@@ -62,7 +62,7 @@ public class ExternalPushPoolLogController extends BaseController {
      *
      * @param id 主键
      */
-    @SaCheckPermission("external:pushPoolLog:query")
+    //@SaCheckPermission("external:pushPoolLog:query")
     @GetMapping("/{id}")
     public R<ExternalPushPoolLogVo> getInfo(@NotNull(message = "主键不能为空")
                                      @PathVariable("id") Long id) {
@@ -72,7 +72,7 @@ public class ExternalPushPoolLogController extends BaseController {
     /**
      * 新增商品池推送记录
      */
-    @SaCheckPermission("external:pushPoolLog:add")
+    //@SaCheckPermission("external:pushPoolLog:add")
     @Log(title = "商品池推送记录", businessType = BusinessType.INSERT)
     @RepeatSubmit()
     @PostMapping()
@@ -83,7 +83,7 @@ public class ExternalPushPoolLogController extends BaseController {
     /**
      * 修改商品池推送记录
      */
-    @SaCheckPermission("external:pushPoolLog:edit")
+    //@SaCheckPermission("external:pushPoolLog:edit")
     @Log(title = "商品池推送记录", businessType = BusinessType.UPDATE)
     @RepeatSubmit()
     @PutMapping()
@@ -96,7 +96,7 @@ public class ExternalPushPoolLogController extends BaseController {
      *
      * @param ids 主键串
      */
-    @SaCheckPermission("external:pushPoolLog:remove")
+    //@SaCheckPermission("external:pushPoolLog:remove")
     @Log(title = "商品池推送记录", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public R<Void> remove(@NotEmpty(message = "主键不能为空")

+ 1 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongzhi/ZhongZhiPullController.java

@@ -123,6 +123,7 @@ public class ZhongZhiPullController {
         String accessToken = this.getAccessToken();
         post.form("token", accessToken);
         post.form("platformCode", code);
+        HashMap<String, String> stringStringHashMap = new HashMap<>();
         String body = post.execute().body();
         Result<List<Map<String,String>>> result = JSONUtil.toBean(body, Result.class);
         if (!result.getSuccess()) {

+ 4 - 9
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/controller/zhongzhi/ZhongZhiPushController.java

@@ -2,11 +2,9 @@ package org.dromara.external.controller.zhongzhi;
 
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.lang.UUID;
 import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.crypto.SecureUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import org.apache.dubbo.config.annotation.DubboReference;
@@ -24,16 +22,13 @@ import org.dromara.product.api.domain.ProductChangeLogApiVo;
 import org.dromara.product.api.domain.ProductVo;
 import org.dromara.product.api.domain.dto.OrderNoticeDto;
 import org.dromara.product.api.domain.dto.OrderPushDto;
-import org.dromara.system.api.RemoteUserService;
 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.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
 
 /**
  * 商品池推送记录
@@ -108,7 +103,7 @@ public class ZhongZhiPushController {
     * 获取商品详情 362031
     * */
     @PostMapping("/product/detail_standard")
-    public Result<ExternalProductVo> detailStandard(GetProductDetailBo bo) {
+    public Result<ZhongzhiExternalProductVo> detailStandard(GetProductDetailBo bo) {
         Result result = checkToken(bo.getToken(), bo.getPlatformCode());
         if(ObjectUtil.isNotEmpty(result)){
             return result;
@@ -131,13 +126,13 @@ public class ZhongZhiPushController {
         );
 
 
-        ExternalProductVo externalProductVo = ExternalProductVo.builder()
+        ZhongzhiExternalProductVo externalProductVo = ZhongzhiExternalProductVo.builder()
             .sku(String.valueOf(productDetail.getId()))
             .url(productDetail.getProductImage())
             .model(productDetail.getItemName())
             .weight(productDetail.getWeight())
             .image_path(productDetail.getProductImageUrl())
-            .state(productDetail.getProductStatus())
+            .state(String.valueOf(productDetail.getProductStatus()))
             .brand_name(productDetail.getBrandName())
             .name(productDetail.getItemName())
             .product_area(null)
@@ -205,7 +200,7 @@ public class ZhongZhiPushController {
             ProductVo productVo = remoteProductService.updateProductShelfState(Long.valueOf(skuId));
             ProductShelfStateVo productShelfStateVo = new ProductShelfStateVo();
             productShelfStateVo.setSku(skuId);
-            productShelfStateVo.setState(productVo.getProductStatus());
+            productShelfStateVo.setState(String.valueOf(productVo.getProductStatus()));
             shelfState.add(productShelfStateVo);
         }
         return Result.ok(shelfState);

+ 2 - 2
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalItem.java

@@ -11,7 +11,7 @@ import java.io.Serial;
  * 第三方对接项目管理对象 external_item
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -28,7 +28,7 @@ public class ExternalItem extends TenantEntity {
     private Long id;
 
     /**
-     * 项目
+     * 项目
      */
     private String itemName;
 

+ 67 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProduct.java

@@ -0,0 +1,67 @@
+package org.dromara.external.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 对外部推送商品对象 external_product
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("external_product")
+public class ExternalProduct extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 商品id
+     */
+    private Long productId;
+
+    /**
+     * 项目id
+     */
+    private Long itemId;
+
+    /**
+     * 分类id
+     */
+    private Long categoryId;
+
+    /**
+     * 外部分类id
+     */
+    private Long externlCategoryId;
+
+    /**
+     * 推送状态 0未推送,1已推送
+     */
+    private Long pushStatus;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 1 - 9
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProductBrand.java

@@ -4,8 +4,6 @@ import org.dromara.common.tenant.core.TenantEntity;
 import com.baomidou.mybatisplus.annotation.*;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import org.dromara.common.translation.annotation.Translation;
-import org.dromara.common.translation.constant.TransConstant;
 
 import java.io.Serial;
 
@@ -13,7 +11,7 @@ import java.io.Serial;
  * 第三方产品品牌信息对象 external_product_brand
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -90,10 +88,4 @@ public class ExternalProductBrand extends TenantEntity {
     @TableLogic
     private String delFlag;
 
-    /**
-     * 备注
-     */
-    private String remark;
-
-
 }

+ 2 - 2
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProductCategory.java

@@ -8,10 +8,10 @@ import lombok.EqualsAndHashCode;
 import java.io.Serial;
 
 /**
- * 第三方产品分类对象 external_product_category
+ * 产品分类对象 external_product_category
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 84 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalProductChangeLog.java

@@ -0,0 +1,84 @@
+package org.dromara.external.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 商品变更消息记录对象 external_product_change_log
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("external_product_change_log")
+public class ExternalProductChangeLog extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 项目id
+     */
+    private Long itemId;
+
+    /**
+     * 商品id
+     */
+    private Long productId;
+
+    /**
+     * type=2商品
+价格变更,后
+续会调用价格
+接口。
+type=4代表
+商品上下架变
+更消息,后续
+会调用上下架
+状态接口。
+type=6代表
+添加、删除商
+品池内的商
+品,触发保存
+商品流程,依
+次调用商品详
+情等接口获取
+商品信息。
+type=16商品
+介绍及规格参
+数变更消息,
+调用商品详情
+等接口更新商
+品信息。
+     */
+    private String type;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+
+}

+ 8 - 8
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/ExternalPushPoolLog.java

@@ -11,7 +11,7 @@ import java.io.Serial;
  * 商品池推送记录对象 external_push_pool_log
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -22,14 +22,14 @@ public class ExternalPushPoolLog extends TenantEntity {
     private static final long serialVersionUID = 1L;
 
     /**
-     *
+     * 
      */
     @TableId(value = "id")
     private Long id;
 
     /**
      * 项目id
-     * */
+     */
     private Long itemId;
 
     /**
@@ -47,16 +47,16 @@ public class ExternalPushPoolLog extends TenantEntity {
      */
     private String pushStatus;
 
-    /**
-     * 失败原因
-     * */
-    private String reason;
-
     /**
      * 状态(0正常 1停用)
      */
     private String status;
 
+    /**
+     * 失败原因
+     */
+    private String reason;
+
     /**
      * 删除标志(0代表存在 2代表删除)
      */

+ 9 - 9
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalItemBo.java

@@ -13,7 +13,7 @@ import jakarta.validation.constraints.*;
  * 第三方对接项目管理业务对象 external_item
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -26,45 +26,45 @@ public class ExternalItemBo extends BaseEntity {
     private Long id;
 
     /**
-     * 项目
+     * 项目
      */
-    @NotBlank(message = "项目表不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目名不能为空", groups = { AddGroup.class, EditGroup.class })
     private String itemName;
 
     /**
      * 项目key
      */
-    @NotBlank(message = "项目key不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目key不能为空", groups = { AddGroup.class, EditGroup.class })
     private String itemKey;
 
     /**
      * 项目用户名
      */
-    @NotBlank(message = "项目用户名不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目用户名不能为空", groups = { AddGroup.class, EditGroup.class })
     private String userName;
 
     /**
      * 项目密码
      */
-    @NotBlank(message = "项目密码不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目密码不能为空", groups = { AddGroup.class, EditGroup.class })
     private String password;
 
     /**
      * 项目url
      */
-    @NotBlank(message = "项目url不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目url不能为空", groups = { AddGroup.class, EditGroup.class })
     private String url;
 
     /**
      * 状态(0正常 1停用)
      */
-    @NotBlank(message = "状态(0正常 1停用)不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "状态(0正常 1停用)不能为空", groups = { AddGroup.class, EditGroup.class })
     private String status;
 
     /**
      * 备注
      */
-    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
     private String remark;
 
 

+ 65 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductBo.java

@@ -0,0 +1,65 @@
+package org.dromara.external.domain.bo;
+
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 对外部推送商品业务对象 external_product
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ExternalProduct.class, reverseConvertGenerate = false)
+public class ExternalProductBo extends BaseEntity {
+
+    /**
+     * 
+     */
+    private Long id;
+
+    /**
+     * 商品id
+     */
+    @NotNull(message = "商品id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long productId;
+
+    /**
+     * 项目id
+     */
+    @NotNull(message = "项目id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long itemId;
+
+    /**
+     * 分类id
+     */
+    @NotNull(message = "分类id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long categoryId;
+
+    /**
+     * 外部分类id
+     */
+    @NotNull(message = "外部分类id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long externlCategoryId;
+
+    /**
+     * 推送状态 0未推送,1已推送
+     */
+    @NotNull(message = "推送状态 0未推送,1已推送不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long pushStatus;
+
+    /**
+     * 备注
+     */
+    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String remark;
+
+
+}

+ 1 - 3
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductBrandBo.java

@@ -8,14 +8,12 @@ import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import jakarta.validation.constraints.*;
-import org.dromara.common.translation.annotation.Translation;
-import org.dromara.common.translation.constant.TransConstant;
 
 /**
  * 第三方产品品牌信息业务对象 external_product_brand
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 2 - 2
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductCategoryBo.java

@@ -10,10 +10,10 @@ import lombok.EqualsAndHashCode;
 import jakarta.validation.constraints.*;
 
 /**
- * 第三方产品分类业务对象 external_product_category
+ * 产品分类业务对象 external_product_category
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)

+ 80 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalProductChangeLogBo.java

@@ -0,0 +1,80 @@
+package org.dromara.external.domain.bo;
+
+import org.dromara.external.domain.ExternalProductChangeLog;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 商品变更消息记录业务对象 external_product_change_log
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ExternalProductChangeLog.class, reverseConvertGenerate = false)
+public class ExternalProductChangeLogBo extends BaseEntity {
+
+    /**
+     *
+     */
+    private Long id;
+
+    /**
+     * 项目id
+     */
+    @NotNull(message = "项目id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long itemId;
+
+    /**
+     * 商品id
+     */
+    @NotNull(message = "商品id不能为空", groups = { AddGroup.class, EditGroup.class })
+    private Long productId;
+
+    /**
+     * type=2商品
+价格变更,后
+续会调用价格
+接口。
+type=4代表
+商品上下架变
+更消息,后续
+会调用上下架
+状态接口。
+type=6代表
+添加、删除商
+品池内的商
+品,触发保存
+商品流程,依
+次调用商品详
+情等接口获取
+商品信息。
+type=16商品
+介绍及规格参
+数变更消息,
+调用商品详情
+等接口更新商
+品信息。
+     */
+    private String type;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @NotBlank(message = "状态(0正常 1停用)不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String status;
+
+    /**
+     * 备注
+     */
+    @NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String remark;
+
+
+}

+ 11 - 9
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/bo/ExternalPushPoolLogBo.java

@@ -13,7 +13,7 @@ import jakarta.validation.constraints.*;
  * 商品池推送记录业务对象 external_push_pool_log
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -21,13 +21,14 @@ import jakarta.validation.constraints.*;
 public class ExternalPushPoolLogBo extends BaseEntity {
 
     /**
-     *
+     * 
      */
     private Long id;
 
     /**
-    * 项目id
-    * */
+     * 项目id
+     */
+    @NotNull(message = "项目id不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long itemId;
 
     /**
@@ -48,17 +49,18 @@ public class ExternalPushPoolLogBo extends BaseEntity {
     @NotBlank(message = "推送状态 0成功 1失败不能为空", groups = { AddGroup.class, EditGroup.class })
     private String pushStatus;
 
-    /**
-    * 失败原因
-    * */
-    private String reason;
-
     /**
      * 状态(0正常 1停用)
      */
     @NotBlank(message = "状态(0正常 1停用)不能为空", groups = { AddGroup.class, EditGroup.class })
     private String status;
 
+    /**
+     * 失败原因
+     */
+    @NotBlank(message = "失败原因不能为空", groups = { AddGroup.class, EditGroup.class })
+    private String reason;
+
     /**
      * 备注
      */

+ 3 - 3
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalItemVo.java

@@ -18,7 +18,7 @@ import java.util.Date;
  * 第三方对接项目管理视图对象 external_item
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @ExcelIgnoreUnannotated
@@ -35,9 +35,9 @@ public class ExternalItemVo implements Serializable {
     private Long id;
 
     /**
-     * 项目
+     * 项目
      */
-    @ExcelProperty(value = "项目")
+    @ExcelProperty(value = "项目")
     private String itemName;
 
     /**

+ 8 - 80
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductBrandVo.java

@@ -1,26 +1,19 @@
 package org.dromara.external.domain.vo;
 
-import org.dromara.common.translation.annotation.Translation;
-import org.dromara.common.translation.constant.TransConstant;
 import org.dromara.external.domain.ExternalProductBrand;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
-import org.dromara.common.excel.annotation.ExcelDictFormat;
-import org.dromara.common.excel.convert.ExcelDictConvert;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
-import java.util.Date;
-
-
 
 /**
  * 第三方产品品牌信息视图对象 external_product_brand
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @ExcelIgnoreUnannotated
@@ -37,86 +30,21 @@ public class ExternalProductBrandVo implements Serializable {
     private Long id;
 
     /**
-     * 原系统品牌id
+     * 官方品牌id
      */
-    @ExcelProperty(value = "原系统品牌id")
+    @ExcelProperty(value = "官方品牌id")
     private Long productBrandId;
 
     /**
-     * 项目id
-     */
-    @ExcelProperty(value = "项目id")
-    private Long itemId;
-
-    /**
-     * 品牌编号(唯一标识)
-     */
-    @ExcelProperty(value = "品牌编号", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "唯=一标识")
-    private String brandNo;
-
-    /**
-     * 品牌中文名称
+     * 官方品牌名称
      */
-    @ExcelProperty(value = "品牌中文名称")
+    @ExcelProperty(value = "官方品牌名称")
     private String brandName;
 
     /**
-     * 品牌首字母缩写(如拼音首字母)
-     */
-    @ExcelProperty(value = "品牌首字母缩写", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "如=拼音首字母")
-    private String brandInitials;
-
-    /**
-     * 品牌英文名称
-     */
-    @ExcelProperty(value = "品牌英文名称")
-    private String brandEnglishName;
-
-    /**
-     * 品牌Logo图片路径或URL
-     */
-    @ExcelProperty(value = "品牌Logo图片路径或URL")
-    private String brandLogo;
-
-    /**
-     * 品牌标题(用于展示)
-     */
-    @ExcelProperty(value = "品牌标题", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "用=于展示")
-    private String brandTitle;
-
-    /**
-     * 品牌大图(横幅/封面图)
-     */
-    @ExcelProperty(value = "品牌大图", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "横=幅/封面图")
-    private String brandBigImage;
-
-    /**
-     * 品牌大图(横幅/封面图)Url
-     */
-    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "brandBigImage")
-    private String brandBigImageUrl;
-    /**
-     * 品牌故事(简介文本)
-     */
-    @ExcelProperty(value = "品牌故事", converter = ExcelDictConvert.class)
-    @ExcelDictFormat(readConverterExp = "简=介文本")
-    private String brandStory;
-
-    /**
-     * 数据来源
+     * 第三方品牌名称
      */
-    @ExcelProperty(value = "数据来源")
-    private String dataSource;
-
-    /**
-     * 备注
-     */
-    @ExcelProperty(value = "备注")
-    private String remark;
-
+    @ExcelProperty(value = "第三方品牌名称")
+    private String thirdPartyBrandName;
 
 }

+ 2 - 2
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductCategoryVo.java

@@ -15,10 +15,10 @@ import java.util.Date;
 
 
 /**
- * 第三方产品分类视图对象 external_product_category
+ * 产品分类视图对象 external_product_category
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Data
 @ExcelIgnoreUnannotated

+ 90 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalProductChangeLogVo.java

@@ -0,0 +1,90 @@
+package org.dromara.external.domain.vo;
+
+import org.dromara.external.domain.ExternalProductChangeLog;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 商品变更消息记录视图对象 external_product_change_log
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ExternalProductChangeLog.class)
+public class ExternalProductChangeLogVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 项目id
+     */
+    @ExcelProperty(value = "项目id")
+    private Long itemId;
+
+    /**
+     * 商品id
+     */
+    @ExcelProperty(value = "商品id")
+    private Long productId;
+
+    /**
+     * type=2商品
+价格变更,后
+续会调用价格
+接口。
+type=4代表
+商品上下架变
+更消息,后续
+会调用上下架
+状态接口。
+type=6代表
+添加、删除商
+品池内的商
+品,触发保存
+商品流程,依
+次调用商品详
+情等接口获取
+商品信息。
+type=16商品
+介绍及规格参
+数变更消息,
+调用商品详情
+等接口更新商
+品信息。
+     */
+    private String type;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

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

@@ -0,0 +1,74 @@
+package org.dromara.external.domain.vo;
+
+import org.dromara.external.domain.ExternalProduct;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 对外部推送商品视图对象 external_product
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ExternalProduct.class)
+public class ExternalProductVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 商品id
+     */
+    @ExcelProperty(value = "商品id")
+    private Long productId;
+
+    /**
+     * 项目id
+     */
+    @ExcelProperty(value = "项目id")
+    private Long itemId;
+
+    /**
+     * 分类id
+     */
+    @ExcelProperty(value = "分类id")
+    private Long categoryId;
+
+    /**
+     * 外部分类id
+     */
+    @ExcelProperty(value = "外部分类id")
+    private Long externlCategoryId;
+
+    /**
+     * 推送状态 0未推送,1已推送
+     */
+    @ExcelProperty(value = "推送状态 0未推送,1已推送")
+    private Long pushStatus;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

+ 10 - 8
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/domain/vo/ExternalPushPoolLogVo.java

@@ -18,7 +18,7 @@ import java.util.Date;
  * 商品池推送记录视图对象 external_push_pool_log
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 @Data
 @ExcelIgnoreUnannotated
@@ -29,14 +29,15 @@ public class ExternalPushPoolLogVo implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
-     *
+     * 
      */
     @ExcelProperty(value = "")
     private Long id;
 
     /**
      * 项目id
-     * */
+     */
+    @ExcelProperty(value = "项目id")
     private Long itemId;
 
     /**
@@ -57,11 +58,6 @@ public class ExternalPushPoolLogVo implements Serializable {
     @ExcelProperty(value = "推送状态 0成功 1失败")
     private String pushStatus;
 
-    /**
-     * 失败原因
-     * */
-    private String reason;
-
     /**
      * 状态(0正常 1停用)
      */
@@ -69,6 +65,12 @@ public class ExternalPushPoolLogVo implements Serializable {
     @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
     private String status;
 
+    /**
+     * 失败原因
+     */
+    @ExcelProperty(value = "失败原因")
+    private String reason;
+
     /**
      * 备注
      */

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalItemMapper.java

@@ -8,7 +8,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * 第三方对接项目管理Mapper接口
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 public interface ExternalItemMapper extends BaseMapperPlus<ExternalItem, ExternalItemVo> {
 

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductBrandMapper.java

@@ -8,7 +8,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * 第三方产品品牌信息Mapper接口
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 public interface ExternalProductBrandMapper extends BaseMapperPlus<ExternalProductBrand, ExternalProductBrandVo> {
 

+ 2 - 2
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductCategoryMapper.java

@@ -5,10 +5,10 @@ import org.dromara.external.domain.vo.ExternalProductCategoryVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
 /**
- * 第三方产品分类Mapper接口
+ * 产品分类Mapper接口
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 public interface ExternalProductCategoryMapper extends BaseMapperPlus<ExternalProductCategory, ExternalProductCategoryVo> {
 

+ 15 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductChangeLogMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.external.mapper;
+
+import org.dromara.external.domain.ExternalProductChangeLog;
+import org.dromara.external.domain.vo.ExternalProductChangeLogVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 商品变更消息记录Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+public interface ExternalProductChangeLogMapper extends BaseMapperPlus<ExternalProductChangeLog, ExternalProductChangeLogVo> {
+
+}

+ 15 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalProductMapper.java

@@ -0,0 +1,15 @@
+package org.dromara.external.mapper;
+
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.domain.vo.ExternalProductVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 对外部推送商品Mapper接口
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+public interface ExternalProductMapper extends BaseMapperPlus<ExternalProduct, ExternalProductVo> {
+
+}

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/mapper/ExternalPushPoolLogMapper.java

@@ -8,7 +8,7 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  * 商品池推送记录Mapper接口
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 public interface ExternalPushPoolLogMapper extends BaseMapperPlus<ExternalPushPoolLog, ExternalPushPoolLogVo> {
 

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalItemService.java

@@ -14,7 +14,7 @@ import java.util.List;
  * 第三方对接项目管理Service接口
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 public interface IExternalItemService extends IService<ExternalItem>{
 

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductBrandService.java

@@ -14,7 +14,7 @@ import java.util.List;
  * 第三方产品品牌信息Service接口
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 public interface IExternalProductBrandService extends IService<ExternalProductBrand>{
 

+ 13 - 13
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductCategoryService.java

@@ -11,56 +11,56 @@ import java.util.Collection;
 import java.util.List;
 
 /**
- * 第三方产品分类Service接口
+ * 产品分类Service接口
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 public interface IExternalProductCategoryService extends IService<ExternalProductCategory>{
 
     /**
-     * 查询第三方产品分类
+     * 查询产品分类
      *
      * @param id 主键
-     * @return 第三方产品分类
+     * @return 产品分类
      */
     ExternalProductCategoryVo queryById(Long id);
 
     /**
-     * 分页查询第三方产品分类列表
+     * 分页查询产品分类列表
      *
      * @param bo        查询条件
      * @param pageQuery 分页参数
-     * @return 第三方产品分类分页列表
+     * @return 产品分类分页列表
      */
     TableDataInfo<ExternalProductCategoryVo> queryPageList(ExternalProductCategoryBo bo, PageQuery pageQuery);
 
     /**
-     * 查询符合条件的第三方产品分类列表
+     * 查询符合条件的产品分类列表
      *
      * @param bo 查询条件
-     * @return 第三方产品分类列表
+     * @return 产品分类列表
      */
     List<ExternalProductCategoryVo> queryList(ExternalProductCategoryBo bo);
 
     /**
-     * 新增第三方产品分类
+     * 新增产品分类
      *
-     * @param bo 第三方产品分类
+     * @param bo 产品分类
      * @return 是否新增成功
      */
     Boolean insertByBo(ExternalProductCategoryBo bo);
 
     /**
-     * 修改第三方产品分类
+     * 修改产品分类
      *
-     * @param bo 第三方产品分类
+     * @param bo 产品分类
      * @return 是否修改成功
      */
     Boolean updateByBo(ExternalProductCategoryBo bo);
 
     /**
-     * 校验并批量删除第三方产品分类信息
+     * 校验并批量删除产品分类信息
      *
      * @param ids     待删除的主键集合
      * @param isValid 是否进行有效性校验

+ 70 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalProductChangeLogService.java

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

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

@@ -0,0 +1,70 @@
+package org.dromara.external.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.external.domain.ExternalProduct;
+import org.dromara.external.domain.vo.ExternalProductVo;
+import org.dromara.external.domain.bo.ExternalProductBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 对外部推送商品Service接口
+ *
+ * @author LionLi
+ * @date 2026-01-08
+ */
+public interface IExternalProductService extends IService<ExternalProduct>{
+
+    /**
+     * 查询对外部推送商品
+     *
+     * @param id 主键
+     * @return 对外部推送商品
+     */
+    ExternalProductVo queryById(Long id);
+
+    /**
+     * 分页查询对外部推送商品列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 对外部推送商品分页列表
+     */
+    TableDataInfo<ExternalProductVo> queryPageList(ExternalProductBo bo, PageQuery pageQuery);
+
+    /**
+     * 查询符合条件的对外部推送商品列表
+     *
+     * @param bo 查询条件
+     * @return 对外部推送商品列表
+     */
+    List<ExternalProductVo> queryList(ExternalProductBo bo);
+
+    /**
+     * 新增对外部推送商品
+     *
+     * @param bo 对外部推送商品
+     * @return 是否新增成功
+     */
+    Boolean insertByBo(ExternalProductBo bo);
+
+    /**
+     * 修改对外部推送商品
+     *
+     * @param bo 对外部推送商品
+     * @return 是否修改成功
+     */
+    Boolean updateByBo(ExternalProductBo bo);
+
+    /**
+     * 校验并批量删除对外部推送商品信息
+     *
+     * @param ids     待删除的主键集合
+     * @param isValid 是否进行有效性校验
+     * @return 是否删除成功
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/IExternalPushPoolLogService.java

@@ -14,7 +14,7 @@ import java.util.List;
  * 商品池推送记录Service接口
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 public interface IExternalPushPoolLogService extends IService<ExternalPushPoolLog>{
 

+ 1 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalItemServiceImpl.java

@@ -25,7 +25,7 @@ import java.util.Collection;
  * 第三方对接项目管理Service业务层处理
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Slf4j
 @RequiredArgsConstructor

+ 25 - 2
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductBrandServiceImpl.java

@@ -1,6 +1,7 @@
 package org.dromara.external.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -10,6 +11,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.product.api.RemoteProductService;
+import org.dromara.product.api.domain.RemoteProductBrand;
 import org.springframework.stereotype.Service;
 import org.dromara.external.domain.bo.ExternalProductBrandBo;
 import org.dromara.external.domain.vo.ExternalProductBrandVo;
@@ -25,7 +28,7 @@ import java.util.Collection;
  * 第三方产品品牌信息Service业务层处理
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Slf4j
 @RequiredArgsConstructor
@@ -34,6 +37,9 @@ public class ExternalProductBrandServiceImpl  extends ServiceImpl<ExternalProduc
 
     private final ExternalProductBrandMapper baseMapper;
 
+    @DubboReference
+    private RemoteProductService remoteProductService;
+
     /**
      * 查询第三方产品品牌信息
      *
@@ -42,7 +48,15 @@ public class ExternalProductBrandServiceImpl  extends ServiceImpl<ExternalProduc
      */
     @Override
     public ExternalProductBrandVo queryById(Long id){
-        return baseMapper.selectVoById(id);
+        ExternalProductBrandVo vo = baseMapper.selectVoById(id);
+        vo.setThirdPartyBrandName(vo.getBrandName());
+        RemoteProductBrand productByBrandId = remoteProductService.getProductByBrandId(vo.getProductBrandId());
+        if (productByBrandId != null) {
+            vo.setBrandName(productByBrandId.getBrandName());
+        }else {
+            vo.setBrandName(null);
+        }
+        return vo;
     }
 
     /**
@@ -56,6 +70,15 @@ public class ExternalProductBrandServiceImpl  extends ServiceImpl<ExternalProduc
     public TableDataInfo<ExternalProductBrandVo> queryPageList(ExternalProductBrandBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<ExternalProductBrand> lqw = buildQueryWrapper(bo);
         Page<ExternalProductBrandVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        result.getRecords().forEach(vo -> {
+            vo.setThirdPartyBrandName(vo.getBrandName());
+            RemoteProductBrand productByBrandId = remoteProductService.getProductByBrandId(vo.getProductBrandId());
+            if (productByBrandId != null) {
+                vo.setBrandName(productByBrandId.getBrandName());
+            }else {
+                vo.setBrandName(null);
+            }
+        });
         return TableDataInfo.build(result);
     }
 

+ 13 - 13
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductCategoryServiceImpl.java

@@ -22,10 +22,10 @@ import java.util.Map;
 import java.util.Collection;
 
 /**
- * 第三方产品分类Service业务层处理
+ * 产品分类Service业务层处理
  *
  * @author LionLi
- * @date 2025-12-29
+ * @date 2026-01-08
  */
 @Slf4j
 @RequiredArgsConstructor
@@ -35,10 +35,10 @@ public class ExternalProductCategoryServiceImpl  extends ServiceImpl<ExternalPro
     private final ExternalProductCategoryMapper baseMapper;
 
     /**
-     * 查询第三方产品分类
+     * 查询产品分类
      *
      * @param id 主键
-     * @return 第三方产品分类
+     * @return 产品分类
      */
     @Override
     public ExternalProductCategoryVo queryById(Long id){
@@ -46,11 +46,11 @@ public class ExternalProductCategoryServiceImpl  extends ServiceImpl<ExternalPro
     }
 
     /**
-     * 分页查询第三方产品分类列表
+     * 分页查询产品分类列表
      *
      * @param bo        查询条件
      * @param pageQuery 分页参数
-     * @return 第三方产品分类分页列表
+     * @return 产品分类分页列表
      */
     @Override
     public TableDataInfo<ExternalProductCategoryVo> queryPageList(ExternalProductCategoryBo bo, PageQuery pageQuery) {
@@ -60,10 +60,10 @@ public class ExternalProductCategoryServiceImpl  extends ServiceImpl<ExternalPro
     }
 
     /**
-     * 查询符合条件的第三方产品分类列表
+     * 查询符合条件的产品分类列表
      *
      * @param bo 查询条件
-     * @return 第三方产品分类列表
+     * @return 产品分类列表
      */
     @Override
     public List<ExternalProductCategoryVo> queryList(ExternalProductCategoryBo bo) {
@@ -91,9 +91,9 @@ public class ExternalProductCategoryServiceImpl  extends ServiceImpl<ExternalPro
     }
 
     /**
-     * 新增第三方产品分类
+     * 新增产品分类
      *
-     * @param bo 第三方产品分类
+     * @param bo 产品分类
      * @return 是否新增成功
      */
     @Override
@@ -108,9 +108,9 @@ public class ExternalProductCategoryServiceImpl  extends ServiceImpl<ExternalPro
     }
 
     /**
-     * 修改第三方产品分类
+     * 修改产品分类
      *
-     * @param bo 第三方产品分类
+     * @param bo 产品分类
      * @return 是否修改成功
      */
     @Override
@@ -128,7 +128,7 @@ public class ExternalProductCategoryServiceImpl  extends ServiceImpl<ExternalPro
     }
 
     /**
-     * 校验并批量删除第三方产品分类信息
+     * 校验并批量删除产品分类信息
      *
      * @param ids     待删除的主键集合
      * @param isValid 是否进行有效性校验

+ 137 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductChangeLogServiceImpl.java

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

+ 138 - 0
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalProductServiceImpl.java

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

+ 3 - 1
ruoyi-modules/ruoyi-external/src/main/java/org/dromara/external/service/impl/ExternalPushPoolLogServiceImpl.java

@@ -25,7 +25,7 @@ import java.util.Collection;
  * 商品池推送记录Service业务层处理
  *
  * @author LionLi
- * @date 2025-12-24
+ * @date 2026-01-08
  */
 @Slf4j
 @RequiredArgsConstructor
@@ -75,10 +75,12 @@ public class ExternalPushPoolLogServiceImpl  extends ServiceImpl<ExternalPushPoo
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<ExternalPushPoolLog> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(ExternalPushPoolLog::getId);
+        lqw.eq(bo.getItemId() != null, ExternalPushPoolLog::getItemId, bo.getItemId());
         lqw.eq(bo.getPoolId() != null, ExternalPushPoolLog::getPoolId, bo.getPoolId());
         lqw.eq(bo.getOperatorId() != null, ExternalPushPoolLog::getOperatorId, bo.getOperatorId());
         lqw.eq(StringUtils.isNotBlank(bo.getPushStatus()), ExternalPushPoolLog::getPushStatus, bo.getPushStatus());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ExternalPushPoolLog::getStatus, bo.getStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getReason()), ExternalPushPoolLog::getReason, bo.getReason());
         lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), ExternalPushPoolLog::getPlatformCode, bo.getPlatformCode());
         return lqw;
     }

+ 7 - 0
ruoyi-modules/ruoyi-external/src/main/resources/mapper/external/ExternalProductChangeLogMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.external.mapper.ExternalProductChangeLogMapper">
+
+</mapper>

+ 7 - 0
ruoyi-modules/ruoyi-external/src/main/resources/mapper/external/ExternalProductMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.external.mapper.ExternalProductMapper">
+
+</mapper>

+ 5 - 0
ruoyi-modules/ruoyi-product/pom.xml

@@ -93,6 +93,11 @@
             <artifactId>ruoyi-common-encrypt</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-elasticsearch</artifactId>
+        </dependency>
+
         <!-- RuoYi Api System -->
         <dependency>
             <groupId>org.dromara</groupId>

+ 30 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductBaseController.java

@@ -59,6 +59,14 @@ public class ProductBaseController extends BaseController {
         return productBaseService.queryPageList(bo, pageQuery);
     }
 
+    /**
+    * 获取商品各个状态数量
+    * */
+    @GetMapping("/getProductStatusCount")
+    public R<StatusCountVo> getProductStatusCount() {
+        return R.ok(productBaseService.getProductStatusCount());
+    }
+
     /**
      * 导出产品基础信息列表
      */
@@ -184,4 +192,26 @@ public class ProductBaseController extends BaseController {
         return productBaseService.querySiteProductPageList(bo, pageQuery);
     }
 
+    /**
+     * 商品审核
+     *
+     * @param bo 审核信息
+     */
+    //@SaCheckPermission("product:base:review")
+    @Log(title = "商品审核", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PostMapping("/review")
+    public R<Void> review(@Validated @RequestBody ProductBaseBo bo) {
+        productBaseService.review(bo);
+        return R.ok();
+    }
+
+    /**
+    * 商品上下架 状态变更
+    * */
+    @PostMapping("/shelfReview")
+    public R<Void> shelfReview(@Validated @RequestBody ProductBaseBo bo) {
+        productBaseService.shelfReview(bo);
+        return R.ok();
+    }
 }

+ 31 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/controller/ProductPoolLinkController.java

@@ -118,4 +118,35 @@ public class ProductPoolLinkController extends BaseController {
     public R<Void> batchAdd(@Validated @RequestBody BatchAddProductBo bo) {
         return toAjax(productPoolLinkService.batchAddProducts(bo));
     }
+
+    /**
+    * 批量审核商品进入商品池
+    * */
+    @PostMapping("/batchReview")
+    public R<Void> batchReview( @RequestBody List<ProductPoolLinkBo> bo) {
+        return toAjax(productPoolLinkService.batchReview(bo));
+    }
+
+    /**
+    * 提交审核商品到商品池
+    * */
+    @PostMapping("/reSubmit")
+    public R<Void> reSubmit( @RequestBody List<ProductPoolLinkBo> bo) {
+        return toAjax(productPoolLinkService.reSubmit(bo));
+    }
+
+    /**
+    * 编辑商品价格
+    * */
+    @PostMapping("/editPrice")
+    public R<Void> editPrice( @RequestBody ProductPoolLinkBo bo) {
+        return toAjax(productPoolLinkService.editPrice(bo));
+    }
+    /**
+    * 编辑商品库存
+    * */
+    @PostMapping("/editStock")
+    public R<Void> editStock( @RequestBody ProductPoolLinkBo bo) {
+        return toAjax(productPoolLinkService.editStock(bo));
+    }
 }

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

@@ -72,27 +72,32 @@ public class ProductBase extends TenantEntity {
     /**
      * 是否自营(1=是,0=否)
      */
-    private String isSelf;
+    private Integer isSelf;
+
+    /**
+     * 商品类型 1=默认类型,2精选商品,3=停售商品
+     * */
+    private Integer productCategory;
 
     /**
      * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
      */
-    private String productReviewStatus;
+    private Integer productReviewStatus;
 
     /**
      * 首页推荐:1=推荐,0=不推荐
      */
-    private String homeRecommended;
+    private Integer homeRecommended;
 
     /**
      * 分类推荐:1=推荐,0=不推荐
      */
-    private String categoryRecommendation;
+    private Integer categoryRecommendation;
 
     /**
      * 购物车推荐:1=推荐,0=不推荐
      */
-    private String cartRecommendation;
+    private Integer cartRecommendation;
 
     /**
      * 推荐产品顺序
@@ -102,17 +107,17 @@ public class ProductBase extends TenantEntity {
     /**
      * 是否热门:1=是,0=否
      */
-    private String isPopular;
+    private Integer isPopular;
 
     /**
      * 是否新品:1=是,0=否
      */
-    private String isNew;
+    private Integer isNew;
 
     /**
-     * 商品状态:1=上架,0=下架等
+     * 商品状态:1=上架,0=下架 2 上架中
      */
-    private String productStatus;
+    Integer productStatus;
 
     /**
      * 数据来源

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

@@ -143,7 +143,10 @@ public class ProductExtend extends TenantEntity {
      * 审核评论
      */
     private String reviewComments;
-
+    /**
+     * 审核评论
+     */
+    private String shelfComments;
     /**
      * 供应商编号
      */

+ 14 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductPool.java

@@ -32,6 +32,20 @@ public class ProductPool extends TenantEntity {
      */
     private String poolNo;
 
+    /**
+    * 项目id
+    * */
+    private Long itemId;
+    /**
+    * 分类id
+    * */
+    private Long categoryId;
+
+    /**
+     * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+     * */
+    private Integer type;
+
     /**
      * 池名称
      */

+ 22 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/ProductPoolLink.java

@@ -36,6 +36,28 @@ public class ProductPoolLink extends TenantEntity {
      */
     private Long poolId;
 
+    /**
+     * 项目id
+     * */
+    private Long itemId;
+    /**
+     * 分类id
+     * */
+    private Long categoryId;
+    /**
+     * 审核人
+     */
+    private String reviewer;
+    /**
+    * 协议价格
+    * */
+    private BigDecimal negotiatedPrice;
+
+    /**
+     * 商品池库存
+     */
+    private Long stock;
+
     /**
      * 产品id
      */

+ 2 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductAttributesBo.java

@@ -31,6 +31,8 @@ public class ProductAttributesBo extends BaseEntity {
     //@NotBlank(message = "关联的产品分类id不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long categoryId;
 
+    private String categoryName;
+
     /**
      * 属性编码(用于系统识别)
      */

+ 33 - 9
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductBaseBo.java

@@ -52,6 +52,16 @@ public class ProductBaseBo extends BaseEntity {
     //@NotNull(message = "品牌id不能为空", groups = {AddGroup.class, EditGroup.class})
     private Long brandId;
 
+    /**
+     * 品牌名称(用于搜索)
+     */
+    private String brandName;
+
+    /**
+     * 分类名称(用于搜索,支持模糊匹配三级分类)
+     */
+    private String categoryName;
+
     /**
      * 顶级分类id
      */
@@ -83,27 +93,32 @@ public class ProductBaseBo extends BaseEntity {
     /**
      * 是否自营(1=是,0=否)
      */
-    private String isSelf;
+    private Integer isSelf;
+
+    /**
+    * 商品类型 1=默认类型,2精选商品,3=停售商品
+    * */
+    private Integer productCategory;
 
     /**
      * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
      */
-    private String productReviewStatus;
+    private Integer productReviewStatus;
 
     /**
      * 首页推荐:1=推荐,0=不推荐
      */
-    private String homeRecommended;
+    private Integer homeRecommended;
 
     /**
      * 分类推荐:1=推荐,0=不推荐
      */
-    private String categoryRecommendation;
+    private Integer categoryRecommendation;
 
     /**
      * 购物车推荐:1=推荐,0=不推荐
      */
-    private String cartRecommendation;
+    private Integer cartRecommendation;
 
     /**
      * 推荐产品顺序
@@ -113,17 +128,17 @@ public class ProductBaseBo extends BaseEntity {
     /**
      * 是否热门:1=是,0=否
      */
-    private String isPopular;
+    private Integer isPopular;
 
     /**
      * 是否新品:1=是,0=否
      */
-    private String isNew;
+    private Integer isNew;
 
     /**
-     * 商品状态:1=上架,0=下架等
+     * 商品状态:1=上架,0=下架 2 上架中
      */
-    private String productStatus;
+    Integer productStatus;
 
     /**
      * 数据来源
@@ -318,4 +333,13 @@ public class ProductBaseBo extends BaseEntity {
      */
     private String customDetailsJson;
 
+    /**
+    * 审核意见
+    * */
+    private String reviewComments;
+    /**
+    * 上架意见
+    * */
+    private String shelfComments;
+
 }

+ 14 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductPoolBo.java

@@ -30,6 +30,20 @@ public class ProductPoolBo extends BaseEntity {
      */
     private String poolNo;
 
+    /**
+     * 项目id
+     * */
+    private Long itemId;
+    /**
+     * 分类id
+     * */
+    private Long categoryId;
+
+    /**
+    * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+    * */
+    private Integer type;
+
     /**
      * 池名称
      */

+ 22 - 4
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/ProductPoolLinkBo.java

@@ -34,6 +34,28 @@ public class ProductPoolLinkBo extends BaseEntity {
     @NotNull(message = "所属池ID不能为空", groups = {AddGroup.class, EditGroup.class})
     private Long poolId;
 
+    /**
+     * 项目id
+     * */
+    private Long itemId;
+    /**
+     * 分类id
+     * */
+    private Long categoryId;
+    /**
+     * 协议价格
+     * */
+    private BigDecimal negotiatedPrice;
+
+    /**
+     * 商品池库存
+     */
+    private Long stock;
+    /**
+     * 审核人
+     */
+    private String reviewer;
+
     /**
      * 产品id
      */
@@ -87,10 +109,6 @@ public class ProductPoolLinkBo extends BaseEntity {
      */
     private Long brandId;
 
-    /**
-     * 分类ID
-     */
-    private Long categoryId;
 
     /**
      * 商品状态 1=上架,0=下架

+ 3 - 3
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/bo/SiteProductBo.java

@@ -41,13 +41,13 @@ public class SiteProductBo implements Serializable {
     private String giftCategoryNo;
 
     /** 是否自营(1=是,0=否) */
-    private String isSelf;
+    private Integer isSelf;
 
     /** 产品审核状态 */
-    private String productReviewStatus;
+    private Integer productReviewStatus;
 
     /** 商品状态(1=上架,0=下架) */
-    private String productStatus;
+    Integer productStatus;
 
     /** 商品类型 */
     private String productType;

+ 6 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductAttributesVo.java

@@ -34,6 +34,12 @@ public class ProductAttributesVo implements Serializable {
     @ExcelProperty(value = "主键,自增ID")
     private Long id;
 
+    /**
+    * 分类名称
+    * */
+    @ExcelProperty(value = "分类名称")
+    private String categoryName;
+
     /**
      * 关联的产品分类id
      */

+ 39 - 11
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductBaseVo.java

@@ -2,6 +2,7 @@ package org.dromara.product.domain.vo;
 
 import org.dromara.common.translation.annotation.Translation;
 import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.easyes.annotation.IndexName;
 import org.dromara.product.domain.ProductBase;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
@@ -25,6 +26,7 @@ import java.util.Date;
 @Data
 @ExcelIgnoreUnannotated
 @AutoMapper(target = ProductBase.class)
+@IndexName("productbasevo")
 public class ProductBaseVo implements Serializable {
 
     @Serial
@@ -78,10 +80,25 @@ public class ProductBaseVo implements Serializable {
     private Long bottomCategoryId;
 
     /**
-     * 分类名称
+     * 分类名称(底级分类)
      */
     private String categoryName;
 
+    /**
+     * 顶级分类名称
+     */
+    private String topCategoryName;
+
+    /**
+     * 中级分类名称
+     */
+    private String mediumCategoryName;
+
+    /**
+     * 底级分类名称
+     */
+    private String bottomCategoryName;
+
     /**
      * 单位id
      */
@@ -104,31 +121,42 @@ public class ProductBaseVo implements Serializable {
      */
     @ExcelProperty(value = "是否自营", converter = ExcelDictConvert.class)
     @ExcelDictFormat(readConverterExp = "1==是,0=否")
-    private String isSelf;
+    private Integer isSelf;
+
+    /**
+     * 商品类型 1=默认类型,2精选商品,3=停售商品
+     * */
+    private Integer productCategory;
 
     /**
      * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
      */
     @ExcelProperty(value = "产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核")
-    private String productReviewStatus;
+    private Integer productReviewStatus;
+
+    /**
+    * 审核意见
+    * */
+    @ExcelProperty(value = "审核意见")
+    private String reviewComments;
 
     /**
      * 首页推荐:1=推荐,0=不推荐
      */
     @ExcelProperty(value = "首页推荐:1=推荐,0=不推荐")
-    private String homeRecommended;
+    private Integer homeRecommended;
 
     /**
      * 分类推荐:1=推荐,0=不推荐
      */
     @ExcelProperty(value = "分类推荐:1=推荐,0=不推荐")
-    private String categoryRecommendation;
+    private Integer categoryRecommendation;
 
     /**
      * 购物车推荐:1=推荐,0=不推荐
      */
     @ExcelProperty(value = "购物车推荐:1=推荐,0=不推荐")
-    private String cartRecommendation;
+    private Integer cartRecommendation;
 
     /**
      * 推荐产品顺序
@@ -140,19 +168,19 @@ public class ProductBaseVo implements Serializable {
      * 是否热门:1=是,0=否
      */
     @ExcelProperty(value = "是否热门:1=是,0=否")
-    private String isPopular;
+    private Integer isPopular;
 
     /**
      * 是否新品:1=是,0=否
      */
     @ExcelProperty(value = "是否新品:1=是,0=否")
-    private String isNew;
+    private Integer isNew;
 
     /**
-     * 商品状态:1=上架,0=下架等
+     * 商品状态:1=上架,0=下架 2 上架中
      */
-    @ExcelProperty(value = "商品状态:1=上架,0=下架等")
-    private String productStatus;
+    @ExcelProperty(value = "商品状态:1=上架,0=下架 2 上架中等")
+    private Integer productStatus;
 
     /**
      * 数据来源

+ 2 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductBrandVo.java

@@ -4,6 +4,7 @@ import org.dromara.common.translation.annotation.Translation;
 import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.easyes.annotation.IndexName;
 import org.dromara.product.domain.ProductBrand;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
@@ -27,6 +28,7 @@ import java.util.Date;
 @Data
 @ExcelIgnoreUnannotated
 @AutoMapper(target = ProductBrand.class)
+@IndexName("productbrandvo")
 public class ProductBrandVo implements Serializable {
 
     @Serial

+ 33 - 1
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductPoolLinkVo.java

@@ -39,6 +39,19 @@ public class ProductPoolLinkVo implements Serializable {
     @ExcelProperty(value = "所属池ID")
     private Long poolId;
 
+    /**
+     * 项目id
+     * */
+    private Long itemId;
+    /**
+     * 分类id
+     * */
+    private Long categoryId;
+    /**
+     * 协议价格
+     * */
+    private BigDecimal negotiatedPrice;
+
     /**
      * 产品id
      */
@@ -90,6 +103,25 @@ public class ProductPoolLinkVo implements Serializable {
     @ExcelProperty(value = "创建时间")
     private Date createTime;
 
+    /**
+    * 产品池名称
+    * */
+    @ExcelProperty(value = "产品池名称")
+    private String poolName;
+    /**
+     * 产品池类型
+     */
+    @ExcelProperty(value = "产品池类型")
+    private String type;
+
+    /**
+     * 审核人
+     */
+    @ExcelProperty(value = "审核人")
+    private String reviewer;
+
+
+
     /**
      * 商品编号
      */
@@ -106,7 +138,7 @@ public class ProductPoolLinkVo implements Serializable {
      * 商品图片URL
      */
     @ExcelProperty(value = "商品图片")
-    private String productImageUrl;
+    private String productImage;
 
     /**
      * 品牌名称

+ 32 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/ProductPoolVo.java

@@ -40,6 +40,38 @@ public class ProductPoolVo implements Serializable {
     @ExcelProperty(value = "池编码")
     private String poolNo;
 
+
+    /**
+     * 项目id
+     * */
+    private Long itemId;
+    /**
+     * 分类id
+     * */
+    private Long categoryId;
+
+    /**
+     * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+     * */
+    private Integer type;
+
+    /**
+    * 待审核的产品数量
+    * */
+    private Integer waitReviewCount;
+    /**
+    * 已驳回的产品数量
+    * */
+    private Integer rejectedCount;
+    /**
+    * 已通过审核的产品数量
+    * */
+    private Integer approvedCount;
+    /**
+    * 待申请的产品数量
+    * */
+    private Integer waitApplyCount;
+
     /**
      * 池名称
      */

+ 3 - 3
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/SiteProductVo.java

@@ -30,13 +30,13 @@ public class SiteProductVo implements Serializable {
     private String productImage;
 
     /** 是否自营(1=是,0=否) */
-    private String isSelf;
+    private Integer isSelf;
 
     /** 产品审核状态 */
-    private String productReviewStatus;
+    private Integer productReviewStatus;
 
     /** 商品状态(1=上架,0=下架) */
-    private String productStatus;
+    private Integer productStatus;
 
     /** 商品类型 */
     private String productType;

+ 35 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/domain/vo/StatusCountVo.java

@@ -0,0 +1,35 @@
+package org.dromara.product.domain.vo;
+
+import lombok.Data;
+
+/**
+ * @author
+ * @date 2026/1/5 下午5:00
+ */
+@Data
+public class StatusCountVo {
+    /**
+     * 总数
+    * */
+    private Long total;
+    /**
+     * 上架数
+    * */
+    private Long onSale;
+    /**
+     * 下架数
+    * */
+    private Long offSale;
+    /**
+     * 待审核数量
+    * */
+    private Long waitAudit;
+    /**
+     * 通过数量
+    * */
+    private Long auditPass;
+    /**
+     * 驳回数量
+    * */
+    private Long auditReject;
+}

+ 20 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/dubbo/RemoteProductServiceImpl.java

@@ -1,17 +1,21 @@
 package org.dromara.product.dubbo;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.dromara.product.api.RemoteProductService;
 import org.dromara.product.api.domain.ProductChangeLogApiVo;
 import org.dromara.product.api.domain.ProductVo;
+import org.dromara.product.api.domain.RemoteProductBrand;
+import org.dromara.product.domain.ProductBrand;
 import org.dromara.product.domain.bo.ProductBaseBo;
 import org.dromara.product.domain.bo.ProductChangeLogBo;
 import org.dromara.product.domain.vo.ProductBaseVo;
 import org.dromara.product.domain.vo.ProductChangeLogVo;
 import org.dromara.product.service.IProductBaseService;
+import org.dromara.product.service.IProductBrandService;
 import org.dromara.product.service.IProductChangeLogService;
 import org.springframework.stereotype.Service;
 
@@ -34,6 +38,8 @@ public class RemoteProductServiceImpl implements RemoteProductService {
 
     private final IProductChangeLogService productChangeLogService;
 
+    private final IProductBrandService productBrandService;
+
     /**
      * 获取商品详情
      *
@@ -89,4 +95,18 @@ public class RemoteProductServiceImpl implements RemoteProductService {
     public void delMessagePool(Long messageId) {
         productBaseService.removeById(messageId);
     }
+
+    /**
+     * 根据品牌id获取单个品牌
+     *
+     * @param brandId
+     */
+    @Override
+    public RemoteProductBrand getProductByBrandId(Long brandId) {
+
+        ProductBrand byId = productBrandService.getById(brandId);
+
+
+        return ObjectUtil.isNotEmpty(byId)?BeanUtil.toBean(byId, RemoteProductBrand.class):null;
+    }
 }

+ 13 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/esmapper/ProductBrandEsMapper.java

@@ -0,0 +1,13 @@
+package org.dromara.product.esmapper;
+
+import org.dromara.easyes.core.kernel.BaseEsMapper;
+import org.dromara.product.domain.ProductBrand;
+import org.dromara.product.domain.vo.ProductBrandVo;
+
+/**
+ * @author
+ * @date 2026/1/4 上午10:27
+ */
+public interface ProductBrandEsMapper extends BaseEsMapper<ProductBrandVo> {
+}
+

+ 13 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/esmapper/ProductEsMapper.java

@@ -0,0 +1,13 @@
+package org.dromara.product.esmapper;
+
+import org.dromara.easyes.core.kernel.BaseEsMapper;
+import org.dromara.product.domain.vo.ProductBaseVo;
+import org.dromara.product.domain.vo.ProductBrandVo;
+
+/**
+ * @author
+ * @date 2026/1/4 上午10:27
+ */
+public interface ProductEsMapper extends BaseEsMapper<ProductBaseVo> {
+}
+

+ 12 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductAttributesMapper.java

@@ -1,6 +1,9 @@
 package org.dromara.product.mapper;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
 import org.dromara.product.domain.ProductAttributes;
+import org.dromara.product.domain.bo.ProductAttributesBo;
 import org.dromara.product.domain.vo.ProductAttributesVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 
@@ -12,4 +15,13 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  */
 public interface ProductAttributesMapper extends BaseMapperPlus<ProductAttributes, ProductAttributesVo> {
 
+    /**
+     * 分页查询产品属性(关联分类表)
+     *
+     * @param page 分页参数
+     * @param bo   查询条件
+     * @return 分页结果
+     */
+    Page<ProductAttributesVo> selectPageWithCategory(@Param("page") Page<ProductAttributesVo> page, @Param("bo") ProductAttributesBo bo);
+
 }

+ 43 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductBaseMapper.java

@@ -1,12 +1,19 @@
 package org.dromara.product.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.cursor.Cursor;
 import org.dromara.product.domain.ProductBase;
 import org.dromara.product.domain.bo.SiteProductBo;
 import org.dromara.product.domain.vo.ProductBaseVo;
 import org.dromara.product.domain.vo.SiteProductVo;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.product.domain.vo.StatusCountVo;
+
+import java.util.List;
 
 /**
  * 产品基础信息Mapper接口
@@ -24,4 +31,40 @@ public interface ProductBaseMapper extends BaseMapperPlus<ProductBase, ProductBa
      * @return 站点产品分页列表
      */
     Page<SiteProductVo> selectSiteProductPage(@Param("page") Page<SiteProductVo> page, @Param("bo") SiteProductBo bo);
+
+    /**
+     * 查询所有产品列表(联表查询)
+     * 注意:此方法会一次性加载所有数据到内存,不适合大数据量场景
+     * 建议使用 selectAllListStream 或分页查询
+     *
+     * @param wrapper 查询条件
+     * @return 产品列表
+     * @deprecated 针对大数据量场景,请使用 {@link #selectAllListStream(Wrapper)} 或分页查询
+     */
+    @Deprecated
+    List<ProductBaseVo> selectAllList(@Param("ew") Wrapper<ProductBase> wrapper);
+
+    /**
+     * 流式查询所有产品列表(推荐用于大数据量场景)
+     * 使用 MyBatis Cursor 实现流式处理,避免内存溢出
+     *
+     * 使用示例:
+     * <pre>
+     * try (Cursor<ProductBaseVo> cursor = baseMapper.selectAllListStream(Wrappers.emptyWrapper())) {
+     *     cursor.forEach(vo -> {
+     *         // 处理每条数据
+     *     });
+     * }
+     * </pre>
+     *
+     * @param wrapper 查询条件
+     * @return 产品数据游标
+     */
+    Cursor<ProductBaseVo> selectAllListStream(@Param("ew") Wrapper<ProductBase> wrapper);
+
+    /**
+     * 查询商品状态统计信息
+     * @return 商品状态统计信息
+     */
+    StatusCountVo selectProductStatusCount();
 }

+ 5 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/mapper/ProductPoolMapper.java

@@ -12,4 +12,9 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
  */
 public interface ProductPoolMapper extends BaseMapperPlus<ProductPool, ProductPoolVo> {
 
+    /**
+    * 查询各个状态的产品数量
+    * */
+    ProductPoolVo selectProductStatusCount(Long poolId );
+
 }

+ 17 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductBaseService.java

@@ -9,6 +9,7 @@ import org.dromara.product.domain.bo.ProductBaseBo;
 import org.dromara.product.domain.bo.SiteProductBo;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.product.domain.vo.StatusCountVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -86,4 +87,20 @@ public interface IProductBaseService extends IService<ProductBase>{
      * @param productId 商品id
      */
     ProductBaseVo updateProductShelfState(Long productId);
+
+    /**
+     * 获取商品状态数量
+     *
+     * @return 商品状态数量
+     */
+    StatusCountVo getProductStatusCount();
+
+    /**
+    * 商品审核
+    * */
+    void review(ProductBaseBo bo);
+    /**
+    * 上架审核
+    * */
+    void shelfReview(ProductBaseBo bo);
 }

+ 21 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/IProductPoolLinkService.java

@@ -74,4 +74,25 @@ public interface IProductPoolLinkService {
      * @return 结果
      */
     Boolean batchAddProducts(BatchAddProductBo bo);
+
+
+    /**
+    * 批量审核商品池
+    * */
+    Boolean batchReview(List<ProductPoolLinkBo> bo);
+
+    /**
+    * 重新提交商品到商品池
+    * */
+    Boolean reSubmit(List<ProductPoolLinkBo> bo);
+
+    /**
+    * 修改商品价格
+    * */
+    Boolean editPrice(ProductPoolLinkBo bo);
+
+    /**
+    * 修改商品库存
+    * */
+    Boolean editStock(ProductPoolLinkBo bo);
 }

+ 4 - 2
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductAttributesServiceImpl.java

@@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.product.service.IProductCategoryService;
 import org.springframework.stereotype.Service;
 import org.dromara.product.domain.bo.ProductAttributesBo;
 import org.dromara.product.domain.vo.ProductAttributesVo;
@@ -35,6 +36,8 @@ public class ProductAttributesServiceImpl  extends ServiceImpl<ProductAttributes
 
     private final ProductAttributesMapper baseMapper;
 
+    private final IProductCategoryService productCategoryService;
+
     /**
      * 查询产品属性定义(用于动态属性配置)
      *
@@ -55,8 +58,7 @@ public class ProductAttributesServiceImpl  extends ServiceImpl<ProductAttributes
      */
     @Override
     public TableDataInfo<ProductAttributesVo> queryPageList(ProductAttributesBo bo, PageQuery pageQuery) {
-        LambdaQueryWrapper<ProductAttributes> lqw = buildQueryWrapper(bo);
-        Page<ProductAttributesVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        Page<ProductAttributesVo> result = baseMapper.selectPageWithCategory(pageQuery.build(), bo);
         return TableDataInfo.build(result);
     }
 

+ 392 - 78
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBaseServiceImpl.java

@@ -1,6 +1,9 @@
 package org.dromara.product.service.impl;
 
 import cn.hutool.core.util.ObjectUtil;
+import co.elastic.clients.elasticsearch._types.FieldValue;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.apache.dubbo.common.logger.FluentLogger;
 import org.dromara.common.core.utils.MapstructUtils;
@@ -12,9 +15,17 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.easyes.core.biz.EsPageInfo;
+import org.dromara.easyes.core.biz.SAPageInfo;
+import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
 import org.dromara.product.api.domain.ProductVo;
 import org.dromara.product.domain.*;
+import org.dromara.product.domain.vo.ProductBrandVo;
+import org.dromara.product.domain.vo.StatusCountVo;
+import org.dromara.product.esmapper.ProductEsMapper;
 import org.dromara.product.mapper.*;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.dromara.product.domain.bo.ProductBaseBo;
@@ -33,17 +44,48 @@ import java.util.Collection;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.core.type.TypeReference;
 import java.math.BigDecimal;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
 
 /**
  * 产品基础信息Service业务层处理
  *
+ * 性能优化说明(针对200万级别数据量):
+ * 1. 启动时ES同步使用分页流式处理,每次只加载1000条数据
+ * 2. 提供流式查询API(selectAllListStream)避免OOM
+ * 3. 单条查询优化,建议添加缓存
+ * 4. 批量删除优化,减少数据库交互
+ *
+ * 数据库索引建议(必须添加):
+ * product_base表:
+ *   - idx_product_no: product_no (产品编号,唯一索引)
+ *   - idx_brand_id: brand_id (品牌ID)
+ *   - idx_category: top_category_id, medium_category_id, bottom_category_id (组合索引)
+ *   - idx_status: product_status, product_review_status (状态组合索引)
+ *   - idx_create_time: create_time (创建时间)
+ *
+ * product_extend表:
+ *   - idx_product_id: product_id (外键索引)
+ *
+ * product_price_inventory表:
+ *   - PRIMARY KEY: product_id (主键)
+ *
+ * product_classification表:
+ *   - idx_product_id: product_id (外键索引)
+ *   - idx_category_id: category_id (分类索引)
+ *
+ * product_customization表:
+ *   - idx_product_id: product_id (外键索引)
+ *
  * @author LionLi
  * @date 2025-12-11
  */
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, ProductBase> implements IProductBaseService {
+public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, ProductBase> implements IProductBaseService, ApplicationRunner {
 
     //产品基础信息Mapper
     private final ProductBaseMapper baseMapper;
@@ -63,8 +105,101 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     //单位信息
     private final ProductUnitMapper unitMapper;
 
+    private final ProductPhotosMapper photosMapper;
+
+    private final ProductEsMapper esMapper;
+
+    /**
+     * Callback used to run the bean.
+     * 优化说明:针对200万级别数据,采用分批流式处理,避免OOM
+     *
+     * @param args incoming application arguments
+     * @throws Exception on error
+     */
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        // 检查索引是否存在,不存在则创建
+        if (!esMapper.existsIndex("productbasevo")) {
+            log.info("索引 [productbasevo] 不存在,正在创建...");
+            esMapper.createIndex();
+        }
+        // 只同步缺失的数据,而不是全量拉取
+        long totalInDb = baseMapper.selectCount(new LambdaQueryWrapper<>());
+        log.info("DbProduct 数量 :" + totalInDb);
+        long totalInEs = esMapper.selectCount(new LambdaEsQueryWrapper<>());
+        log.info("EsProduct 数量 :" + totalInEs);
+
+        if (totalInEs < totalInDb) {
+            log.info("ES 数据不完整,开始同步...");
+
+            // 优化:使用分页流式处理,每次只加载1000条到内存
+            int pageSize = 1000;
+            int pageNum = 1;
+            long totalSynced = 0;
+
+            // 使用线程池处理批量插入
+            int threadCount = 10;
+            ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
+
+            try {
+                while (true) {
+                    // 分页查询,避免一次性加载所有数据
+                    Page<ProductBase> page = new Page<>(pageNum, pageSize);
+                    Page<ProductBaseVo> resultPage = baseMapper.selectVoPage(page, Wrappers.emptyWrapper());
+
+                    if (resultPage.getRecords().isEmpty()) {
+                        break;
+                    }
+
+                    List<ProductBaseVo> currentBatch = resultPage.getRecords();
+
+                    // 异步插入ES
+                    int finalPageNum = pageNum;
+                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                        try {
+                            esMapper.insertBatch(currentBatch);
+                            log.info("成功同步第 {} 页,共 {} 条记录", finalPageNum, currentBatch.size());
+                        } catch (Exception e) {
+                            log.error("同步第 {} 页数据失败: {}", finalPageNum, e.getMessage(), e);
+                            throw new RuntimeException(e);
+                        }
+                    }, executorService);
+
+                    // 等待当前批次完成(控制并发,避免ES压力过大)
+                    future.join();
+
+                    totalSynced += currentBatch.size();
+                    log.info("已同步进度: {}/{}", totalSynced, totalInDb);
+
+                    // 如果是最后一页,退出循环
+                    if (resultPage.getRecords().size() < pageSize || !resultPage.hasNext()) {
+                        break;
+                    }
+
+                    pageNum++;
+
+                    // 添加短暂延迟,避免对数据库和ES造成过大压力
+                    Thread.sleep(100);
+                }
+
+                log.info("ES 数据同步完成,共同步 {} 条记录", totalSynced);
+            } finally {
+                executorService.shutdown();
+            }
+        }
+    }
+
     /**
      * 查询产品基础信息(包含扩展信息、价格库存、属性、定制信息)
+     * 性能优化说明:
+     * 1. 使用联表查询减少数据库交互次数(建议在Mapper中实现)
+     * 2. 对于高频访问场景,建议添加缓存(Redis)
+     * 3. 已优化为单次主查询+关联查询,避免N+1问题
+     *
+     * TODO: 性能优化建议
+     * - 将分类、品牌、单位等字典数据缓存到Redis
+     * - 考虑使用@Cacheable注解实现方法级缓存
+     * - 高并发场景建议使用Guava本地缓存+Redis二级缓存
      *
      * @param id 主键
      * @return 产品基础信息
@@ -76,6 +211,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         if (vo == null) {
             return null;
         }
+
         //获取分类信息
         ProductCategory productCategory = categoryMapper.selectById(vo.getBottomCategoryId());
         if (ObjectUtil.isNotEmpty(productCategory)){
@@ -149,11 +285,11 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
             StringBuilder styles = new StringBuilder();
             StringBuilder crafts = new StringBuilder();
             for (ProductCustomization custom : customizations) {
-                if (StringUtils.isNotBlank(custom.getCustomizedStyle())) {
+                if (ObjectUtil.isNotEmpty(custom.getCustomizedStyle())) {
                     if (styles.length() > 0) styles.append(",");
                     styles.append(custom.getCustomizedStyle());
                 }
-                if (StringUtils.isNotBlank(custom.getCustomizedCraft())) {
+                if (ObjectUtil.isNotEmpty(custom.getCustomizedCraft())) {
                     if (crafts.length() > 0) crafts.append(",");
                     crafts.append(custom.getCustomizedCraft());
                 }
@@ -169,6 +305,14 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
                 log.error("转换定制详情为JSON失败: {}", e.getMessage());
             }
         }
+        //获取详情
+        LambdaQueryWrapper<ProductPhotos>  photosWrapper= Wrappers.lambdaQuery();
+        photosWrapper.eq(ProductPhotos::getProductId, id);
+        ProductPhotos productPhotos = photosMapper.selectOne(photosWrapper);
+        if(ObjectUtil.isNotEmpty(productPhotos)){
+            vo.setPcDetail(productPhotos.getProductDetailsPc());
+            vo.setMobileDetail(productPhotos.getProductDetailsApp());
+        }
 
         return vo;
     }
@@ -182,16 +326,35 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
      */
     @Override
     public TableDataInfo<ProductBaseVo> queryPageList(ProductBaseBo bo, PageQuery pageQuery) {
-        LambdaQueryWrapper<ProductBase> lqw = buildQueryWrapper(bo);
-        Page<ProductBaseVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
-        for (ProductBaseVo productBaseVo : result.getRecords()) {
-            ProductPriceInventory productPriceInventory = priceInventoryMapper.selectById(productBaseVo.getId());
-            productBaseVo.setPurchasingPrice(productPriceInventory.getPurchasingPrice());
-            productBaseVo.setMarketPrice(productPriceInventory.getMarketPrice());
-            productBaseVo.setMemberPrice(productPriceInventory.getMemberPrice());
-            productBaseVo.setMinSellingPrice(productPriceInventory.getMinSellingPrice());
-        }
-        return TableDataInfo.build(result);
+        QueryWrapper<ProductBase> lqw = Wrappers.query();
+        lqw.ge(ObjectUtil.isNotEmpty(pageQuery.getFirstSeenId()) && pageQuery.getWay() == 0,"b.id", pageQuery.getFirstSeenId());
+        lqw.gt(ObjectUtil.isNotEmpty(pageQuery.getLastSeenId()) && pageQuery.getWay() == 1,"b.id", pageQuery.getLastSeenId());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getBottomCategoryId()),"b.bottom_category_id", bo.getBottomCategoryId());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductStatus()), "b.product_status", bo.getProductStatus());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductReviewStatus()),"b.product_review_status", bo.getProductReviewStatus());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getDataSource()),"b.data_source", bo.getDataSource());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getIsSelf()),"b.is_self", bo.getIsSelf());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductNo()),"b.product_no", bo.getProductNo());
+        lqw.like(ObjectUtil.isNotEmpty(bo.getBrandName()),"br.brand_name", bo.getBrandName());
+        // 支持分类名称模糊搜索(匹配三级分类中的任意一个)
+        if (ObjectUtil.isNotEmpty(bo.getCategoryName())) {
+            lqw.and(wrapper -> wrapper
+                .like("tc.category_name", bo.getCategoryName())
+                .or().like("mc.category_name", bo.getCategoryName())
+                .or().like("bc.category_name", bo.getCategoryName())
+            );
+        }
+        lqw.orderByAsc("b.id");
+        int limit = pageQuery.getPageSize() + 1;
+        lqw.last("limit "+ limit );
+        List<ProductBaseVo> result = baseMapper.selectAllList(lqw);
+        int size = result.size();
+        if (size > pageQuery.getPageSize()) {
+            result.remove(result.size() - 1);
+        }
+        TableDataInfo<ProductBaseVo> tableDataInfo = TableDataInfo.build(result);
+        tableDataInfo.setTotal( size);
+        return tableDataInfo;
     }
 
     /**
@@ -205,35 +368,50 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         LambdaQueryWrapper<ProductBase> lqw = buildQueryWrapper(bo);
         return baseMapper.selectVoList(lqw);
     }
+    private LambdaEsQueryWrapper<ProductBaseVo> buildEsQueryWrapper(ProductBaseBo bo) {
+        return new LambdaEsQueryWrapper<ProductBaseVo>()
+            .eq(ObjectUtil.isNotEmpty(bo.getProductNo()), ProductBaseVo::getProductNo, bo.getProductNo())
+            .like(ObjectUtil.isNotEmpty(bo.getItemName()), ProductBaseVo::getItemName, bo.getItemName())
+            .eq(bo.getBrandId() != null, ProductBaseVo::getBrandId, bo.getBrandId())
+            .eq(bo.getTopCategoryId() != null, ProductBaseVo::getTopCategoryId, bo.getTopCategoryId())
+            .eq(bo.getMediumCategoryId() != null, ProductBaseVo::getMediumCategoryId, bo.getMediumCategoryId())
+            .eq(bo.getBottomCategoryId() != null, ProductBaseVo::getBottomCategoryId, bo.getBottomCategoryId())
+            .eq(ObjectUtil.isNotEmpty(bo.getUnitId()), ProductBaseVo::getUnitId, bo.getUnitId())
+            .eq(ObjectUtil.isNotEmpty(bo.getProductStatus()), ProductBaseVo::getProductStatus, bo.getProductStatus())
+            .eq(ObjectUtil.isNotEmpty(bo.getIsSelf()), ProductBaseVo::getIsSelf, bo.getIsSelf())
+            .eq(ObjectUtil.isNotEmpty(bo.getProductReviewStatus()), ProductBaseVo::getProductReviewStatus, bo.getProductReviewStatus())
+            .eq(ObjectUtil.isNotEmpty(bo.getDataSource()), ProductBaseVo::getDataSource, bo.getDataSource())
+            ;
+    }
 
     private LambdaQueryWrapper<ProductBase> buildQueryWrapper(ProductBaseBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<ProductBase> lqw = Wrappers.lambdaQuery();
         lqw.orderByAsc(ProductBase::getId);
-        lqw.in(StringUtils.isNotBlank(bo.getProductIds()), ProductBase::getId, bo.getProductIds().split( ","));
-        lqw.eq(StringUtils.isNotBlank(bo.getProductNo()), ProductBase::getProductNo, bo.getProductNo());
-        lqw.like(StringUtils.isNotBlank(bo.getItemName()), ProductBase::getItemName, bo.getItemName());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductNo()), ProductBase::getProductNo, bo.getProductNo());
+        lqw.like(ObjectUtil.isNotEmpty(bo.getItemName()), ProductBase::getItemName, bo.getItemName());
         lqw.eq(bo.getBrandId() != null, ProductBase::getBrandId, bo.getBrandId());
         lqw.eq(bo.getTopCategoryId() != null, ProductBase::getTopCategoryId, bo.getTopCategoryId());
         lqw.eq(bo.getMediumCategoryId() != null, ProductBase::getMediumCategoryId, bo.getMediumCategoryId());
         lqw.eq(bo.getBottomCategoryId() != null, ProductBase::getBottomCategoryId, bo.getBottomCategoryId());
-        lqw.eq(StringUtils.isNotBlank(bo.getUnitId()), ProductBase::getUnitId, bo.getUnitId());
-        lqw.eq(StringUtils.isNotBlank(bo.getProductImage()), ProductBase::getProductImage, bo.getProductImage());
-        lqw.eq(StringUtils.isNotBlank(bo.getIsSelf()), ProductBase::getIsSelf, bo.getIsSelf());
-        lqw.eq(StringUtils.isNotBlank(bo.getProductReviewStatus()), ProductBase::getProductReviewStatus, bo.getProductReviewStatus());
-        lqw.eq(StringUtils.isNotBlank(bo.getHomeRecommended()), ProductBase::getHomeRecommended, bo.getHomeRecommended());
-        lqw.eq(StringUtils.isNotBlank(bo.getCategoryRecommendation()), ProductBase::getCategoryRecommendation, bo.getCategoryRecommendation());
-        lqw.eq(StringUtils.isNotBlank(bo.getCartRecommendation()), ProductBase::getCartRecommendation, bo.getCartRecommendation());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getUnitId()), ProductBase::getUnitId, bo.getUnitId());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductImage()), ProductBase::getProductImage, bo.getProductImage());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getIsSelf()), ProductBase::getIsSelf, bo.getIsSelf());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductReviewStatus()), ProductBase::getProductReviewStatus, bo.getProductReviewStatus());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getHomeRecommended()), ProductBase::getHomeRecommended, bo.getHomeRecommended());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getCategoryRecommendation()), ProductBase::getCategoryRecommendation, bo.getCategoryRecommendation());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getCartRecommendation()), ProductBase::getCartRecommendation, bo.getCartRecommendation());
         lqw.eq(bo.getRecommendedProductOrder() != null, ProductBase::getRecommendedProductOrder, bo.getRecommendedProductOrder());
-        lqw.eq(StringUtils.isNotBlank(bo.getIsPopular()), ProductBase::getIsPopular, bo.getIsPopular());
-        lqw.eq(StringUtils.isNotBlank(bo.getIsNew()), ProductBase::getIsNew, bo.getIsNew());
-        lqw.eq(StringUtils.isNotBlank(bo.getProductStatus()), ProductBase::getProductStatus, bo.getProductStatus());
-        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), ProductBase::getPlatformCode, bo.getPlatformCode());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getIsPopular()), ProductBase::getIsPopular, bo.getIsPopular());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getIsNew()), ProductBase::getIsNew, bo.getIsNew());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getProductStatus()), ProductBase::getProductStatus, bo.getProductStatus());
+        lqw.eq(ObjectUtil.isNotEmpty(bo.getPlatformCode()), ProductBase::getPlatformCode, bo.getPlatformCode());
         return lqw;
     }
 
     /**
      * 新增产品基础信息
+     * 优化说明:新增后自动同步到ES索引,保证数据一致性
      *
      * @param bo 产品基础信息
      * @return 是否新增成功
@@ -269,6 +447,11 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
             // 5. 保存产品定制信息
             saveProductCustomization(bo, productId);
 
+            // 6. 保存详情信息
+            saveProductDetail(bo, productId);
+            // 7. 同步到ES索引
+            syncToES(productId);
+
             log.info("成功新增产品,ID: {}, 名称: {}", productId, bo.getItemName());
             return true;
 
@@ -278,8 +461,17 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
     }
 
+    private void saveProductDetail(ProductBaseBo bo, Long productId) {
+        ProductPhotos productPhotos= new ProductPhotos();
+        productPhotos.setProductId(productId);
+        productPhotos.setProductDetailsPc(bo.getPcDetail());
+        productPhotos.setProductDetailsApp(bo.getMobileDetail());
+        photosMapper.insert(productPhotos);
+    }
+
     /**
      * 修改产品基础信息
+     * 优化说明:更新后自动同步到ES索引,保证数据一致性
      *
      * @param bo 产品基础信息
      * @return 是否修改成功
@@ -315,6 +507,12 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
             // 5. 更新产品定制信息
             updateProductCustomization(bo, productId);
 
+            // 6. 更新详情信息
+            updateProductDetail(bo, productId);
+
+            // 7. 同步到ES索引
+            syncToES(productId);
+
             log.info("成功更新产品,ID: {}, 名称: {}", productId, bo.getItemName());
             return true;
 
@@ -324,33 +522,41 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
     }
 
+    private void updateProductDetail(ProductBaseBo bo, Long productId) {
+        ProductPhotos productPhotos= new ProductPhotos();
+        productPhotos.setProductId(productId);
+        productPhotos.setProductDetailsPc(bo.getPcDetail());
+        productPhotos.setProductDetailsApp(bo.getMobileDetail());
+        photosMapper.update(productPhotos, new LambdaUpdateWrapper<ProductPhotos>().eq(ProductPhotos::getProductId, productId));
+    }
+
     /**
      * 设置默认值
      */
     private void setDefaultValues(ProductBase entity) {
-        if (StringUtils.isBlank(entity.getProductReviewStatus())) {
-            entity.setProductReviewStatus("0"); // 默认待提交
+        if (ObjectUtil.isEmpty(entity.getProductReviewStatus())) {
+            entity.setProductReviewStatus(0); // 默认待提交
         }
-        if (StringUtils.isBlank(entity.getIsSelf())) {
-            entity.setIsSelf("0"); // 默认非自营
+        if (ObjectUtil.isEmpty(entity.getIsSelf())) {
+            entity.setIsSelf(0); // 默认非自营
         }
-        if (StringUtils.isBlank(entity.getHomeRecommended())) {
-            entity.setHomeRecommended("0"); // 默认不推荐
+        if (ObjectUtil.isEmpty(entity.getHomeRecommended())) {
+            entity.setHomeRecommended(0); // 默认不推荐
         }
-        if (StringUtils.isBlank(entity.getCategoryRecommendation())) {
-            entity.setCategoryRecommendation("0"); // 默认不推荐
+        if (ObjectUtil.isEmpty(entity.getCategoryRecommendation())) {
+            entity.setCategoryRecommendation(0); // 默认不推荐
         }
-        if (StringUtils.isBlank(entity.getCartRecommendation())) {
-            entity.setCartRecommendation("0"); // 默认不推荐
+        if (ObjectUtil.isEmpty(entity.getCartRecommendation())) {
+            entity.setCartRecommendation(0); // 默认不推荐
         }
-        if (StringUtils.isBlank(entity.getIsPopular())) {
-            entity.setIsPopular("0"); // 默认不热门
+        if (ObjectUtil.isEmpty(entity.getIsPopular())) {
+            entity.setIsPopular(0); // 默认不热门
         }
-        if (StringUtils.isBlank(entity.getIsNew())) {
-            entity.setIsNew("0"); // 默认不是新品
+        if (ObjectUtil.isEmpty(entity.getIsNew())) {
+            entity.setIsNew(0); // 默认不是新品
         }
-        if (StringUtils.isBlank(entity.getProductStatus())) {
-            entity.setProductStatus("0"); // 默认下架
+        if (ObjectUtil.isEmpty(entity.getProductStatus())) {
+            entity.setProductStatus(0); // 默认下架
         }
         if (entity.getRecommendedProductOrder() == null) {
             entity.setRecommendedProductOrder(0L); // 默认排序为0
@@ -476,7 +682,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
      */
     private void validEntityBeforeSave(ProductBase entity){
         // 校验产品编号唯一性(新增时)
-        if (entity.getId() == null && StringUtils.isNotBlank(entity.getProductNo())) {
+        if (entity.getId() == null && ObjectUtil.isNotEmpty(entity.getProductNo())) {
             LambdaQueryWrapper<ProductBase> wrapper = Wrappers.lambdaQuery();
             wrapper.eq(ProductBase::getProductNo, entity.getProductNo());
             Long count = baseMapper.selectCount(wrapper);
@@ -486,7 +692,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
 
         // 校验产品编号唯一性(更新时)
-        if (entity.getId() != null && StringUtils.isNotBlank(entity.getProductNo())) {
+        if (entity.getId() != null && ObjectUtil.isNotEmpty(entity.getProductNo())) {
             LambdaQueryWrapper<ProductBase> wrapper = Wrappers.lambdaQuery();
             wrapper.eq(ProductBase::getProductNo, entity.getProductNo());
             wrapper.ne(ProductBase::getId, entity.getId());
@@ -497,7 +703,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
 
         // 校验必填字段
-        if (StringUtils.isBlank(entity.getItemName())) {
+        if (ObjectUtil.isEmpty(entity.getItemName())) {
             throw new RuntimeException("产品名称不能为空");
         }
 
@@ -514,6 +720,8 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
 
     /**
      * 校验并批量删除产品基础信息信息
+     * 性能优化:使用批量删除替代循环删除,减少数据库交互次数
+     * ES同步:删除后自动从ES索引中移除
      *
      * @param ids     待删除的主键集合
      * @param isValid 是否进行有效性校验
@@ -524,12 +732,12 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
         if(isValid){
             // 校验是否有关联的订单或其他业务数据
-            for (Long id : ids) {
-                ProductBase product = baseMapper.selectById(id);
+            // 性能优化:批量查询替代循环查询
+            List<ProductBase> products = baseMapper.selectBatchIds(ids);
+            for (ProductBase product : products) {
                 if (product == null) {
                     continue;
                 }
-
                 // 校验产品状态,如果是上架状态不允许删除
                 if ("1".equals(product.getProductStatus())) {
                     throw new RuntimeException("产品【" + product.getItemName() + "】处于上架状态,不允许删除");
@@ -538,29 +746,40 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
 
         try {
-            // 删除关联的扩展信息、价格库存信息、分类关联信息
-            for (Long id : ids) {
-                // 删除扩展信息
-                LambdaQueryWrapper<ProductExtend> extendWrapper = Wrappers.lambdaQuery();
-                extendWrapper.eq(ProductExtend::getProductId, id);
-                extendMapper.delete(extendWrapper);
-
-                // 删除价格库存信息
-                priceInventoryMapper.deleteById(id);
-
-                // 删除分类关联信息
-                LambdaQueryWrapper<ProductClassification> classWrapper = Wrappers.lambdaQuery();
-                classWrapper.eq(ProductClassification::getProductId, id);
-                classificationMapper.delete(classWrapper);
-
-                // 删除定制信息
-                LambdaQueryWrapper<ProductCustomization> customWrapper = Wrappers.lambdaQuery();
-                customWrapper.eq(ProductCustomization::getProductId, id);
-                customizationMapper.delete(customWrapper);
-            }
+            // 性能优化:使用批量删除替代循环删除
+
+            // 批量删除扩展信息
+            LambdaQueryWrapper<ProductExtend> extendWrapper = Wrappers.lambdaQuery();
+            extendWrapper.in(ProductExtend::getProductId, ids);
+            extendMapper.delete(extendWrapper);
+
+            // 批量删除价格库存信息
+            priceInventoryMapper.deleteByIds(ids);
+
+            // 批量删除分类关联信息
+            LambdaQueryWrapper<ProductClassification> classWrapper = Wrappers.lambdaQuery();
+            classWrapper.in(ProductClassification::getProductId, ids);
+            classificationMapper.delete(classWrapper);
+
+            // 批量删除定制信息
+            LambdaQueryWrapper<ProductCustomization> customWrapper = Wrappers.lambdaQuery();
+            customWrapper.in(ProductCustomization::getProductId, ids);
+            customizationMapper.delete(customWrapper);
+
+            //删除详情信息
+            LambdaQueryWrapper<ProductPhotos> detailWrapper = Wrappers.lambdaQuery();
+            detailWrapper.in(ProductPhotos::getProductId, ids);
+            photosMapper.delete(detailWrapper);
 
             // 最后删除基础信息
-            return baseMapper.deleteByIds(ids) > 0;
+            boolean result = baseMapper.deleteByIds(ids) > 0;
+
+            // 从ES索引中批量删除
+            if (result) {
+                deleteFromES(ids);
+            }
+
+            return result;
 
         } catch (Exception e) {
             log.error("删除产品失败: {}", e.getMessage(), e);
@@ -578,7 +797,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
 
         // 解析定制详情JSON数组
-        if (StringUtils.isNotBlank(bo.getCustomDetailsJson())) {
+        if (ObjectUtil.isNotEmpty(bo.getCustomDetailsJson())) {
             try {
                 ObjectMapper objectMapper = new ObjectMapper();
                 // 解析JSON数组为List<Map>
@@ -606,16 +825,16 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
                     String samplePeriod = (String) detail.get("samplePeriod");
                     String productionPeriod = (String) detail.get("productionPeriod");
 
-                    if (StringUtils.isNotBlank(minOrderQty)) {
+                    if (ObjectUtil.isNotEmpty(minOrderQty)) {
                         customization.setMoq(Long.parseLong(minOrderQty));
                     }
-                    if (StringUtils.isNotBlank(minOrderPrice)) {
+                    if (ObjectUtil.isNotEmpty(minOrderPrice)) {
                         customization.setMoqPrice(new BigDecimal(minOrderPrice));
                     }
-                    if (StringUtils.isNotBlank(samplePeriod)) {
+                    if (ObjectUtil.isNotEmpty(samplePeriod)) {
                         customization.setProofingPeriod(Long.parseLong(samplePeriod));
                     }
-                    if (StringUtils.isNotBlank(productionPeriod)) {
+                    if (ObjectUtil.isNotEmpty(productionPeriod)) {
                         customization.setProductionCycle(Long.parseLong(productionPeriod));
                     }
 
@@ -633,6 +852,8 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
         }
     }
 
+
+
     /**
      * 映射装饰方法中文名称到值
      */
@@ -691,6 +912,7 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
 
     /**
      * 修改商品上架状态
+     * 优化说明:状态变更后自动同步到ES索引
      *
      * @param productId  商品id
      */
@@ -698,15 +920,107 @@ public class ProductBaseServiceImpl  extends ServiceImpl<ProductBaseMapper, Prod
     public ProductBaseVo updateProductShelfState(Long productId) {
         ProductBaseVo productBase = baseMapper.selectVoById(productId);
 
-        if(productBase.getProductStatus().equals("1")){
-            productBase.setProductStatus("0");
+        if(productBase.getProductStatus().equals(1)){
+            productBase.setProductStatus(0);
         }else{
-            productBase.setProductStatus("1");
+            productBase.setProductStatus(1);
         }
         baseMapper.update(Wrappers.lambdaUpdate(ProductBase.class)
             .set(ProductBase::getProductStatus, productBase.getProductStatus())
             .eq(ProductBase::getId, productId)
         );
+
+        // 同步到ES索引
+        syncToES(productId);
+
         return productBase;
     }
+
+    /**
+     * 同步产品信息到ES索引
+     * 异步执行,避免影响主业务
+     *
+     * @param productId 产品ID
+     */
+    private void syncToES(Long productId) {
+        try {
+            // 查询完整的产品信息(包含关联表数据)
+            ProductBaseVo vo = queryById(productId);
+            if (vo != null) {
+                // 先尝试更新,如果不存在则插入
+                try {
+                    esMapper.updateById(vo);
+                    log.debug("成功更新ES索引,产品ID: {}", productId);
+                } catch (Exception e) {
+                    // 如果更新失败,尝试插入
+                    esMapper.insert(vo);
+                    log.debug("成功插入ES索引,产品ID: {}", productId);
+                }
+            }
+        } catch (Exception e) {
+            // ES同步失败不影响主业务,只记录日志
+            log.error("同步产品到ES失败,产品ID: {}, 错误: {}", productId, e.getMessage());
+        }
+    }
+
+    /**
+     * 从ES索引中批量删除产品
+     *
+     * @param ids 产品ID集合
+     */
+    private void deleteFromES(Collection<Long> ids) {
+        try {
+            // 批量删除
+            esMapper.deleteBatchIds(ids);
+            log.info("成功从ES索引中删除 {} 条产品记录", ids.size());
+        } catch (Exception e) {
+            // ES删除失败不影响主业务,只记录日志
+            log.error("从ES索引中删除产品失败,产品IDs: {}, 错误: {}", ids, e.getMessage());
+        }
+    }
+
+    /**
+     * 获取商品状态数量
+     *
+     * @return 商品状态数量
+     */
+    @Override
+    public StatusCountVo getProductStatusCount() {
+        StatusCountVo statusCountVo = baseMapper.selectProductStatusCount();
+        // 计算下架数量 = 总数 - 上架数量
+        statusCountVo.setOffSale(statusCountVo.getTotal() - statusCountVo.getOnSale());
+        return statusCountVo;
+    }
+
+    /**
+    * 商品审核
+    * */
+    @Override
+    public void review(ProductBaseBo bo) {
+        baseMapper.update(Wrappers.lambdaUpdate(ProductBase.class)
+            .set(ProductBase::getProductReviewStatus, bo.getProductReviewStatus())
+            .eq(ProductBase::getId, bo.getId())
+        );
+        extendMapper.update(Wrappers.lambdaUpdate(ProductExtend.class)
+            .set(ProductExtend::getReviewComments, bo.getReviewComments())
+            .eq(ProductExtend::getProductId, bo.getId())
+        );
+    }
+
+    /**
+     * 上架审核
+     *
+     * @param bo
+     */
+    @Override
+    public void shelfReview(ProductBaseBo bo) {
+        baseMapper.update(Wrappers.lambdaUpdate(ProductBase.class)
+            .set(ProductBase::getIsSelf, bo.getIsSelf())
+            .eq(ProductBase::getId, bo.getId())
+        );
+        extendMapper.update(Wrappers.lambdaUpdate(ProductExtend.class)
+            .set(ProductExtend::getShelfComments, bo.getShelfComments())
+            .eq(ProductExtend::getProductId, bo.getId())
+        );
+    }
 }

+ 58 - 3
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductBrandServiceImpl.java

@@ -1,5 +1,7 @@
 package org.dromara.product.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -10,12 +12,17 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
+import org.dromara.product.esmapper.ProductBrandEsMapper;
+import org.springframework.boot.ApplicationArguments;
 import org.springframework.stereotype.Service;
 import org.dromara.product.domain.bo.ProductBrandBo;
 import org.dromara.product.domain.vo.ProductBrandVo;
 import org.dromara.product.domain.ProductBrand;
 import org.dromara.product.mapper.ProductBrandMapper;
 import org.dromara.product.service.IProductBrandService;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
 
 import java.util.List;
 import java.util.Map;
@@ -30,10 +37,31 @@ import java.util.Collection;
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class ProductBrandServiceImpl  extends ServiceImpl<ProductBrandMapper, ProductBrand> implements IProductBrandService {
+public class ProductBrandServiceImpl  extends ServiceImpl<ProductBrandMapper, ProductBrand> implements IProductBrandService, ApplicationRunner {
 
     private final ProductBrandMapper baseMapper;
 
+    private final ProductBrandEsMapper esMapper;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        // 检查索引是否存在,不存在则创建
+        if (!esMapper.existsIndex("productbrandvo")) {
+            log.info("索引 [productbrandvo] 不存在,正在创建...");
+            esMapper.createIndex();
+        }
+        // 只同步缺失的数据,而不是全量拉取
+        long totalInDb = baseMapper.selectCount(new LambdaQueryWrapper<>());
+        log.info("DbBrand 数量 :"+totalInDb);
+        long totalInEs = esMapper.selectCount(new LambdaEsQueryWrapper<>());
+        log.info("EsBrand 数量 :"+totalInEs);
+        if (totalInEs < totalInDb) {
+            log.info("ES 数据不完整,开始同步...");
+            List<ProductBrandVo> allFromDb = baseMapper.selectVoList(Wrappers.emptyWrapper());
+            esMapper.insertBatch(allFromDb);
+        }
+    }
+
     /**
      * 查询产品品牌信息
      *
@@ -67,8 +95,27 @@ public class ProductBrandServiceImpl  extends ServiceImpl<ProductBrandMapper, Pr
      */
     @Override
     public List<ProductBrandVo> queryList(ProductBrandBo bo) {
-        LambdaQueryWrapper<ProductBrand> lqw = buildQueryWrapper(bo);
-        return baseMapper.selectVoList(lqw);
+//        LambdaQueryWrapper<ProductBrand> lqw = buildQueryWrapper(bo);
+        LambdaEsQueryWrapper<ProductBrandVo> esQueryWrapper = buildQueryEsWrapper(bo);
+        List<ProductBrandVo> productBrandVos = esMapper.selectList(esQueryWrapper);
+//        if(ObjectUtil.isEmpty(productBrandVos)){
+//            productBrandVos = baseMapper.selectVoList(lqw);
+//            esMapper.insertBatch(productBrandVos);
+//        }
+        return productBrandVos;
+    }
+
+    private LambdaEsQueryWrapper buildQueryEsWrapper(ProductBrandBo bo){
+        return new LambdaEsQueryWrapper<ProductBrandVo>()
+                .eq(ObjectUtil.isNotEmpty(bo.getBrandNo()),ProductBrandVo::getBrandNo, bo.getBrandNo())
+                .like(ObjectUtil.isNotEmpty(bo.getBrandName()),ProductBrandVo::getBrandName, bo.getBrandName())
+                .eq(ObjectUtil.isNotEmpty(bo.getBrandInitials()),ProductBrandVo::getBrandInitials, bo.getBrandInitials())
+                .like(ObjectUtil.isNotEmpty(bo.getBrandEnglishName()),ProductBrandVo::getBrandEnglishName, bo.getBrandEnglishName())
+                .eq(ObjectUtil.isNotEmpty(bo.getRecommendValue()),ProductBrandVo::getRecommendValue, bo.getRecommendValue())
+                .like(ObjectUtil.isNotEmpty(bo.getBrandLogo()),ProductBrandVo::getBrandLogo, bo.getBrandLogo())
+                .like(ObjectUtil.isNotEmpty(bo.getBrandTitle()),ProductBrandVo::getBrandTitle, bo.getBrandTitle());
+
+
     }
 
     private LambdaQueryWrapper<ProductBrand> buildQueryWrapper(ProductBrandBo bo) {
@@ -107,7 +154,10 @@ public class ProductBrandServiceImpl  extends ServiceImpl<ProductBrandMapper, Pr
     public Boolean insertByBo(ProductBrandBo bo) {
         ProductBrand add = MapstructUtils.convert(bo, ProductBrand.class);
         validEntityBeforeSave(add);
+        ProductBrandVo bean = BeanUtil.toBean(add, ProductBrandVo.class);
+        esMapper.insert(bean);
         boolean flag = baseMapper.insert(add) > 0;
+
         if (flag) {
             bo.setId(add.getId());
         }
@@ -124,6 +174,8 @@ public class ProductBrandServiceImpl  extends ServiceImpl<ProductBrandMapper, Pr
     public Boolean updateByBo(ProductBrandBo bo) {
         ProductBrand update = MapstructUtils.convert(bo, ProductBrand.class);
         validEntityBeforeSave(update);
+        ProductBrandVo bean = BeanUtil.toBean(update, ProductBrandVo.class);
+        esMapper.updateById(bean);
         return baseMapper.updateById(update) > 0;
     }
 
@@ -146,6 +198,9 @@ public class ProductBrandServiceImpl  extends ServiceImpl<ProductBrandMapper, Pr
         if(isValid){
             //TODO 做一些业务上的校验,判断是否需要校验
         }
+        esMapper.deleteBatchIds(ids);
         return baseMapper.deleteByIds(ids) > 0;
     }
+
+
 }

+ 1 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductCategoryServiceImpl.java

@@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 import org.dromara.product.domain.bo.ProductCategoryBo;
 import org.dromara.product.domain.vo.ProductCategoryVo;

+ 52 - 0
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductPoolLinkServiceImpl.java

@@ -162,4 +162,56 @@ public class ProductPoolLinkServiceImpl implements IProductPoolLinkService {
 
         return true;
     }
+
+    /**
+     * 批量审核商品池
+     *
+     * @param bo
+     */
+    @Override
+    public Boolean batchReview(List<ProductPoolLinkBo> bo) {
+
+        List<ProductPoolLink> productPoolLinks = BeanUtil.copyToList(bo, ProductPoolLink.class);
+
+        return baseMapper.updateBatchById(productPoolLinks);
+    }
+
+    /**
+     * 重新提交商品到商品池
+     *
+     * @param bo
+     */
+    @Override
+    public Boolean reSubmit(List<ProductPoolLinkBo> bo) {
+        List<ProductPoolLink> productPoolLinks = BeanUtil.copyToList(bo, ProductPoolLink.class);
+        return baseMapper.updateBatchById(productPoolLinks);
+    }
+
+    /**
+     * 修改商品价格
+     *
+     * @param bo
+     */
+    @Override
+    public Boolean editPrice(ProductPoolLinkBo bo) {
+        ProductPoolLink productPoolLink = new ProductPoolLink();
+        productPoolLink.setId(bo.getId());
+        productPoolLink.setNegotiatedPrice(bo.getNegotiatedPrice());
+        productPoolLink.setProductPrice(bo.getProductPrice());
+        return baseMapper.updateById(productPoolLink) > 0;
+    }
+
+    /**
+     * 修改商品库存
+     *
+     * @param bo
+     */
+    @Override
+    public Boolean editStock(ProductPoolLinkBo bo) {
+
+        ProductPoolLink productPoolLink = new ProductPoolLink();
+        productPoolLink.setId(bo.getId());
+        productPoolLink.setStock(bo.getStock());
+        return baseMapper.updateById(productPoolLink) > 0;
+    }
 }

+ 19 - 1
ruoyi-modules/ruoyi-product/src/main/java/org/dromara/product/service/impl/ProductPoolServiceImpl.java

@@ -1,5 +1,6 @@
 package org.dromara.product.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -56,6 +57,20 @@ public class ProductPoolServiceImpl  extends ServiceImpl<ProductPoolMapper, Prod
     public TableDataInfo<ProductPoolVo> queryPageList(ProductPoolBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<ProductPool> lqw = buildQueryWrapper(bo);
         Page<ProductPoolVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        result.getRecords().forEach(o -> {
+            ProductPoolVo vo = baseMapper.selectProductStatusCount(o.getId());
+            if(ObjectUtil.isNotEmpty(vo)){
+                o.setWaitReviewCount(vo.getWaitReviewCount());
+                o.setRejectedCount(vo.getRejectedCount());
+                o.setApprovedCount(vo.getApprovedCount());
+                o.setWaitApplyCount(vo.getWaitApplyCount());
+            }else{
+                o.setWaitReviewCount(0);
+                o.setRejectedCount(0);
+                o.setApprovedCount(0);
+                o.setWaitApplyCount(0);
+            }
+        });
         return TableDataInfo.build(result);
     }
 
@@ -78,9 +93,12 @@ public class ProductPoolServiceImpl  extends ServiceImpl<ProductPoolMapper, Prod
         lqw.eq(StringUtils.isNotBlank(bo.getPoolNo()), ProductPool::getPoolNo, bo.getPoolNo());
         lqw.like(StringUtils.isNotBlank(bo.getName()), ProductPool::getName, bo.getName());
         lqw.eq(StringUtils.isNotBlank(bo.getIsShow()), ProductPool::getIsShow, bo.getIsShow());
-        lqw.eq(StringUtils.isNotBlank(bo.getProductReviewStatus()), ProductPool::getProductReviewStatus, bo.getProductReviewStatus());
+
         lqw.eq(StringUtils.isNotBlank(bo.getReviewReason()), ProductPool::getReviewReason, bo.getReviewReason());
         lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), ProductPool::getPlatformCode, bo.getPlatformCode());
+        lqw.exists(StringUtils.isNotBlank(bo.getProductReviewStatus()),
+            "SELECT 1  FROM product_pool_link WHERE pool_id = product_pool.id and product_review_status = '" +bo.getProductReviewStatus() + "'");
+
         return lqw;
     }
 

+ 45 - 0
ruoyi-modules/ruoyi-product/src/main/resources/application.yml

@@ -34,3 +34,48 @@ spring:
       - optional:nacos:application-common.yml
       - optional:nacos:datasource.yml
       - optional:nacos:${spring.application.name}.yml
+--- # elasticsearch 功能配置
+# 文档地址: https://www.easy-es.cn/
+# 更改包名需要去 EasyEsConfiguration 修改包扫描(后续版本支持配置文件读取)
+easy-es:
+  # 是否开启EE自动配置
+  enable: true
+  # 兼容模式
+  compatible: true
+  # es连接地址+端口 格式必须为ip:port,如果是集群则可用逗号隔开
+  address : 119.97.180.88:9200
+  # 默认为http
+  schema: http
+  # 注意ES建议使用账号认证 不使用会报警告日志
+  #如果无账号密码则可不配置此行
+  username: elastic
+  #如果无账号密码则可不配置此行
+  password: kRhwhe4Mf4pyPYHN
+  # 心跳策略时间 单位:ms
+  keep-alive-millis: 18000
+  # 连接超时时间 单位:ms
+  connectTimeout: 100000
+  # 通信超时时间 单位:ms
+  socketTimeout: 100000
+  # 连接请求超时时间 单位:ms
+  connectionRequestTimeout: 100000
+  # 最大连接数 单位:个
+  maxConnTotal: 100
+  # 最大连接路由数 单位:个
+  maxConnPerRoute: 100
+  global-config:
+    # 开启控制台打印通过本框架生成的DSL语句,默认为开启,测试稳定后的生产环境建议关闭,以提升少量性能
+    print-dsl: true
+    # 异步处理索引是否阻塞主线程 默认阻塞 数据量过大时调整为非阻塞异步进行 项目启动更快
+    asyncProcessIndexBlocking: true
+    db-config:
+      # 是否开启下划线转驼峰 默认为false
+      map-underscore-to-camel-case: true
+      # id生成策略 customize为自定义,id值由用户生成,比如取MySQL中的数据id,如缺省此项配置,则id默认策略为es自动生成
+      id-type: customize
+      # 字段更新策略 默认为not_null
+      field-strategy: not_null
+      # 默认开启,查询若指定了size超过1w条时也会自动开启,开启后查询所有匹配数据,若不开启,会导致无法获取数据总条数,其它功能不受影响.
+      enable-track-total-hits: true
+      # 数据刷新策略,默认为不刷新
+      refresh-policy: immediate

+ 63 - 0
ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductAttributesMapper.xml

@@ -4,4 +4,67 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.dromara.product.mapper.ProductAttributesMapper">
 
+    <resultMap id="ProductAttributesVoResult" type="org.dromara.product.domain.vo.ProductAttributesVo">
+        <id property="id" column="id"/>
+        <result property="categoryId" column="category_id"/>
+        <result property="categoryName" column="category_name"/>
+        <result property="productAttributesCode" column="product_attributes_code"/>
+        <result property="productAttributesName" column="product_attributes_name"/>
+        <result property="isOptional" column="is_optional"/>
+        <result property="entryMethod" column="entry_method"/>
+        <result property="isFilter" column="is_filter"/>
+        <result property="attributesList" column="attributes_list"/>
+        <result property="required" column="required"/>
+        <result property="remark" column="remark"/>
+    </resultMap>
+
+    <sql id="selectProductAttributesVo">
+        SELECT
+            pa.id,
+            pa.category_id,
+            pc.category_name,
+            pa.product_attributes_code,
+            pa.product_attributes_name,
+            pa.is_optional,
+            pa.entry_method,
+            pa.is_filter,
+            pa.attributes_list,
+            pa.required,
+            pa.remark
+        FROM product_attributes pa
+        LEFT JOIN product_category pc ON pa.category_id = pc.id
+    </sql>
+
+    <select id="selectPageWithCategory" resultMap="ProductAttributesVoResult">
+        <include refid="selectProductAttributesVo"/>
+        <where>
+            pa.del_flag = '0'
+            <if test="bo.categoryId != null">
+                AND pa.category_id = #{bo.categoryId}
+            </if>
+            <if test="bo.categoryName != null and bo.categoryName != ''">
+                AND pc.category_name LIKE CONCAT('%', #{bo.categoryName}, '%')
+            </if>
+            <if test="bo.productAttributesCode != null and bo.productAttributesCode != ''">
+                AND pa.product_attributes_code = #{bo.productAttributesCode}
+            </if>
+            <if test="bo.productAttributesName != null and bo.productAttributesName != ''">
+                AND pa.product_attributes_name LIKE CONCAT('%', #{bo.productAttributesName}, '%')
+            </if>
+            <if test="bo.isOptional != null and bo.isOptional != ''">
+                AND pa.is_optional = #{bo.isOptional}
+            </if>
+            <if test="bo.entryMethod != null and bo.entryMethod != ''">
+                AND pa.entry_method = #{bo.entryMethod}
+            </if>
+            <if test="bo.isFilter != null and bo.isFilter != ''">
+                AND pa.is_filter = #{bo.isFilter}
+            </if>
+            <if test="bo.required != null and bo.required != ''">
+                AND pa.required = #{bo.required}
+            </if>
+        </where>
+        ORDER BY pa.id ASC
+    </select>
+
 </mapper>

+ 85 - 0
ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductBaseMapper.xml

@@ -67,5 +67,90 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
         ORDER BY b.create_time DESC
     </select>
+    <select id="selectAllList" resultType="org.dromara.product.domain.vo.ProductBaseVo">
+        SELECT
+            b.id,
+            b.product_no AS productNo,
+            b.item_name AS itemName,
+            b.brand_id AS brandId,
+            br.brand_name AS brandName,
+            b.top_category_id AS topCategoryId,
+            tc.category_name AS topCategoryName,
+            b.medium_category_id AS mediumCategoryId,
+            mc.category_name AS mediumCategoryName,
+            b.bottom_category_id AS bottomCategoryId,
+            bc.category_name AS bottomCategoryName,
+            bc.category_name AS categoryName,
+            b.unit_id AS unitId,
+            u.unit_name AS unitName,
+            b.product_image AS productImage,
+            b.is_self AS isSelf,
+            b.product_review_status AS productReviewStatus,
+            b.home_recommended AS homeRecommended,
+            b.category_recommendation AS categoryRecommendation,
+            b.cart_recommendation AS cartRecommendation,
+            b.recommended_product_order AS recommendedProductOrder,
+            b.is_popular AS isPopular,
+            b.is_new AS isNew,
+            b.product_status AS productStatus,
+            b.data_source AS dataSource,
+            b.remark,
+            -- 扩展表字段
+            e.invoice_name AS invoiceName,
+            e.invoice_specs AS invoiceSpec,
+            e.bar_coding AS upcBarcode,
+            e.product_weight AS weight,
+            e.weight_unit AS weightUnit,
+            e.product_volume AS volume,
+            e.volume_unit AS volumeUnit,
+            e.after_sales_service AS afterSalesService,
+            e.service_guarantee AS serviceGuarantee,
+            e.is_install_service AS freeInstallation,
+            e.reference_link AS referenceLink,
+            e.sales_volume AS salesVolume,
+            e.is_customize AS customizable,
+            e.custom_description AS customDescription,
+            e.review_comments AS reviewComments,
+            -- 价格库存表字段
+            p.market_price AS marketPrice,
+            p.member_price AS memberPrice,
+            p.min_selling_price AS minSellingPrice,
+            p.purchasing_price AS purchasingPrice,
+            p.market_price AS midRangePrice,
+            p.member_price AS standardPrice,
+            p.min_selling_price AS certificatePrice,
+            p.purchasing_price AS purchasePrice,
+            p.max_purchase_price AS estimatedPurchasePrice,
+            p.tax_rate AS taxRate,
+            p.currency,
+            p.min_order_quantity AS minOrderQuantity,
+            p.total_inventory AS totalInventory,
+            p.now_inventory AS nowInventory,
+            p.virtual_inventory AS virtualInventory,
+            -- 属性分类表字段
+            c.attributes_list AS attributesList
+        FROM product_base b
+        LEFT JOIN product_extend e ON b.id = e.product_id AND e.del_flag = '0'
+        LEFT JOIN product_price_inventory p ON b.id = p.product_id AND p.del_flag = '0'
+        LEFT JOIN product_classification c ON b.id = c.product_id AND c.del_flag = '0'
+        LEFT JOIN product_brand br ON b.brand_id = br.id AND br.del_flag = '0'
+        LEFT JOIN product_category tc ON b.top_category_id = tc.id AND tc.del_flag = '0'
+        LEFT JOIN product_category mc ON b.medium_category_id = mc.id AND mc.del_flag = '0'
+        LEFT JOIN product_category bc ON b.bottom_category_id = bc.id AND bc.del_flag = '0'
+        LEFT JOIN product_unit u ON b.unit_id = u.id AND u.del_flag = '0'
+        ${ew.customSqlSegment}
+    </select>
+
+    <!-- 查询商品状态统计信息(优化版) -->
+    <select id="selectProductStatusCount" resultType="org.dromara.product.domain.vo.StatusCountVo">
+        SELECT
+            COUNT(*) AS total,
+            SUM(CASE WHEN product_status = '1' THEN 1 ELSE 0 END) AS onSale,
+            SUM(CASE WHEN product_review_status IN ('0', '3') THEN 1 ELSE 0 END) AS waitAudit,
+            SUM(CASE WHEN product_review_status = '1' THEN 1 ELSE 0 END) AS auditPass,
+            SUM(CASE WHEN product_review_status = '2' THEN 1 ELSE 0 END) AS auditReject
+        FROM product_base
+        WHERE del_flag = '0'
+    </select>
 
 </mapper>

+ 27 - 2
ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductPoolLinkMapper.xml

@@ -7,11 +7,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="org.dromara.product.domain.vo.ProductPoolLinkVo" id="ProductPoolLinkResult">
         <result property="id"    column="id"    />
         <result property="poolId"    column="pool_id"    />
+        <result property="itemId"    column="item_id"    />
+        <result property="categoryId"    column="category_id"    />
+        <result property="negotiatedPrice"    column="negotiated_price"    />
+        <result property="poolName"    column="pool_name"    />
+        <result property="type"    column="type"    />
         <result property="productId"    column="product_id"    />
         <result property="productPrice"    column="product_price"    />
         <result property="isPoolStatus"    column="is_pool_status"    />
         <result property="productReviewStatus"    column="product_review_status"    />
         <result property="reviewReason"    column="review_reason"    />
+        <result property="reviewer"    column="reviewer"    />
         <result property="isShow"    column="is_show"    />
         <result property="remark"    column="remark"    />
         <result property="createTime"    column="create_time"    />
@@ -19,7 +25,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <!-- 商品基础信息 -->
         <result property="productNo"    column="product_no"    />
         <result property="itemName"    column="item_name"    />
-        <result property="productImageUrl"    column="product_image_url"    />
+        <result property="productImage"    column="product_image"    />
         <result property="brandName"    column="brand_name"    />
         <result property="categoryName"    column="category_name"    />
         <result property="unitName"    column="unit_name"    />
@@ -49,13 +55,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             ppl.is_show,
             ppl.remark,
             ppl.create_time,
+            ppl.product_id,
+            ppl.negotiated_price,
+            ppl.reviewer,
+
+            pp.item_id,
+            pp.category_id,
+            pp.name as pool_name,
+            pp.type,
 
             pb.product_no,
             pb.item_name,
-            pb.product_image_url,
             pb.product_status,
             pb.brand_id,
             pb.bottom_category_id,
+            pb.product_image,
 
             pbr.brand_name,
             pc.category_name,
@@ -75,6 +89,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         left join product_category pc on pb.bottom_category_id = pc.id
         left join product_unit pu on pb.unit_id = pu.id
         left join product_price_inventory ppi on pb.id = ppi.product_id
+        left join product_pool pp on ppl.pool_id = pp.id
     </sql>
 
     <!-- 查询产品池商品列表 -->
@@ -85,6 +100,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="bo.poolId != null">
                 AND ppl.pool_id = #{bo.poolId}
             </if>
+            <!-- 商品池审核状态 -->
+            <if test="bo.productReviewStatus != null and bo.productReviewStatus != ''">
+                AND ppl.product_review_status = #{bo.productReviewStatus}
+            </if>
             <!-- 商品编号 -->
             <if test="bo.productNo != null and bo.productNo != ''">
                 AND pb.product_no like concat('%', #{bo.productNo}, '%')
@@ -128,6 +147,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="bo.poolId != null">
                 AND ppl.pool_id = #{bo.poolId}
             </if>
+            <!-- 商品池审核状态 -->
+            <if test="bo.productReviewStatus != null and bo.productReviewStatus != ''">
+                AND ppl.product_review_status = #{bo.productReviewStatus}
+            </if>
             <!-- 商品编号 -->
             <if test="bo.productNo != null and bo.productNo != ''">
                 AND pb.product_no like concat('%', #{bo.productNo}, '%')
@@ -169,4 +192,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where ppl.id = #{id}
     </select>
 
+
+
 </mapper>

+ 11 - 0
ruoyi-modules/ruoyi-product/src/main/resources/mapper/product/ProductPoolMapper.xml

@@ -4,4 +4,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.dromara.product.mapper.ProductPoolMapper">
 
+	<select id="selectProductStatusCount" resultType="org.dromara.product.domain.vo.ProductPoolVo">
+        SELECT
+            pool_id AS poolId,
+            COUNT(CASE WHEN product_review_status = '0' THEN 1 END) AS waitReviewCount,
+            COUNT(CASE WHEN product_review_status = '1' THEN 1 END) AS rejectedCount,
+            COUNT(CASE WHEN product_review_status = '2' THEN 1 END) AS approvedCount,
+            COUNT(CASE WHEN product_review_status = '3' THEN 1 END) AS waitApplyCount
+        FROM product_pool_link
+        WHERE pool_id = #{poolId}
+        GROUP BY product_review_status
+    </select>
 </mapper>

+ 0 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java

@@ -98,7 +98,6 @@ public class SysDeptServiceImpl implements ISysDeptService {
         lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL);
         lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
         lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
-        lqw.eq(ObjectUtil.isNotNull(bo.getCustomerId()), SysDept::getCustomerId, bo.getCustomerId());
         lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
         lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());

+ 50 - 50
script/docker/docker-compose.yml

@@ -13,9 +13,9 @@ services:
       - "3306:3306"
     volumes:
       # 数据挂载
-      - /docker/mysql/data/:/var/lib/mysql/
+      - /home/docker/mysql/data/:/var/lib/mysql/
       # 配置挂载
-      - /docker/mysql/conf/:/etc/mysql/conf.d/
+      - /home/docker/mysql/conf/:/etc/mysql/conf.d/
     command:
       # 将mysql8.0默认密码策略 修改为 原先 策略 (mysql8.0对其默认策略做了更改 会导致密码无法匹配)
       --default-authentication-plugin=mysql_native_password
@@ -38,9 +38,9 @@ services:
       JAVA_OPTS: "-Xms256m -Xmx512m"
     volumes:
       # 日志目录 注意集群模式下 日志目录不能一致 需要区分例如 nacos1 nacos2
-      - /docker/nacos/logs/:/root/nacos/logs
+      - /home/docker/nacos/logs/:/root/nacos/logs
       # 集群配置文件 集群所有nacos都必须使用此文件
-      - /docker/nacos/conf/cluster.conf:/root/nacos/conf/cluster.conf
+      - /home/docker/nacos/conf/cluster.conf:/root/nacos/conf/cluster.conf
     network_mode: "host"
 
   redis:
@@ -53,9 +53,9 @@ services:
       TZ: Asia/Shanghai
     volumes:
       # 配置文件
-      - /docker/redis/conf:/redis/config
+      - /home/docker/redis/conf:/redis/config
       # 数据文件
-      - /docker/redis/data/:/redis/data/
+      - /home/docker/redis/data/:/redis/data/
     command: "redis-server /redis/config/redis.conf"
     privileged: true
     network_mode: "host"
@@ -106,9 +106,9 @@ services:
       # SEATA_IP: 127.0.0.1
       SEATA_PORT: 8091
     volumes:
-      - /docker/ruoyi-seata-server/logs/:/ruoyi/seata-server/logs
+      - /home/docker/ruoyi-seata-server/logs/:/ruoyi/seata-server/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -123,13 +123,13 @@ services:
       - "443:443"
     volumes:
       # 证书映射
-      - /docker/nginx/cert:/etc/nginx/cert
+      - /home/docker/nginx/cert:/etc/nginx/cert
       # 配置文件映射
-      - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
+      - /home/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
       # 页面目录
-      - /docker/nginx/html:/usr/share/nginx/html
+      - /home/docker/nginx/html:/usr/share/nginx/html
       # 日志目录
-      - /docker/nginx/log:/var/log/nginx
+      - /home/docker/nginx/log:/var/log/nginx
     privileged: true
     network_mode: "host"
 
@@ -142,9 +142,9 @@ services:
       - "8718:8718"
     volumes:
       # 配置文件
-      - /docker/ruoyi-sentinel-dashboard/logs/:/ruoyi/sentinel-dashboard/logs
+      - /home/docker/ruoyi-sentinel-dashboard/logs/:/ruoyi/sentinel-dashboard/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     restart: always
     network_mode: "host"
 
@@ -158,9 +158,9 @@ services:
       - "9100:9100"
     volumes:
       # 配置文件
-      - /docker/ruoyi-monitor/logs/:/ruoyi/monitor/logs
+      - /home/docker/ruoyi-monitor/logs/:/ruoyi/monitor/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -174,7 +174,7 @@ services:
       - "8800:8800"
       - "17888:17888"
     volumes:
-      - /docker/snailjob/logs/:/ruoyi/snailjob/logs
+      - /home/docker/snailjob/logs/:/ruoyi/snailjob/logs
     privileged: true
     network_mode: "host"
 
@@ -188,9 +188,9 @@ services:
       - "8080:8080"
     volumes:
       # 配置文件
-      - /docker/ruoyi-gateway/logs/:/ruoyi/gateway/logs
+      - /home/docker/ruoyi-gateway/logs/:/ruoyi/gateway/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -204,9 +204,9 @@ services:
       - "9210:9210"
     volumes:
       # 配置文件
-      - /docker/ruoyi-auth/logs/:/ruoyi/auth/logs
+      - /home/docker/ruoyi-auth/logs/:/ruoyi/auth/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -220,9 +220,9 @@ services:
       - "9201:9201"
     volumes:
       # 配置文件
-      - /docker/ruoyi-system/logs/:/ruoyi/system/logs
+      - /home/docker/ruoyi-system/logs/:/ruoyi/system/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -236,9 +236,9 @@ services:
       - "9202:9202"
     volumes:
       # 配置文件
-      - /docker/ruoyi-gen/logs/:/ruoyi/gen/logs
+      - /home/docker/ruoyi-gen/logs/:/ruoyi/gen/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -254,9 +254,9 @@ services:
       - "9203:9203"
     volumes:
       # 配置文件
-      - /docker/ruoyi-job/logs/:/ruoyi/job/logs
+      - /home/docker/ruoyi-job/logs/:/ruoyi/job/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -270,9 +270,9 @@ services:
       - "9204:9204"
     volumes:
       # 配置文件
-      - /docker/ruoyi-resource/logs/:/ruoyi/resource/logs
+      - /home/docker/ruoyi-resource/logs/:/ruoyi/resource/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -286,9 +286,9 @@ services:
       - "9205:9205"
     volumes:
       # 配置文件
-      - /docker/ruoyi-workflow/logs/:/ruoyi/workflow/logs
+      - /home/docker/ruoyi-workflow/logs/:/ruoyi/workflow/logs
       # skywalking 探针
-      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+      - /home/docker/skywalking/agent/:/ruoyi/skywalking/agent
     privileged: true
     network_mode: "host"
 
@@ -308,11 +308,11 @@ services:
       cluster.name: elasticsearch
       # 以单一节点模式启动
       discovery.type: single-node
-      ES_JAVA_OPTS: "-Xms512m -Xmx512m"
+      ES_JAVA_OPTS: "-Xms512m -Xmx1024m"
     volumes:
-      - /docker/elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins
-      - /docker/elk/elasticsearch/data:/usr/share/elasticsearch/data
-      - /docker/elk/elasticsearch/logs:/usr/share/elasticsearch/logs
+      - /home/docker/elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins
+      - /home/docker/elk/elasticsearch/data:/usr/share/elasticsearch/data
+      - /home/docker/elk/elasticsearch/logs:/usr/share/elasticsearch/logs
     network_mode: "host"
 
   kibana:
@@ -329,7 +329,7 @@ services:
       # 访问域名
       # SERVER_PUBLICBASEURL: https://kibana.cloud.com
     volumes:
-      - /docker/elk/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
+      - /home/docker/elk/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
     network_mode: "host"
 
   logstash:
@@ -338,8 +338,8 @@ services:
     ports:
       - "4560:4560"
     volumes:
-      - /docker/elk/logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
-      - /docker/elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
+      - /home/docker/elk/logstash/pipeline/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
+      - /home/docker/elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
     depends_on:
       - elasticsearch
     network_mode: "host"
@@ -353,7 +353,7 @@ services:
       JAVA_OPT: -server -Xms512m -Xmx512m
     command: sh mqnamesrv
     volumes:
-      - /docker/rocketmq/namesrv/logs:/home/rocketmq/logs/rocketmqlogs
+      - /home/docker/rocketmq/namesrv/logs:/home/rocketmq/logs/rocketmqlogs
     network_mode: "host"
 
   rmqbroker1:
@@ -371,9 +371,9 @@ services:
     depends_on:
       - rmqnamesrv
     volumes:
-      - /docker/rocketmq/broker1/conf/broker.conf:/home/rocketmq/rocketmq-5.2.0/conf/broker.conf
-      - /docker/rocketmq/broker1/logs:/home/rocketmq/logs/rocketmqlogs
-      - /docker/rocketmq/broker1/store:/home/rocketmq/store
+      - /home/docker/rocketmq/broker1/conf/broker.conf:/home/rocketmq/rocketmq-5.2.0/conf/broker.conf
+      - /home/docker/rocketmq/broker1/logs:/home/rocketmq/logs/rocketmqlogs
+      - /home/docker/rocketmq/broker1/store:/home/rocketmq/store
     privileged: true
     network_mode: "host"
 
@@ -399,8 +399,8 @@ services:
       - "15672:15672" # 管理界面端口
       - "5672:5672"   # api 端口
     volumes:
-      - /docker/rabbitmq/log:/var/log/rabbitmq
-      - /docker/rabbitmq/data:/var/lib/rabbitmq
+      - /home/docker/rabbitmq/log:/var/log/rabbitmq
+      - /home/docker/rabbitmq/data:/var/lib/rabbitmq
     network_mode: "host"
 
   zookeeper:
@@ -435,7 +435,7 @@ services:
       KAFKA_CFG_ZOOKEEPER_CONNECT: 127.0.0.1:2181
       ALLOW_PLAINTEXT_LISTENER: "yes"
     volumes:
-      - /docker/kafka/data:/bitnami/kafka/data
+      - /home/docker/kafka/data:/bitnami/kafka/data
     depends_on:
       - zookeeper
     network_mode: "host"
@@ -491,7 +491,7 @@ services:
     ports:
       - "9090:9090"
     volumes:
-      - /docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
+      - /home/docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
     network_mode: "host"
 
   grafana:
@@ -506,8 +506,8 @@ services:
     ports:
       - "3000:3000"
     volumes:
-      - /docker/grafana/grafana.ini:/etc/grafana/grafana.ini
-      - /docker/grafana:/var/lib/grafana
+      - /home/docker/grafana/grafana.ini:/etc/grafana/grafana.ini
+      - /home/docker/grafana:/var/lib/grafana
     network_mode: "host"
 
   shardingproxy:
@@ -517,8 +517,8 @@ services:
     ports:
       - "3307:3307"
     volumes:
-      - /docker/shardingproxy/conf:/opt/shardingsphere-proxy/conf
-      - /docker/shardingproxy/ext-lib:/opt/shardingsphere-proxy/ext-lib
+      - /home/docker/shardingproxy/conf:/opt/shardingsphere-proxy/conf
+      - /home/docker/shardingproxy/ext-lib:/opt/shardingsphere-proxy/ext-lib
     environment:
       - JVM_OPTS="-Djava.awt.headless=true"
     network_mode: "host"