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;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
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.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.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 io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -17,8 +23,11 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
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.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 限时折扣活动")
@RestController
@ -29,6 +38,9 @@ public class DiscountActivityController {
@Resource
private DiscountActivityService discountActivityService;
@Resource
private ProductSpuApi productSpuApi;
@PostMapping("/create")
@Operation(summary = "创建限时折扣活动")
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')")
@ -49,7 +61,7 @@ public class DiscountActivityController {
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')")
public CommonResult<Boolean> closeRewardActivity(@RequestParam("id") Long id) {
discountActivityService.closeRewardActivity(id);
discountActivityService.closeDiscountActivity(id);
return success(true);
}
@ -81,7 +93,18 @@ public class DiscountActivityController {
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO 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 java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 限时折扣活动 Response VO")
@Data
@ -24,4 +25,25 @@ public class DiscountActivityRespVO extends DiscountActivityBaseVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
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.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.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.DiscountProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* 限时折扣活动 Convert
@ -29,14 +36,57 @@ public interface DiscountActivityConvert {
DiscountActivityRespVO convert(DiscountActivityDO bean);
List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
List<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list);
List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list);
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);
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.module.promotion.dal.dataobject.discount.DiscountProductDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
@ -23,4 +24,10 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
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 编号
*/
void closeRewardActivity(Long id);
void closeDiscountActivity(Long id);
/**
* 删除限时折扣活动
@ -81,4 +81,12 @@ public interface DiscountActivityService {
*/
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.CollectionUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.DiscountActivityCreateReqVO;
@ -20,6 +21,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
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.util.collection.CollectionUtils.convertList;
@ -41,8 +43,9 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
@Override
public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) {
// TODO 芋艿开启满足 skuId日期内
return null;
// 芋艿开启满足 skuId日期内
List<DiscountProductDO> matchDiscountProductList = discountProductMapper.getMatchDiscountProductList(skuIds);
return matchDiscountProductList;
}
@Override
@ -66,7 +69,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) {
// 校验存在
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);
}
// 校验商品是否冲突
@ -99,7 +102,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
}
}
// TODO 芋艿校验逻辑简化只查询时间冲突的活动开启状态的
// 芋艿校验逻辑简化只查询时间冲突的活动开启状态的
/**
* 校验商品是否冲突
*
@ -111,27 +114,30 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
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(
// convertSet(products, DiscountActivityBaseVO.Product::getSkuId),
// asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus()));
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);
}
}
@Override
public void closeRewardActivity(Long id) {
public void closeDiscountActivity(Long 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);
}
if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动不能关闭噢
if (dbDiscountActivity.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) { // 已关闭的活动不能关闭噢
throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END);
}
@ -144,7 +150,7 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
public void deleteDiscountActivity(Long 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);
}
@ -175,4 +181,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService {
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>