Commit 04061b028c9ab583e905c7415e244a8ff076275e

Authored by zhangshuai
1 parent 82fd800a

mall模块-限时折扣功能

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.discount;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
  7 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 8 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
6 9 import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
  10 +import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
7 11 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
8 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  13 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
  14 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
9 15 import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
10 16 import io.swagger.v3.oas.annotations.Operation;
11 17 import io.swagger.v3.oas.annotations.Parameter;
... ... @@ -17,8 +23,11 @@ import org.springframework.web.bind.annotation.*;
17 23 import javax.annotation.Resource;
18 24 import javax.validation.Valid;
19 25 import java.util.List;
  26 +import java.util.Set;
  27 +import java.util.stream.Collectors;
20 28  
21 29 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
22 31  
23 32 @Tag(name = "管理后台 - 限时折扣活动")
24 33 @RestController
... ... @@ -29,6 +38,9 @@ public class DiscountActivityController {
29 38 @Resource
30 39 private DiscountActivityService discountActivityService;
31 40  
  41 + @Resource
  42 + private ProductSpuApi productSpuApi;
  43 +
32 44 @PostMapping("/create")
33 45 @Operation(summary = "创建限时折扣活动")
34 46 @PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')")
... ... @@ -49,7 +61,7 @@ public class DiscountActivityController {
49 61 @Parameter(name = "id", description = "编号", required = true)
50 62 @PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')")
51 63 public CommonResult<Boolean> closeRewardActivity(@RequestParam("id") Long id) {
52   - discountActivityService.closeRewardActivity(id);
  64 + discountActivityService.closeDiscountActivity(id);
53 65 return success(true);
54 66 }
55 67  
... ... @@ -81,7 +93,18 @@ public class DiscountActivityController {
81 93 @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
82 94 public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) {
83 95 PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(pageVO);
84   - return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult));
  96 +
  97 + if (CollUtil.isEmpty(pageResult.getList())) {
  98 + return success(PageResult.empty(pageResult.getTotal()));
  99 + }
  100 + // 拼接数据
  101 + List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
  102 + convertSet(pageResult.getList(), DiscountActivityDO::getId));
  103 +
  104 + List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(
  105 + convertSet(products, DiscountProductDO::getSpuId));
  106 +
  107 + return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
85 108 }
86 109  
87 110 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java
... ... @@ -7,6 +7,7 @@ import lombok.ToString;
7 7  
8 8 import javax.validation.constraints.NotNull;
9 9 import java.time.LocalDateTime;
  10 +import java.util.List;
10 11  
11 12 @Schema(description = "管理后台 - 限时折扣活动 Response VO")
12 13 @Data
... ... @@ -24,4 +25,25 @@ public class DiscountActivityRespVO extends DiscountActivityBaseVO {
24 25 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
25 26 private LocalDateTime createTime;
26 27  
  28 +
  29 + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  30 + private Long spuId;
  31 +
  32 + @Schema(description = "限时折扣商品", requiredMode = Schema.RequiredMode.REQUIRED)
  33 + private List<DiscountActivityBaseVO.Product> products;
  34 +
  35 +
  36 + // ========== 商品字段 ==========
  37 +
  38 + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 name 读取
  39 + example = "618大促")
  40 + private String spuName;
  41 + @Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 picUrl 读取
  42 + example = "https://www.iocoder.cn/xx.png")
  43 + private String picUrl;
  44 + @Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // 从 SPU 的 marketPrice 读取
  45 + example = "50")
  46 + private Integer marketPrice;
  47 +
  48 +
27 49 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java
... ... @@ -2,15 +2,22 @@ package cn.iocoder.yudao.module.promotion.convert.discount;
2 2  
3 3 import cn.hutool.core.util.ObjectUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
5 8 import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
6 9 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
  10 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
  11 +import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
7 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
8 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  14 +import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
9 15 import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
10 16 import org.mapstruct.Mapper;
11 17 import org.mapstruct.factory.Mappers;
12 18  
13 19 import java.util.List;
  20 +import java.util.Map;
14 21  
15 22 /**
16 23 * 限时折扣活动 Convert
... ... @@ -29,14 +36,57 @@ public interface DiscountActivityConvert {
29 36 DiscountActivityRespVO convert(DiscountActivityDO bean);
30 37  
31 38 List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
  39 + List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
32 40  
33 41 List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list);
34 42  
35 43 PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
36 44  
  45 + default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page,
  46 + List<DiscountProductDO> discountProductDOList,
  47 + List<ProductSpuRespDTO> spuList) {
  48 + PageResult<DiscountActivityRespVO> pageResult = convertPage(page);
  49 +
  50 + // 拼接商品
  51 + Map<Long, DiscountProductDO> discountActivityMap = CollectionUtils.convertMap(discountProductDOList, DiscountProductDO::getActivityId);
  52 + Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
  53 + pageResult.getList().forEach(item -> {
  54 + item.setProducts(convertList2(discountProductDOList));
  55 + item.setSpuId(discountActivityMap.get(item.getId())==null?null: discountActivityMap.get(item.getId()).getSpuId());
  56 + if (item.getSpuId() != null) {
  57 + MapUtils.findAndThen(spuMap, item.getSpuId(),
  58 + spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
  59 + }
  60 +
  61 + });
  62 + return pageResult;
  63 + }
  64 +
37 65 DiscountProductDO convert(DiscountActivityBaseVO.Product bean);
38 66  
39   - DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products);
  67 + default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products){
  68 + if ( activity == null && products == null ) {
  69 + return null;
  70 + }
  71 +
  72 + DiscountActivityDetailRespVO discountActivityDetailRespVO = new DiscountActivityDetailRespVO();
  73 +
  74 + if ( activity != null ) {
  75 + discountActivityDetailRespVO.setName( activity.getName() );
  76 + discountActivityDetailRespVO.setStartTime( activity.getStartTime() );
  77 + discountActivityDetailRespVO.setEndTime( activity.getEndTime() );
  78 + discountActivityDetailRespVO.setRemark( activity.getRemark() );
  79 + discountActivityDetailRespVO.setId( activity.getId() );
  80 + discountActivityDetailRespVO.setStatus( activity.getStatus() );
  81 + discountActivityDetailRespVO.setCreateTime( activity.getCreateTime() );
  82 + }
  83 + if (!products.isEmpty()) {
  84 + discountActivityDetailRespVO.setSpuId(products.get(0).getSpuId());
  85 + }
  86 + discountActivityDetailRespVO.setProducts( convertList2( products ) );
  87 +
  88 + return discountActivityDetailRespVO;
  89 + }
40 90  
41 91 // =========== 比较是否相等 ==========
42 92 /**
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
3 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 4 import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
5 5 import org.apache.ibatis.annotations.Mapper;
  6 +import org.apache.ibatis.annotations.Param;
6 7  
7 8 import java.util.Collection;
8 9 import java.util.List;
... ... @@ -23,4 +24,10 @@ public interface DiscountProductMapper extends BaseMapperX&lt;DiscountProductDO&gt; {
23 24 return selectList(DiscountProductDO::getActivityId, activityId);
24 25 }
25 26  
  27 + default List<DiscountProductDO> selectListByActivityId(Collection<Long> activityIds) {
  28 + return selectList(DiscountProductDO::getActivityId, activityIds);
  29 + }
  30 +
  31 +
  32 + List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
26 33 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java
... ... @@ -48,7 +48,7 @@ public interface DiscountActivityService {
48 48 *
49 49 * @param id 编号
50 50 */
51   - void closeRewardActivity(Long id);
  51 + void closeDiscountActivity(Long id);
52 52  
53 53 /**
54 54 * 删除限时折扣活动
... ... @@ -81,4 +81,12 @@ public interface DiscountActivityService {
81 81 */
82 82 List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId);
83 83  
  84 + /**
  85 + * 获得活动编号,对应对应的商品列表
  86 + *
  87 + * @param activityIds 活动编号
  88 + * @return 活动的商品列表
  89 + */
  90 + List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds);
  91 +
84 92 }
... ...
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 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.collection.CollectionUtil;
  5 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 7 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
7 8 import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
... ... @@ -20,6 +21,7 @@ import org.springframework.validation.annotation.Validated;
20 21 import javax.annotation.Resource;
21 22 import java.util.Collection;
22 23 import java.util.List;
  24 +import java.util.stream.Collectors;
23 25  
24 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 27 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
... ... @@ -41,8 +43,9 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
41 43  
42 44 @Override
43 45 public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
44   - // TODO 芋艿:开启、满足 skuId、日期内
45   - return null;
  46 + // 芋艿:开启、满足 skuId、日期内
  47 + List<DiscountProductDO> matchDiscountProductList = discountProductMapper.getMatchDiscountProductList(skuIds);
  48 + return matchDiscountProductList;
46 49 }
47 50  
48 51 @Override
... ... @@ -66,7 +69,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
66 69 public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) {
67 70 // 校验存在
68 71 DiscountActivityDO discountActivity = validateDiscountActivityExists(updateReqVO.getId());
69   - if (discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢
  72 + if (discountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能修改噢
70 73 throw exception(DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
71 74 }
72 75 // 校验商品是否冲突
... ... @@ -99,7 +102,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
99 102 }
100 103 }
101 104  
102   - // TODO 芋艿:校验逻辑简化,只查询时间冲突的活动,开启状态的。
  105 + // 芋艿:校验逻辑简化,只查询时间冲突的活动,开启状态的。
103 106 /**
104 107 * 校验商品是否冲突
105 108 *
... ... @@ -111,27 +114,30 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
111 114 return;
112 115 }
113 116 // 查询商品参加的活动
114   - List<DiscountProductDO> discountActivityProductList = null;
  117 +
  118 + List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id);
  119 + List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
  120 + List<DiscountProductDO> matchDiscountProductList = getMatchDiscountProductList(skuIds);
115 121 // getRewardProductListBySkuIds(
116 122 // convertSet(products, DiscountActivityBaseVO.Product::getSkuId),
117 123 // asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus()));
118 124 if (id != null) { // 排除自己这个活动
119   - discountActivityProductList.removeIf(product -> id.equals(product.getActivityId()));
  125 + matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));
120 126 }
121 127 // 如果非空,则说明冲突
122   - if (CollUtil.isNotEmpty(discountActivityProductList)) {
  128 + if (CollUtil.isNotEmpty(matchDiscountProductList)) {
123 129 throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS);
124 130 }
125 131 }
126 132  
127 133 @Override
128   - public void closeRewardActivity(Long id) {
  134 + public void closeDiscountActivity(Long id) {
129 135 // 校验存在
130 136 DiscountActivityDO dbDiscountActivity = validateDiscountActivityExists(id);
131   - if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢
  137 + if (dbDiscountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能关闭噢
132 138 throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
133 139 }
134   - if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢
  140 + if (dbDiscountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动,不能关闭噢
135 141 throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END);
136 142 }
137 143  
... ... @@ -144,7 +150,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
144 150 public void deleteDiscountActivity(Long id) {
145 151 // 校验存在
146 152 DiscountActivityDO discountActivity = validateDiscountActivityExists(id);
147   - if (!discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢
  153 + if (!discountActivity.getStatus().equals(CommonStatusEnum.ENABLE.getStatus())) { // 未关闭的活动,不能删除噢
148 154 throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
149 155 }
150 156  
... ... @@ -175,4 +181,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
175 181 return discountProductMapper.selectListByActivityId(activityId);
176 182 }
177 183  
  184 + @Override
  185 + public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
  186 + return discountProductMapper.selectList("activity_id", activityIds);
  187 + }
178 188 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/discount/DiscountProductMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
  4 +
  5 +
  6 + <select id="getMatchDiscountProductList" resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO">
  7 + SELECT pdp.*
  8 + FROM promotion_discount_product pdp
  9 + LEFT JOIN promotion_discount_activity pda
  10 + ON pdp.activity_id = pda.id
  11 + <where>
  12 + <if test="skuIds != null and skuIds.size > 0">
  13 + AND pdp.sku_id in
  14 + <foreach collection="skuIds" item="skuId" index="index" open="(" close=")" separator=",">
  15 + #{skuId}
  16 + </foreach>
  17 + </if>
  18 + AND pda.start_time &lt;= CURRENT_TIME AND pda.end_time &gt;= CURRENT_TIME
  19 + AND pda.`status` = 20
  20 + AND pda.deleted != 1
  21 + </where>
  22 + </select>
  23 +
  24 +</mapper>
... ...