mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 18:49:06 +08:00 
			
		
		
		
	【代码优化】商城: 限时折扣活动
This commit is contained in:
		| @ -11,7 +11,7 @@ public interface ErrorCodeConstants { | |||||||
|  |  | ||||||
|     // ========== 促销活动相关 1-013-001-000 ============ |     // ========== 促销活动相关 1-013-001-000 ============ | ||||||
|     ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_001_000, "限时折扣活动不存在"); |     ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_001_000, "限时折扣活动不存在"); | ||||||
|     ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_001_001, "存在商品参加了其它限时折扣活动"); |     ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1_013_001_001, "存在商品参加了其它限时折扣活动【{}】"); | ||||||
|     ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改"); |     ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_002, "限时折扣活动已关闭,不能修改"); | ||||||
|     ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除"); |     ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除"); | ||||||
|     ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭"); |     ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭"); | ||||||
|  | |||||||
| @ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.controller.admin.discount; | |||||||
| import cn.hutool.core.collection.CollUtil; | 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.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; | import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; | ||||||
| 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; | ||||||
| @ -13,12 +14,12 @@ import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityServic | |||||||
| 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; | ||||||
| import io.swagger.v3.oas.annotations.tags.Tag; | import io.swagger.v3.oas.annotations.tags.Tag; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import jakarta.validation.Valid; | ||||||
| import org.springframework.security.access.prepost.PreAuthorize; | import org.springframework.security.access.prepost.PreAuthorize; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
|  |  | ||||||
| import jakarta.annotation.Resource; |  | ||||||
| import jakarta.validation.Valid; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||||
| @ -33,9 +34,6 @@ 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')") | ||||||
| @ -73,7 +71,7 @@ public class DiscountActivityController { | |||||||
|     @Operation(summary = "获得限时折扣活动") |     @Operation(summary = "获得限时折扣活动") | ||||||
|     @Parameter(name = "id", description = "编号", required = true, example = "1024") |     @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||||||
|     @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") |     @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") | ||||||
|     public CommonResult<DiscountActivityDetailRespVO> getDiscountActivity(@RequestParam("id") Long id) { |     public CommonResult<DiscountActivityRespVO> getDiscountActivity(@RequestParam("id") Long id) { | ||||||
|         DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id); |         DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id); | ||||||
|         if (discountActivity == null) { |         if (discountActivity == null) { | ||||||
|             return success(null); |             return success(null); | ||||||
| @ -88,18 +86,14 @@ 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); | ||||||
|  |         if (CollUtil.isEmpty(pageResult.getList())) { | ||||||
|         if (CollUtil.isEmpty(pageResult.getList())) { // TODO @zhangshuai:方法里的空行,目的是让代码分块,可以更清晰;所以上面这个空格可以不要,而下面判断之后的,空格,其实加下比较好;类似的还有 spuList、以及后面的 convert |  | ||||||
|             return success(PageResult.empty(pageResult.getTotal())); |             return success(PageResult.empty(pageResult.getTotal())); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 拼接数据 |         // 拼接数据 | ||||||
|         List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId( |         List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId( | ||||||
|                 convertSet(pageResult.getList(), DiscountActivityDO::getId)); |                 convertSet(pageResult.getList(), DiscountActivityDO::getId)); | ||||||
|  |         return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products)); | ||||||
|         List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList( |  | ||||||
|                 convertSet(products, DiscountProductDO::getSpuId)); |  | ||||||
|  |  | ||||||
|         return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult, products, spuList)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,21 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; |  | ||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; |  | ||||||
| import lombok.Data; |  | ||||||
| import lombok.EqualsAndHashCode; |  | ||||||
| import lombok.ToString; |  | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| @Schema(description = "管理后台 - 限时折扣活动的详细 Response VO") |  | ||||||
| @Data |  | ||||||
| @EqualsAndHashCode(callSuper = true) |  | ||||||
| @ToString(callSuper = true) |  | ||||||
| public class DiscountActivityDetailRespVO extends DiscountActivityRespVO { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 商品列表 |  | ||||||
|      */ |  | ||||||
|     private List<Product> products; |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @ -1,11 +1,11 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; | package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; | ||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.ToString; | import lombok.ToString; | ||||||
|  |  | ||||||
| import jakarta.validation.constraints.NotNull; |  | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| @ -25,25 +25,7 @@ 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") // TODO @zhangshuai:属性和属性之间,最多空一行噢; |  | ||||||
|     private Long spuId; |  | ||||||
|  |  | ||||||
|     @Schema(description = "限时折扣商品", requiredMode = Schema.RequiredMode.REQUIRED) |     @Schema(description = "限时折扣商品", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|     private List<DiscountActivityBaseVO.Product> products; |     private List<Product> products; | ||||||
|  |  | ||||||
|     // ========== 商品字段 ========== |  | ||||||
|  |  | ||||||
|     // TODO @zhangshuai:一个优惠活动,会关联多个商品,所以它不用返回 spuName 哈; |  | ||||||
|     // TODO 最终界面展示字段就:编号、活动名称、参与商品数、活动状态、开始时间、结束时间、操作 |  | ||||||
|     @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; |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +1,13 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; | package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; | ||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.Valid; | ||||||
|  | import jakarta.validation.constraints.NotEmpty; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.ToString; | import lombok.ToString; | ||||||
|  |  | ||||||
| import jakarta.validation.Valid; |  | ||||||
| import jakarta.validation.constraints.NotEmpty; |  | ||||||
| import jakarta.validation.constraints.NotNull; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| @Schema(description = "管理后台 - 限时折扣活动更新 Request VO") | @Schema(description = "管理后台 - 限时折扣活动更新 Request VO") | ||||||
| @ -25,6 +25,6 @@ public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO { | |||||||
|      */ |      */ | ||||||
|     @NotEmpty(message = "商品列表不能为空") |     @NotEmpty(message = "商品列表不能为空") | ||||||
|     @Valid |     @Valid | ||||||
|     private List<DiscountActivityCreateReqVO.Product> products; |     private List<Product> products; | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,20 +1,18 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.convert.discount; | 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.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
| 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.DiscountActivityBaseVO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO; | ||||||
|  | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; | ||||||
| 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.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 | ||||||
| @ -33,6 +31,7 @@ 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<DiscountActivityBaseVO.Product> convertList2(List<DiscountProductDO> list); | ||||||
|  |  | ||||||
|     List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list); |     List<DiscountProductRespDTO> convertList02(List<DiscountProductDO> list); | ||||||
| @ -40,98 +39,16 @@ public interface DiscountActivityConvert { | |||||||
|     PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); |     PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page); | ||||||
|  |  | ||||||
|     default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page, |     default PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page, | ||||||
|                                                            List<DiscountProductDO> discountProductDOList, |                                                            List<DiscountProductDO> discountProductDOList) { | ||||||
|                                                            List<ProductSpuRespDTO> spuList) { |  | ||||||
|         PageResult<DiscountActivityRespVO> pageResult = convertPage(page); |         PageResult<DiscountActivityRespVO> pageResult = convertPage(page); | ||||||
|  |         pageResult.getList().forEach(item -> item.setProducts(convertList2(discountProductDOList))); | ||||||
|         // 拼接商品 TODO @zhangshuai:类似空行的问题,也可以看看 |  | ||||||
|         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; |         return pageResult; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DiscountProductDO convert(DiscountActivityBaseVO.Product bean); |     DiscountProductDO convert(DiscountActivityBaseVO.Product bean); | ||||||
|  |  | ||||||
|     default DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products){ |     default DiscountActivityRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products) { | ||||||
|         if ( activity == null && products == null ) { |         return BeanUtils.toBean(activity, DiscountActivityRespVO.class).setProducts(convertList2(products)); | ||||||
|             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; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // =========== 比较是否相等 ========== |  | ||||||
|     /** |  | ||||||
|      * 比较两个限时折扣商品是否相等 |  | ||||||
|      * |  | ||||||
|      * @param productDO 数据库中的商品 |  | ||||||
|      * @param productVO 前端传入的商品 |  | ||||||
|      * @return 是否匹配 |  | ||||||
|      */ |  | ||||||
|     @SuppressWarnings("DuplicatedCode") |  | ||||||
|     default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) { |  | ||||||
|         if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) |  | ||||||
|                 || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) |  | ||||||
|                 || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { |  | ||||||
|             return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice()); |  | ||||||
|         } |  | ||||||
|         if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) { |  | ||||||
|             return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent()); |  | ||||||
|         } |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 比较两个限时折扣商品是否相等 |  | ||||||
|      * 注意,比较时忽略 id 编号 |  | ||||||
|      * |  | ||||||
|      * @param productDO 商品 1 |  | ||||||
|      * @param productVO 商品 2 |  | ||||||
|      * @return 是否匹配 |  | ||||||
|      */ |  | ||||||
|     @SuppressWarnings("DuplicatedCode") |  | ||||||
|     default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) { |  | ||||||
|         if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) |  | ||||||
|                 || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) |  | ||||||
|                 || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { |  | ||||||
|             return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice()); |  | ||||||
|         } |  | ||||||
|         if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) { |  | ||||||
|             return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent()); |  | ||||||
|         } |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,9 +18,6 @@ import java.util.Map; | |||||||
| @Mapper | @Mapper | ||||||
| public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { | public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> { | ||||||
|  |  | ||||||
|     default List<DiscountProductDO> selectListBySkuId(Collection<Long> skuIds) { |  | ||||||
|         return selectList(DiscountProductDO::getSkuId, skuIds); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     default List<DiscountProductDO> selectListByActivityId(Long activityId) { |     default List<DiscountProductDO> selectListByActivityId(Long activityId) { | ||||||
|         return selectList(DiscountProductDO::getActivityId, activityId); |         return selectList(DiscountProductDO::getActivityId, activityId); | ||||||
|  | |||||||
| @ -1,11 +1,14 @@ | |||||||
| package cn.iocoder.yudao.module.promotion.service.discount; | 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.map.MapUtil; | import cn.hutool.core.map.MapUtil; | ||||||
|  | import cn.hutool.core.util.ObjectUtil; | ||||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 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.framework.common.util.collection.CollectionUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
|  | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||||||
|  | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||||||
| 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; | ||||||
| import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; | import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; | ||||||
| @ -27,11 +30,12 @@ import java.util.Collection; | |||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.stream.Collectors; |  | ||||||
|  |  | ||||||
|  | import static cn.hutool.core.collection.CollUtil.intersectionDistinct; | ||||||
| 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.*; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; | ||||||
|  | import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | ||||||
| import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -47,6 +51,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | |||||||
|     private DiscountActivityMapper discountActivityMapper; |     private DiscountActivityMapper discountActivityMapper; | ||||||
|     @Resource |     @Resource | ||||||
|     private DiscountProductMapper discountProductMapper; |     private DiscountProductMapper discountProductMapper; | ||||||
|  |     @Resource | ||||||
|  |     private ProductSkuApi productSkuApi; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) { |     public List<DiscountProductDO> getMatchDiscountProductList(Collection<Long> skuIds) { | ||||||
| @ -58,6 +64,8 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | |||||||
|     public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { |     public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { | ||||||
|         // 校验商品是否冲突 |         // 校验商品是否冲突 | ||||||
|         validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); |         validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); | ||||||
|  |         // 校验商品是否存在 | ||||||
|  |         validateProductExists(createReqVO.getProducts()); | ||||||
|  |  | ||||||
|         // 插入活动 |         // 插入活动 | ||||||
|         DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) |         DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) | ||||||
| @ -82,36 +90,40 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | |||||||
|         } |         } | ||||||
|         // 校验商品是否冲突 |         // 校验商品是否冲突 | ||||||
|         validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); |         validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); | ||||||
|  |         // 校验商品是否存在 | ||||||
|  |         validateProductExists(updateReqVO.getProducts()); | ||||||
|  |  | ||||||
|         // 更新活动 |         // 更新活动 | ||||||
|         DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO) |         DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO) | ||||||
|                 .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); |                 .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime())); | ||||||
|         discountActivityMapper.updateById(updateObj); |         discountActivityMapper.updateById(updateObj); | ||||||
|         // 更新商品 |         // 更新商品 | ||||||
|         updateDiscountProduct(updateReqVO); |         updateDiscountProduct(updateObj, updateReqVO.getProducts()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) { |     private void updateDiscountProduct(DiscountActivityDO activity, List<DiscountActivityCreateReqVO.Product> products) { | ||||||
|         // TODO @zhangshuai:这里的逻辑,可以优化下哈;参考 CombinationActivityServiceImpl 的 updateCombinationProduct,主要是 CollectionUtils.diffList 的使用哈; |         // 第一步,对比新老数据,获得添加、修改、删除的列表 | ||||||
|         //  然后原先是使用 DiscountActivityConvert.INSTANCE.isEquals 对比,现在看看是不是简化就基于 skuId 对比就完事了;之前写的太精细,意义不大; |         List<DiscountProductDO> newList = BeanUtils.toBean(products, DiscountProductDO.class, | ||||||
|         List<DiscountProductDO> dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId()); |                 product -> product.setActivityId(activity.getId()).setActivityStatus(activity.getStatus()) | ||||||
|         // 计算要删除的记录 |                         .setActivityStartTime(activity.getStartTime()).setActivityEndTime(activity.getEndTime())); | ||||||
|         List<Long> deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId, |         List<DiscountProductDO> oldList = discountProductMapper.selectListByActivityId(activity.getId()); | ||||||
|                 discountProductDO -> updateReqVO.getProducts().stream() |         List<List<DiscountProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> { | ||||||
|                         .noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product))); |             boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId()); | ||||||
|         if (CollUtil.isNotEmpty(deleteIds)) { |             if (same) { | ||||||
|             discountProductMapper.deleteBatchIds(deleteIds); |                 newVal.setId(oldVal.getId()); | ||||||
|  |             } | ||||||
|  |             return same; | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // 第二步,批量添加、修改、删除 | ||||||
|  |         if (CollUtil.isNotEmpty(diffList.get(0))) { | ||||||
|  |             discountProductMapper.insertBatch(diffList.get(0)); | ||||||
|         } |         } | ||||||
|         // 计算新增的记录 |         if (CollUtil.isNotEmpty(diffList.get(1))) { | ||||||
|         List<DiscountProductDO> newDiscountProducts = convertList(updateReqVO.getProducts(), |             discountProductMapper.updateBatch(diffList.get(1)); | ||||||
|                 product -> DiscountActivityConvert.INSTANCE.convert(product) |         } | ||||||
|                         .setActivityId(updateReqVO.getId()) |         if (CollUtil.isNotEmpty(diffList.get(2))) { | ||||||
|                         .setActivityStartTime(updateReqVO.getStartTime()) |             discountProductMapper.deleteBatchIds(convertList(diffList.get(2), DiscountProductDO::getId)); | ||||||
|                         .setActivityEndTime(updateReqVO.getEndTime())); |  | ||||||
|         newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch( |  | ||||||
|                 dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到,说明是更新的 |  | ||||||
|         if (CollectionUtil.isNotEmpty(newDiscountProducts)) { |  | ||||||
|             discountProductMapper.insertBatch(newDiscountProducts); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -122,22 +134,44 @@ public class DiscountActivityServiceImpl implements DiscountActivityService { | |||||||
|      * @param products 商品列表 |      * @param products 商品列表 | ||||||
|      */ |      */ | ||||||
|     private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) { |     private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) { | ||||||
|         if (CollUtil.isEmpty(products)) { |         // 1.1 查询所有开启的折扣活动 | ||||||
|             return; |         List<DiscountActivityDO> activityList = discountActivityMapper.selectList(DiscountActivityDO::getStatus, | ||||||
|         } |                 CommonStatusEnum.ENABLE.getStatus()); | ||||||
|         // 查询商品参加的活动 |         if (id != null) { // 时排除自己 | ||||||
|         // TODO @zhangshuai:下面 121 这个查询,是不是不用做呀;直接 convert 出 skuId 集合就 ok 啦; |             activityList.removeIf(item -> ObjectUtil.equal(item.getId(), id)); | ||||||
|         List<DiscountProductDO> list = discountProductMapper.selectListByActivityId(id); |  | ||||||
|         // TODO @zhangshuai:一般简单的 stream 方法,建议是使用 CollectionUtils,例如说这里是 convertList 对把。 |  | ||||||
|         List<Long> skuIds = list.stream().map(item -> item.getSkuId()).collect(Collectors.toList()); |  | ||||||
|         List<DiscountProductDO> matchDiscountProductList = getMatchDiscountProductList(skuIds); |  | ||||||
|         if (id != null) { // 排除自己这个活动 |  | ||||||
|             matchDiscountProductList.removeIf(product -> id.equals(product.getActivityId())); |  | ||||||
|         } |  | ||||||
|         // 如果非空,则说明冲突 |  | ||||||
|         if (CollUtil.isNotEmpty(matchDiscountProductList)) { |  | ||||||
|             throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS); |  | ||||||
|         } |         } | ||||||
|  |         // 1.2 查询活动下的所有商品 | ||||||
|  |         List<DiscountProductDO> productList = discountProductMapper.selectListByActivityId( | ||||||
|  |                 convertList(activityList, DiscountActivityDO::getId)); | ||||||
|  |         Map<Long, List<DiscountProductDO>> productListMap = convertMultiMap(productList, DiscountProductDO::getActivityId); | ||||||
|  |  | ||||||
|  |         // 2. 校验商品是否冲突 | ||||||
|  |         activityList.forEach(item -> { | ||||||
|  |             findAndThen(productListMap, item.getId(), discountProducts -> { | ||||||
|  |                 if (!intersectionDistinct(convertList(discountProducts, DiscountProductDO::getSpuId), | ||||||
|  |                         convertList(products, DiscountActivityBaseVO.Product::getSpuId)).isEmpty()) { | ||||||
|  |                     throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS, item.getName()); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 校验活动商品是否都存在 | ||||||
|  |      * | ||||||
|  |      * @param products 活动商品 | ||||||
|  |      */ | ||||||
|  |     private void validateProductExists(List<DiscountActivityBaseVO.Product> products) { | ||||||
|  |         // 1.获得商品所有的 sku | ||||||
|  |         List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId( | ||||||
|  |                 convertList(products, DiscountActivityBaseVO.Product::getSpuId)); | ||||||
|  |         Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId); | ||||||
|  |         // 2. 校验商品 sku 都存在 | ||||||
|  |         products.forEach(product -> { | ||||||
|  |             if (!skuMap.containsKey(product.getSkuId())) { | ||||||
|  |                 throw exception(SKU_NOT_EXISTS); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 puhui999
					puhui999