Procházet zdrojové kódy

fix:完善 mall seckill 相关 ②

puhui999 před 1 rokem
rodič
revize
ab30ff6480
15 změnil soubory, kde provedl 166 přidání a 119 odebrání
  1. 9 1
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
  2. 9 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
  3. 5 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
  4. 5 4
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
  5. 4 11
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
  6. 3 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
  7. 3 27
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
  8. 21 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
  9. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java
  10. 12 3
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillProductDO.java
  11. 7 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
  12. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
  13. 2 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
  14. 79 48
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
  15. 3 10
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java

+ 9 - 1
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.product.api.sku;
 
-import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
+import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
 
 import java.util.Collection;
 import java.util.List;
@@ -30,6 +30,14 @@ public interface ProductSkuApi {
      */
     List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
 
+    /**
+     * 批量查询 SKU 数组
+     *
+     * @param spuIds SPU 编号列表
+     * @return SKU 数组
+     */
+    List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds);
+
     /**
      * 更新 SKU 库存
      *

+ 9 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java

@@ -42,6 +42,15 @@ public class ProductSkuApiImpl implements ProductSkuApi {
         return ProductSkuConvert.INSTANCE.convertList04(skus);
     }
 
+    @Override
+    public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) {
+        if (CollUtil.isEmpty(spuIds)) {
+            return Collections.emptyList();
+        }
+        List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds);
+        return ProductSkuConvert.INSTANCE.convertList04(skus);
+    }
+
     @Override
     public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) {
         productSkuService.updateSkuStock(updateStockReqDTO);

+ 5 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.module.product.api.spu;
 
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.hutool.core.collection.CollectionUtil;
 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
 import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
@@ -14,7 +14,7 @@ import java.util.Collections;
 import java.util.List;
 
 /**
- * TODO LeeYan9: 类注释;
+ * 商品 SPU API 接口实现类
  *
  * @author LeeYan9
  * @since 2022-09-06
@@ -28,11 +28,12 @@ public class ProductSpuApiImpl implements ProductSpuApi {
 
     @Override
     public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) {
-        // TODO TODO LeeYan9: AllEmpty?
-        if (CollectionUtils.isAnyEmpty(spuIds)) {
+        // TODO 需不需要判断集合中是否有 null 值
+        if (CollectionUtil.isEmpty(spuIds)) {
             return Collections.emptyList();
         }
         List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds);
         return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList);
     }
+
 }

+ 5 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java

@@ -55,7 +55,7 @@ public interface ProductSkuService {
      * 批量创建 SKU
      *
      * @param spuId 商品 SPU 编号
-     * @param list SKU 对象集合
+     * @param list  SKU 对象集合
      */
     void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list);
 
@@ -63,13 +63,13 @@ public interface ProductSkuService {
      * 根据 SPU 编号,批量更新它的 SKU 信息
      *
      * @param spuId SPU 编码
-     * @param skus SKU 的集合
+     * @param skus  SKU 的集合
      */
     void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus);
 
     /**
      * 更新 SKU 库存(增量)
-     *
+     * <p>
      * 如果更新的库存不足,会抛出异常
      *
      * @param updateStockReqDTO 更行请求
@@ -88,7 +88,7 @@ public interface ProductSkuService {
      * 获得 spu 对应的 SKU 集合
      *
      * @param spuIds spu 编码集合
-     * @return  商品 sku 集合
+     * @return 商品 sku 集合
      */
     List<ProductSkuDO> getSkuListBySpuId(List<Long> spuIds);
 
@@ -123,4 +123,5 @@ public interface ProductSkuService {
      * @return int 影响的行数
      */
     int updateSkuPropertyValue(Long propertyValueId, String propertyValueName);
+
 }

+ 4 - 11
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java

@@ -1,17 +1,14 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import javax.validation.constraints.Min;
 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;
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
 
 /**
  * 秒杀活动基地签证官
@@ -23,18 +20,14 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE
 @Data
 public class SeckillActivityBaseVO {
 
-    @Schema(description = "秒杀活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "121")
+    @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
     @NotNull(message = "秒杀活动商品不能为空")
-    private Long spuId;
+    private List<Long> spuIds;
 
     @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
     @NotNull(message = "秒杀活动名称不能为空")
     private String name;
 
-    @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
-    @NotNull(message = "活动状态 开启:0 禁用:1不能为空")
-    private Integer status;
-
     @Schema(description = "备注", example = "清仓大甩卖割韭菜")
     private String remark;
 
@@ -52,8 +45,8 @@ public class SeckillActivityBaseVO {
     @NotNull(message = "排序不能为空")
     private Integer sort;
 
-    @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "秒杀时段id不能为空")
+    @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3]")
+    @NotNull(message = "秒杀时段不能为空")
     private List<Long> configIds;
 
     @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12877")

+ 3 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java

@@ -6,7 +6,6 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
-import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -24,8 +23,10 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
     private Long id;
 
     @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<SeckillProductRespVO> products;
+    private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除
 
+    @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+    private Integer status;
 
 
 }

+ 3 - 27
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java

@@ -1,12 +1,9 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-import java.time.LocalDateTime;
-import javax.validation.constraints.*;
-import org.springframework.format.annotation.DateTimeFormat;
+import lombok.Data;
 
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+import javax.validation.constraints.NotNull;
 
 /**
  * 秒杀参与商品 Base VO,提供给添加、修改、详细的子 VO 使用
@@ -17,15 +14,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @Data
 public class SeckillProductBaseVO {
 
-    @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20173")
-    @NotNull(message = "秒杀活动id不能为空")
-    private Long activityId;
-
-    @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "秒杀时段id不能为空")
-    private String configIds;
-
-    @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "10290")
+    @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
     @NotNull(message = "商品spu_id不能为空")
     private Long spuId;
 
@@ -41,18 +30,5 @@ public class SeckillProductBaseVO {
     @NotNull(message = "秒杀库存不能为空")
     private Integer stock;
 
-    @Schema(description = "秒杀商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
-    @NotNull(message = "秒杀商品状态不能为空")
-    private Integer activityStatus;
-
-    @Schema(description = "活动开始时间点", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "活动开始时间点不能为空")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime activityStartTime;
-
-    @Schema(description = "活动结束时间点", requiredMode = Schema.RequiredMode.REQUIRED)
-    @NotNull(message = "活动结束时间点不能为空")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime activityEndTime;
 
 }

+ 21 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
 
 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.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
@@ -12,6 +13,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -47,7 +49,7 @@ public interface SeckillActivityConvert {
      * @return 是否匹配
      */
     default boolean isEquals(SeckillProductDO productDO, SeckillProductCreateReqVO productVO) {
-        return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
+        return ObjectUtil.equals(productDO.getSpuId(), 1) // TODO puhui:再看看
                 && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
                 && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice());
         //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())
@@ -65,9 +67,25 @@ public interface SeckillActivityConvert {
         return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId())
                 && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId())
                 && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice());
-                //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())
-                //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount());
+        //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota())
+        //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount());
 
     }
 
+    default List<SeckillProductDO> convertList(SeckillActivityDO seckillActivity, List<SeckillProductCreateReqVO> products) {
+        List<SeckillProductDO> list = new ArrayList<>();
+        products.forEach(sku -> {
+            SeckillProductDO productDO = new SeckillProductDO();
+            productDO.setActivityId(seckillActivity.getId());
+            productDO.setConfigIds(seckillActivity.getConfigIds());
+            productDO.setSpuId(sku.getSpuId());
+            productDO.setSkuId(sku.getSkuId());
+            productDO.setSeckillPrice(sku.getSeckillPrice());
+            productDO.setStock(sku.getStock());
+            productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
+            productDO.setActivityStartTime(seckillActivity.getStartTime());
+            productDO.setActivityEndTime(seckillActivity.getEndTime());
+        });
+        return list;
+    }
 }

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity
 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 cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -35,7 +34,8 @@ public class SeckillActivityDO extends BaseDO {
     /**
      * 秒杀活动商品
      */
-    private Long spuId;
+    @TableField(typeHandler = LongListTypeHandler.class)
+    private List<Long> spuIds;
     /**
      * 秒杀活动名称
      */

+ 12 - 3
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillProductDO.java

@@ -1,9 +1,16 @@
 package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity;
 
+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 lombok.*;
+
 import java.time.LocalDateTime;
-import com.baomidou.mybatisplus.annotation.*;
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import java.util.List;
 
 /**
  * 秒杀参与商品 DO
@@ -32,7 +39,8 @@ public class SeckillProductDO extends BaseDO {
     /**
      * 秒杀时段 id
      */
-    private String configIds;
+    @TableField(typeHandler = LongListTypeHandler.class)
+    private List<Long> configIds;
     /**
      * 商品 spu_id
      */
@@ -51,6 +59,7 @@ public class SeckillProductDO extends BaseDO {
     private Integer stock;
     /**
      * 秒杀商品状态
+     * 枚举 {@link CommonStatusEnum 对应的类}
      */
     private Integer activityStatus;
     /**

+ 7 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java

@@ -8,6 +8,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 秒杀活动 Mapper
  *
@@ -23,4 +25,9 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
                 .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0")
                 .orderByDesc(SeckillActivityDO::getId));
     }
+
+    default List<SeckillActivityDO> selectListByStatus(Integer status) {
+        return selectList(new LambdaQueryWrapperX<SeckillActivityDO>()
+                .eqIfPresent(SeckillActivityDO::getStatus, status));
+    }
 }

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java

@@ -52,7 +52,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
 
         // 插入活动
         DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
         discountActivityMapper.insert(discountActivity);
         // 插入商品
         List<DiscountProductDO> discountProducts = convertList(createReqVO.getProducts(),
@@ -74,7 +74,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
 
         // 更新活动
         DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
         discountActivityMapper.updateById(updateObj);
         // 更新商品
         updateDiscountProduct(updateReqVO);

+ 2 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java

@@ -41,7 +41,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
 
         // 插入
         RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
         rewardActivityMapper.insert(rewardActivity);
         // 返回
         return rewardActivity.getId();
@@ -59,7 +59,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
 
         // 更新
         RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
         rewardActivityMapper.updateById(updateObj);
     }
 

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

@@ -1,16 +1,19 @@
 package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
 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.promotion.controller.admin.seckill.vo.activity.SeckillActivityBaseVO;
+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.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.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;
@@ -25,8 +28,12 @@ import org.springframework.validation.annotation.Validated;
 import javax.annotation.Resource;
 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 java.util.Arrays.asList;
 
@@ -45,40 +52,94 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     private SeckillProductMapper seckillProductMapper;
     @Resource
     private SeckillConfigService seckillConfigService;
+    @Resource
+    private ProductSpuApi productSpuApi;
+    @Resource
+    private ProductSkuApi productSkuApi;
 
     @Override
     public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
-        // 校验商品是否冲突
-        validateSeckillActivityProductConflicts(null, createReqVO.getProducts());
-        // 校验秒杀时段是否存在
-        seckillConfigService.validateSeckillConfigExists(createReqVO.getConfigIds());
+        // 校验商品秒秒杀时段是否冲突
+        validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds());
+        // 校验商品 sku 是否存在
+        validateProductSkuExistence(createReqVO.getSpuIds(), createReqVO.getProducts());
 
-        // 插入秒杀活动 TODO 活动日期拼接上秒杀时段 -> 2023-06-08 09:00:00
+        // 插入秒杀活动
         SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
         seckillActivityMapper.insert(seckillActivity);
         // 插入商品
-        //List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), seckillActivity);
-        //seckillProductMapper.insertBatch(productDOs);
+        List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(seckillActivity, createReqVO.getProducts());
+        seckillProductMapper.insertBatch(productDOs);
         return seckillActivity.getId();
     }
 
+    private <T extends SeckillProductBaseVO> void validateProductSkuExistence(List<Long> spuIds, List<T> products) {
+        Set<Long> convertedSpuIds = CollectionUtils.convertSet(products, T::getSpuId);
+        // 校验 spu 个数是否相等
+        if (ObjectUtil.notEqual(spuIds.size(), convertedSpuIds.size())) {
+            throw exception(SKU_NOT_EXISTS);
+        }
+        // 获取所选 spu下的所有 sku
+        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);
+        // 校验商品 spu 是否存在
+        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
+        if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) {
+            throw exception(SPU_NOT_EXISTS);
+        }
+        // 查询所有开启的秒杀活动
+        List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        // 过滤出所有 spuIds 有交集的活动
+        List<SeckillActivityDO> doList = activityDOs.stream().filter(s -> {
+            // 判断 spu 是否有交集
+            List<Long> spuIdsClone = ArrayUtil.clone(s.getSpuIds());
+            spuIdsClone.retainAll(spuIds);
+            if (CollUtil.isEmpty(spuIdsClone)) {
+                return false;
+            }
+            // 判断秒杀时段是否有交集
+            List<Long> configIdsClone = ArrayUtil.clone(s.getConfigIds());
+            configIdsClone.retainAll(configIds);
+            return CollUtil.isNotEmpty(configIdsClone);
+        }).collect(Collectors.toList());
+        if (CollUtil.isNotEmpty(doList)) {
+            throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
+        }
+    }
+
     @Override
     public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
         // 校验存在
         SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
-        if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
+        if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
             throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
         }
         // 校验商品是否冲突
-        validateSeckillActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
+        validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds());
+        // 校验商品 sku 是否存在
+        validateProductSkuExistence(updateReqVO.getSpuIds(), updateReqVO.getProducts());
 
         // 更新活动
         SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
         seckillActivityMapper.updateById(updateObj);
         // 更新商品
-        updateSeckillProduct(updateReqVO);
+        //updateSeckillProduct(updateReqVO);
     }
 
 
@@ -92,10 +153,11 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
      * @param updateReqVO 更新的请求VO
      */
     private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {
-        List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
-        //List<SeckillActivityBaseVO.Product> products = updateReqVO.getProducts();
+        // TODO puhui999:后续完善
+        //List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId());
+        //List<SeckillProductUpdateReqVO> products = updateReqVO.getProducts();
 
-        // 计算需要删除的数据
+        ////计算需要删除的数据
         //List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOs, SeckillProductDO::getId,
         //        seckillProductDO -> products.stream()
         //                .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product)));
@@ -116,37 +178,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds());
     }
 
-    /**
-     * 校验商品是否冲突
-     *
-     * @param id       秒杀活动编号
-     * @param products 商品列表
-     */
-    private <T extends SeckillProductBaseVO> void  validateSeckillActivityProductConflicts(Long id, List<T> products) {
-        if (CollUtil.isEmpty(products)) {
-            return;
-        }
-        // 校验秒杀商品是否存在
-        List<SeckillProductDO> seckillProductDOs = seckillProductMapper
-                .selectListBySkuIds(CollectionUtils.convertSet(products, T::getSkuId));
-        if (CollUtil.isEmpty(seckillProductDOs)) {
-            return;
-        }
-        // 获取秒杀商品所在活动
-        List<SeckillActivityDO> seckillActivityDOs = seckillActivityMapper
-                .selectBatchIds(CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getActivityId));
-        if (id != null) {
-            // 排除自己这个活动
-            seckillActivityDOs.removeIf(item -> id.equals(item.getId()));
-        }
-        // 排除关闭了的活动
-        seckillActivityDOs.removeIf(item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
-        // 如果非空,则说明冲突
-        if (CollUtil.isNotEmpty(seckillActivityDOs)) {
-            throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
-        }
-    }
-
     @Override
     public void closeSeckillActivity(Long id) {
         // 校验存在

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

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.promotion.util;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
 
 import java.time.LocalDateTime;
 
@@ -15,18 +15,11 @@ public class PromotionUtils {
     /**
      * 根据时间,计算活动状态
      *
-     * @param startTime 开始时间
      * @param endTime 结束时间
      * @return 活动状态
      */
-    public static Integer calculateActivityStatus(LocalDateTime startTime, LocalDateTime endTime) {
-        if (LocalDateTimeUtils.beforeNow(endTime)) {
-            return PromotionActivityStatusEnum.END.getStatus();
-        }
-        if (LocalDateTimeUtils.afterNow(startTime)) {
-            return PromotionActivityStatusEnum.WAIT.getStatus();
-        }
-        return PromotionActivityStatusEnum.RUN.getStatus();
+    public static Integer calculateActivityStatus(LocalDateTime endTime) {
+        return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
     }
 
 }