Commit 60e684c4556c7796032d14845d6db8b5971fcd34

Authored by puhui999
1 parent e8ade5f1

营销活动:获取商品近期参与的每个活动新增满减送和限时折扣活动

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/activity/AppActivityController.java
@@ -7,26 +7,33 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; @@ -7,26 +7,33 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
7 import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO; 7 import cn.iocoder.yudao.module.promotion.controller.app.activity.vo.AppActivityRespVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
9 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  11 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  12 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
  14 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
11 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; 15 import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
12 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; 16 import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
13 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; 17 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
  18 +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
  19 +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
14 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; 20 import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
15 import io.swagger.v3.oas.annotations.Operation; 21 import io.swagger.v3.oas.annotations.Operation;
16 import io.swagger.v3.oas.annotations.Parameter; 22 import io.swagger.v3.oas.annotations.Parameter;
17 import io.swagger.v3.oas.annotations.tags.Tag; 23 import io.swagger.v3.oas.annotations.tags.Tag;
  24 +import jakarta.annotation.Resource;
18 import org.springframework.validation.annotation.Validated; 25 import org.springframework.validation.annotation.Validated;
19 import org.springframework.web.bind.annotation.GetMapping; 26 import org.springframework.web.bind.annotation.GetMapping;
20 import org.springframework.web.bind.annotation.RequestMapping; 27 import org.springframework.web.bind.annotation.RequestMapping;
21 import org.springframework.web.bind.annotation.RequestParam; 28 import org.springframework.web.bind.annotation.RequestParam;
22 import org.springframework.web.bind.annotation.RestController; 29 import org.springframework.web.bind.annotation.RestController;
23 30
24 -import jakarta.annotation.Resource;  
25 import java.time.LocalDateTime; 31 import java.time.LocalDateTime;
26 import java.util.*; 32 import java.util.*;
  33 +import java.util.stream.Collectors;
27 34
28 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 35 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
29 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; 36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
30 37
31 @Tag(name = "用户 APP - 营销活动") // 用于提供跨多个活动的 HTTP 接口 38 @Tag(name = "用户 APP - 营销活动") // 用于提供跨多个活动的 HTTP 接口
32 @RestController 39 @RestController
@@ -40,6 +47,10 @@ public class AppActivityController { @@ -40,6 +47,10 @@ public class AppActivityController {
40 private SeckillActivityService seckillActivityService; 47 private SeckillActivityService seckillActivityService;
41 @Resource 48 @Resource
42 private BargainActivityService bargainActivityService; 49 private BargainActivityService bargainActivityService;
  50 + @Resource
  51 + private DiscountActivityService discountActivityService;
  52 + @Resource
  53 + private RewardActivityService rewardActivityService;
43 54
44 @GetMapping("/list-by-spu-id") 55 @GetMapping("/list-by-spu-id")
45 @Operation(summary = "获得单个商品,近期参与的每个活动") 56 @Operation(summary = "获得单个商品,近期参与的每个活动")
@@ -64,45 +75,105 @@ public class AppActivityController { @@ -64,45 +75,105 @@ public class AppActivityController {
64 if (CollUtil.isEmpty(spuIds)) { 75 if (CollUtil.isEmpty(spuIds)) {
65 return new ArrayList<>(); 76 return new ArrayList<>();
66 } 77 }
  78 +
67 LocalDateTime now = LocalDateTime.now(); 79 LocalDateTime now = LocalDateTime.now();
  80 + // 获取开启的且开始的且没有结束的活动
68 List<AppActivityRespVO> activityList = new ArrayList<>(); 81 List<AppActivityRespVO> activityList = new ArrayList<>();
  82 + // 1. 拼团活动
  83 + getCombinationActivities(spuIds, now, activityList);
  84 + // 2. 秒杀活动
  85 + getSeckillActivities(spuIds, now, activityList);
  86 + // 3. 砍价活动
  87 + getBargainActivities(spuIds, now, activityList);
  88 + // 4. 限时折扣活动
  89 + getDiscountActivities(spuIds, now, activityList);
  90 + // 5. 满减送活动
  91 + getRewardActivities(spuIds, now, activityList);
  92 + return activityList;
  93 + }
69 94
70 - // 1. 拼团活动 - 获取开启的且开始的且没有结束的活动 95 + private void getCombinationActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
71 List<CombinationActivityDO> combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt( 96 List<CombinationActivityDO> combinationActivities = combinationActivityService.getCombinationActivityBySpuIdsAndStatusAndDateTimeLt(
72 spuIds, CommonStatusEnum.ENABLE.getStatus(), now); 97 spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
73 - if (CollUtil.isNotEmpty(combinationActivities)) {  
74 - combinationActivities.forEach(item -> {  
75 - activityList.add(new AppActivityRespVO().setId(item.getId())  
76 - .setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType()).setName(item.getName())  
77 - .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));  
78 - }); 98 + if (CollUtil.isEmpty(combinationActivities)) {
  99 + return;
79 } 100 }
80 101
81 - // 2. 秒杀活动 - 获取开启的且开始的且没有结束的活动 102 + combinationActivities.forEach(item -> {
  103 + activityList.add(new AppActivityRespVO().setId(item.getId())
  104 + .setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType()).setName(item.getName())
  105 + .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));
  106 + });
  107 + }
  108 +
  109 + private void getSeckillActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
82 List<SeckillActivityDO> seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt( 110 List<SeckillActivityDO> seckillActivities = seckillActivityService.getSeckillActivityBySpuIdsAndStatusAndDateTimeLt(
83 spuIds, CommonStatusEnum.ENABLE.getStatus(), now); 111 spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
84 - if (CollUtil.isNotEmpty(seckillActivities)) {  
85 - seckillActivities.forEach(item -> {  
86 - activityList.add(new AppActivityRespVO().setId(item.getId())  
87 - .setType(PromotionTypeEnum.SECKILL_ACTIVITY.getType()).setName(item.getName())  
88 - .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));  
89 - }); 112 + if (CollUtil.isEmpty(seckillActivities)) {
  113 + return;
90 } 114 }
91 115
92 - // 3. 砍价活动 - 获取开启的且开始的且没有结束的活动 116 + seckillActivities.forEach(item -> {
  117 + activityList.add(new AppActivityRespVO().setId(item.getId())
  118 + .setType(PromotionTypeEnum.SECKILL_ACTIVITY.getType()).setName(item.getName())
  119 + .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));
  120 + });
  121 + }
  122 +
  123 + private void getBargainActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
93 List<BargainActivityDO> bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt( 124 List<BargainActivityDO> bargainActivities = bargainActivityService.getBargainActivityBySpuIdsAndStatusAndDateTimeLt(
94 spuIds, CommonStatusEnum.ENABLE.getStatus(), now); 125 spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
95 if (CollUtil.isNotEmpty(bargainActivities)) { 126 if (CollUtil.isNotEmpty(bargainActivities)) {
96 - bargainActivities.forEach(item -> {  
97 - activityList.add(new AppActivityRespVO().setId(item.getId())  
98 - .setType(PromotionTypeEnum.BARGAIN_ACTIVITY.getType()).setName(item.getName())  
99 - .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));  
100 - }); 127 + return;
101 } 128 }
102 129
103 - // TODO 芋艿:满减送活动  
104 - // TODO 芋艿:限时折扣活动  
105 - return activityList; 130 + bargainActivities.forEach(item -> {
  131 + activityList.add(new AppActivityRespVO().setId(item.getId())
  132 + .setType(PromotionTypeEnum.BARGAIN_ACTIVITY.getType()).setName(item.getName())
  133 + .setSpuId(item.getSpuId()).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));
  134 + });
  135 + }
  136 +
  137 + private void getDiscountActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
  138 + List<DiscountActivityDO> discountActivities = discountActivityService.getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(
  139 + spuIds, CommonStatusEnum.ENABLE.getStatus(), now);
  140 + if (CollUtil.isEmpty(discountActivities)) {
  141 + return;
  142 + }
  143 +
  144 + List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
  145 + convertSet(discountActivities, DiscountActivityDO::getId));
  146 + Map<Long, Long> productMap = convertMap(products, DiscountProductDO::getActivityId, DiscountProductDO::getSpuId);
  147 + discountActivities.forEach(item -> {
  148 + activityList.add(new AppActivityRespVO().setId(item.getId())
  149 + .setType(PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()).setName(item.getName())
  150 + .setSpuId(productMap.get(item.getId())).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));
  151 + });
  152 + }
  153 +
  154 + private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
  155 + List<RewardActivityDO> rewardActivityList = rewardActivityService.getRewardActivityBySpuIdsAndStatusAndDateTimeLt(
  156 + spuIds, PromotionActivityStatusEnum.RUN.getStatus(), now);
  157 + if (CollUtil.isEmpty(rewardActivityList)) {
  158 + return;
  159 + }
  160 +
  161 + Map<Long, Optional<RewardActivityDO>> spuIdAndActivityMap = spuIds.stream()
  162 + .collect(Collectors.toMap(
  163 + spuId -> spuId,
  164 + spuId -> rewardActivityList.stream()
  165 + .filter(activity -> activity.getProductSpuIds().contains(spuId))
  166 + .max(Comparator.comparing(RewardActivityDO::getCreateTime))));
  167 + for (Long supId : spuIdAndActivityMap.keySet()) {
  168 + if (spuIdAndActivityMap.get(supId).isEmpty()) {
  169 + continue;
  170 + }
  171 +
  172 + RewardActivityDO rewardActivityDO = spuIdAndActivityMap.get(supId).get();
  173 + activityList.add(new AppActivityRespVO().setId(rewardActivityDO.getId())
  174 + .setType(PromotionTypeEnum.REWARD_ACTIVITY.getType()).setName(rewardActivityDO.getName())
  175 + .setSpuId(supId).setStartTime(rewardActivityDO.getStartTime()).setEndTime(rewardActivityDO.getEndTime()));
  176 + }
106 } 177 }
107 178
108 } 179 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java
@@ -7,9 +7,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc @@ -7,9 +7,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
  10 +import java.time.LocalDateTime;
10 import java.util.Collection; 11 import java.util.Collection;
11 import java.util.List; 12 import java.util.List;
12 -import java.util.Set;  
13 13
14 /** 14 /**
15 * 限时折扣活动 Mapper 15 * 限时折扣活动 Mapper
@@ -27,4 +27,20 @@ public interface DiscountActivityMapper extends BaseMapperX&lt;DiscountActivityDO&gt; @@ -27,4 +27,20 @@ public interface DiscountActivityMapper extends BaseMapperX&lt;DiscountActivityDO&gt;
27 .orderByDesc(DiscountActivityDO::getId)); 27 .orderByDesc(DiscountActivityDO::getId));
28 } 28 }
29 29
  30 + /**
  31 + * 获取指定活动编号的活动列表且
  32 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表
  33 + *
  34 + * @param ids 活动编号
  35 + * @param dateTime 指定日期
  36 + * @return 活动列表
  37 + */
  38 + default List<DiscountActivityDO> selectListByIdsAndDateTimeLt(Collection<Long> ids, LocalDateTime dateTime) {
  39 + return selectList(new LambdaQueryWrapperX<DiscountActivityDO>()
  40 + .in(DiscountActivityDO::getId, ids)
  41 + .lt(DiscountActivityDO::getStartTime, dateTime)
  42 + .gt(DiscountActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
  43 + .orderByDesc(DiscountActivityDO::getCreateTime));
  44 + }
  45 +
30 } 46 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java
@@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount; @@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  5 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
5 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
6 import org.apache.ibatis.annotations.Param; 7 import org.apache.ibatis.annotations.Param;
7 8
8 import java.util.Collection; 9 import java.util.Collection;
9 import java.util.List; 10 import java.util.List;
  11 +import java.util.Map;
10 12
11 /** 13 /**
12 * 限时折扣商城 Mapper 14 * 限时折扣商城 Mapper
@@ -30,4 +32,20 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; { @@ -30,4 +32,20 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
30 32
31 // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的 33 // TODO @zhangshuai:逻辑里,尽量避免写 join 语句哈,你可以看看这个查询,有什么办法优化?目前的一个思路,是分 2 次查询,性能也是 ok 的
32 List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds); 34 List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
  35 +
  36 + /**
  37 + * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
  38 + *
  39 + * @param spuIds spu 编号
  40 + * @param status 状态
  41 + * @return 包含 spuId 和 activityId 的 map 对象列表
  42 + */
  43 + default List<Map<String, Object>> selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
  44 + return selectMaps(new QueryWrapper<DiscountProductDO>()
  45 + .select("spu_id AS spuId, MAX(DISTINCT(activity_id)) AS activityId")
  46 + .in("spu_id", spuIds)
  47 + .eq("activity_status", status)
  48 + .groupBy("spu_id"));
  49 + }
  50 +
33 } 51 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java
1 package cn.iocoder.yudao.module.promotion.dal.mysql.reward; 1 package cn.iocoder.yudao.module.promotion.dal.mysql.reward;
2 2
  3 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  9 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
8 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
9 11
  12 +import java.time.LocalDateTime;
10 import java.util.Collection; 13 import java.util.Collection;
11 import java.util.List; 14 import java.util.List;
  15 +import java.util.function.Function;
  16 +import java.util.stream.Collectors;
12 17
13 /** 18 /**
14 * 满减送活动 Mapper 19 * 满减送活动 Mapper
@@ -35,4 +40,30 @@ public interface RewardActivityMapper extends BaseMapperX&lt;RewardActivityDO&gt; { @@ -35,4 +40,30 @@ public interface RewardActivityMapper extends BaseMapperX&lt;RewardActivityDO&gt; {
35 .eq(RewardActivityDO::getStatus, status)); 40 .eq(RewardActivityDO::getStatus, status));
36 } 41 }
37 42
  43 + default List<RewardActivityDO> selectListBySpuIdsAndStatus(Collection<Long> spuIds, Integer status) {
  44 + Function<Collection<Long>, String> productScopeValuesFindInSetFunc = ids -> ids.stream()
  45 + .map(id -> StrUtil.format("FIND_IN_SET({}, product_spu_ids) ", id))
  46 + .collect(Collectors.joining(" OR "));
  47 + return selectList(new QueryWrapper<RewardActivityDO>()
  48 + .eq("status", status)
  49 + .apply(productScopeValuesFindInSetFunc.apply(spuIds)));
  50 + }
  51 +
  52 + /**
  53 + * 获取指定活动编号的活动列表且
  54 + * 开始时间和结束时间小于给定时间 dateTime 的活动列表
  55 + *
  56 + * @param ids 活动编号
  57 + * @param dateTime 指定日期
  58 + * @return 活动列表
  59 + */
  60 + default List<RewardActivityDO> selectListByIdsAndDateTimeLt(Collection<Long> ids, LocalDateTime dateTime) {
  61 + return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
  62 + .in(RewardActivityDO::getId, ids)
  63 + .lt(RewardActivityDO::getStartTime, dateTime)
  64 + .gt(RewardActivityDO::getEndTime, dateTime)// 开始时间 < 指定时间 < 结束时间,也就是说获取指定时间段的活动
  65 + .orderByDesc(RewardActivityDO::getCreateTime)
  66 + );
  67 + }
  68 +
38 } 69 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java
@@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc @@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountAc
6 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
9 -  
10 import jakarta.validation.Valid; 9 import jakarta.validation.Valid;
  10 +
  11 +import java.time.LocalDateTime;
11 import java.util.Collection; 12 import java.util.Collection;
12 import java.util.List; 13 import java.util.List;
13 14
@@ -89,4 +90,14 @@ public interface DiscountActivityService { @@ -89,4 +90,14 @@ public interface DiscountActivityService {
89 */ 90 */
90 List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds); 91 List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds);
91 92
  93 + /**
  94 + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
  95 + *
  96 + * @param spuIds spu 编号
  97 + * @param status 状态
  98 + * @param dateTime 当前日期时间
  99 + * @return 折扣活动列表
  100 + */
  101 + List<DiscountActivityDO> getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
  102 +
92 } 103 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.discount; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.discount;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.CollectionUtil; 4 import cn.hutool.core.collection.CollectionUtil;
  5 +import cn.hutool.core.map.MapUtil;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; 8 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
@@ -15,16 +16,20 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapp @@ -15,16 +16,20 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapp
15 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; 16 import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
16 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; 17 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
17 import cn.iocoder.yudao.module.promotion.util.PromotionUtils; 18 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
  19 +import jakarta.annotation.Resource;
18 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
19 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
20 22
21 -import jakarta.annotation.Resource; 23 +import java.time.LocalDateTime;
22 import java.util.Collection; 24 import java.util.Collection;
  25 +import java.util.Collections;
23 import java.util.List; 26 import java.util.List;
  27 +import java.util.Map;
24 import java.util.stream.Collectors; 28 import java.util.stream.Collectors;
25 29
26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 31 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  32 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
28 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 33 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
29 34
30 /** 35 /**
@@ -109,7 +114,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -109,7 +114,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
109 /** 114 /**
110 * 校验商品是否冲突 115 * 校验商品是否冲突
111 * 116 *
112 - * @param id 编号 117 + * @param id 编号
113 * @param products 商品列表 118 * @param products 商品列表
114 */ 119 */
115 private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) { 120 private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) {
@@ -184,4 +189,17 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { @@ -184,4 +189,17 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
184 return discountProductMapper.selectList("activity_id", activityIds); 189 return discountProductMapper.selectList("activity_id", activityIds);
185 } 190 }
186 191
  192 + @Override
  193 + public List<DiscountActivityDO> getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
  194 + // 1. 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
  195 + List<Map<String, Object>> spuIdAndActivityIdMaps = discountProductMapper.selectSpuIdAndActivityIdMapsBySpuIdsAndStatus(spuIds, status);
  196 + if (CollUtil.isEmpty(spuIdAndActivityIdMaps)) {
  197 + return Collections.emptyList();
  198 + }
  199 +
  200 + // 2. 查询活动详情
  201 + return discountActivityMapper.selectListByIdsAndDateTimeLt(
  202 + convertSet(spuIdAndActivityIdMaps, map -> MapUtil.getLong(map, "activityId")), dateTime);
  203 + }
  204 +
187 } 205 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java
@@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi @@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
6 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; 6 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
7 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; 7 import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
9 -  
10 import jakarta.validation.Valid; 9 import jakarta.validation.Valid;
  10 +
  11 +import java.time.LocalDateTime;
11 import java.util.Collection; 12 import java.util.Collection;
12 import java.util.List; 13 import java.util.List;
13 14
@@ -71,4 +72,14 @@ public interface RewardActivityService { @@ -71,4 +72,14 @@ public interface RewardActivityService {
71 */ 72 */
72 List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds); 73 List<RewardActivityMatchRespDTO> getMatchRewardActivityList(Collection<Long> spuIds);
73 74
  75 + /**
  76 + * 获取指定 spu 编号最近参加的活动,每个 spuId 只返回一条记录
  77 + *
  78 + * @param spuIds spu 编号
  79 + * @param status 状态
  80 + * @param dateTime 当前日期时间
  81 + * @return 满减送活动列表
  82 + */
  83 + List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
  84 +
74 } 85 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java
@@ -11,14 +11,17 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; @@ -11,14 +11,17 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
11 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; 11 import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
12 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; 12 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
13 import cn.iocoder.yudao.module.promotion.util.PromotionUtils; 13 import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
  14 +import jakarta.annotation.Resource;
14 import org.springframework.stereotype.Service; 15 import org.springframework.stereotype.Service;
15 import org.springframework.validation.annotation.Validated; 16 import org.springframework.validation.annotation.Validated;
16 17
17 -import jakarta.annotation.Resource; 18 +import java.time.LocalDateTime;
18 import java.util.Collection; 19 import java.util.Collection;
  20 +import java.util.Collections;
19 import java.util.List; 21 import java.util.List;
20 22
21 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
22 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; 25 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
23 import static java.util.Arrays.asList; 26 import static java.util.Arrays.asList;
24 27
@@ -100,10 +103,11 @@ public class RewardActivityServiceImpl implements RewardActivityService { @@ -100,10 +103,11 @@ public class RewardActivityServiceImpl implements RewardActivityService {
100 } 103 }
101 104
102 // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验; 105 // TODO @芋艿:逻辑有问题,需要优化;要分成全场、和指定来校验;
  106 +
103 /** 107 /**
104 * 校验商品参加的活动是否冲突 108 * 校验商品参加的活动是否冲突
105 * 109 *
106 - * @param id 活动编号 110 + * @param id 活动编号
107 * @param spuIds 商品 SPU 编号数组 111 * @param spuIds 商品 SPU 编号数组
108 */ 112 */
109 private void validateRewardActivitySpuConflicts(Long id, Collection<Long> spuIds) { 113 private void validateRewardActivitySpuConflicts(Long id, Collection<Long> spuIds) {
@@ -125,7 +129,7 @@ public class RewardActivityServiceImpl implements RewardActivityService { @@ -125,7 +129,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
125 /** 129 /**
126 * 获得商品参加的满减送活动的数组 130 * 获得商品参加的满减送活动的数组
127 * 131 *
128 - * @param spuIds 商品 SPU 编号数组 132 + * @param spuIds 商品 SPU 编号数组
129 * @param statuses 活动状态数组 133 * @param statuses 活动状态数组
130 * @return 商品参加的满减送活动的数组 134 * @return 商品参加的满减送活动的数组
131 */ 135 */
@@ -163,4 +167,16 @@ public class RewardActivityServiceImpl implements RewardActivityService { @@ -163,4 +167,16 @@ public class RewardActivityServiceImpl implements RewardActivityService {
163 return null; 167 return null;
164 } 168 }
165 169
  170 + @Override
  171 + public List<RewardActivityDO> getRewardActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime) {
  172 + // 1. 查询出指定 spuId 的 spu 参加的活动
  173 + List<RewardActivityDO> rewardActivityList = rewardActivityMapper.selectListBySpuIdsAndStatus(spuIds, status);
  174 + if (CollUtil.isEmpty(rewardActivityList)) {
  175 + return Collections.emptyList();
  176 + }
  177 +
  178 + // 2. 查询活动详情
  179 + return rewardActivityMapper.selectListByIdsAndDateTimeLt(convertSet(rewardActivityList, RewardActivityDO::getId), dateTime);
  180 + }
  181 +
166 } 182 }