Browse Source

feat:mall promotion CombinationProduct

puhui999 2 years ago
parent
commit
41d996f7f3
29 changed files with 561 additions and 166 deletions
  1. 1 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  2. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
  3. 9 32
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java
  4. 20 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java
  5. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExcelVO.java
  6. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExportReqVO.java
  7. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java
  8. 43 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java
  9. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java
  10. 27 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java
  11. 3 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java
  12. 43 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExcelVO.java
  13. 42 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExportReqVO.java
  14. 47 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java
  15. 4 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java
  16. 20 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java
  17. 26 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
  18. 8 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationActivityDO.java
  19. 60 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationProductDO.java
  20. 1 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/package-info.java
  21. 0 59
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java
  22. 37 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationActivityMapper.java
  23. 47 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationProductMapper.java
  24. 1 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/package-info.java
  25. 5 5
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
  26. 70 10
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java
  27. 9 28
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
  28. 22 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
  29. 10 10
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java

+ 1 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java

@@ -61,4 +61,5 @@ public interface ErrorCodeConstants {
 
     // ========== 拼团活动 1013010000 ==========
     ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");
+    ErrorCode COMBINATION_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013010000, "存在商品参加了其它拼团活动");
 }

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java

@@ -4,9 +4,9 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.*;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.*;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;

+ 9 - 32
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityBaseVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityBaseVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
@@ -6,6 +6,7 @@ import org.springframework.format.annotation.DateTimeFormat;
 
 import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
@@ -16,12 +17,13 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @Data
 public class CombinationActivityBaseVO {
 
-    @Schema(description = "拼团名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
+    @Schema(description = "拼团名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "越拼越省钱")
     @NotNull(message = "拼团名称不能为空")
     private String name;
 
-    @Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
-    private Long spuId;
+    @Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "[1,2,3]")
+    @NotNull(message = "拼团商品不能为空")
+    private List<Long> spuIds;
 
     @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218")
     @NotNull(message = "总限购数量不能为空")
@@ -31,40 +33,15 @@ public class CombinationActivityBaseVO {
     @NotNull(message = "单次限购数量不能为空")
     private Integer singleLimitCount;
 
-    @Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "开始时间不能为空")
+    @Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
+    @NotNull(message = "活动时间不能为空")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime startTime;
-
-    @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "结束时间不能为空")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime endTime;
-
-    @Schema(description = "购买人数", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "购买人数不能为空")
-    private Integer userSize;
-
-    @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "开团组数不能为空")
-    private Integer totalNum;
-
-    @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "成团组数不能为空")
-    private Integer successNum;
+    private LocalDateTime[] activityTime;
 
     @Schema(description = "参与人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
     @NotNull(message = "参与人数不能为空")
     private Integer orderUserCount;
 
-    @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "虚拟成团不能为空")
-    private Integer virtualGroup;
-
-    @Schema(description = "活动状态:0开启 1关闭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
-    @NotNull(message = "活动状态:0开启 1关闭不能为空")
-    private Integer status;
-
     @Schema(description = "限制时长(小时)", requiredMode = Schema.RequiredMode.REQUIRED)
     @NotNull(message = "限制时长(小时)不能为空")
     private Integer limitDuration;

+ 20 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityCreateReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 拼团活动创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO {
+
+    @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
+    private List<CombinationProductCreateReqVO> products;
+
+}

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityExcelVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExcelVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityExportReqVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityExportReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityPageReqVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityPageReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.v3.oas.annotations.media.Schema;

+ 43 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityRespVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 拼团活动 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationActivityRespVO extends CombinationActivityBaseVO {
+
+    @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
+    private Long id;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+    @Schema(description = "购买人数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "购买人数不能为空")
+    private Integer userSize;
+
+    @Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "开团组数不能为空")
+    private Integer totalNum;
+
+    @Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "成团组数不能为空")
+    private Integer successNum;
+
+    @Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "虚拟成团不能为空")
+    private Integer virtualGroup;
+
+    @Schema(description = "活动状态:0开启 1关闭", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    @NotNull(message = "活动状态:0开启 1关闭不能为空")
+    private Integer status;
+
+}

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityUpdateReqVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/activity/CombinationActivityUpdateReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;

+ 27 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductBaseVO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 拼团商品 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class CombinationProductBaseVO {
+
+    @Schema(description = "商品 spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
+    @NotNull(message = "商品 spuId 不能为空")
+    private Long spuId;
+
+    @Schema(description = "商品 skuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
+    @NotNull(message = "商品 skuId 不能为空")
+    private Long skuId;
+
+    @Schema(description = "拼团价格,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "27682")
+    @NotNull(message = "拼团价格,单位分不能为空")
+    private Integer activePrice;
+
+}

+ 3 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityCreateReqVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductCreateReqVO.java

@@ -1,14 +1,14 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
-@Schema(description = "管理后台 - 拼团活动创建 Request VO")
+@Schema(description = "管理后台 - 拼团商品创建 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
-public class CombinationActivityCreateReqVO extends CombinationActivityBaseVO {
+public class CombinationProductCreateReqVO extends CombinationProductBaseVO {
 
 }

+ 43 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExcelVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 拼团商品 Excel VO
+ *
+ * @author HUIHUI
+ */
+@Data
+public class CombinationProductExcelVO {
+
+    @ExcelProperty("编号")
+    private Long id;
+
+    @ExcelProperty("拼团活动编号")
+    private Long activityId;
+
+    @ExcelProperty("商品 SPU 编号")
+    private Long spuId;
+
+    @ExcelProperty("商品 SKU 编号")
+    private Long skuId;
+
+    @ExcelProperty("拼团商品状态")
+    private Integer activityStatus;
+
+    @ExcelProperty("活动开始时间点")
+    private LocalDateTime activityStartTime;
+
+    @ExcelProperty("活动结束时间点")
+    private LocalDateTime activityEndTime;
+
+    @ExcelProperty("拼团价格,单位分")
+    private Integer activePrice;
+
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 42 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductExportReqVO.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 拼团商品 Excel 导出 Request VO,参数和 CombinationProductPageReqVO 是一致的")
+@Data
+public class CombinationProductExportReqVO {
+
+    @Schema(description = "拼团活动编号", example = "6829")
+    private Long activityId;
+
+    @Schema(description = "商品 SPU 编号", example = "18731")
+    private Long spuId;
+
+    @Schema(description = "商品 SKU 编号", example = "31675")
+    private Long skuId;
+
+    @Schema(description = "拼团商品状态", example = "2")
+    private Integer activityStatus;
+
+    @Schema(description = "活动开始时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityStartTime;
+
+    @Schema(description = "活动结束时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityEndTime;
+
+    @Schema(description = "拼团价格,单位分", example = "27682")
+    private Integer activePrice;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 47 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductPageReqVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 拼团商品分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationProductPageReqVO extends PageParam {
+
+    @Schema(description = "拼团活动编号", example = "6829")
+    private Long activityId;
+
+    @Schema(description = "商品 SPU 编号", example = "18731")
+    private Long spuId;
+
+    @Schema(description = "商品 SKU 编号", example = "31675")
+    private Long skuId;
+
+    @Schema(description = "拼团商品状态", example = "2")
+    private Integer activityStatus;
+
+    @Schema(description = "活动开始时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityStartTime;
+
+    @Schema(description = "活动结束时间点")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] activityEndTime;
+
+    @Schema(description = "拼团价格,单位分", example = "27682")
+    private Integer activePrice;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 4 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/CombinationActivityRespVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo;
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
@@ -7,13 +7,13 @@ import lombok.ToString;
 
 import java.time.LocalDateTime;
 
-@Schema(description = "管理后台 - 拼团活动 Response VO")
+@Schema(description = "管理后台 - 拼团商品 Response VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
-public class CombinationActivityRespVO extends CombinationActivityBaseVO {
+public class CombinationProductRespVO extends CombinationProductBaseVO {
 
-    @Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28322")
     private Long id;
 
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

+ 20 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/product/CombinationProductUpdateReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 拼团商品更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class CombinationProductUpdateReqVO extends CombinationProductBaseVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28322")
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+}

+ 26 - 5
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java

@@ -1,14 +1,18 @@
 package cn.iocoder.yudao.module.promotion.convert.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityExcelVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityRespVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExcelVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
 import org.mapstruct.factory.Mappers;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -21,6 +25,8 @@ public interface CombinationActivityConvert {
 
     CombinationActivityConvert INSTANCE = Mappers.getMapper(CombinationActivityConvert.class);
 
+    @Mapping(target = "startTime", expression = "java(bean.getActivityTime()[0])")
+    @Mapping(target = "endTime", expression = "java(bean.getActivityTime()[1])")
     CombinationActivityDO convert(CombinationActivityCreateReqVO bean);
 
     CombinationActivityDO convert(CombinationActivityUpdateReqVO bean);
@@ -33,4 +39,19 @@ public interface CombinationActivityConvert {
 
     List<CombinationActivityExcelVO> convertList02(List<CombinationActivityDO> list);
 
+    default List<CombinationProductDO> convertList(CombinationActivityDO activityDO, List<CombinationProductCreateReqVO> products) {
+        ArrayList<CombinationProductDO> productDOs = new ArrayList<>();
+        products.forEach(item -> {
+            CombinationProductDO productDO = new CombinationProductDO();
+            productDO.setActivityId(activityDO.getId());
+            productDO.setSpuId(item.getSpuId());
+            productDO.setSkuId(item.getSkuId());
+            productDO.setActivityStatus(0); // TODO 拼团状态枚举未定义不确定有些什么状态
+            productDO.setActivityStartTime(activityDO.getStartTime());
+            productDO.setActivityEndTime(activityDO.getEndTime());
+            productDO.setActivePrice(item.getActivePrice());
+            productDOs.add(productDO);
+        });
+        return productDOs;
+    }
 }

+ 8 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationActivityDO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationActivityDO.java

@@ -1,13 +1,16 @@
-package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;
+package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
 import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.sun.xml.internal.bind.v2.TODO;
 import lombok.*;
 
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * 拼团活动 DO
@@ -36,7 +39,8 @@ public class CombinationActivityDO extends BaseDO {
     /**
      * 商品 SPU 编号关联 ProductSpuDO 的 id
      */
-    private Long spuId;
+    @TableField(typeHandler = LongListTypeHandler.class)
+    private List<Long> spuIds;
     /**
      * 总限购数量
      */
@@ -76,7 +80,7 @@ public class CombinationActivityDO extends BaseDO {
     /**
      * 活动状态:0开启 1关闭
      * <p>
-     * 枚举 {@link TODO common_status 对应的类}
+     * 枚举 {@link CommonStatusEnum}
      */
     private Integer status;
     /**

+ 60 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/combinationactivity/CombinationProductDO.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * 拼团商品 DO
+ *
+ * @author HUIHUI
+ */
+@TableName("promotion_combination_product")
+@KeySequence("promotion_combination_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CombinationProductDO extends BaseDO {
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 拼团活动编号
+     */
+    private Long activityId;
+    /**
+     * 商品 SPU 编号
+     */
+    private Long spuId;
+    /**
+     * 商品 SKU 编号
+     */
+    private Long skuId;
+    /**
+     * 拼团商品状态
+     */
+    private Integer activityStatus;
+    /**
+     * 活动开始时间点
+     */
+    private LocalDateTime activityStartTime;
+    /**
+     * 活动结束时间点
+     */
+    private LocalDateTime activityEndTime;
+    /**
+     * 拼团价格,单位分
+     */
+    private Integer activePrice;
+
+}

+ 1 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.promotion.dal.dataobject.combination;

+ 0 - 59
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationActivityMapper.java

@@ -1,59 +0,0 @@
-package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityExportReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityPageReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.List;
-
-/**
- * 拼团活动 Mapper
- *
- * @author HUIHUI
- */
-@Mapper
-public interface CombinationActivityMapper extends BaseMapperX<CombinationActivityDO> {
-
-    default PageResult<CombinationActivityDO> selectPage(CombinationActivityPageReqVO reqVO) {
-        return selectPage(reqVO, new LambdaQueryWrapperX<CombinationActivityDO>()
-                .likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
-                .eqIfPresent(CombinationActivityDO::getSpuId, reqVO.getSpuId())
-                .eqIfPresent(CombinationActivityDO::getTotalLimitCount, reqVO.getTotalLimitCount())
-                .eqIfPresent(CombinationActivityDO::getSingleLimitCount, reqVO.getSingleLimitCount())
-                .betweenIfPresent(CombinationActivityDO::getStartTime, reqVO.getStartTime())
-                .betweenIfPresent(CombinationActivityDO::getEndTime, reqVO.getEndTime())
-                .eqIfPresent(CombinationActivityDO::getUserSize, reqVO.getUserSize())
-                .eqIfPresent(CombinationActivityDO::getTotalNum, reqVO.getTotalNum())
-                .eqIfPresent(CombinationActivityDO::getSuccessNum, reqVO.getSuccessNum())
-                .eqIfPresent(CombinationActivityDO::getOrderUserCount, reqVO.getOrderUserCount())
-                .eqIfPresent(CombinationActivityDO::getVirtualGroup, reqVO.getVirtualGroup())
-                .eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus())
-                .eqIfPresent(CombinationActivityDO::getLimitDuration, reqVO.getLimitDuration())
-                .betweenIfPresent(CombinationActivityDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(CombinationActivityDO::getId));
-    }
-
-    default List<CombinationActivityDO> selectList(CombinationActivityExportReqVO reqVO) {
-        return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
-                .likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
-                .eqIfPresent(CombinationActivityDO::getSpuId, reqVO.getSpuId())
-                .eqIfPresent(CombinationActivityDO::getTotalLimitCount, reqVO.getTotalLimitCount())
-                .eqIfPresent(CombinationActivityDO::getSingleLimitCount, reqVO.getSingleLimitCount())
-                .betweenIfPresent(CombinationActivityDO::getStartTime, reqVO.getStartTime())
-                .betweenIfPresent(CombinationActivityDO::getEndTime, reqVO.getEndTime())
-                .eqIfPresent(CombinationActivityDO::getUserSize, reqVO.getUserSize())
-                .eqIfPresent(CombinationActivityDO::getTotalNum, reqVO.getTotalNum())
-                .eqIfPresent(CombinationActivityDO::getSuccessNum, reqVO.getSuccessNum())
-                .eqIfPresent(CombinationActivityDO::getOrderUserCount, reqVO.getOrderUserCount())
-                .eqIfPresent(CombinationActivityDO::getVirtualGroup, reqVO.getVirtualGroup())
-                .eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus())
-                .eqIfPresent(CombinationActivityDO::getLimitDuration, reqVO.getLimitDuration())
-                .betweenIfPresent(CombinationActivityDO::getCreateTime, reqVO.getCreateTime())
-                .orderByDesc(CombinationActivityDO::getId));
-    }
-
-}

+ 37 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationActivityMapper.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 拼团活动 Mapper
+ *
+ * @author HUIHUI
+ */
+@Mapper
+public interface CombinationActivityMapper extends BaseMapperX<CombinationActivityDO> {
+
+    default PageResult<CombinationActivityDO> selectPage(CombinationActivityPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<CombinationActivityDO>()
+                .likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
+                .orderByDesc(CombinationActivityDO::getId));
+    }
+
+    default List<CombinationActivityDO> selectList(CombinationActivityExportReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
+                .likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
+                .eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus())
+                .orderByDesc(CombinationActivityDO::getId));
+    }
+
+    default List<CombinationActivityDO> selectListByStatus(Integer status) {
+        return selectList(CombinationActivityDO::getStatus, status);
+    }
+}

+ 47 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/combinationactivity/CombinationProductMapper.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductExportReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductPageReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 拼团商品 Mapper
+ *
+ * @author HUIHUI
+ */
+@Mapper
+public interface CombinationProductMapper extends BaseMapperX<CombinationProductDO> {
+
+    default PageResult<CombinationProductDO> selectPage(CombinationProductPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<CombinationProductDO>()
+                .eqIfPresent(CombinationProductDO::getActivityId, reqVO.getActivityId())
+                .eqIfPresent(CombinationProductDO::getSpuId, reqVO.getSpuId())
+                .eqIfPresent(CombinationProductDO::getSkuId, reqVO.getSkuId())
+                .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
+                .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
+                .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
+                .eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice())
+                .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(CombinationProductDO::getId));
+    }
+
+    default List<CombinationProductDO> selectList(CombinationProductExportReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<CombinationProductDO>()
+                .eqIfPresent(CombinationProductDO::getActivityId, reqVO.getActivityId())
+                .eqIfPresent(CombinationProductDO::getSpuId, reqVO.getSpuId())
+                .eqIfPresent(CombinationProductDO::getSkuId, reqVO.getSkuId())
+                .eqIfPresent(CombinationProductDO::getActivityStatus, reqVO.getActivityStatus())
+                .betweenIfPresent(CombinationProductDO::getActivityStartTime, reqVO.getActivityStartTime())
+                .betweenIfPresent(CombinationProductDO::getActivityEndTime, reqVO.getActivityEndTime())
+                .eqIfPresent(CombinationProductDO::getActivePrice, reqVO.getActivePrice())
+                .betweenIfPresent(CombinationProductDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(CombinationProductDO::getId));
+    }
+
+}

+ 1 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/package-info.java

@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.promotion.dal.mysql.combination;

+ 5 - 5
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java

@@ -1,11 +1,11 @@
 package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityExportReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityPageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
 
 import javax.validation.Valid;
 import java.util.Collection;

+ 70 - 10
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImpl.java

@@ -1,22 +1,37 @@
 package cn.iocoder.yudao.module.promotion.service.combination;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityExportReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityPageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityUpdateReqVO;
+import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
+import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationProductDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationActivityMapper;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationProductMapper;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_ACTIVITY_NOT_EXISTS;
+import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_ACTIVITY_SPU_CONFLICTS;
+import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
 
 /**
  * 拼团活动 Service 实现类
@@ -29,14 +44,59 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
 
     @Resource
     private CombinationActivityMapper combinationActivityMapper;
+    @Resource
+    private CombinationProductMapper combinationProductMapper;
+    @Resource
+    private ProductSpuApi productSpuApi;
+    @Resource
+    private ProductSkuApi productSkuApi;
 
     @Override
     public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) {
-        // 插入
-        CombinationActivityDO combinationActivity = CombinationActivityConvert.INSTANCE.convert(createReqVO);
-        combinationActivityMapper.insert(combinationActivity);
+        // 校验商品 SPU 是否存在是否参加的别的活动
+        validateProductCombinationConflict(createReqVO.getSpuIds());
+        // 获取所选 spu下的所有 sku
+        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds());
+        // 校验商品 sku 是否存在
+        validateProductSkuExistence(skus, createReqVO.getProducts(), CombinationProductCreateReqVO::getSkuId);
+
+        // TODO 艿艿 有个小问题:现在有活动时间和限制时长,活动时间的结束时间早于设置的限制时间怎么算状态比如:
+        //  活动时间 2023-08-05 15:00:00 - 2023-08-05 15:20:00 限制时长 2小时,那么活动时间结束就结束还是加时到满两小时
+        // 插入拼团活动
+        CombinationActivityDO activityDO = CombinationActivityConvert.INSTANCE.convert(createReqVO);
+        // TODO 营销相关属性初始化
+        activityDO.setUserSize(0);
+        activityDO.setTotalNum(0);
+        activityDO.setSuccessNum(0);
+        activityDO.setOrderUserCount(0);
+        activityDO.setVirtualGroup(0);
+        activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        combinationActivityMapper.insert(activityDO);
+        // 插入商品
+        List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(activityDO, createReqVO.getProducts());
+        combinationProductMapper.insertBatch(productDOs);
         // 返回
-        return combinationActivity.getId();
+        return activityDO.getId();
+    }
+
+    private void validateProductCombinationConflict(List<Long> spuIds) {
+        // 校验商品 spu 是否存在
+        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
+        if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) {
+            throw exception(SPU_NOT_EXISTS);
+        }
+        // 查询所有开启的秒杀活动
+        List<CombinationActivityDO> activityDOs = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        // 过滤出所有 spuIds 有交集的活动
+        List<CombinationActivityDO> doList = activityDOs.stream().filter(s -> {
+            // 判断 spu 是否有交集
+            ArrayList<Long> spuIdsClone = CollUtil.newArrayList(s.getSpuIds());
+            spuIdsClone.retainAll(spuIds);
+            return CollUtil.isNotEmpty(spuIdsClone);
+        }).collect(Collectors.toList());
+        if (CollUtil.isNotEmpty(doList)) {
+            throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS);
+        }
     }
 
     @Override

+ 9 - 28
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java

@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@@ -12,7 +11,8 @@ import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
@@ -28,13 +28,12 @@ import javax.annotation.Resource;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
 import static java.util.Arrays.asList;
 
 /**
@@ -61,8 +60,10 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
         // 校验商品秒秒杀时段是否冲突
         validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds());
+        // 获取所选 spu下的所有 sku
+        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds());
         // 校验商品 sku 是否存在
-        validateProductSkuExistence(createReqVO.getSpuIds(), createReqVO.getProducts());
+        validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId);
 
         // 插入秒杀活动
         SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
@@ -74,28 +75,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         return activity.getId();
     }
 
-    private <T extends SeckillProductBaseVO> void validateProductSkuExistence(List<Long> spuIds, List<T> products) {
-        // 校验 spu 个数是否相等
-        // TODO @puhui999:不用校验 SPU 哈,只校验 sku 对应的 spuId 是否一致;
-        Set<Long> convertedSpuIds = CollectionUtils.convertSet(products, T::getSpuId);
-        if (ObjectUtil.notEqual(spuIds.size(), convertedSpuIds.size())) {
-            throw exception(SKU_NOT_EXISTS);
-        }
-        // 获取所选 spu下的所有 sku
-        // TODO @puhui999:变量可以简单一点;skus
-        List<ProductSkuRespDTO> skuRespDTOs = productSkuApi.getSkuListBySpuId(spuIds);
-        // 校验 sku 个数是否一致
-        Set<Long> skuIdsSet = CollectionUtils.convertSet(products, T::getSkuId);
-        Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skuRespDTOs, ProductSkuRespDTO::getId);
-        if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) {
-            throw exception(SKU_NOT_EXISTS);
-        }
-        // 校验 skuId 是否存在
-        if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) {
-            throw exception(SKU_NOT_EXISTS);
-        }
-    }
-
     private void validateProductSpuSeckillConflict(List<Long> configIds, List<Long> spuIds) {
         // 校验秒杀时段是否存在
         seckillConfigService.validateSeckillConfigExists(configIds);
@@ -133,8 +112,10 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         }
         // 校验商品是否冲突
         validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds());
+        // 获取所选 spu下的所有 sku
+        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(updateReqVO.getSpuIds());
         // 校验商品 sku 是否存在
-        validateProductSkuExistence(updateReqVO.getSpuIds(), updateReqVO.getProducts());
+        validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
 
         // 更新活动
         SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)

+ 22 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java

@@ -1,9 +1,18 @@
 package cn.iocoder.yudao.module.promotion.util;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 
 import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 
 /**
  * 活动工具类
@@ -22,4 +31,17 @@ public class PromotionUtils {
         return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
     }
 
+    public static <T> void validateProductSkuExistence(List<ProductSkuRespDTO> skus, List<T> products, Function<T, Long> func) {
+        // 校验 sku 个数是否一致
+        Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
+        Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
+        if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) {
+            throw exception(SKU_NOT_EXISTS);
+        }
+        // 校验 skuId 是否存在
+        if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) {
+            throw exception(SKU_NOT_EXISTS);
+        }
+    }
+
 }

+ 10 - 10
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityServiceImplTest.java

@@ -2,12 +2,12 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityCreateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityExportReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityPageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.CombinationActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
-import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityExportReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.combinationactivity.CombinationActivityDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.combination.combinationactivity.CombinationActivityMapper;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.annotation.Import;
@@ -107,7 +107,7 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
         // mock 数据
         CombinationActivityDO dbCombinationActivity = randomPojo(CombinationActivityDO.class, o -> { // 等会查询到
             o.setName(null);
-            o.setSpuId(null);
+            //o.setSpuId(null);
             o.setTotalLimitCount(null);
             o.setSingleLimitCount(null);
             o.setStartTime(null);
@@ -125,7 +125,7 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
         // 测试 name 不匹配
         combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setName(null)));
         // 测试 spuId 不匹配
-        combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSpuId(null)));
+        //combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSpuId(null)));
         // 测试 totalLimitCount 不匹配
         combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalLimitCount(null)));
         // 测试 singleLimitCount 不匹配
@@ -181,7 +181,7 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
         // mock 数据
         CombinationActivityDO dbCombinationActivity = randomPojo(CombinationActivityDO.class, o -> { // 等会查询到
             o.setName(null);
-            o.setSpuId(null);
+            //o.setSpuId(null);
             o.setTotalLimitCount(null);
             o.setSingleLimitCount(null);
             o.setStartTime(null);
@@ -199,7 +199,7 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
         // 测试 name 不匹配
         combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setName(null)));
         // 测试 spuId 不匹配
-        combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSpuId(null)));
+        //combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSpuId(null)));
         // 测试 totalLimitCount 不匹配
         combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalLimitCount(null)));
         // 测试 singleLimitCount 不匹配