Commit 408df683d8867330ca69adb09681f07653981b17

Authored by puhui999
1 parent af6016bb

秒杀活动: 完善 app 端获取活动分页、列表、详情接口

Showing 12 changed files with 217 additions and 101 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
@@ -43,6 +43,16 @@ public class LocalDateTimeUtils { @@ -43,6 +43,16 @@ public class LocalDateTimeUtils {
43 return LocalDateTime.of(year, mouth, day, 0, 0, 0); 43 return LocalDateTime.of(year, mouth, day, 0, 0, 0);
44 } 44 }
45 45
  46 + /**
  47 + * 创建指定时间
  48 + *
  49 + * @param timeStr 时间字符串
  50 + * @return 指定时间
  51 + */
  52 + public static LocalDateTime buildTime(String timeStr) {
  53 + return LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeStr));
  54 + }
  55 +
46 public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1, 56 public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
47 int year2, int mouth2, int day2) { 57 int year2, int mouth2, int day2) {
48 return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)}; 58 return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
@@ -63,6 +73,22 @@ public class LocalDateTimeUtils { @@ -63,6 +73,22 @@ public class LocalDateTimeUtils {
63 } 73 }
64 74
65 /** 75 /**
  76 + * 判断当前时间是否在该时间范围内
  77 + *
  78 + * @param startTime 开始时间
  79 + * @param endTime 结束时间
  80 + * @return 是否
  81 + */
  82 + public static boolean isBetween(String startTime, String endTime) {
  83 + if (startTime == null || endTime == null) {
  84 + return false;
  85 + }
  86 + LocalDate nowDate = LocalDate.now();
  87 + return LocalDateTimeUtil.isIn(LocalDateTime.now(), LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
  88 + LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
  89 + }
  90 +
  91 + /**
66 * 判断时间段是否重叠 92 * 判断时间段是否重叠
67 * 93 *
68 * @param startTime1 开始 time1 94 * @param startTime1 开始 time1
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -56,6 +56,7 @@ public interface ErrorCodeConstants { @@ -56,6 +56,7 @@ public interface ErrorCodeConstants {
56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除"); 56 ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭"); 57 ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
58 ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足"); 58 ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
  59 + ErrorCode SECKILL_ACTIVITY_FAIL_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
59 60
60 // ========== 秒杀时段 1013009000 ========== 61 // ========== 秒杀时段 1013009000 ==========
61 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在"); 62 ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillActivityController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.seckill; 1 package cn.iocoder.yudao.module.promotion.controller.app.seckill;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  9 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; 10 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
6 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; 11 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
7 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
8 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; 13 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
9 -import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; 14 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
  15 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
  16 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  17 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
  18 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
  19 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
10 import io.swagger.v3.oas.annotations.Operation; 20 import io.swagger.v3.oas.annotations.Operation;
11 import io.swagger.v3.oas.annotations.Parameter; 21 import io.swagger.v3.oas.annotations.Parameter;
12 import io.swagger.v3.oas.annotations.tags.Tag; 22 import io.swagger.v3.oas.annotations.tags.Tag;
  23 +import org.springframework.context.annotation.Lazy;
13 import org.springframework.validation.annotation.Validated; 24 import org.springframework.validation.annotation.Validated;
14 import org.springframework.web.bind.annotation.GetMapping; 25 import org.springframework.web.bind.annotation.GetMapping;
15 import org.springframework.web.bind.annotation.RequestMapping; 26 import org.springframework.web.bind.annotation.RequestMapping;
16 import org.springframework.web.bind.annotation.RequestParam; 27 import org.springframework.web.bind.annotation.RequestParam;
17 import org.springframework.web.bind.annotation.RestController; 28 import org.springframework.web.bind.annotation.RestController;
18 29
19 -import java.time.LocalDateTime;  
20 -import java.util.ArrayList; 30 +import javax.annotation.Resource;
  31 +import java.util.Arrays;
21 import java.util.List; 32 import java.util.List;
22 33
  34 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 35 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
  37 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst;
  38 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
  39 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_FAIL_STATUS_CLOSED;
24 40
25 @Tag(name = "用户 App - 秒杀活动") 41 @Tag(name = "用户 App - 秒杀活动")
26 @RestController 42 @RestController
27 @RequestMapping("/promotion/seckill-activity") 43 @RequestMapping("/promotion/seckill-activity")
28 @Validated 44 @Validated
29 public class AppSeckillActivityController { 45 public class AppSeckillActivityController {
  46 + @Resource
  47 + private SeckillActivityService activityService;
  48 + @Resource
  49 + @Lazy
  50 + private SeckillConfigService configService;
  51 +
  52 + @Resource
  53 + private ProductSpuApi spuApi;
30 54
31 @GetMapping("/get-now") 55 @GetMapping("/get-now")
32 @Operation(summary = "获得当前秒杀活动") // 提供给首页使用 56 @Operation(summary = "获得当前秒杀活动") // 提供给首页使用
33 // TODO 芋艿:需要增加 spring cache 57 // TODO 芋艿:需要增加 spring cache
34 public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() { 58 public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
35 - AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();  
36 - respVO.setConfig(new AppSeckillConfigRespVO().setId(10L).setStartTime("01:00").setEndTime("09:59"));  
37 - List<AppSeckillActivityRespVO> activityList = new ArrayList<>();  
38 - AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();  
39 - activity1.setId(1L);  
40 - activity1.setName("618 大秒杀");  
41 - activity1.setSpuId(2048L);  
42 - activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
43 - activity1.setMarketPrice(50);  
44 - activity1.setSeckillPrice(100);  
45 - activityList.add(activity1); 59 + // 1、获取当前时间处在哪个秒杀阶段
  60 + List<SeckillConfigDO> configList = configService.getSeckillConfigList();
  61 + SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
  62 + CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
  63 + // 1、1 时段不存在直接返回 null
  64 + if (filteredConfig == null) {
  65 + return success(null);
  66 + }
46 67
47 - AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();  
48 - activity2.setId(2L);  
49 - activity2.setName("双十一大秒杀");  
50 - activity2.setSpuId(4096L);  
51 - activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");  
52 - activity2.setMarketPrice(100);  
53 - activity2.setSeckillPrice(200);  
54 - activityList.add(activity2);  
55 - respVO.setActivities(activityList);  
56 - return success(respVO); 68 + // 2、查询满足当前阶段的活动
  69 + List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIds(Arrays.asList(filteredConfig.getId()));
  70 + List<SeckillActivityDO> filteredList = filterList(activityList, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
  71 + // 2、1 获取 spu 信息
  72 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(filteredList, SeckillActivityDO::getSpuId));
  73 + return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
57 } 74 }
58 75
59 @GetMapping("/page") 76 @GetMapping("/page")
60 @Operation(summary = "获得秒杀活动分页") 77 @Operation(summary = "获得秒杀活动分页")
61 - // TODO @芋艿:分页参数  
62 public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) { 78 public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
63 - List<AppSeckillActivityRespVO> activityList = new ArrayList<>();  
64 - AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();  
65 - activity1.setId(1L);  
66 - activity1.setName("618 大秒杀");  
67 - activity1.setSpuId(2048L);  
68 - activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");  
69 - activity1.setMarketPrice(50);  
70 - activity1.setSeckillPrice(100);  
71 - activity1.setUnitName("个");  
72 - activity1.setStock(1);  
73 - activity1.setTotalStock(2);  
74 - activityList.add(activity1);  
75 -  
76 - AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();  
77 - activity2.setId(2L);  
78 - activity2.setName("双十一大秒杀");  
79 - activity2.setSpuId(4096L);  
80 - activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");  
81 - activity2.setMarketPrice(100);  
82 - activity2.setSeckillPrice(200);  
83 - activity2.setUnitName("套");  
84 - activity2.setStock(2);  
85 - activity2.setTotalStock(3);  
86 - activityList.add(activity2);  
87 - return success(new PageResult<>(activityList, 100L)); 79 + // 1、查询满足当前阶段的活动
  80 + PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
  81 + // 1、1 获取 spu 信息
  82 + List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
  83 + return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
88 } 84 }
89 85
90 @GetMapping("/get-detail") 86 @GetMapping("/get-detail")
91 @Operation(summary = "获得秒杀活动明细") 87 @Operation(summary = "获得秒杀活动明细")
92 @Parameter(name = "id", description = "活动编号", required = true, example = "1024") 88 @Parameter(name = "id", description = "活动编号", required = true, example = "1024")
93 public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) { 89 public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
  90 + // 1、获取当前时间处在哪个秒杀阶段
  91 + List<SeckillConfigDO> configList = configService.getSeckillConfigList();
  92 + SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
  93 + CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
  94 + // 1、1 时段不存在直接返回 null
  95 + if (filteredConfig == null) {
  96 + return success(null);
  97 + }
  98 +
  99 + // 2、获取活动
  100 + SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
  101 + if (seckillActivity == null) {
  102 + return success(null);
  103 + }
94 // TODO 芋艿:如果禁用的时候,需要抛出异常; 104 // TODO 芋艿:如果禁用的时候,需要抛出异常;
95 - AppSeckillActivityDetailRespVO obj = new AppSeckillActivityDetailRespVO();  
96 - // 设置其属性的值  
97 - obj.setId(id);  
98 - obj.setName("晚九点限时秒杀");  
99 - obj.setStatus(1);  
100 - obj.setStartTime(LocalDateTime.of(2023, 6, 16, 0, 0, 0));  
101 - obj.setEndTime(LocalDateTime.of(2023, 6, 20, 23, 59, 0));  
102 - obj.setSpuId(633L);  
103 - obj.setSingleLimitCount(2);  
104 - obj.setTotalLimitCount(3);  
105 - obj.setStock(100);  
106 - obj.setTotalStock(200); 105 + if (ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
  106 + throw exception(SECKILL_ACTIVITY_FAIL_STATUS_CLOSED);
  107 + }
107 108
108 - // 创建一个Product对象的列表  
109 - List<AppSeckillActivityDetailRespVO.Product> productList = new ArrayList<>();  
110 - // 创建三个新的Product对象并设置其属性的值  
111 - AppSeckillActivityDetailRespVO.Product product1 = new AppSeckillActivityDetailRespVO.Product();  
112 - product1.setSkuId(1L);  
113 - product1.setSeckillPrice(100);  
114 - product1.setStock(50);  
115 - // 将第一个Product对象添加到列表中  
116 - productList.add(product1);  
117 - // 创建第二个Product对象并设置其属性的值  
118 - AppSeckillActivityDetailRespVO.Product product2 = new AppSeckillActivityDetailRespVO.Product();  
119 - product2.setSkuId(2L);  
120 - product2.setSeckillPrice(200);  
121 - product2.setStock(100);  
122 - // 将第二个Product对象添加到列表中  
123 - productList.add(product2);  
124 - // 创建第三个Product对象并设置其属性的值  
125 - AppSeckillActivityDetailRespVO.Product product3 = new AppSeckillActivityDetailRespVO.Product();  
126 - product3.setSkuId(3L);  
127 - product3.setSeckillPrice(300);  
128 - product3.setStock(150);  
129 - // 将第三个Product对象添加到列表中  
130 - productList.add(product3);  
131 - // 将Product列表设置为对象的属性值  
132 - obj.setProducts(productList);  
133 - return success(obj); 109 + // 3、获取活动商品
  110 + List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
  111 + return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
134 } 112 }
135 113
136 } 114 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/AppSeckillConfigController.java
1 package cn.iocoder.yudao.module.promotion.controller.app.seckill; 1 package cn.iocoder.yudao.module.promotion.controller.app.seckill;
2 2
  3 +import cn.hutool.core.collection.CollectionUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; 6 import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
  7 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
  9 +import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
5 import io.swagger.v3.oas.annotations.Operation; 10 import io.swagger.v3.oas.annotations.Operation;
6 import io.swagger.v3.oas.annotations.tags.Tag; 11 import io.swagger.v3.oas.annotations.tags.Tag;
7 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
@@ -9,7 +14,8 @@ import org.springframework.web.bind.annotation.GetMapping; @@ -9,7 +14,8 @@ import org.springframework.web.bind.annotation.GetMapping;
9 import org.springframework.web.bind.annotation.RequestMapping; 14 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RestController; 15 import org.springframework.web.bind.annotation.RestController;
11 16
12 -import java.util.Arrays; 17 +import javax.annotation.Resource;
  18 +import java.util.Collections;
13 import java.util.List; 19 import java.util.List;
14 20
15 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 21 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -19,18 +25,26 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -19,18 +25,26 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
19 @RequestMapping("/promotion/seckill-config") 25 @RequestMapping("/promotion/seckill-config")
20 @Validated 26 @Validated
21 public class AppSeckillConfigController { 27 public class AppSeckillConfigController {
  28 + @Resource
  29 + private SeckillConfigService configService;
22 30
23 @GetMapping("/list") 31 @GetMapping("/list")
24 @Operation(summary = "获得秒杀时间段列表") 32 @Operation(summary = "获得秒杀时间段列表")
25 public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() { 33 public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
26 - return success(Arrays.asList(  
27 - new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59")  
28 - .setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg",  
29 - "https://static.iocoder.cn/mall/132.jpeg")),  
30 - new AppSeckillConfigRespVO().setId(2L).setStartTime("10:00").setEndTime("12:59"),  
31 - new AppSeckillConfigRespVO().setId(2L).setStartTime("13:00").setEndTime("22:59"),  
32 - new AppSeckillConfigRespVO().setId(2L).setStartTime("23:00").setEndTime("23:59")  
33 - )); 34 + List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
  35 + if (CollectionUtil.isEmpty(list)) {
  36 + return success(Collections.emptyList());
  37 + }
  38 +
  39 + return success(SeckillConfigConvert.INSTANCE.convertList2(list));
  40 + //return success(Arrays.asList(
  41 + // new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59")
  42 + // .setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg",
  43 + // "https://static.iocoder.cn/mall/132.jpeg")),
  44 + // new AppSeckillConfigRespVO().setId(2L).setStartTime("10:00").setEndTime("12:59"),
  45 + // new AppSeckillConfigRespVO().setId(2L).setStartTime("13:00").setEndTime("22:59"),
  46 + // new AppSeckillConfigRespVO().setId(2L).setStartTime("23:00").setEndTime("23:59")
  47 + //));
34 } 48 }
35 49
36 } 50 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityDetailRespVO.java
@@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO { @@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO {
19 @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 19 @Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20 private Integer status; 20 private Integer status;
21 21
22 - // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈; 22 + // TODO @芋艿:开始时间、结束时间,要和场次结合起来;就是要算到当前场次,是几点哈;
23 23
24 @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED) 24 @Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
25 private LocalDateTime startTime; 25 private LocalDateTime startTime;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/seckill/vo/activity/AppSeckillActivityRespVO.java
@@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO { @@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO {
31 private Integer totalStock; 31 private Integer totalStock;
32 32
33 @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") 33 @Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
34 - // 从秒杀商品里取最低价  
35 private Integer seckillPrice; 34 private Integer seckillPrice;
36 35
37 } 36 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
@@ -3,15 +3,22 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; @@ -3,15 +3,22 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
6 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; 7 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
  8 +import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
8 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; 10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO; 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
  15 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
  16 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
  17 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
  18 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
13 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
14 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 20 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
  21 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
15 import org.mapstruct.Mapper; 22 import org.mapstruct.Mapper;
16 import org.mapstruct.Mapping; 23 import org.mapstruct.Mapping;
17 import org.mapstruct.Mappings; 24 import org.mapstruct.Mappings;
@@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers; @@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers;
20 import java.util.List; 27 import java.util.List;
21 import java.util.Map; 28 import java.util.Map;
22 29
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  31 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  32 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  33 +
23 /** 34 /**
24 * 秒杀活动 Convert 35 * 秒杀活动 Convert
25 * 36 *
@@ -79,4 +90,50 @@ public interface SeckillActivityConvert { @@ -79,4 +90,50 @@ public interface SeckillActivityConvert {
79 90
80 List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list); 91 List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list);
81 92
  93 + List<AppSeckillActivityRespVO> convertList3(List<SeckillActivityDO> activityList);
  94 +
  95 + default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List<SeckillActivityDO> activityList, List<ProductSpuRespDTO> spuList) {
  96 + AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
  97 + respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig));
  98 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  99 + respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> {
  100 + findAndThen(spuMap, item.getSpuId(), spu -> {
  101 + item.setPicUrl(spu.getPicUrl());
  102 + item.setMarketPrice(spu.getMarketPrice());
  103 + item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
  104 + });
  105 + return item;
  106 + }));
  107 + return respVO;
  108 + }
  109 +
  110 + PageResult<AppSeckillActivityRespVO> convertPage1(PageResult<SeckillActivityDO> pageResult);
  111 +
  112 + default PageResult<AppSeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> pageResult, List<ProductSpuRespDTO> spuList) {
  113 + PageResult<AppSeckillActivityRespVO> result = convertPage1(pageResult);
  114 + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
  115 + List<AppSeckillActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
  116 + findAndThen(spuMap, item.getSpuId(), spu -> {
  117 + item.setPicUrl(spu.getPicUrl());
  118 + item.setMarketPrice(spu.getMarketPrice());
  119 + item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
  120 + });
  121 + return item;
  122 + });
  123 + result.setList(list);
  124 + return result;
  125 + }
  126 +
  127 + AppSeckillActivityDetailRespVO convert2(SeckillActivityDO seckillActivity);
  128 +
  129 + List<AppSeckillActivityDetailRespVO.Product> convertList1(List<SeckillProductDO> products);
  130 +
  131 + default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
  132 + AppSeckillActivityDetailRespVO respVO = convert2(seckillActivity);
  133 + respVO.setProducts(convertList1(products));
  134 + respVO.setStartTime(buildTime(filteredConfig.getStartTime()));
  135 + respVO.setEndTime(buildTime(filteredConfig.getEndTime()));
  136 + return respVO;
  137 + }
  138 +
82 } 139 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillconfig/SeckillConfigConvert.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
9 import org.mapstruct.Mapper; 10 import org.mapstruct.Mapper;
10 import org.mapstruct.factory.Mappers; 11 import org.mapstruct.factory.Mappers;
@@ -33,4 +34,7 @@ public interface SeckillConfigConvert { @@ -33,4 +34,7 @@ public interface SeckillConfigConvert {
33 34
34 PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page); 35 PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page);
35 36
  37 + List<AppSeckillConfigRespVO> convertList2(List<SeckillConfigDO> list);
  38 +
  39 + AppSeckillConfigRespVO convert1(SeckillConfigDO filteredConfig);
36 } 40 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillactivity/SeckillActivityDO.java
@@ -87,7 +87,7 @@ public class SeckillActivityDO extends BaseDO { @@ -87,7 +87,7 @@ public class SeckillActivityDO extends BaseDO {
87 */ 87 */
88 private Integer singleLimitCount; 88 private Integer singleLimitCount;
89 /** 89 /**
90 - * 秒杀库存 90 + * 秒杀库存(剩余库存秒杀时扣减)
91 */ 91 */
92 private Integer stock; 92 private Integer stock;
93 /** 93 /**
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillactivity/SeckillActivityMapper.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
9 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 10 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
10 import org.apache.ibatis.annotations.Mapper; 11 import org.apache.ibatis.annotations.Mapper;
@@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; { @@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
24 .likeIfPresent(SeckillActivityDO::getName, reqVO.getName()) 25 .likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
25 .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus()) 26 .eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
26 .betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime()) 27 .betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
27 - .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0") 28 + .apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ", config_ids) > 0")
28 .orderByDesc(SeckillActivityDO::getId)); 29 .orderByDesc(SeckillActivityDO::getId));
29 } 30 }
30 31
@@ -48,4 +49,10 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; { @@ -48,4 +49,10 @@ public interface SeckillActivityMapper extends BaseMapperX&lt;SeckillActivityDO&gt; {
48 .setSql("totalStock = totalStock - " + count)); 49 .setSql("totalStock = totalStock - " + count));
49 } 50 }
50 51
  52 + default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
  53 + return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
  54 + .eqIfPresent(SeckillActivityDO::getStatus, status)
  55 + .apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
  56 + }
  57 +
51 } 58 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityService.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; 4 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 5 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
9 10
@@ -88,4 +89,20 @@ public interface SeckillActivityService { @@ -88,4 +89,20 @@ public interface SeckillActivityService {
88 */ 89 */
89 List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds); 90 List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
90 91
  92 + /**
  93 + * 通过活动时段获取秒杀活动
  94 + *
  95 + * @param ids 时段配置编号
  96 + * @return 秒杀活动列表
  97 + */
  98 + List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids);
  99 +
  100 + /**
  101 + * 通过活动时段获取秒杀活动
  102 + *
  103 + * @param pageReqVO 请求
  104 + * @return 秒杀活动列表
  105 + */
  106 + PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
  107 +
91 } 108 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.seckill; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.seckill;
3 import cn.hutool.core.util.ObjectUtil; 3 import cn.hutool.core.util.ObjectUtil;
4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; 7 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
7 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
8 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 9 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@@ -11,6 +12,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se @@ -11,6 +12,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO; 12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
12 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; 13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
13 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; 14 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
  15 +import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
14 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; 16 import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
15 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO; 17 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
16 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO; 18 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
@@ -264,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { @@ -264,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
264 return seckillProductMapper.selectListByActivityId(activityIds); 266 return seckillProductMapper.selectListByActivityId(activityIds);
265 } 267 }
266 268
  269 + @Override
  270 + public List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids) {
  271 + return CollectionUtils.filterList(seckillActivityMapper.selectList(),
  272 + item -> CollectionUtils.anyMatch(item.getConfigIds(), ids::contains));
  273 + }
  274 +
  275 + @Override
  276 + public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) {
  277 + return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
  278 + }
  279 +
267 } 280 }