Commit 60e684c4556c7796032d14845d6db8b5971fcd34
1 parent
e8ade5f1
营销活动:获取商品近期参与的每个活动新增满减送和限时折扣活动
Showing
8 changed files
with
225 additions
and
33 deletions
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<DiscountActivityDO> | @@ -27,4 +27,20 @@ public interface DiscountActivityMapper extends BaseMapperX<DiscountActivityDO> | ||
| 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<DiscountProductDO> { | @@ -30,4 +32,20 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { | ||
| 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<RewardActivityDO> { | @@ -35,4 +40,30 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> { | ||
| 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 | } |