Commit ab30ff64804ee892cadccaa36ed70fac48abf590
1 parent
b44ad3a0
fix:完善 mall seckill 相关 ②
Showing
15 changed files
with
166 additions
and
119 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
| 1 | 1 | package cn.iocoder.yudao.module.product.api.sku; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | |
| 4 | 3 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 4 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | |
| 5 | 5 | |
| 6 | 6 | import java.util.Collection; |
| 7 | 7 | import java.util.List; |
| ... | ... | @@ -31,6 +31,14 @@ public interface ProductSkuApi { |
| 31 | 31 | List<ProductSkuRespDTO> getSkuList(Collection<Long> ids); |
| 32 | 32 | |
| 33 | 33 | /** |
| 34 | + * 批量查询 SKU 数组 | |
| 35 | + * | |
| 36 | + * @param spuIds SPU 编号列表 | |
| 37 | + * @return SKU 数组 | |
| 38 | + */ | |
| 39 | + List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds); | |
| 40 | + | |
| 41 | + /** | |
| 34 | 42 | * 更新 SKU 库存 |
| 35 | 43 | * |
| 36 | 44 | * @param updateStockReqDTO 更新请求 | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
| ... | ... | @@ -43,6 +43,15 @@ public class ProductSkuApiImpl implements ProductSkuApi { |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | @Override |
| 46 | + public List<ProductSkuRespDTO> getSkuListBySpuId(List<Long> spuIds) { | |
| 47 | + if (CollUtil.isEmpty(spuIds)) { | |
| 48 | + return Collections.emptyList(); | |
| 49 | + } | |
| 50 | + List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spuIds); | |
| 51 | + return ProductSkuConvert.INSTANCE.convertList04(skus); | |
| 52 | + } | |
| 53 | + | |
| 54 | + @Override | |
| 46 | 55 | public void updateSkuStock(ProductSkuUpdateStockReqDTO updateStockReqDTO) { |
| 47 | 56 | productSkuService.updateSkuStock(updateStockReqDTO); |
| 48 | 57 | } | ... | ... |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.product.api.spu; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 3 | +import cn.hutool.core.collection.CollectionUtil; | |
| 4 | 4 | import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; |
| 6 | 6 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| ... | ... | @@ -14,7 +14,7 @@ import java.util.Collections; |
| 14 | 14 | import java.util.List; |
| 15 | 15 | |
| 16 | 16 | /** |
| 17 | - * TODO LeeYan9: 类注释; | |
| 17 | + * 商品 SPU API 接口实现类 | |
| 18 | 18 | * |
| 19 | 19 | * @author LeeYan9 |
| 20 | 20 | * @since 2022-09-06 |
| ... | ... | @@ -28,11 +28,12 @@ public class ProductSpuApiImpl implements ProductSpuApi { |
| 28 | 28 | |
| 29 | 29 | @Override |
| 30 | 30 | public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) { |
| 31 | - // TODO TODO LeeYan9: AllEmpty? | |
| 32 | - if (CollectionUtils.isAnyEmpty(spuIds)) { | |
| 31 | + // TODO 需不需要判断集合中是否有 null 值 | |
| 32 | + if (CollectionUtil.isEmpty(spuIds)) { | |
| 33 | 33 | return Collections.emptyList(); |
| 34 | 34 | } |
| 35 | 35 | List<ProductSpuDO> productSpuDOList = productSpuMapper.selectBatchIds(spuIds); |
| 36 | 36 | return ProductSpuConvert.INSTANCE.convertList2(productSpuDOList); |
| 37 | 37 | } |
| 38 | + | |
| 38 | 39 | } | ... | ... |
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 { |
| 55 | 55 | * 批量创建 SKU |
| 56 | 56 | * |
| 57 | 57 | * @param spuId 商品 SPU 编号 |
| 58 | - * @param list SKU 对象集合 | |
| 58 | + * @param list SKU 对象集合 | |
| 59 | 59 | */ |
| 60 | 60 | void createSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> list); |
| 61 | 61 | |
| ... | ... | @@ -63,13 +63,13 @@ public interface ProductSkuService { |
| 63 | 63 | * 根据 SPU 编号,批量更新它的 SKU 信息 |
| 64 | 64 | * |
| 65 | 65 | * @param spuId SPU 编码 |
| 66 | - * @param skus SKU 的集合 | |
| 66 | + * @param skus SKU 的集合 | |
| 67 | 67 | */ |
| 68 | 68 | void updateSkuList(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus); |
| 69 | 69 | |
| 70 | 70 | /** |
| 71 | 71 | * 更新 SKU 库存(增量) |
| 72 | - * | |
| 72 | + * <p> | |
| 73 | 73 | * 如果更新的库存不足,会抛出异常 |
| 74 | 74 | * |
| 75 | 75 | * @param updateStockReqDTO 更行请求 |
| ... | ... | @@ -88,7 +88,7 @@ public interface ProductSkuService { |
| 88 | 88 | * 获得 spu 对应的 SKU 集合 |
| 89 | 89 | * |
| 90 | 90 | * @param spuIds spu 编码集合 |
| 91 | - * @return 商品 sku 集合 | |
| 91 | + * @return 商品 sku 集合 | |
| 92 | 92 | */ |
| 93 | 93 | List<ProductSkuDO> getSkuListBySpuId(List<Long> spuIds); |
| 94 | 94 | |
| ... | ... | @@ -123,4 +123,5 @@ public interface ProductSkuService { |
| 123 | 123 | * @return int 影响的行数 |
| 124 | 124 | */ |
| 125 | 125 | int updateSkuPropertyValue(Long propertyValueId, String propertyValueName); |
| 126 | + | |
| 126 | 127 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityBaseVO.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity; |
| 2 | 2 | |
| 3 | -import com.fasterxml.jackson.annotation.JsonFormat; | |
| 4 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 4 | import lombok.Data; |
| 6 | 5 | import org.springframework.format.annotation.DateTimeFormat; |
| 7 | 6 | |
| 8 | -import javax.validation.constraints.Min; | |
| 9 | 7 | import javax.validation.constraints.NotNull; |
| 10 | 8 | import java.time.LocalDateTime; |
| 11 | 9 | import java.util.List; |
| 12 | 10 | |
| 13 | 11 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 14 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; | |
| 15 | 12 | |
| 16 | 13 | /** |
| 17 | 14 | * 秒杀活动基地签证官 |
| ... | ... | @@ -23,18 +20,14 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE |
| 23 | 20 | @Data |
| 24 | 21 | public class SeckillActivityBaseVO { |
| 25 | 22 | |
| 26 | - @Schema(description = "秒杀活动商品", requiredMode = Schema.RequiredMode.REQUIRED, example = "121") | |
| 23 | + @Schema(description = "秒杀活动商品id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[121,1212]") | |
| 27 | 24 | @NotNull(message = "秒杀活动商品不能为空") |
| 28 | - private Long spuId; | |
| 25 | + private List<Long> spuIds; | |
| 29 | 26 | |
| 30 | 27 | @Schema(description = "秒杀活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促") |
| 31 | 28 | @NotNull(message = "秒杀活动名称不能为空") |
| 32 | 29 | private String name; |
| 33 | 30 | |
| 34 | - @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | |
| 35 | - @NotNull(message = "活动状态 开启:0 禁用:1不能为空") | |
| 36 | - private Integer status; | |
| 37 | - | |
| 38 | 31 | @Schema(description = "备注", example = "清仓大甩卖割韭菜") |
| 39 | 32 | private String remark; |
| 40 | 33 | |
| ... | ... | @@ -52,8 +45,8 @@ public class SeckillActivityBaseVO { |
| 52 | 45 | @NotNull(message = "排序不能为空") |
| 53 | 46 | private Integer sort; |
| 54 | 47 | |
| 55 | - @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 56 | - @NotNull(message = "秒杀时段id不能为空") | |
| 48 | + @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3]") | |
| 49 | + @NotNull(message = "秒杀时段不能为空") | |
| 57 | 50 | private List<Long> configIds; |
| 58 | 51 | |
| 59 | 52 | @Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12877") | ... | ... |
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; |
| 6 | 6 | import lombok.EqualsAndHashCode; |
| 7 | 7 | import lombok.ToString; |
| 8 | 8 | |
| 9 | -import java.time.LocalDateTime; | |
| 10 | 9 | import java.util.List; |
| 11 | 10 | |
| 12 | 11 | /** |
| ... | ... | @@ -24,8 +23,10 @@ public class SeckillActivityRespVO extends SeckillActivityBaseVO { |
| 24 | 23 | private Long id; |
| 25 | 24 | |
| 26 | 25 | @Schema(description = "秒杀商品", requiredMode = Schema.RequiredMode.REQUIRED) |
| 27 | - private List<SeckillProductRespVO> products; | |
| 26 | + private List<SeckillProductRespVO> products; // TODO puhui: 考虑是否去除 | |
| 28 | 27 | |
| 28 | + @Schema(description = "活动状态 开启:0 禁用:1", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | |
| 29 | + private Integer status; | |
| 29 | 30 | |
| 30 | 31 | |
| 31 | 32 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductBaseVO.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product; |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | |
| 5 | -import java.time.LocalDateTime; | |
| 6 | -import javax.validation.constraints.*; | |
| 7 | -import org.springframework.format.annotation.DateTimeFormat; | |
| 4 | +import lombok.Data; | |
| 8 | 5 | |
| 9 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 6 | +import javax.validation.constraints.NotNull; | |
| 10 | 7 | |
| 11 | 8 | /** |
| 12 | 9 | * 秒杀参与商品 Base VO,提供给添加、修改、详细的子 VO 使用 |
| ... | ... | @@ -17,15 +14,7 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ |
| 17 | 14 | @Data |
| 18 | 15 | public class SeckillProductBaseVO { |
| 19 | 16 | |
| 20 | - @Schema(description = "秒杀活动id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20173") | |
| 21 | - @NotNull(message = "秒杀活动id不能为空") | |
| 22 | - private Long activityId; | |
| 23 | - | |
| 24 | - @Schema(description = "秒杀时段id", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 25 | - @NotNull(message = "秒杀时段id不能为空") | |
| 26 | - private String configIds; | |
| 27 | - | |
| 28 | - @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "10290") | |
| 17 | + @Schema(description = "商品spu_id", requiredMode = Schema.RequiredMode.REQUIRED, example = "30563") | |
| 29 | 18 | @NotNull(message = "商品spu_id不能为空") |
| 30 | 19 | private Long spuId; |
| 31 | 20 | |
| ... | ... | @@ -41,18 +30,5 @@ public class SeckillProductBaseVO { |
| 41 | 30 | @NotNull(message = "秒杀库存不能为空") |
| 42 | 31 | private Integer stock; |
| 43 | 32 | |
| 44 | - @Schema(description = "秒杀商品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 45 | - @NotNull(message = "秒杀商品状态不能为空") | |
| 46 | - private Integer activityStatus; | |
| 47 | - | |
| 48 | - @Schema(description = "活动开始时间点", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 49 | - @NotNull(message = "活动开始时间点不能为空") | |
| 50 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 51 | - private LocalDateTime activityStartTime; | |
| 52 | - | |
| 53 | - @Schema(description = "活动结束时间点", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 54 | - @NotNull(message = "活动结束时间点不能为空") | |
| 55 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 56 | - private LocalDateTime activityEndTime; | |
| 57 | 33 | |
| 58 | 34 | } | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 6 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; |
| 6 | 7 | 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. |
| 12 | 13 | import org.mapstruct.Mapper; |
| 13 | 14 | import org.mapstruct.factory.Mappers; |
| 14 | 15 | |
| 16 | +import java.util.ArrayList; | |
| 15 | 17 | import java.util.List; |
| 16 | 18 | |
| 17 | 19 | /** |
| ... | ... | @@ -47,7 +49,7 @@ public interface SeckillActivityConvert { |
| 47 | 49 | * @return 是否匹配 |
| 48 | 50 | */ |
| 49 | 51 | default boolean isEquals(SeckillProductDO productDO, SeckillProductCreateReqVO productVO) { |
| 50 | - return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId()) | |
| 52 | + return ObjectUtil.equals(productDO.getSpuId(), 1) // TODO puhui:再看看 | |
| 51 | 53 | && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId()) |
| 52 | 54 | && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice()); |
| 53 | 55 | //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota()) |
| ... | ... | @@ -65,9 +67,25 @@ public interface SeckillActivityConvert { |
| 65 | 67 | return ObjectUtil.equals(productDO.getSpuId(), productVO.getSpuId()) |
| 66 | 68 | && ObjectUtil.equals(productDO.getSkuId(), productVO.getSkuId()) |
| 67 | 69 | && ObjectUtil.equals(productDO.getSeckillPrice(), productVO.getSeckillPrice()); |
| 68 | - //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota()) | |
| 69 | - //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount()); | |
| 70 | + //&& ObjectUtil.equals(productDO.getQuota(), productVO.getQuota()) | |
| 71 | + //&& ObjectUtil.equals(productDO.getLimitCount(), productVO.getLimitCount()); | |
| 70 | 72 | |
| 71 | 73 | } |
| 72 | 74 | |
| 75 | + default List<SeckillProductDO> convertList(SeckillActivityDO seckillActivity, List<SeckillProductCreateReqVO> products) { | |
| 76 | + List<SeckillProductDO> list = new ArrayList<>(); | |
| 77 | + products.forEach(sku -> { | |
| 78 | + SeckillProductDO productDO = new SeckillProductDO(); | |
| 79 | + productDO.setActivityId(seckillActivity.getId()); | |
| 80 | + productDO.setConfigIds(seckillActivity.getConfigIds()); | |
| 81 | + productDO.setSpuId(sku.getSpuId()); | |
| 82 | + productDO.setSkuId(sku.getSkuId()); | |
| 83 | + productDO.setSeckillPrice(sku.getSeckillPrice()); | |
| 84 | + productDO.setStock(sku.getStock()); | |
| 85 | + productDO.setActivityStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 86 | + productDO.setActivityStartTime(seckillActivity.getStartTime()); | |
| 87 | + productDO.setActivityEndTime(seckillActivity.getEndTime()); | |
| 88 | + }); | |
| 89 | + return list; | |
| 90 | + } | |
| 73 | 91 | } | ... | ... |
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 |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 5 | 5 | import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; |
| 6 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | |
| 7 | 6 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | 7 | import com.baomidou.mybatisplus.annotation.TableField; |
| 9 | 8 | import com.baomidou.mybatisplus.annotation.TableId; |
| ... | ... | @@ -35,7 +34,8 @@ public class SeckillActivityDO extends BaseDO { |
| 35 | 34 | /** |
| 36 | 35 | * 秒杀活动商品 |
| 37 | 36 | */ |
| 38 | - private Long spuId; | |
| 37 | + @TableField(typeHandler = LongListTypeHandler.class) | |
| 38 | + private List<Long> spuIds; | |
| 39 | 39 | /** |
| 40 | 40 | * 秒杀活动名称 |
| 41 | 41 | */ | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillProductDO.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; | |
| 6 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 3 | 10 | import lombok.*; |
| 11 | + | |
| 4 | 12 | import java.time.LocalDateTime; |
| 5 | -import com.baomidou.mybatisplus.annotation.*; | |
| 6 | -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 13 | +import java.util.List; | |
| 7 | 14 | |
| 8 | 15 | /** |
| 9 | 16 | * 秒杀参与商品 DO |
| ... | ... | @@ -32,7 +39,8 @@ public class SeckillProductDO extends BaseDO { |
| 32 | 39 | /** |
| 33 | 40 | * 秒杀时段 id |
| 34 | 41 | */ |
| 35 | - private String configIds; | |
| 42 | + @TableField(typeHandler = LongListTypeHandler.class) | |
| 43 | + private List<Long> configIds; | |
| 36 | 44 | /** |
| 37 | 45 | * 商品 spu_id |
| 38 | 46 | */ |
| ... | ... | @@ -51,6 +59,7 @@ public class SeckillProductDO extends BaseDO { |
| 51 | 59 | private Integer stock; |
| 52 | 60 | /** |
| 53 | 61 | * 秒杀商品状态 |
| 62 | + * 枚举 {@link CommonStatusEnum 对应的类} | |
| 54 | 63 | */ |
| 55 | 64 | private Integer activityStatus; |
| 56 | 65 | /** | ... | ... |
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 |
| 8 | 8 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; |
| 9 | 9 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 10 | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 11 | 13 | /** |
| 12 | 14 | * 秒杀活动 Mapper |
| 13 | 15 | * |
| ... | ... | @@ -23,4 +25,9 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> { |
| 23 | 25 | .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0") |
| 24 | 26 | .orderByDesc(SeckillActivityDO::getId)); |
| 25 | 27 | } |
| 28 | + | |
| 29 | + default List<SeckillActivityDO> selectListByStatus(Integer status) { | |
| 30 | + return selectList(new LambdaQueryWrapperX<SeckillActivityDO>() | |
| 31 | + .eqIfPresent(SeckillActivityDO::getStatus, status)); | |
| 32 | + } | |
| 26 | 33 | } | ... | ... |
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 { |
| 52 | 52 | |
| 53 | 53 | // 插入活动 |
| 54 | 54 | DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) |
| 55 | - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime())); | |
| 55 | + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); | |
| 56 | 56 | discountActivityMapper.insert(discountActivity); |
| 57 | 57 | // 插入商品 |
| 58 | 58 | List<DiscountProductDO> discountProducts = convertList(createReqVO.getProducts(), |
| ... | ... | @@ -74,7 +74,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { |
| 74 | 74 | |
| 75 | 75 | // 更新活动 |
| 76 | 76 | DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO) |
| 77 | - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime())); | |
| 77 | + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); | |
| 78 | 78 | discountActivityMapper.updateById(updateObj); |
| 79 | 79 | // 更新商品 |
| 80 | 80 | updateDiscountProduct(updateReqVO); | ... | ... |
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 { |
| 41 | 41 | |
| 42 | 42 | // 插入 |
| 43 | 43 | RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO) |
| 44 | - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime())); | |
| 44 | + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); | |
| 45 | 45 | rewardActivityMapper.insert(rewardActivity); |
| 46 | 46 | // 返回 |
| 47 | 47 | return rewardActivity.getId(); |
| ... | ... | @@ -59,7 +59,7 @@ public class RewardActivityServiceImpl implements RewardActivityService { |
| 59 | 59 | |
| 60 | 60 | // 更新 |
| 61 | 61 | RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO) |
| 62 | - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime())); | |
| 62 | + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); | |
| 63 | 63 | rewardActivityMapper.updateById(updateObj); |
| 64 | 64 | } |
| 65 | 65 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.util.ArrayUtil; | |
| 4 | 5 | import cn.hutool.core.util.ObjectUtil; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | 8 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 8 | -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityBaseVO; | |
| 9 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | |
| 10 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | |
| 11 | +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | |
| 12 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | |
| 9 | 13 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; |
| 10 | 14 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; |
| 11 | 15 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; |
| 12 | 16 | import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; |
| 13 | -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductCreateReqVO; | |
| 14 | 17 | import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; |
| 15 | 18 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; |
| 16 | 19 | import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; |
| ... | ... | @@ -25,8 +28,12 @@ import org.springframework.validation.annotation.Validated; |
| 25 | 28 | import javax.annotation.Resource; |
| 26 | 29 | import java.util.Collection; |
| 27 | 30 | import java.util.List; |
| 31 | +import java.util.Set; | |
| 32 | +import java.util.stream.Collectors; | |
| 28 | 33 | |
| 29 | 34 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 35 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | |
| 36 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS; | |
| 30 | 37 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; |
| 31 | 38 | import static java.util.Arrays.asList; |
| 32 | 39 | |
| ... | ... | @@ -45,40 +52,94 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 45 | 52 | private SeckillProductMapper seckillProductMapper; |
| 46 | 53 | @Resource |
| 47 | 54 | private SeckillConfigService seckillConfigService; |
| 55 | + @Resource | |
| 56 | + private ProductSpuApi productSpuApi; | |
| 57 | + @Resource | |
| 58 | + private ProductSkuApi productSkuApi; | |
| 48 | 59 | |
| 49 | 60 | @Override |
| 50 | 61 | public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) { |
| 51 | - // 校验商品是否冲突 | |
| 52 | - validateSeckillActivityProductConflicts(null, createReqVO.getProducts()); | |
| 53 | - // 校验秒杀时段是否存在 | |
| 54 | - seckillConfigService.validateSeckillConfigExists(createReqVO.getConfigIds()); | |
| 62 | + // 校验商品秒秒杀时段是否冲突 | |
| 63 | + validateProductSpuSeckillConflict(createReqVO.getConfigIds(), createReqVO.getSpuIds()); | |
| 64 | + // 校验商品 sku 是否存在 | |
| 65 | + validateProductSkuExistence(createReqVO.getSpuIds(), createReqVO.getProducts()); | |
| 55 | 66 | |
| 56 | - // 插入秒杀活动 TODO 活动日期拼接上秒杀时段 -> 2023-06-08 09:00:00 | |
| 67 | + // 插入秒杀活动 | |
| 57 | 68 | SeckillActivityDO seckillActivity = SeckillActivityConvert.INSTANCE.convert(createReqVO) |
| 58 | - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime())); | |
| 69 | + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime())); | |
| 59 | 70 | seckillActivityMapper.insert(seckillActivity); |
| 60 | 71 | // 插入商品 |
| 61 | - //List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), seckillActivity); | |
| 62 | - //seckillProductMapper.insertBatch(productDOs); | |
| 72 | + List<SeckillProductDO> productDOs = SeckillActivityConvert.INSTANCE.convertList(seckillActivity, createReqVO.getProducts()); | |
| 73 | + seckillProductMapper.insertBatch(productDOs); | |
| 63 | 74 | return seckillActivity.getId(); |
| 64 | 75 | } |
| 65 | 76 | |
| 77 | + private <T extends SeckillProductBaseVO> void validateProductSkuExistence(List<Long> spuIds, List<T> products) { | |
| 78 | + Set<Long> convertedSpuIds = CollectionUtils.convertSet(products, T::getSpuId); | |
| 79 | + // 校验 spu 个数是否相等 | |
| 80 | + if (ObjectUtil.notEqual(spuIds.size(), convertedSpuIds.size())) { | |
| 81 | + throw exception(SKU_NOT_EXISTS); | |
| 82 | + } | |
| 83 | + // 获取所选 spu下的所有 sku | |
| 84 | + List<ProductSkuRespDTO> skuRespDTOs = productSkuApi.getSkuListBySpuId(spuIds); | |
| 85 | + // 校验 sku 个数是否一致 | |
| 86 | + Set<Long> skuIdsSet = CollectionUtils.convertSet(products, T::getSkuId); | |
| 87 | + Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skuRespDTOs, ProductSkuRespDTO::getId); | |
| 88 | + if (ObjectUtil.notEqual(skuIdsSet.size(), skuIdsSet1.size())) { | |
| 89 | + throw exception(SKU_NOT_EXISTS); | |
| 90 | + } | |
| 91 | + // 校验 skuId 是否存在 | |
| 92 | + if (!skuIdsSet1.containsAll(skuIdsSet) || !skuIdsSet.containsAll(skuIdsSet1)) { | |
| 93 | + throw exception(SKU_NOT_EXISTS); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + private void validateProductSpuSeckillConflict(List<Long> configIds, List<Long> spuIds) { | |
| 98 | + // 校验秒杀时段是否存在 | |
| 99 | + seckillConfigService.validateSeckillConfigExists(configIds); | |
| 100 | + // 校验商品 spu 是否存在 | |
| 101 | + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds); | |
| 102 | + if (ObjectUtil.notEqual(spuIds.size(), spuList.size())) { | |
| 103 | + throw exception(SPU_NOT_EXISTS); | |
| 104 | + } | |
| 105 | + // 查询所有开启的秒杀活动 | |
| 106 | + List<SeckillActivityDO> activityDOs = seckillActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 107 | + // 过滤出所有 spuIds 有交集的活动 | |
| 108 | + List<SeckillActivityDO> doList = activityDOs.stream().filter(s -> { | |
| 109 | + // 判断 spu 是否有交集 | |
| 110 | + List<Long> spuIdsClone = ArrayUtil.clone(s.getSpuIds()); | |
| 111 | + spuIdsClone.retainAll(spuIds); | |
| 112 | + if (CollUtil.isEmpty(spuIdsClone)) { | |
| 113 | + return false; | |
| 114 | + } | |
| 115 | + // 判断秒杀时段是否有交集 | |
| 116 | + List<Long> configIdsClone = ArrayUtil.clone(s.getConfigIds()); | |
| 117 | + configIdsClone.retainAll(configIds); | |
| 118 | + return CollUtil.isNotEmpty(configIdsClone); | |
| 119 | + }).collect(Collectors.toList()); | |
| 120 | + if (CollUtil.isNotEmpty(doList)) { | |
| 121 | + throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); | |
| 122 | + } | |
| 123 | + } | |
| 124 | + | |
| 66 | 125 | @Override |
| 67 | 126 | public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) { |
| 68 | 127 | // 校验存在 |
| 69 | 128 | SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId()); |
| 70 | - if (PromotionActivityStatusEnum.CLOSE.getStatus().equals(seckillActivity.getStatus())) { | |
| 129 | + if (CommonStatusEnum.ENABLE.getStatus().equals(seckillActivity.getStatus())) { | |
| 71 | 130 | throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); |
| 72 | 131 | } |
| 73 | 132 | // 校验商品是否冲突 |
| 74 | - validateSeckillActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); | |
| 133 | + validateProductSpuSeckillConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuIds()); | |
| 134 | + // 校验商品 sku 是否存在 | |
| 135 | + validateProductSkuExistence(updateReqVO.getSpuIds(), updateReqVO.getProducts()); | |
| 75 | 136 | |
| 76 | 137 | // 更新活动 |
| 77 | 138 | SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO) |
| 78 | - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime())); | |
| 139 | + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); | |
| 79 | 140 | seckillActivityMapper.updateById(updateObj); |
| 80 | 141 | // 更新商品 |
| 81 | - updateSeckillProduct(updateReqVO); | |
| 142 | + //updateSeckillProduct(updateReqVO); | |
| 82 | 143 | } |
| 83 | 144 | |
| 84 | 145 | |
| ... | ... | @@ -92,10 +153,11 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 92 | 153 | * @param updateReqVO 更新的请求VO |
| 93 | 154 | */ |
| 94 | 155 | private void updateSeckillProduct(SeckillActivityUpdateReqVO updateReqVO) { |
| 95 | - List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId()); | |
| 96 | - //List<SeckillActivityBaseVO.Product> products = updateReqVO.getProducts(); | |
| 156 | + // TODO puhui999:后续完善 | |
| 157 | + //List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateReqVO.getId()); | |
| 158 | + //List<SeckillProductUpdateReqVO> products = updateReqVO.getProducts(); | |
| 97 | 159 | |
| 98 | - // 计算需要删除的数据 | |
| 160 | + ////计算需要删除的数据 | |
| 99 | 161 | //List<Long> deleteIds = CollectionUtils.convertList(seckillProductDOs, SeckillProductDO::getId, |
| 100 | 162 | // seckillProductDO -> products.stream() |
| 101 | 163 | // .noneMatch(product -> SeckillActivityConvert.INSTANCE.isEquals(seckillProductDO, product))); |
| ... | ... | @@ -116,37 +178,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { |
| 116 | 178 | seckillProductMapper.updateTimeIdsByActivityId(updateReqVO.getId(), updateReqVO.getConfigIds()); |
| 117 | 179 | } |
| 118 | 180 | |
| 119 | - /** | |
| 120 | - * 校验商品是否冲突 | |
| 121 | - * | |
| 122 | - * @param id 秒杀活动编号 | |
| 123 | - * @param products 商品列表 | |
| 124 | - */ | |
| 125 | - private <T extends SeckillProductBaseVO> void validateSeckillActivityProductConflicts(Long id, List<T> products) { | |
| 126 | - if (CollUtil.isEmpty(products)) { | |
| 127 | - return; | |
| 128 | - } | |
| 129 | - // 校验秒杀商品是否存在 | |
| 130 | - List<SeckillProductDO> seckillProductDOs = seckillProductMapper | |
| 131 | - .selectListBySkuIds(CollectionUtils.convertSet(products, T::getSkuId)); | |
| 132 | - if (CollUtil.isEmpty(seckillProductDOs)) { | |
| 133 | - return; | |
| 134 | - } | |
| 135 | - // 获取秒杀商品所在活动 | |
| 136 | - List<SeckillActivityDO> seckillActivityDOs = seckillActivityMapper | |
| 137 | - .selectBatchIds(CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getActivityId)); | |
| 138 | - if (id != null) { | |
| 139 | - // 排除自己这个活动 | |
| 140 | - seckillActivityDOs.removeIf(item -> id.equals(item.getId())); | |
| 141 | - } | |
| 142 | - // 排除关闭了的活动 | |
| 143 | - seckillActivityDOs.removeIf(item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.DISABLE.getStatus())); | |
| 144 | - // 如果非空,则说明冲突 | |
| 145 | - if (CollUtil.isNotEmpty(seckillActivityDOs)) { | |
| 146 | - throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS); | |
| 147 | - } | |
| 148 | - } | |
| 149 | - | |
| 150 | 181 | @Override |
| 151 | 182 | public void closeSeckillActivity(Long id) { |
| 152 | 183 | // 校验存在 | ... | ... |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
| 1 | 1 | package cn.iocoder.yudao.module.promotion.util; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; |
| 4 | -import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; | |
| 5 | 5 | |
| 6 | 6 | import java.time.LocalDateTime; |
| 7 | 7 | |
| ... | ... | @@ -15,18 +15,11 @@ public class PromotionUtils { |
| 15 | 15 | /** |
| 16 | 16 | * 根据时间,计算活动状态 |
| 17 | 17 | * |
| 18 | - * @param startTime 开始时间 | |
| 19 | 18 | * @param endTime 结束时间 |
| 20 | 19 | * @return 活动状态 |
| 21 | 20 | */ |
| 22 | - public static Integer calculateActivityStatus(LocalDateTime startTime, LocalDateTime endTime) { | |
| 23 | - if (LocalDateTimeUtils.beforeNow(endTime)) { | |
| 24 | - return PromotionActivityStatusEnum.END.getStatus(); | |
| 25 | - } | |
| 26 | - if (LocalDateTimeUtils.afterNow(startTime)) { | |
| 27 | - return PromotionActivityStatusEnum.WAIT.getStatus(); | |
| 28 | - } | |
| 29 | - return PromotionActivityStatusEnum.RUN.getStatus(); | |
| 21 | + public static Integer calculateActivityStatus(LocalDateTime endTime) { | |
| 22 | + return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus(); | |
| 30 | 23 | } |
| 31 | 24 | |
| 32 | 25 | } | ... | ... |