mall模块-限时折扣功能

This commit is contained in:
zhangshuai 2023-10-20 20:54:16 +08:00
parent 82fd800ad2
commit 04061b028c
7 changed files with 159 additions and 15 deletions

View File

@ -1,11 +1,17 @@
package cn.iocoder.yudao.module.promotion.controller.admin.discount; package cn.iocoder.yudao.module.promotion.controller.admin.discount;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@ -17,8 +23,11 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 限时折扣活动") @Tag(name = "管理后台 - 限时折扣活动")
@RestController @RestController
@ -29,6 +38,9 @@ public class DiscountActivityController {
@Resource @Resource
private DiscountActivityService discountActivityService; private DiscountActivityService discountActivityService;
@Resource
private ProductSpuApi productSpuApi;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建限时折扣活动") @Operation(summary = "创建限时折扣活动")
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')") @PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')")
@ -49,7 +61,7 @@ public class DiscountActivityController {
@Parameter(name = "id", description = "编号", required = true) @Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')") @PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')")
public CommonResult<Boolean> closeRewardActivity(@RequestParam("id") Long id) { public CommonResult<Boolean> closeRewardActivity(@RequestParam("id") Long id) {
discountActivityService.closeRewardActivity(id); discountActivityService.closeDiscountActivity(id);
return success(true); return success(true);
} }
@ -81,7 +93,18 @@ public class DiscountActivityController {
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) { public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) {
PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(pageVO); PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(pageVO);
return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult));
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
// 拼接数据
List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
convertSet(pageResult.getList(), DiscountActivityDO::getId));
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(
convertSet(products, DiscountProductDO::getSpuId));
return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products, spuList));
} }
} }

View File

@ -7,6 +7,7 @@ import lombok.ToString;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 限时折扣活动 Response VO") @Schema(description = "管理后台 - 限时折扣活动 Response VO")
@Data @Data
@ -24,4 +25,25 @@ public class DiscountActivityRespVO extends DiscountActivityBaseVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
private Long spuId;
@Schema(description = "限时折扣商品", requiredMode = Schema.RequiredMode.REQUIRED)
private List<DiscountActivityBaseVO.Product> products;
// ========== 商品字段 ==========
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, // SPU name 读取
example = "618大促")
private String spuName;
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, // SPU picUrl 读取
example = "https://www.iocoder.cn/xx.png")
private String picUrl;
@Schema(description = "商品市场价,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, // SPU marketPrice 读取
example = "50")
private Integer marketPrice;
} }

View File

@ -2,15 +2,22 @@ package cn.iocoder.yudao.module.promotion.convert.discount;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 限时折扣活动 Convert * 限时折扣活动 Convert
@ -29,14 +36,57 @@ public interface DiscountActivityConvert {
DiscountActivityRespVO convert(DiscountActivityDO bean); DiscountActivityRespVO convert(DiscountActivityDO bean);
List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list); List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list); List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list);
PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page,
List<DiscountProductDO> discountProductDOList,
List<ProductSpuRespDTO> spuList) {
PageResult<DiscountActivityRespVO> pageResult = convertPage(page);
// 拼接商品
Map<Long, DiscountProductDO> discountActivityMap = CollectionUtils.convertMap(discountProductDOList, DiscountProductDO::getActivityId);
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
pageResult.getList().forEach(item -> {
item.setProducts(convertList2(discountProductDOList));
item.setSpuId(discountActivityMap.get(item.getId())==null?null: discountActivityMap.get(item.getId()).getSpuId());
if (item.getSpuId() != null) {
MapUtils.findAndThen(spuMap, item.getSpuId(),
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
}
});
return pageResult;
}
DiscountProductDO convert(DiscountActivityBaseVO.Product bean); DiscountProductDO convert(DiscountActivityBaseVO.Product bean);
DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products); default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products){
if ( activity == null && products == null ) {
return null;
}
DiscountActivityDetailRespVO discountActivityDetailRespVO = new DiscountActivityDetailRespVO();
if ( activity != null ) {
discountActivityDetailRespVO.setName( activity.getName() );
discountActivityDetailRespVO.setStartTime( activity.getStartTime() );
discountActivityDetailRespVO.setEndTime( activity.getEndTime() );
discountActivityDetailRespVO.setRemark( activity.getRemark() );
discountActivityDetailRespVO.setId( activity.getId() );
discountActivityDetailRespVO.setStatus( activity.getStatus() );
discountActivityDetailRespVO.setCreateTime( activity.getCreateTime() );
}
if (!products.isEmpty()) {
discountActivityDetailRespVO.setSpuId(products.get(0).getSpuId());
}
discountActivityDetailRespVO.setProducts( convertList2( products ) );
return discountActivityDetailRespVO;
}
// =========== 比较是否相等 ========== // =========== 比较是否相等 ==========
/** /**

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -23,4 +24,10 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
return selectList(DiscountProductDO::getActivityId, activityId); return selectList(DiscountProductDO::getActivityId, activityId);
} }
default List<DiscountProductDO> selectListByActivityId(Collection<Long> activityIds) {
return selectList(DiscountProductDO::getActivityId, activityIds);
}
List<DiscountProductDO> getMatchDiscountProductList(@Param("skuIds") Collection<Long> skuIds);
} }

View File

@ -48,7 +48,7 @@ public interface DiscountActivityService {
* *
* @param id 编号 * @param id 编号
*/ */
void closeRewardActivity(Long id); void closeDiscountActivity(Long id);
/** /**
* 删除限时折扣活动 * 删除限时折扣活动
@ -81,4 +81,12 @@ public interface DiscountActivityService {
*/ */
List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId); List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId);
/**
* 获得活动编号对应对应的商品列表
*
* @param activityIds 活动编号
* @return 活动的商品列表
*/
List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds);
} }

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.discount;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
@ -20,6 +21,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -41,8 +43,9 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
@Override @Override
public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) { public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
// TODO 芋艿开启满足 skuId日期内 // 芋艿开启满足 skuId日期内
return null; List<DiscountProductDO> matchDiscountProductList = discountProductMapper.getMatchDiscountProductList(skuIds);
return matchDiscountProductList;
} }
@Override @Override
@ -66,7 +69,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) { public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
DiscountActivityDO discountActivity = validateDiscountActivityExists(updateReqVO.getId()); DiscountActivityDO discountActivity = validateDiscountActivityExists(updateReqVO.getId());
if (discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动不能修改噢 if (discountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动不能修改噢
throw exception(DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); throw exception(DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
} }
// 校验商品是否冲突 // 校验商品是否冲突
@ -99,7 +102,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
} }
} }
// TODO 芋艿校验逻辑简化只查询时间冲突的活动开启状态的 // 芋艿校验逻辑简化只查询时间冲突的活动开启状态的
/** /**
* 校验商品是否冲突 * 校验商品是否冲突
* *
@ -111,27 +114,30 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
return; return;
} }
// 查询商品参加的活动 // 查询商品参加的活动
List<DiscountProductDO> discountActivityProductList = null;
List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id);
List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
List<DiscountProductDO> matchDiscountProductList = getMatchDiscountProductList(skuIds);
// getRewardProductListBySkuIds( // getRewardProductListBySkuIds(
// convertSet(products, DiscountActivityBaseVO.Product::getSkuId), // convertSet(products, DiscountActivityBaseVO.Product::getSkuId),
// asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); // asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus()));
if (id != null) { // 排除自己这个活动 if (id != null) { // 排除自己这个活动
discountActivityProductList.removeIf(product -> id.equals(product.getActivityId())); matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId()));
} }
// 如果非空则说明冲突 // 如果非空则说明冲突
if (CollUtil.isNotEmpty(discountActivityProductList)) { if (CollUtil.isNotEmpty(matchDiscountProductList)) {
throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS); throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS);
} }
} }
@Override @Override
public void closeRewardActivity(Long id) { public void closeDiscountActivity(Long id) {
// 校验存在 // 校验存在
DiscountActivityDO dbDiscountActivity = validateDiscountActivityExists(id); DiscountActivityDO dbDiscountActivity = validateDiscountActivityExists(id);
if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动不能关闭噢 if (dbDiscountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动不能关闭噢
throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
} }
if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动不能关闭噢 if (dbDiscountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动不能关闭噢
throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END); throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END);
} }
@ -144,7 +150,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
public void deleteDiscountActivity(Long id) { public void deleteDiscountActivity(Long id) {
// 校验存在 // 校验存在
DiscountActivityDO discountActivity = validateDiscountActivityExists(id); DiscountActivityDO discountActivity = validateDiscountActivityExists(id);
if (!discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动不能删除噢 if (!discountActivity.getStatus().equals(CommonStatusEnum.ENABLE.getStatus())) { // 未关闭的活动不能删除噢
throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
} }
@ -175,4 +181,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
return discountProductMapper.selectListByActivityId(activityId); return discountProductMapper.selectListByActivityId(activityId);
} }
@Override
public List<DiscountProductDO> getDiscountProductsByActivityId(Collection<Long> activityIds) {
return discountProductMapper.selectList("activity_id", activityIds);
}
} }

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper">
<select id="getMatchDiscountProductList" resultType="cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO">
SELECT pdp.*
FROM promotion_discount_product pdp
LEFT JOIN promotion_discount_activity pda
ON pdp.activity_id = pda.id
<where>
<if test="skuIds != null and skuIds.size > 0">
AND pdp.sku_id in
<foreach collection="skuIds" item="skuId" index="index" open="(" close=")" separator=",">
#{skuId}
</foreach>
</if>
AND pda.start_time &lt;= CURRENT_TIME AND pda.end_time &gt;= CURRENT_TIME
AND pda.`status` = 20
AND pda.deleted != 1
</where>
</select>
</mapper>