Commit a1e9bedf343f05c4cf2f654ca0189db00af561ae

Authored by YunaiV
1 parent ac55a965

promotion:完善秒杀的 uniapp 接口

yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
... ... @@ -79,7 +79,8 @@ public class LocalDateTimeUtils {
79 79 return false;
80 80 }
81 81 LocalDate nowDate = LocalDate.now();
82   - return LocalDateTimeUtil.isIn(LocalDateTime.now(), LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
  82 + return LocalDateTimeUtil.isIn(LocalDateTime.now(),
  83 + LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
83 84 LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
84 85 }
85 86  
... ... @@ -99,46 +100,6 @@ public class LocalDateTimeUtils {
99 100 }
100 101  
101 102 /**
102   - * 构建日期时间 TODO 后面有需要的话再继续扩展
103   - *
104   - * @author HUIHUI
105   - */
106   - public static class BuilderDateTime {
107   -
108   - /**
109   - * 日期;2023-10-01
110   - */
111   - private String localDate;
112   - /**
113   - * 时间;10:01:00
114   - */
115   - private String localTime;
116   -
117   - public BuilderDateTime() {
118   - }
119   -
120   - public BuilderDateTime withDate(String date) {
121   - this.localDate = date;
122   - return this;
123   - }
124   -
125   - public BuilderDateTime withDate(LocalDateTime date) {
126   - this.localDate = LocalDateTimeUtil.format(date, "yyyy-MM-dd");
127   - return this;
128   - }
129   -
130   - public BuilderDateTime withTime(String time) {
131   - this.localTime = time;
132   - return this;
133   - }
134   -
135   - public LocalDateTime build() {
136   - return LocalDateTimeUtil.parse(this.localDate + " " + this.localTime, "yyyy-MM-dd HH:mm:ss");
137   - }
138   -
139   - }
140   -
141   - /**
142 103 * 获取指定日期所在的月份的开始时间
143 104 * 例如:2023-09-30 00:00:00,000
144 105 *
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
5 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
8 9 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
9 10 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
10 11 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
... ... @@ -13,10 +14,12 @@ import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppS
13 14 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
14 15 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
15 16 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
16   -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
17 17 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
  18 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
18 19 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
19 20 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
  21 +import com.google.common.cache.CacheLoader;
  22 +import com.google.common.cache.LoadingCache;
20 23 import io.swagger.v3.oas.annotations.Operation;
21 24 import io.swagger.v3.oas.annotations.Parameter;
22 25 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -28,16 +31,37 @@ import org.springframework.web.bind.annotation.RequestParam;
28 31 import org.springframework.web.bind.annotation.RestController;
29 32  
30 33 import javax.annotation.Resource;
  34 +import java.time.Duration;
  35 +import java.time.LocalDate;
  36 +import java.time.LocalDateTime;
  37 +import java.time.LocalTime;
31 38 import java.util.List;
32 39  
33 40 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  41 +import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
34 42 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  43 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst;
  44 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
35 45  
36 46 @Tag(name = "用户 App - 秒杀活动")
37 47 @RestController
38 48 @RequestMapping("/promotion/seckill-activity")
39 49 @Validated
40 50 public class AppSeckillActivityController {
  51 +
  52 + /**
  53 + * {@link AppSeckillActivityNowRespVO} 缓存,通过它异步刷新 {@link #getNowSeckillActivity()} 所要的首页数据
  54 + */
  55 + private final LoadingCache<String, AppSeckillActivityNowRespVO> nowSeckillActivityCache = buildAsyncReloadingCache(Duration.ofSeconds(10L),
  56 + new CacheLoader<String, AppSeckillActivityNowRespVO>() {
  57 +
  58 + @Override
  59 + public AppSeckillActivityNowRespVO load(String key) {
  60 + return getNowSeckillActivity0();
  61 + }
  62 +
  63 + });
  64 +
41 65 @Resource
42 66 private SeckillActivityService activityService;
43 67 @Resource
... ... @@ -47,21 +71,25 @@ public class AppSeckillActivityController {
47 71 @Resource
48 72 private ProductSpuApi spuApi;
49 73  
50   - // TODO 芋艿:需要增加 spring cache
51 74 @GetMapping("/get-now")
52 75 @Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用")
53 76 public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
  77 + return success(nowSeckillActivityCache.getUnchecked(""));
  78 + }
  79 +
  80 + private AppSeckillActivityNowRespVO getNowSeckillActivity0() {
54 81 // 1. 获取当前时间处在哪个秒杀阶段
55   - SeckillConfigDO configList = configService.getSeckillConfigListByStatusOnCurrentTime(CommonStatusEnum.ENABLE.getStatus());
56   - if (configList == null) { // 时段不存在直接返回 null
57   - return success(null);
  82 + SeckillConfigDO config = configService.getCurrentSeckillConfig();
  83 + if (config == null) { // 时段不存在直接返回 null
  84 + return new AppSeckillActivityNowRespVO();
58 85 }
59 86  
60   - // 2. 查询满足当前阶段的活动
61   - List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIdAndStatus(configList.getId(), CommonStatusEnum.ENABLE.getStatus());
62   - // 3 获取 spu 信息
  87 + // 2.1 查询满足当前阶段的活动
  88 + List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIdAndStatus(config.getId(), CommonStatusEnum.ENABLE.getStatus());
  89 + List<SeckillProductDO> productList = activityService.getSeckillProductListByActivityId(convertList(activityList, SeckillActivityDO::getId));
  90 + // 2.2 获取 spu 信息
63 91 List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(activityList, SeckillActivityDO::getSpuId));
64   - return success(SeckillActivityConvert.INSTANCE.convert(configList, activityList, spuList));
  92 + return SeckillActivityConvert.INSTANCE.convert(config, activityList, productList, spuList);
65 93 }
66 94  
67 95 @GetMapping("/page")
... ... @@ -72,31 +100,52 @@ public class AppSeckillActivityController {
72 100 if (CollUtil.isEmpty(pageResult.getList())) {
73 101 return success(PageResult.empty(pageResult.getTotal()));
74 102 }
  103 + List<SeckillProductDO> productList = activityService.getSeckillProductListByActivityId(
  104 + convertList(pageResult.getList(), SeckillActivityDO::getId));
  105 +
75 106 // 2. 拼接数据
76 107 List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
77   - return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
  108 + return success(SeckillActivityConvert.INSTANCE.convertPage02(pageResult, productList, spuList));
78 109 }
79 110  
80 111 @GetMapping("/get-detail")
81 112 @Operation(summary = "获得秒杀活动明细")
82 113 @Parameter(name = "id", description = "活动编号", required = true, example = "1024")
83 114 public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
84   - // 1. 获取当前时间处在哪个秒杀阶段
85   - SeckillConfigDO configList = configService.getSeckillConfigListByStatusOnCurrentTime(CommonStatusEnum.ENABLE.getStatus());
86   - if (configList == null) { // 时段不存在直接返回 null
  115 + // 1. 获取活动
  116 + SeckillActivityDO activity = activityService.getSeckillActivity(id);
  117 + if (activity == null
  118 + || ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
87 119 return success(null);
88 120 }
89 121  
90   - // 2. 获取活动
91   - SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
92   - if (seckillActivity == null
93   - || ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
94   - return success(null);
  122 + // 2. 获取时间段
  123 + List<SeckillConfigDO> configs = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
  124 + configs.removeIf(config -> !CollUtil.contains(activity.getConfigIds(), config.getId()));
  125 + // 2.1 优先使用当前时间段
  126 + SeckillConfigDO config = findFirst(configs, config0 -> isBetween(config0.getStartTime(), config0.getEndTime()));
  127 + // 2.2 如果没有,则获取最后一个,因为倾向优先展示“未开始” > “已结束”
  128 + if (config == null) {
  129 + config = CollUtil.getLast(configs);
  130 + }
  131 + if (config == null) {
  132 + return null;
  133 + }
  134 + // 3. 计算开始时间、结束时间
  135 + LocalDate nowDate;
  136 + // 3.1 如果在活动日期范围内,则以今天为 nowDate
  137 + if (LocalDateTimeUtils.isBetween(activity.getStartTime(), activity.getEndTime())) {
  138 + nowDate = LocalDate.now();
  139 + } else {
  140 + // 3.2 如果不在活动时间范围内,则直接以活动的 endTime 作为 nowDate,因为还是倾向优先展示“未开始” > “已结束”
  141 + nowDate = activity.getEndTime().toLocalDate();
95 142 }
  143 + LocalDateTime startTime = LocalDateTime.of(nowDate, LocalTime.parse(config.getStartTime()));
  144 + LocalDateTime endTime = LocalDateTime.of(nowDate, LocalTime.parse(config.getEndTime()));
96 145  
97   - // 3. 拼接数据
98   - List<SeckillProductDO> productList = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
99   - return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, productList, configList));
  146 + // 4. 拼接数据
  147 + List<SeckillProductDO> productList = activityService.getSeckillProductListByActivityId(activity.getId());
  148 + return success(SeckillActivityConvert.INSTANCE.convert3(activity, productList, startTime, endTime));
100 149 }
101 150  
102 151 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 5 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
6 6 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
7 8 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
8 9 import io.swagger.v3.oas.annotations.Operation;
9 10 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -28,8 +29,8 @@ public class AppSeckillConfigController {
28 29 @GetMapping("/list")
29 30 @Operation(summary = "获得秒杀时间段列表")
30 31 public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
31   - return success(SeckillConfigConvert.INSTANCE.convertList2(
32   - configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus())));
  32 + List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
  33 + return success(SeckillConfigConvert.INSTANCE.convertList2(list));
33 34 }
34 35  
35 36 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java
... ... @@ -19,8 +19,6 @@ public class AppSeckillActivityDetailRespVO {
19 19 @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 20 private Integer status;
21 21  
22   - // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈;
23   -
24 22 @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
25 23 private LocalDateTime startTime;
26 24  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
6   -import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
7 6 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
8 7 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
9 8 import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
... ... @@ -19,17 +18,18 @@ import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppS
19 18 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
20 19 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
21 20 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
22   -import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
23 21 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
  22 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
24 23 import org.mapstruct.Mapper;
25 24 import org.mapstruct.Mapping;
26 25 import org.mapstruct.Mappings;
27 26 import org.mapstruct.factory.Mappers;
28 27  
  28 +import java.time.LocalDateTime;
29 29 import java.util.List;
30 30 import java.util.Map;
31 31  
32   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  32 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
33 33 import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
34 34  
35 35 /**
... ... @@ -93,16 +93,19 @@ public interface SeckillActivityConvert {
93 93  
94 94 List<AppSeckillActivityRespVO> convertList3(List<SeckillActivityDO> activityList);
95 95  
96   - default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List<SeckillActivityDO> activityList, List<ProductSpuRespDTO> spuList) {
  96 + default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List<SeckillActivityDO> activityList,
  97 + List<SeckillProductDO> productList, List<ProductSpuRespDTO> spuList) {
97 98 AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
98 99 respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig));
99 100 Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  101 + Map<Long, List<SeckillProductDO>> productMap = convertMultiMap(productList, SeckillProductDO::getActivityId);
100 102 respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> {
101   - findAndThen(spuMap, item.getSpuId(), spu -> {
102   - item.setPicUrl(spu.getPicUrl())
103   - .setMarketPrice(spu.getMarketPrice())
104   - .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
105   - });
  103 + // product 信息
  104 + item.setSeckillPrice(getMinValue(productMap.get(item.getId()), SeckillProductDO::getSeckillPrice));
  105 + // spu 信息
  106 + findAndThen(spuMap, item.getSpuId(), spu ->
  107 + item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())
  108 + .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit())));
106 109 return item;
107 110 }));
108 111 return respVO;
... ... @@ -110,10 +113,14 @@ public interface SeckillActivityConvert {
110 113  
111 114 PageResult<AppSeckillActivityRespVO> convertPage1(PageResult<SeckillActivityDO> pageResult);
112 115  
113   - default PageResult<AppSeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> pageResult, List<ProductSpuRespDTO> spuList) {
  116 + default PageResult<AppSeckillActivityRespVO> convertPage02(PageResult<SeckillActivityDO> pageResult, List<SeckillProductDO> productList, List<ProductSpuRespDTO> spuList) {
114 117 PageResult<AppSeckillActivityRespVO> result = convertPage1(pageResult);
115 118 Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  119 + Map<Long, List<SeckillProductDO>> productMap = convertMultiMap(productList, SeckillProductDO::getActivityId);
116 120 List<AppSeckillActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
  121 + // product 信息
  122 + item.setSeckillPrice(getMinValue(productMap.get(item.getId()), SeckillProductDO::getSeckillPrice));
  123 + // spu 信息
117 124 findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())
118 125 .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit())));
119 126 return item;
... ... @@ -126,17 +133,11 @@ public interface SeckillActivityConvert {
126 133  
127 134 List<AppSeckillActivityDetailRespVO.Product> convertList1(List<SeckillProductDO> products);
128 135  
129   - default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
130   - return convert2(seckillActivity)
  136 + default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO activity, List<SeckillProductDO> products,
  137 + LocalDateTime startTime, LocalDateTime endTime) {
  138 + return convert2(activity)
131 139 .setProducts(convertList1(products))
132   - .setStartTime(new LocalDateTimeUtils.BuilderDateTime()
133   - .withDate(seckillActivity.getStartTime())
134   - .withTime(filteredConfig.getStartTime())
135   - .build())// 活动开始日期和时段结合
136   - .setEndTime(new LocalDateTimeUtils.BuilderDateTime()
137   - .withDate(seckillActivity.getEndTime())
138   - .withTime(filteredConfig.getEndTime())
139   - .build()); // 活动结束日期和时段结合
  140 + .setStartTime(startTime).setEndTime(endTime);
140 141 }
141 142  
142 143 List<SeckillActivityProductRespDTO> convertList4(List<SeckillProductDO> seckillActivityProductList);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/SeckillActivityDO.java
... ... @@ -66,18 +66,7 @@ public class SeckillActivityDO extends BaseDO {
66 66 */
67 67 @TableField(typeHandler = LongListTypeHandler.class)
68 68 private List<Long> configIds;
69   - /**
70   - * 新增订单数
71   - */
72   - private Integer orderCount;
73   - /**
74   - * 付款人数
75   - */
76   - private Integer userCount;
77   - /**
78   - * 订单实付金额,单位:分
79   - */
80   - private Long totalPrice;
  69 +
81 70 /**
82 71 * 总限购数量
83 72 */
... ... @@ -86,6 +75,7 @@ public class SeckillActivityDO extends BaseDO {
86 75 * 单次限够数量
87 76 */
88 77 private Integer singleLimitCount;
  78 +
89 79 /**
90 80 * 秒杀库存(剩余库存秒杀时扣减)
91 81 */
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
... ... @@ -90,14 +90,6 @@ public interface SeckillActivityService {
90 90 List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
91 91  
92 92 /**
93   - * 通过活动时段获取秒杀活动
94   - *
95   - * @param ids 时段配置编号
96   - * @return 秒杀活动列表
97   - */
98   - List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids);
99   -
100   - /**
101 93 * 通过活动时段编号获取指定 status 的秒杀活动
102 94 *
103 95 * @param configId 时段配置编号
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
... ... @@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityD
18 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
19 19 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillActivityMapper;
20 20 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillactivity.SeckillProductMapper;
21   -import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
22 21 import org.springframework.stereotype.Service;
23 22 import org.springframework.transaction.annotation.Transactional;
24 23 import org.springframework.validation.annotation.Validated;
... ... @@ -60,17 +59,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
60 59 @Override
61 60 @Transactional(rollbackFor = Exception.class)
62 61 public Long createSeckillActivity(SeckillActivityCreateReqVO createReqVO) {
63   - // 校验商品秒杀时段是否冲突
  62 + // 1.1 校验商品秒杀时段是否冲突
64 63 validateProductConflict(createReqVO.getConfigIds(), createReqVO.getSpuId(), null);
65   - // 校验商品是否存在
  64 + // 1.2 校验商品是否存在
66 65 validateProductExists(createReqVO.getSpuId(), createReqVO.getProducts());
67 66  
68   - // 插入秒杀活动
  67 + // 2.1 插入秒杀活动
69 68 SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
70   - .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()))
71   - .setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
  69 + .setStatus(CommonStatusEnum.ENABLE.getStatus())
  70 + .setStock(getSumValue(createReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
  71 + activity.setTotalStock(activity.getStock());
72 72 seckillActivityMapper.insert(activity);
73   - // 插入商品
  73 + // 2.2 插入商品
74 74 List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
75 75 seckillProductMapper.insertBatch(products);
76 76 return activity.getId();
... ... @@ -128,22 +128,24 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
128 128 @Override
129 129 @Transactional(rollbackFor = Exception.class)
130 130 public void updateSeckillActivity(SeckillActivityUpdateReqVO updateReqVO) {
131   - // 校验存在
132   - SeckillActivityDO seckillActivity = validateSeckillActivityExists(updateReqVO.getId());
133   - if (CommonStatusEnum.DISABLE.getStatus().equals(seckillActivity.getStatus())) {
  131 + // 1.1 校验存在
  132 + SeckillActivityDO activity = validateSeckillActivityExists(updateReqVO.getId());
  133 + if (CommonStatusEnum.DISABLE.getStatus().equals(activity.getStatus())) {
134 134 throw exception(SECKILL_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
135 135 }
136   - // 校验商品是否冲突
  136 + // 1.2 校验商品是否冲突
137 137 validateProductConflict(updateReqVO.getConfigIds(), updateReqVO.getSpuId(), updateReqVO.getId());
138   - // 校验商品是否存在
  138 + // 1.3 校验商品是否存在
139 139 validateProductExists(updateReqVO.getSpuId(), updateReqVO.getProducts());
140 140  
141   - // 更新活动
  141 + // 2.1 更新活动
142 142 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
143   - .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()))
144   - .setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
  143 + .setStock(getSumValue(updateReqVO.getProducts(), SeckillProductBaseVO::getStock, Integer::sum));
  144 + if (updateObj.getStock() > activity.getTotalStock()) { // 如果更新的库存大于原来的库存,则更新总库存
  145 + updateObj.setTotalStock(updateObj.getStock());
  146 + }
145 147 seckillActivityMapper.updateById(updateObj);
146   - // 更新商品
  148 + // 2.2 更新商品
147 149 updateSeckillProduct(updateObj, updateReqVO.getProducts());
148 150 }
149 151  
... ... @@ -151,7 +153,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
151 153 @Transactional(rollbackFor = Exception.class)
152 154 public void updateSeckillStock(Long id, Long skuId, Integer count) {
153 155 // 1.1 校验活动库存是否充足
154   - SeckillActivityDO seckillActivity = getSeckillActivity(id);
  156 + SeckillActivityDO seckillActivity = validateSeckillActivityExists(id);
155 157 if (count > seckillActivity.getTotalStock()) {
156 158 throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
157 159 }
... ... @@ -243,7 +245,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
243 245  
244 246 @Override
245 247 public SeckillActivityDO getSeckillActivity(Long id) {
246   - return validateSeckillActivityExists(id);
  248 + return seckillActivityMapper.selectById(id);
247 249 }
248 250  
249 251 @Override
... ... @@ -262,12 +264,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
262 264 }
263 265  
264 266 @Override
265   - public List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids) {
266   - return filterList(seckillActivityMapper.selectList(),
267   - item -> anyMatch(item.getConfigIds(), ids::contains));
268   - }
269   -
270   - @Override
271 267 public List<SeckillActivityDO> getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status) {
272 268 return filterList(seckillActivityMapper.selectList(SeckillActivityDO::getStatus, status),
273 269 item -> anyMatch(item.getConfigIds(), id -> ObjectUtil.equal(id, configId)) // 校验时段
... ... @@ -289,7 +285,6 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
289 285 if (CollectionUtil.isEmpty(productList)) {
290 286 throw exception(SKU_NOT_EXISTS);
291 287 }
292   -
293 288 return productList;
294 289 }
295 290  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigService.java
... ... @@ -54,7 +54,6 @@ public interface SeckillConfigService {
54 54 */
55 55 List<SeckillConfigDO> getSeckillConfigList();
56 56  
57   -
58 57 /**
59 58 * 校验秒杀时段是否存在
60 59 *
... ... @@ -87,11 +86,12 @@ public interface SeckillConfigService {
87 86 void updateSeckillConfigStatus(Long id, Integer status);
88 87  
89 88 /**
90   - * 获取当前日期时间处于的秒杀时段且状态为 status
  89 + * 获得当前的秒杀时段
  90 + *
  91 + * 要求必须处于开启状态、且在当前时间段内
91 92 *
92   - * @param status 状态
93 93 * @return 时段
94 94 */
95   - SeckillConfigDO getSeckillConfigListByStatusOnCurrentTime(Integer status);
  95 + SeckillConfigDO getCurrentSeckillConfig();
96 96  
97 97 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillConfigServiceImpl.java
... ... @@ -17,6 +17,7 @@ import org.springframework.validation.annotation.Validated;
17 17 import javax.annotation.Resource;
18 18 import java.time.LocalTime;
19 19 import java.util.Collection;
  20 +import java.util.Comparator;
20 21 import java.util.List;
21 22  
22 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -70,9 +71,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
70 71 }
71 72  
72 73 @Override
73   - public SeckillConfigDO getSeckillConfigListByStatusOnCurrentTime(Integer status) {
74   - return findFirst(seckillConfigMapper.selectList(SeckillConfigDO::getStatus, status),
75   - config -> isBetween(config.getStartTime(), config.getEndTime()));
  74 + public SeckillConfigDO getCurrentSeckillConfig() {
  75 + List<SeckillConfigDO> list = seckillConfigMapper.selectList(SeckillConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
  76 + return findFirst(list, config -> isBetween(config.getStartTime(), config.getEndTime()));
76 77 }
77 78  
78 79 @Override
... ... @@ -151,7 +152,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
151 152  
152 153 @Override
153 154 public List<SeckillConfigDO> getSeckillConfigListByStatus(Integer status) {
154   - return seckillConfigMapper.selectListByStatus(status);
  155 + List<SeckillConfigDO> list = seckillConfigMapper.selectListByStatus(status);
  156 + list.sort(Comparator.comparing(SeckillConfigDO::getStartTime));
  157 + return list;
155 158 }
156 159  
157 160 }
... ...