Browse Source

fix:mall promotion Combination

puhui999 2 years ago
parent
commit
78b3d2a20f
12 changed files with 125 additions and 139 deletions
  1. 1 2
      yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
  2. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
  3. 2 1
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
  4. 1 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
  5. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
  6. 0 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
  7. 3 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java
  8. 32 43
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
  9. 1 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java
  10. 71 65
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
  11. 12 2
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java
  12. 0 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java

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

@@ -30,14 +30,13 @@ public interface ProductSkuApi {
      */
     List<ProductSkuRespDTO> getSkuList(Collection<Long> ids);
 
-    // TODO puhui999:入参用 Collection<Long> 更通用
     /**
      * 批量查询 SKU 数组
      *
      * @param spuIds SPU 编号列表
      * @return SKU 数组
      */
-    List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds);
+    List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds);
 
     /**
      * 更新 SKU 库存

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

@@ -43,7 +43,7 @@ public class ProductSkuApiImpl implements ProductSkuApi {
     }
 
     @Override
-    public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) {
+    public List<ProductSkuRespDTO> getSkuListBySpuId(Collection<Long> spuIds) {
         if (CollUtil.isEmpty(spuIds)) {
             return Collections.emptyList();
         }

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

@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 
 /**
  * Promotion 错误码枚举类
- *
+ * <p>
  * promotion 系统,使用 1-013-000-000 段
  */
 public interface ErrorCodeConstants {
@@ -58,6 +58,7 @@ public interface ErrorCodeConstants {
     ErrorCode SECKILL_TIME_CONFLICTS = new ErrorCode(1013009001, "秒杀时段冲突");
     ErrorCode SECKILL_TIME_EQUAL = new ErrorCode(1013009002, "秒杀时段开始时间和结束时间不能相等");
     ErrorCode SECKILL_START_TIME_BEFORE_END_TIME = new ErrorCode(1013009003, "秒杀时段开始时间不能在结束时间之后");
+    ErrorCode SECKILL_TIME_DISABLE = new ErrorCode(1013009004, "秒杀时段已关闭");
 
     // ========== 拼团活动 1013010000 ==========
     ErrorCode COMBINATION_ACTIVITY_NOT_EXISTS = new ErrorCode(1013010000, "拼团活动不存在");

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

@@ -20,10 +20,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @Data
 public class SeckillActivityBaseVO {
 
-    // TODO @puhui999:对应单 spuId 哈
     @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]")
     @NotNull(message = "秒杀活动商品不能为空")
-    private List<Long> spuIds;
+    private Long spuId;
 
     @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
     @NotNull(message = "秒杀活动名称不能为空")
@@ -56,8 +55,4 @@ public class SeckillActivityBaseVO {
     @Schema(description = "单次限够数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "31683")
     private Integer singleLimitCount;
 
-    // TODO @puhui999:这个应该是计算出来的字段,只返回,create 和 update 不用哈
-    @Schema(description = "秒杀总库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
-    private Integer totalStock;
-
 }

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

@@ -23,7 +23,7 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO {
     private Long id;
 
     @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED)
-    private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除
+    private List<SeckillProductRespVO> products;
 
     @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
     private Integer status;

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

@@ -14,11 +14,6 @@ import javax.validation.constraints.NotNull;
 @Data
 public class SeckillProductBaseVO {
 
-    // TODO @puhui:spuId 不用传递;因为一个秒杀活动只对应一个 SPU  哈;
-    @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
-    @NotNull(message = "商品spu_id不能为空")
-    private Long spuId;
-
     @Schema(description = "商品sku_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563")
     @NotNull(message = "商品sku_id不能为空")
     private Long skuId;
@@ -31,5 +26,4 @@ public class SeckillProductBaseVO {
     @NotNull(message = "秒杀库存不能为空")
     private Integer stock;
 
-
 }

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

@@ -1,8 +1,9 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-import javax.validation.constraints.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 
 /**
  * 管理后台 - 秒杀参与商品更新 Request VO
@@ -15,8 +16,4 @@ import javax.validation.constraints.*;
 @ToString(callSuper = true)
 public class SeckillProductUpdateReqVO extends SeckillProductBaseVO {
 
-    @Schema(description = "秒杀参与商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "256")
-    @NotNull(message = "秒杀参与商品编号不能为空")
-    private Long id;
-
 }

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

@@ -1,20 +1,24 @@
 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.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
 import org.mapstruct.factory.Mappers;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 秒杀活动 Convert
@@ -26,8 +30,6 @@ public interface SeckillActivityConvert {
 
     SeckillActivityConvert INSTANCE = Mappers.getMapper(SeckillActivityConvert.class);
 
-    SeckillProductDO convert(SeckillProductCreateReqVO product);
-
     SeckillActivityDO convert(SeckillActivityCreateReqVO bean);
 
     SeckillActivityDO convert(SeckillActivityUpdateReqVO bean);
@@ -40,51 +42,38 @@ public interface SeckillActivityConvert {
 
     SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts);
 
+    @Mappings({
+            @Mapping(target = "activityId", source = "activityDO.id"),
+            @Mapping(target = "configIds", source = "activityDO.configIds"),
+            @Mapping(target = "spuId", source = "activityDO.spuId"),
+            @Mapping(target = "skuId", source = "vo.skuId"),
+            @Mapping(target = "seckillPrice", source = "vo.seckillPrice"),
+            @Mapping(target = "stock", source = "vo.stock"),
+            @Mapping(target = "activityStartTime", source = "activityDO.startTime"),
+            @Mapping(target = "activityEndTime", source = "activityDO.endTime")
+    })
+    SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo);
 
-    /**
-     * 比较两个秒杀商品对象是否相等
-     *
-     * @param productDO 数据库中的商品
-     * @param productVO 前端传入的商品
-     * @return 是否匹配
-     */
-    default boolean isEquals(SeckillProductDO productDO, SeckillProductCreateReqVO productVO) {
-        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())
-        //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount());
-    }
-
-    /**
-     * 比较两个秒杀商品对象是否相等
-     *
-     * @param productDO 商品1
-     * @param productVO 商品2
-     * @return 是否匹配
-     */
-    default boolean isEquals(SeckillProductDO productDO, SeckillProductDO productVO) {
-        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());
+    default List<SeckillProductDO> convertList(SeckillActivityDO activityDO, List<? extends SeckillProductBaseVO> products) {
+        List<SeckillProductDO> list = new ArrayList<>();
+        products.forEach(sku -> {
+            SeckillProductDO productDO = convert(activityDO, sku);
+            productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
+            list.add(productDO);
+        });
+        return list;
     }
 
-    default List<SeckillProductDO> convertList(SeckillActivityDO seckillActivity, List<SeckillProductCreateReqVO> products) {
+    default List<SeckillProductDO> convertList1(SeckillActivityDO activityDO, List<SeckillProductUpdateReqVO> vos, List<SeckillProductDO> productDOs) {
+        Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
         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());
+        vos.forEach(sku -> {
+            SeckillProductDO productDO = convert(activityDO, sku);
+            productDO.setId(longMap.get(sku.getSkuId()));
             productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus());
-            productDO.setActivityStartTime(seckillActivity.getStartTime());
-            productDO.setActivityEndTime(seckillActivity.getEndTime());
+            list.add(productDO);
         });
         return list;
     }
+
 }

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

@@ -34,8 +34,7 @@ public class SeckillActivityDO extends BaseDO {
     /**
      * 秒杀活动商品
      */
-    @TableField(typeHandler = LongListTypeHandler.class)
-    private List<Long> spuIds;
+    private Long spuId;
     /**
      * 秒杀活动名称
      */

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

@@ -4,6 +4,7 @@ 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;
@@ -18,23 +19,21 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.
 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
-import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
 import cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig.SeckillConfigService;
 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 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 java.util.Set;
 
 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.*;
 import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
-import static java.util.Arrays.asList;
 
 /**
  * 秒杀活动 Service 实现类
@@ -57,17 +56,19 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
     private ProductSkuApi productSkuApi;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
         // 校验商品秒秒杀时段是否冲突
-        validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds());
+        validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
         // 获取所选 spu下的所有 sku
-        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(createReqVO.getSpuIds());
+        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(createReqVO.getSpuId()));
         // 校验商品 sku 是否存在
         validateProductSkuExistence(skus, createReqVO.getProducts(), SeckillProductCreateReqVO::getSkuId);
 
         // 插入秒杀活动
         SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()))
+                .setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
         seckillActivityMapper.insert(activity);
         // 插入商品
         List<SeckillProductDO> product = SeckillActivityConvert.INSTANCE.convertList(activity, createReqVO.getProducts());
@@ -75,119 +76,124 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
         return activity.getId();
     }
 
-    private void validateProductSpuSeckillConflict(List<Long> configIds, List<Long> spuIds) {
+    private void validateProductSpuSeckillConflict(List<Long> configIds, Long spuId, Long activityId) {
         // 校验秒杀时段是否存在
         seckillConfigService.validateSeckillConfigExists(configIds);
         // 校验商品 spu 是否存在
-        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
-        if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) {
+        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
+        if (CollUtil.isEmpty(spuList)) {
             throw exception(SPU_NOT_EXISTS);
         }
         // 查询所有开启的秒杀活动
         List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
-        // 过滤出所有 spuIds 有交集的活动
-        List<SeckillActivityDO> doList = activityDOs.stream().filter(s -> {
-            // 判断 spu 是否有交集
-            ArrayList<Long> spuIdsClone = CollUtil.newArrayList(s.getSpuIds());
-            spuIdsClone.retainAll(spuIds);
-            if (CollUtil.isEmpty(spuIdsClone)) {
-                return false;
-            }
+        if (activityId != null) {
+            // 更新时移除本活动
+            activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
+        }
+        // 过滤出所有 spuId 有交集的活动
+        List<SeckillActivityDO> activityDOs1 = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
+        if (CollUtil.isNotEmpty(activityDOs1)) {
+            throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
+        }
+        List<SeckillActivityDO> activityDOs2 = CollectionUtils.convertList(activityDOs, c -> c, s -> {
             // 判断秒杀时段是否有交集
             List<Long> configIdsClone = CollUtil.newArrayList(s.getConfigIds());
             configIdsClone.retainAll(configIds);
             return CollUtil.isNotEmpty(configIdsClone);
-        }).collect(Collectors.toList());
-        if (CollUtil.isNotEmpty(doList)) {
-            throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
+        });
+        if (CollUtil.isNotEmpty(activityDOs2)) {
+            throw exception(SECKILL_TIME_CONFLICTS);
         }
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
         // 校验存在
         SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
-        if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
+        if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
             throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
         }
         // 校验商品是否冲突
-        validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds());
+        validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
         // 获取所选 spu下的所有 sku
-        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(updateReqVO.getSpuIds());
+        List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
         // 校验商品 sku 是否存在
         validateProductSkuExistence(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
 
         // 更新活动
         SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
-                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()));
+                .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()))
+                .setTotalStock(CollectionUtils.getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum));
         seckillActivityMapper.updateById(updateObj);
         // 更新商品
-        //updateSeckillProduct(updateReqVO);
+        updateSeckillProduct(updateObj, updateReqVO.getProducts());
     }
 
 
     /**
      * 更新秒杀商品
-     * 后台查出的数据和前台查出的数据进行遍历,
-     * 1. 对前台数据进行遍历:如果不存在于后台的 sku 中需要新增
-     * 2. 对后台数据进行遍历:如果不存在于前台的 sku 中需要删除
-     * 3. 最后对当前活动商品全部更新,更新秒杀时段id列表
      *
-     * @param updateReqVO 更新的请求VO
+     * @param updateObj DO
+     * @param products  商品配置
      */
-    private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) {
-        // TODO puhui999:要不这里简单一点;删除原本的,插入新增的;不做的这么细致
-        // 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)));
-        //if (CollUtil.isNotEmpty(deleteIds)) {
-        //    seckillProductMapper.deleteBatchIds(deleteIds);
-        //}
-        //
-        //// 计算需要新增的数据
-        //List<SeckillProductDO> newSeckillProductDOs = CollectionUtils.convertList(products,
-        //        product -> SeckillActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId()));
-        //newSeckillProductDOs.removeIf(product -> seckillProductDOs.stream()
-        //        .anyMatch(seckillProduct -> SeckillActivityConvert.INSTANCE.isEquals(seckillProduct, product)));
-        //if (CollUtil.isNotEmpty(newSeckillProductDOs)) {
-        //    seckillProductMapper.insertBatch(newSeckillProductDOs);
-        //}
-
-        //全量更新当前活动商品的秒杀时段id列表(timeIds)
-        seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds());
+    private void updateSeckillProduct(SeckillActivityDO updateObj, List<SeckillProductUpdateReqVO> products) {
+        List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateObj.getId());
+        // 数据库中的活动商品
+        Set<Long> convertSet = CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getSkuId);
+        // 前端传过来的活动商品
+        Set<Long> convertSet1 = CollectionUtils.convertSet(products, SeckillProductUpdateReqVO::getSkuId);
+        // 删除后台存在的前端不存在的商品
+        List<Long> d = CollectionUtils.filterList(convertSet, item -> !convertSet1.contains(item));
+        if (CollUtil.isNotEmpty(d)) {
+            seckillProductMapper.deleteBatchIds(d);
+        }
+        // 前端存在的后端不存在的商品
+        List<Long> c = CollectionUtils.filterList(convertSet1, item -> !convertSet.contains(item));
+        if (CollUtil.isNotEmpty(c)) {
+            List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> c.contains(item.getSkuId()));
+            List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(updateObj, vos);
+            seckillProductMapper.insertBatch(productDOs);
+        }
+        // 更新已存在的商品
+        List<Long> u = CollectionUtils.filterList(convertSet1, convertSet::contains);
+        if (CollUtil.isNotEmpty(u)) {
+            List<SeckillProductUpdateReqVO> vos = CollectionUtils.filterList(products, item -> u.contains(item.getSkuId()));
+            List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList1(updateObj, vos, seckillProductDOs);
+            seckillProductMapper.insertBatch(productDOs);
+        }
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void closeSeckillActivity(Long id) {
+        // TODO 待验证没使用过
         // 校验存在
-        SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
-        if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) {
+        SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
+        if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
             throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
         }
-        if (PromotionActivityStatusEnum.END.getStatus().equals(seckillActivity.getStatus())) {
-            throw exception(SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_END);
-        }
+
         // 更新
-        SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
+        SeckillActivityDO updateObj = new SeckillActivityDO().setId(id).setStatus(CommonStatusEnum.DISABLE.getStatus());
         seckillActivityMapper.updateById(updateObj);
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void deleteSeckillActivity(Long id) {
         // 校验存在
         SeckillActivityDO seckillActivity = this.validateSeckillActivityExists(id);
-        List<Integer> statuses = asList(PromotionActivityStatusEnum.CLOSE.getStatus(), PromotionActivityStatusEnum.END.getStatus());
-        if (!statuses.contains(seckillActivity.getStatus())) {
+        if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) {
             throw exception(SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
         }
 
-        // 删除
+        // 删除活动
         seckillActivityMapper.deleteById(id);
+        // 删除活动商品
+        List<SeckillProductDO> productDOs = seckillProductMapper.selectListByActivityId(id);
+        Set<Long> convertSet = CollectionUtils.convertSet(productDOs, SeckillProductDO::getSkuId);
+        seckillProductMapper.deleteBatchIds(convertSet);
     }
 
     private SeckillActivityDO validateSeckillActivityExists(Long id) {

+ 12 - 2
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java

@@ -1,8 +1,10 @@
 package cn.iocoder.yudao.module.promotion.service.seckill.seckillconfig;
 
 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.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
@@ -127,10 +129,18 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
         if (CollUtil.isEmpty(configIds)) {
             throw exception(SECKILL_TIME_NOT_EXISTS);
         }
-        if (seckillConfigMapper.selectBatchIds(configIds).size() != configIds.size()) {
+        List<SeckillConfigDO> configDOs = seckillConfigMapper.selectBatchIds(configIds);
+        if (CollUtil.isEmpty(configDOs)) {
+            throw exception(SECKILL_TIME_NOT_EXISTS);
+        }
+        // 过滤出关闭的时段
+        List<SeckillConfigDO> filterList = CollectionUtils.filterList(configDOs, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus()));
+        if (CollUtil.isNotEmpty(filterList)) {
+            throw exception(SECKILL_TIME_DISABLE);
+        }
+        if (configDOs.size() != configIds.size()) {
             throw exception(SECKILL_TIME_NOT_EXISTS);
         }
-        // TODO @puhui999:应该要校验个 status 哈;如果有禁用的,也不行
     }
 
     @Override

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

@@ -1,6 +1,5 @@
 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;
@@ -35,9 +34,6 @@ public class PromotionUtils {
         // 校验 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);