mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	!625 完善订单和活动 review 提到的问题,完善 app 端获取拼团活动分页、列表、详情接口
Merge pull request !625 from puhui999/feature/mall_product
This commit is contained in:
		@@ -43,17 +43,6 @@ public class LocalDateTimeUtils {
 | 
			
		||||
        return LocalDateTime.of(year, mouth, day, 0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建指定时间
 | 
			
		||||
     *
 | 
			
		||||
     * @param timeStr 时间字符串
 | 
			
		||||
     * @return 指定时间
 | 
			
		||||
     */
 | 
			
		||||
    public static LocalDateTime buildTime(String timeStr) {
 | 
			
		||||
        // TODO @puhui999:这个方法的实现,和 LocalDateTimeUtil.parse() 的差异点是啥呀
 | 
			
		||||
        return LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeStr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
 | 
			
		||||
                                                   int year2, int mouth2, int day2) {
 | 
			
		||||
        return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
 | 
			
		||||
 
 | 
			
		||||
@@ -7,14 +7,13 @@ package cn.iocoder.yudao.module.promotion.api.seckill;
 | 
			
		||||
 */
 | 
			
		||||
public interface SeckillActivityApi {
 | 
			
		||||
 | 
			
		||||
    // TODO @puhui999:activityId 改成 id 好点哈;
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新秒杀库存
 | 
			
		||||
     *
 | 
			
		||||
     * @param activityId 活动编号
 | 
			
		||||
     * @param id 活动编号
 | 
			
		||||
     * @param skuId      sku 编号
 | 
			
		||||
     * @param count      数量
 | 
			
		||||
     */
 | 
			
		||||
    void updateSeckillStock(Long activityId, Long skuId, Integer count);
 | 
			
		||||
    void updateSeckillStock(Long id, Long skuId, Integer count);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ public interface ErrorCodeConstants {
 | 
			
		||||
    ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
 | 
			
		||||
    ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
 | 
			
		||||
    ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
 | 
			
		||||
    ErrorCode SECKILL_ACTIVITY_FAIL_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
 | 
			
		||||
    ErrorCode SECKILL_ACTIVITY_APP_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
 | 
			
		||||
 | 
			
		||||
    // ========== 秒杀时段 1013009000 ==========
 | 
			
		||||
    ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");
 | 
			
		||||
@@ -69,6 +69,7 @@ public interface ErrorCodeConstants {
 | 
			
		||||
    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE_NOT_UPDATE = new ErrorCode(1013010002, "拼团活动已关闭不能修改");
 | 
			
		||||
    ErrorCode COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013010003, "拼团活动未关闭或未结束,不能删除");
 | 
			
		||||
    ErrorCode COMBINATION_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013010004, "拼团失败,原因:拼团活动已关闭");
 | 
			
		||||
    ErrorCode COMBINATION_ACTIVITY_APP_STATUS_DISABLE = new ErrorCode(1013010005, "拼团活动已关闭");
 | 
			
		||||
 | 
			
		||||
    // ========== 拼团记录 1013011000 ==========
 | 
			
		||||
    ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013011000, "拼团不存在");
 | 
			
		||||
 
 | 
			
		||||
@@ -17,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
 | 
			
		||||
    private SeckillActivityService activityService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
 | 
			
		||||
        activityService.updateSeckillStock(activityId, skuId, count);
 | 
			
		||||
    public void updateSeckillStock(Long id, Long skuId, Integer count) {
 | 
			
		||||
        activityService.updateSeckillStock(id, skuId, count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.hutool.core.util.ObjectUtil.defaultIfNull;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +40,7 @@ public class AppBargainActivityController {
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
    @Operation(summary = "获得砍价活动分页")
 | 
			
		||||
    public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
 | 
			
		||||
        PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPageForApp(pageReqVO);
 | 
			
		||||
        PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityPage(pageReqVO);
 | 
			
		||||
        if (CollUtil.isEmpty(result.getList())) {
 | 
			
		||||
            return success(PageResult.empty(result.getTotal()));
 | 
			
		||||
        }
 | 
			
		||||
@@ -54,7 +55,7 @@ public class AppBargainActivityController {
 | 
			
		||||
    @Parameter(name = "count", description = "需要展示的数量", example = "6")
 | 
			
		||||
    public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
 | 
			
		||||
            @RequestParam(name = "count", defaultValue = "6") Integer count) {
 | 
			
		||||
        List<BargainActivityDO> list = bargainActivityService.getBargainActivityListForApp(count);
 | 
			
		||||
        List<BargainActivityDO> list = bargainActivityService.getBargainActivityListByCount(defaultIfNull(count, 6));
 | 
			
		||||
        if (CollUtil.isEmpty(list)) {
 | 
			
		||||
            return success(BargainActivityConvert.INSTANCE.convertAppList(list));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,19 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.controller.app.combination;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
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.app.combination.vo.activity.AppCombinationActivityDetailRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
			
		||||
@@ -14,11 +23,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.hutool.core.util.ObjectUtil.defaultIfNull;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_ACTIVITY_APP_STATUS_DISABLE;
 | 
			
		||||
 | 
			
		||||
@Tag(name = "用户 APP - 拼团活动")
 | 
			
		||||
@RestController
 | 
			
		||||
@@ -26,104 +39,55 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
@Validated
 | 
			
		||||
public class AppCombinationActivityController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private CombinationActivityService activityService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private ProductSpuApi spuApi;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    @Operation(summary = "获得拼团活动列表", description = "用于小程序首页")
 | 
			
		||||
    // TODO 芋艿:增加 Spring Cache
 | 
			
		||||
    // TODO 芋艿:缺少 swagger 注解
 | 
			
		||||
    @Parameter(name = "count", description = "需要展示的数量", example = "6")
 | 
			
		||||
    public CommonResult<List<AppCombinationActivityRespVO>> getCombinationActivityList(
 | 
			
		||||
            @RequestParam(name = "count", defaultValue = "6") Integer count) {
 | 
			
		||||
        List<AppCombinationActivityRespVO> activityList = new ArrayList<>();
 | 
			
		||||
        AppCombinationActivityRespVO activity1 = new AppCombinationActivityRespVO();
 | 
			
		||||
        activity1.setId(1L);
 | 
			
		||||
        activity1.setName("618 大拼团");
 | 
			
		||||
        activity1.setUserSize(3);
 | 
			
		||||
        activity1.setSpuId(2048L);
 | 
			
		||||
        activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
 | 
			
		||||
        activity1.setMarketPrice(50);
 | 
			
		||||
        activity1.setCombinationPrice(100);
 | 
			
		||||
        activityList.add(activity1);
 | 
			
		||||
        List<CombinationActivityDO> list = activityService.getCombinationActivityListByCount(defaultIfNull(count, 6));
 | 
			
		||||
        if (CollUtil.isEmpty(list)) {
 | 
			
		||||
            return success(CombinationActivityConvert.INSTANCE.convertAppList(list));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AppCombinationActivityRespVO activity2 = new AppCombinationActivityRespVO();
 | 
			
		||||
        activity2.setId(2L);
 | 
			
		||||
        activity2.setName("双十一拼团");
 | 
			
		||||
        activity2.setUserSize(5);
 | 
			
		||||
        activity2.setSpuId(4096L);
 | 
			
		||||
        activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
 | 
			
		||||
        activity2.setMarketPrice(100);
 | 
			
		||||
        activity2.setCombinationPrice(200);
 | 
			
		||||
        activityList.add(activity2);
 | 
			
		||||
 | 
			
		||||
        return success(activityList);
 | 
			
		||||
        List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(list, CombinationActivityDO::getSpuId));
 | 
			
		||||
        // TODO 芋艿:增加 Spring Cache
 | 
			
		||||
        return success(CombinationActivityConvert.INSTANCE.convertAppList(list, spuList));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
    @Operation(summary = "获得拼团活动分页")
 | 
			
		||||
    public CommonResult<PageResult<AppCombinationActivityRespVO>> getCombinationActivityPage(PageParam pageParam) {
 | 
			
		||||
        List<AppCombinationActivityRespVO> activityList = new ArrayList<>();
 | 
			
		||||
        AppCombinationActivityRespVO activity1 = new AppCombinationActivityRespVO();
 | 
			
		||||
        activity1.setId(1L);
 | 
			
		||||
        activity1.setName("618 大拼团");
 | 
			
		||||
        activity1.setUserSize(3);
 | 
			
		||||
        activity1.setSpuId(2048L);
 | 
			
		||||
        activity1.setPicUrl("商品图片地址");
 | 
			
		||||
        activity1.setMarketPrice(50);
 | 
			
		||||
        activity1.setCombinationPrice(100);
 | 
			
		||||
        activityList.add(activity1);
 | 
			
		||||
        PageResult<CombinationActivityDO> result = activityService.getCombinationActivityPage(pageParam);
 | 
			
		||||
        if (CollUtil.isEmpty(result.getList())) {
 | 
			
		||||
            return success(PageResult.empty(result.getTotal()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AppCombinationActivityRespVO activity2 = new AppCombinationActivityRespVO();
 | 
			
		||||
        activity2.setId(2L);
 | 
			
		||||
        activity2.setName("双十一拼团");
 | 
			
		||||
        activity2.setUserSize(5);
 | 
			
		||||
        activity2.setSpuId(4096L);
 | 
			
		||||
        activity2.setPicUrl("商品图片地址");
 | 
			
		||||
        activity2.setMarketPrice(100);
 | 
			
		||||
        activity2.setCombinationPrice(200);
 | 
			
		||||
        activityList.add(activity2);
 | 
			
		||||
 | 
			
		||||
        return success(new PageResult<>(activityList, 2L));
 | 
			
		||||
        List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(result.getList(), CombinationActivityDO::getSpuId));
 | 
			
		||||
        return success(CombinationActivityConvert.INSTANCE.convertAppPage(result, spuList));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get-detail")
 | 
			
		||||
    @Operation(summary = "获得拼团活动明细")
 | 
			
		||||
    @Parameter(name = "id", description = "活动编号", required = true, example = "1024")
 | 
			
		||||
    public CommonResult<AppCombinationActivityDetailRespVO> getCombinationActivityDetail(@RequestParam("id") Long id) {
 | 
			
		||||
        // TODO 芋艿:如果禁用的时候,需要抛出异常;
 | 
			
		||||
        AppCombinationActivityDetailRespVO obj = new AppCombinationActivityDetailRespVO();
 | 
			
		||||
        // 设置其属性的值
 | 
			
		||||
        obj.setId(id);
 | 
			
		||||
        obj.setName("晚九点限时秒杀");
 | 
			
		||||
        obj.setStatus(1);
 | 
			
		||||
        obj.setStartTime(LocalDateTime.of(2023, 6, 15, 0, 0, 0));
 | 
			
		||||
        obj.setEndTime(LocalDateTime.of(2023, 6, 20, 23, 59, 0));
 | 
			
		||||
        obj.setUserSize(2);
 | 
			
		||||
        obj.setSuccessCount(100);
 | 
			
		||||
        obj.setSpuId(633L);
 | 
			
		||||
        obj.setSingleLimitCount(2);
 | 
			
		||||
        obj.setTotalLimitCount(3);
 | 
			
		||||
        // 1、获取活动
 | 
			
		||||
        CombinationActivityDO combinationActivity = activityService.getCombinationActivity(id);
 | 
			
		||||
        if (combinationActivity == null) {
 | 
			
		||||
            return success(null);
 | 
			
		||||
        }
 | 
			
		||||
        if (ObjectUtil.equal(combinationActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
 | 
			
		||||
            throw exception(COMBINATION_ACTIVITY_APP_STATUS_DISABLE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 创建一个Product对象的列表
 | 
			
		||||
        List<AppCombinationActivityDetailRespVO.Product> productList = new ArrayList<>();
 | 
			
		||||
        // 创建三个新的Product对象并设置其属性的值
 | 
			
		||||
        AppCombinationActivityDetailRespVO.Product product1 = new AppCombinationActivityDetailRespVO.Product();
 | 
			
		||||
        product1.setSkuId(1L);
 | 
			
		||||
        product1.setCombinationPrice(100);
 | 
			
		||||
        // 将第一个Product对象添加到列表中
 | 
			
		||||
        productList.add(product1);
 | 
			
		||||
        // 创建第二个Product对象并设置其属性的值
 | 
			
		||||
        AppCombinationActivityDetailRespVO.Product product2 = new AppCombinationActivityDetailRespVO.Product();
 | 
			
		||||
        product2.setSkuId(2L);
 | 
			
		||||
        product2.setCombinationPrice(200);
 | 
			
		||||
        // 将第二个Product对象添加到列表中
 | 
			
		||||
        productList.add(product2);
 | 
			
		||||
        // 创建第三个Product对象并设置其属性的值
 | 
			
		||||
        AppCombinationActivityDetailRespVO.Product product3 = new AppCombinationActivityDetailRespVO.Product();
 | 
			
		||||
        product3.setSkuId(3L);
 | 
			
		||||
        product3.setCombinationPrice(300);
 | 
			
		||||
        // 将第三个Product对象添加到列表中
 | 
			
		||||
        productList.add(product3);
 | 
			
		||||
        // 将Product列表设置为对象的属性值
 | 
			
		||||
        obj.setProducts(productList);
 | 
			
		||||
        return success(obj);
 | 
			
		||||
        // 2、获取活动商品
 | 
			
		||||
        List<CombinationProductDO> products = activityService.getCombinationProductsByActivityIds(Arrays.asList(combinationActivity.getId()));
 | 
			
		||||
        return success(CombinationActivityConvert.INSTANCE.convert3(combinationActivity, products));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@ public class AppCombinationActivityRespVO {
 | 
			
		||||
    private Integer marketPrice;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "拼团金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
 | 
			
		||||
    // 从拼团商品里取最低价
 | 
			
		||||
    private Integer combinationPrice;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,14 +27,12 @@ import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_FAIL_STATUS_CLOSED;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_APP_STATUS_CLOSED;
 | 
			
		||||
 | 
			
		||||
@Tag(name = "用户 App - 秒杀活动")
 | 
			
		||||
@RestController
 | 
			
		||||
@@ -51,26 +49,20 @@ public class AppSeckillActivityController {
 | 
			
		||||
    private ProductSpuApi spuApi;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get-now")
 | 
			
		||||
    @Operation(summary = "获得当前秒杀活动") // 提供给首页使用
 | 
			
		||||
    // TODO 芋艿:需要增加 spring cache
 | 
			
		||||
    @Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用")
 | 
			
		||||
    public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
 | 
			
		||||
        // 1. 获取当前时间处在哪个秒杀阶段
 | 
			
		||||
        // TODO @puhui999:可以考虑在 service 写个方法;这样 controller 不用关注过多逻辑
 | 
			
		||||
        List<SeckillConfigDO> configList = configService.getSeckillConfigList();
 | 
			
		||||
        SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
 | 
			
		||||
                CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
 | 
			
		||||
        if (filteredConfig == null) { // 时段不存在直接返回 null
 | 
			
		||||
        SeckillConfigDO configList = configService.getSeckillConfigListByStatusOnCurrentTime(CommonStatusEnum.ENABLE.getStatus());
 | 
			
		||||
        if (configList == null) { // 时段不存在直接返回 null
 | 
			
		||||
            return success(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 2. 查询满足当前阶段的活动
 | 
			
		||||
        // TODO @puhui999:最好直接返回开启的;不多查询数据
 | 
			
		||||
        List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIds(Arrays.asList(filteredConfig.getId()));
 | 
			
		||||
        List<SeckillActivityDO> filteredList = filterList(activityList, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
 | 
			
		||||
 | 
			
		||||
        // 3. 拼接数据
 | 
			
		||||
        List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(filteredList, SeckillActivityDO::getSpuId));
 | 
			
		||||
        return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
 | 
			
		||||
        List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIdAndStatus(configList.getId(), CommonStatusEnum.ENABLE.getStatus());
 | 
			
		||||
        // 3 获取 spu 信息
 | 
			
		||||
        List<ProductSpuRespDTO> spuList = spuApi.getSpuList(convertList(activityList, SeckillActivityDO::getSpuId));
 | 
			
		||||
        // TODO 芋艿:需要增加 spring cache
 | 
			
		||||
        return success(SeckillActivityConvert.INSTANCE.convert(configList, activityList, spuList));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
@@ -88,12 +80,9 @@ public class AppSeckillActivityController {
 | 
			
		||||
    @Operation(summary = "获得秒杀活动明细")
 | 
			
		||||
    @Parameter(name = "id", description = "活动编号", required = true, example = "1024")
 | 
			
		||||
    public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
 | 
			
		||||
        // 1、获取当前时间处在哪个秒杀阶段
 | 
			
		||||
        // TODO puhui999:这里,和 58 行是雷同的
 | 
			
		||||
        List<SeckillConfigDO> configList = configService.getSeckillConfigList();
 | 
			
		||||
        SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
 | 
			
		||||
                CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
 | 
			
		||||
        if (filteredConfig == null) { // 时段不存在直接返回 null
 | 
			
		||||
        // 1. 获取当前时间处在哪个秒杀阶段
 | 
			
		||||
        SeckillConfigDO configList = configService.getSeckillConfigListByStatusOnCurrentTime(CommonStatusEnum.ENABLE.getStatus());
 | 
			
		||||
        if (configList == null) { // 时段不存在直接返回 null
 | 
			
		||||
            return success(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -102,14 +91,13 @@ public class AppSeckillActivityController {
 | 
			
		||||
        if (seckillActivity == null) {
 | 
			
		||||
            return success(null);
 | 
			
		||||
        }
 | 
			
		||||
        // TODO 芋艿:如果禁用的时候,需要抛出异常;
 | 
			
		||||
        if (ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
 | 
			
		||||
            throw exception(SECKILL_ACTIVITY_FAIL_STATUS_CLOSED);
 | 
			
		||||
            throw exception(SECKILL_ACTIVITY_APP_STATUS_CLOSED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 3. 拼接数据
 | 
			
		||||
        List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
 | 
			
		||||
        return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
 | 
			
		||||
        return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, configList));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,9 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.controller.app.seckill;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollectionUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
			
		||||
@@ -15,7 +13,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
@@ -31,13 +28,7 @@ public class AppSeckillConfigController {
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    @Operation(summary = "获得秒杀时间段列表")
 | 
			
		||||
    public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
 | 
			
		||||
        List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
 | 
			
		||||
        // TODO @puhui999:如果这种,不用判空也问题不大;
 | 
			
		||||
        if (CollectionUtil.isEmpty(list)) {
 | 
			
		||||
            return success(Collections.emptyList());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return success(SeckillConfigConvert.INSTANCE.convertList2(list));
 | 
			
		||||
        return success(SeckillConfigConvert.INSTANCE.convertList2(configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,9 @@ public class AppSeckillActivityRespVO {
 | 
			
		||||
    // 从 SPU 的 marketPrice 读取
 | 
			
		||||
    private Integer marketPrice;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "秒杀活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    private Integer status;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "秒杀库存(剩余)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
 | 
			
		||||
    private Integer stock;
 | 
			
		||||
    @Schema(description = "秒杀库存(总共)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
 | 
			
		||||
 
 | 
			
		||||
@@ -46,9 +46,7 @@ public interface BargainActivityConvert {
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        List<BargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                // TODO @puhui999:这里可以使用链式哈
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl());
 | 
			
		||||
                item.setSpuName(spu.getName());
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl()).setSpuName(spu.getName());
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        });
 | 
			
		||||
@@ -76,9 +74,7 @@ public interface BargainActivityConvert {
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        List<AppBargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                // TODO @puhui999:这里可以使用链式哈
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl());
 | 
			
		||||
                item.setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        });
 | 
			
		||||
@@ -93,9 +89,7 @@ public interface BargainActivityConvert {
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        return CollectionUtils.convertList(activityList, item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                // TODO @puhui999:这里可以使用链式哈
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl());
 | 
			
		||||
                item.setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activit
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
 | 
			
		||||
@@ -25,6 +27,7 @@ import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 拼团活动 Convert
 | 
			
		||||
@@ -59,8 +62,7 @@ public interface CombinationActivityConvert {
 | 
			
		||||
        PageResult<CombinationActivityRespVO> pageResult = convertPage(page);
 | 
			
		||||
        pageResult.getList().forEach(item -> {
 | 
			
		||||
            MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                item.setSpuName(spu.getName());
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl());
 | 
			
		||||
                item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl());
 | 
			
		||||
            });
 | 
			
		||||
            item.setProducts(convertList2(productList));
 | 
			
		||||
        });
 | 
			
		||||
@@ -97,18 +99,53 @@ public interface CombinationActivityConvert {
 | 
			
		||||
    default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
 | 
			
		||||
                                        CombinationActivityDO activity, MemberUserRespDTO user,
 | 
			
		||||
                                        ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
 | 
			
		||||
        // TODO @puhui999:搞成链式的 set;这样会更规整一点;
 | 
			
		||||
        CombinationRecordDO record = convert(reqDTO);
 | 
			
		||||
        record.setVirtualGroup(false);
 | 
			
		||||
        record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
 | 
			
		||||
        record.setUserSize(activity.getUserSize());
 | 
			
		||||
        record.setNickname(user.getNickname());
 | 
			
		||||
        record.setAvatar(user.getAvatar());
 | 
			
		||||
        record.setSpuName(spu.getName());
 | 
			
		||||
        record.setPicUrl(sku.getPicUrl());
 | 
			
		||||
        return record;
 | 
			
		||||
        // TODO @puhui999:订单付款后需要设置开始时间和结束时间;
 | 
			
		||||
        return convert(reqDTO)
 | 
			
		||||
                .setVirtualGroup(false)
 | 
			
		||||
                .setExpireTime(activity.getStartTime().plusHours(activity.getLimitDuration()))
 | 
			
		||||
                .setUserSize(activity.getUserSize())
 | 
			
		||||
                .setNickname(user.getNickname())
 | 
			
		||||
                .setAvatar(user.getAvatar())
 | 
			
		||||
                .setSpuName(spu.getName())
 | 
			
		||||
                .setPicUrl(sku.getPicUrl());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);
 | 
			
		||||
 | 
			
		||||
    List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list);
 | 
			
		||||
 | 
			
		||||
    default List<AppCombinationActivityRespVO> convertAppList(List<CombinationActivityDO> list, List<ProductSpuRespDTO> spuList) {
 | 
			
		||||
        List<AppCombinationActivityRespVO> activityList = convertAppList(list);
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        return CollectionUtils.convertList(activityList, item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PageResult<AppCombinationActivityRespVO> convertAppPage(PageResult<CombinationActivityDO> result);
 | 
			
		||||
 | 
			
		||||
    default PageResult<AppCombinationActivityRespVO> convertAppPage(PageResult<CombinationActivityDO> result, List<ProductSpuRespDTO> spuList) {
 | 
			
		||||
        PageResult<AppCombinationActivityRespVO> appPage = convertAppPage(result);
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        List<AppCombinationActivityRespVO> list = CollectionUtils.convertList(appPage.getList(), item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        });
 | 
			
		||||
        appPage.setList(list);
 | 
			
		||||
        return appPage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    AppCombinationActivityDetailRespVO convert2(CombinationActivityDO combinationActivity);
 | 
			
		||||
 | 
			
		||||
    List<AppCombinationActivityDetailRespVO.Product> convertList1(List<CombinationProductDO> products);
 | 
			
		||||
 | 
			
		||||
    default AppCombinationActivityDetailRespVO convert3(CombinationActivityDO combinationActivity, List<CombinationProductDO> products) {
 | 
			
		||||
        return convert2(combinationActivity).setProducts(convertList1(products));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.date.LocalDateTimeUtil;
 | 
			
		||||
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;
 | 
			
		||||
@@ -29,7 +30,6 @@ import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 秒杀活动 Convert
 | 
			
		||||
@@ -98,10 +98,9 @@ public interface SeckillActivityConvert {
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                // TODO @puhui999:可以尝试链式 set 哈;
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl());
 | 
			
		||||
                item.setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
                item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl())
 | 
			
		||||
                        .setMarketPrice(spu.getMarketPrice())
 | 
			
		||||
                        .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        }));
 | 
			
		||||
@@ -115,10 +114,9 @@ public interface SeckillActivityConvert {
 | 
			
		||||
        Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
 | 
			
		||||
        List<AppSeckillActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
 | 
			
		||||
            findAndThen(spuMap, item.getSpuId(), spu -> {
 | 
			
		||||
                // TODO @puhui999:可以尝试链式 set 哈;
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl());
 | 
			
		||||
                item.setMarketPrice(spu.getMarketPrice());
 | 
			
		||||
                item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
 | 
			
		||||
                item.setPicUrl(spu.getPicUrl())
 | 
			
		||||
                        .setMarketPrice(spu.getMarketPrice())
 | 
			
		||||
                        .setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
 | 
			
		||||
            });
 | 
			
		||||
            return item;
 | 
			
		||||
        });
 | 
			
		||||
@@ -131,12 +129,12 @@ public interface SeckillActivityConvert {
 | 
			
		||||
    List<AppSeckillActivityDetailRespVO.Product> convertList1(List<SeckillProductDO> products);
 | 
			
		||||
 | 
			
		||||
    default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
 | 
			
		||||
        AppSeckillActivityDetailRespVO respVO = convert2(seckillActivity);
 | 
			
		||||
        respVO.setProducts(convertList1(products));
 | 
			
		||||
        // TODO @puhui999:可以尝试链式 set 哈;
 | 
			
		||||
        respVO.setStartTime(buildTime(filteredConfig.getStartTime()));
 | 
			
		||||
        respVO.setEndTime(buildTime(filteredConfig.getEndTime()));
 | 
			
		||||
        return respVO;
 | 
			
		||||
        return convert2(seckillActivity)
 | 
			
		||||
                .setProducts(convertList1(products))
 | 
			
		||||
                .setStartTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getStartTime(), "yyyy-MM-dd") + " " + filteredConfig.getStartTime(),
 | 
			
		||||
                        "yyyy-MM-dd HH:mm:ss")) // 活动开始日期和时段结合
 | 
			
		||||
                .setEndTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getEndTime(), "yyyy-MM-dd") + " " + filteredConfig.getEndTime(),
 | 
			
		||||
                        "yyyy-MM-dd HH:mm:ss")); // 活动结束日期和时段结合
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,11 +45,34 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
 | 
			
		||||
                .setSql("stock = stock - " + count));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default PageResult<BargainActivityDO> selectAppPage(PageParam pageReqVO, Integer status, LocalDateTime now) {
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询处在 now 日期时间且是 status 状态的活动分页
 | 
			
		||||
     *
 | 
			
		||||
     * @param pageReqVO 分页参数
 | 
			
		||||
     * @param status    状态
 | 
			
		||||
     * @param now       当前日期时间
 | 
			
		||||
     * @return 活动分页
 | 
			
		||||
     */
 | 
			
		||||
    default PageResult<BargainActivityDO> selectPage(PageParam pageReqVO, Integer status, LocalDateTime now) {
 | 
			
		||||
        return selectPage(pageReqVO, new LambdaQueryWrapperX<BargainActivityDO>()
 | 
			
		||||
                .eq(BargainActivityDO::getStatus, status)
 | 
			
		||||
                .le(BargainActivityDO::getStartTime, now)
 | 
			
		||||
                .ge(BargainActivityDO::getEndTime, now));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询处在 now 日期时间且是 status 状态的活动分页
 | 
			
		||||
     *
 | 
			
		||||
     * @param status 状态
 | 
			
		||||
     * @param now    当前日期时间
 | 
			
		||||
     * @return 活动分页
 | 
			
		||||
     */
 | 
			
		||||
    default List<BargainActivityDO> selectList(Integer count, Integer status, LocalDateTime now) {
 | 
			
		||||
        return selectList(new LambdaQueryWrapperX<BargainActivityDO>()
 | 
			
		||||
                .eq(BargainActivityDO::getStatus, status)
 | 
			
		||||
                .le(BargainActivityDO::getStartTime, now)
 | 
			
		||||
                .ge(BargainActivityDO::getEndTime, now)
 | 
			
		||||
                .last("LIMIT " + count));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.dal.mysql.combination;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
			
		||||
@@ -28,4 +29,29 @@ public interface CombinationActivityMapper extends BaseMapperX<CombinationActivi
 | 
			
		||||
        return selectList(CombinationActivityDO::getStatus, status);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询 status 状态的活动分页
 | 
			
		||||
     *
 | 
			
		||||
     * @param pageParam 分页参数
 | 
			
		||||
     * @param status    状态
 | 
			
		||||
     * @return 活动分页
 | 
			
		||||
     */
 | 
			
		||||
    default PageResult<CombinationActivityDO> selectPage(PageParam pageParam, Integer status) {
 | 
			
		||||
        return selectPage(pageParam, new LambdaQueryWrapperX<CombinationActivityDO>()
 | 
			
		||||
                .eq(CombinationActivityDO::getStatus, status));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 查询 status 状态的活动分页
 | 
			
		||||
     *
 | 
			
		||||
     * @param status 状态
 | 
			
		||||
     * @param count  限制条数
 | 
			
		||||
     * @return 活动分页
 | 
			
		||||
     */
 | 
			
		||||
    default List<CombinationActivityDO> selectList(Integer status, Integer count) {
 | 
			
		||||
        return selectList(new LambdaQueryWrapperX<CombinationActivityDO>()
 | 
			
		||||
                .eq(CombinationActivityDO::getStatus, status)
 | 
			
		||||
                .last("LIMIT " + count));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -63,22 +63,20 @@ public interface BargainActivityService {
 | 
			
		||||
     */
 | 
			
		||||
    PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
 | 
			
		||||
 | 
			
		||||
    // TODO @puhui999:这里可以改成进行中的活动;尽量避免专门为 app 定制,或者类似的名字哈;mapper 那也是
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取 APP 端活动分页数据
 | 
			
		||||
     * 获取正在进行的活动分页数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param pageReqVO 分页请求
 | 
			
		||||
     * @return 砍价活动分页
 | 
			
		||||
     */
 | 
			
		||||
    PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO);
 | 
			
		||||
    PageResult<BargainActivityDO> getBargainActivityPage(PageParam pageReqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取 APP 端活动展示数据
 | 
			
		||||
     * 获取正在进行的活动分页数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param count 需要的数量
 | 
			
		||||
     * @return 砍价活动分页
 | 
			
		||||
     */
 | 
			
		||||
    List<BargainActivityDO> getBargainActivityListForApp(Integer count);
 | 
			
		||||
    List<BargainActivityDO> getBargainActivityListByCount(Integer count);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -114,7 +114,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
 | 
			
		||||
    public void deleteBargainActivity(Long id) {
 | 
			
		||||
        // 校验存在
 | 
			
		||||
        BargainActivityDO activityDO = validateBargainActivityExists(id);
 | 
			
		||||
        // 校验状态
 | 
			
		||||
        // 校验状态 TODO puhui: 测试完成后需要恢复校验
 | 
			
		||||
        //if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
 | 
			
		||||
        //    throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
 | 
			
		||||
        //}
 | 
			
		||||
@@ -142,21 +142,14 @@ public class BargainActivityServiceImpl implements BargainActivityService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResult<BargainActivityDO> getBargainActivityPageForApp(PageParam pageReqVO) {
 | 
			
		||||
    public PageResult<BargainActivityDO> getBargainActivityPage(PageParam pageReqVO) {
 | 
			
		||||
        // 只查询进行中,且在时间范围内的
 | 
			
		||||
        return bargainActivityMapper.selectAppPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
 | 
			
		||||
        return bargainActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<BargainActivityDO> getBargainActivityListForApp(Integer count) {
 | 
			
		||||
        // TODO @puhui999:这种 default count 的逻辑,可以放到 controller 哈;然后可以使用 ObjectUtils.default 方法
 | 
			
		||||
        if (count == null) {
 | 
			
		||||
            count = 6;
 | 
			
		||||
        }
 | 
			
		||||
        // TODO @puhui999:这种不要用 page;会浪费一次 count;
 | 
			
		||||
        PageResult<BargainActivityDO> result = bargainActivityMapper.selectAppPage(new PageParam().setPageSize(count),
 | 
			
		||||
                CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
 | 
			
		||||
        return result.getList();
 | 
			
		||||
    public List<BargainActivityDO> getBargainActivityListByCount(Integer count) {
 | 
			
		||||
        return bargainActivityMapper.selectList(count, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.promotion.service.combination;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
 | 
			
		||||
@@ -83,4 +84,20 @@ public interface CombinationActivityService {
 | 
			
		||||
     */
 | 
			
		||||
    void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取正在进行的活动分页数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param count 需要的数量
 | 
			
		||||
     * @return 拼团活动分页
 | 
			
		||||
     */
 | 
			
		||||
    List<CombinationActivityDO> getCombinationActivityListByCount(Integer count);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取正在进行的活动分页数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param pageParam 分页请求
 | 
			
		||||
     * @return 拼团活动分页
 | 
			
		||||
     */
 | 
			
		||||
    PageResult<CombinationActivityDO> getCombinationActivityPage(PageParam pageParam);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.service.combination;
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 | 
			
		||||
@@ -223,8 +224,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
 | 
			
		||||
            throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
 | 
			
		||||
        }
 | 
			
		||||
        // 1.3 校验是否超出单次限购数量
 | 
			
		||||
        // TODO puhui999:count > activity.getSingleLimitCount() 会更好理解点;
 | 
			
		||||
        if (activity.getSingleLimitCount() < count) {
 | 
			
		||||
        if (count > activity.getSingleLimitCount()) {
 | 
			
		||||
            throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -245,4 +245,14 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<CombinationActivityDO> getCombinationActivityListByCount(Integer count) {
 | 
			
		||||
        return combinationActivityMapper.selectList(CommonStatusEnum.ENABLE.getStatus(), count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResult<CombinationActivityDO> getCombinationActivityPage(PageParam pageParam) {
 | 
			
		||||
        return combinationActivityMapper.selectPage(pageParam, CommonStatusEnum.ENABLE.getStatus());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,11 +37,11 @@ public interface SeckillActivityService {
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新秒杀库存
 | 
			
		||||
     *
 | 
			
		||||
     * @param activityId 活动编号
 | 
			
		||||
     * @param id 活动编号
 | 
			
		||||
     * @param skuId      sku 编号
 | 
			
		||||
     * @param count      数量
 | 
			
		||||
     */
 | 
			
		||||
    void updateSeckillStock(Long activityId, Long skuId, Integer count);
 | 
			
		||||
    void updateSeckillStock(Long id, Long skuId, Integer count);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 关闭秒杀活动
 | 
			
		||||
@@ -97,6 +97,15 @@ public interface SeckillActivityService {
 | 
			
		||||
     */
 | 
			
		||||
    List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通过活动时段编号获取指定 status 的秒杀活动
 | 
			
		||||
     *
 | 
			
		||||
     * @param configId 时段配置编号
 | 
			
		||||
     * @param status   状态
 | 
			
		||||
     * @return 秒杀活动列表
 | 
			
		||||
     */
 | 
			
		||||
    List<SeckillActivityDO> getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通过活动时段获取秒杀活动
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.seckill;
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
 | 
			
		||||
@@ -31,6 +30,7 @@ import java.util.Map;
 | 
			
		||||
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
 | 
			
		||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
 | 
			
		||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
 | 
			
		||||
@@ -148,16 +148,16 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
 | 
			
		||||
    public void updateSeckillStock(Long id, Long skuId, Integer count) {
 | 
			
		||||
        // 1、校验秒杀活动是否存在
 | 
			
		||||
        SeckillActivityDO seckillActivity = getSeckillActivity(activityId);
 | 
			
		||||
        SeckillActivityDO seckillActivity = getSeckillActivity(id);
 | 
			
		||||
        // 1.1、校验库存是否充足
 | 
			
		||||
        if (seckillActivity.getTotalStock() < count) {
 | 
			
		||||
            throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 2、获取活动商品
 | 
			
		||||
        List<SeckillProductDO> products = getSeckillProductListByActivityId(activityId);
 | 
			
		||||
        List<SeckillProductDO> products = getSeckillProductListByActivityId(id);
 | 
			
		||||
        // 2.1、过滤出购买的商品
 | 
			
		||||
        SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(skuId, item.getSkuId()));
 | 
			
		||||
        // 2.2、检查活动商品库存是否充足
 | 
			
		||||
@@ -268,8 +268,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids) {
 | 
			
		||||
        return CollectionUtils.filterList(seckillActivityMapper.selectList(),
 | 
			
		||||
                item -> CollectionUtils.anyMatch(item.getConfigIds(), ids::contains));
 | 
			
		||||
        return filterList(seckillActivityMapper.selectList(),
 | 
			
		||||
                item -> anyMatch(item.getConfigIds(), ids::contains));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<SeckillActivityDO> getSeckillActivityListByConfigIdAndStatus(Long configId, Integer status) {
 | 
			
		||||
        return filterList(seckillActivityMapper.selectList(SeckillActivityDO::getStatus, status),
 | 
			
		||||
                item -> anyMatch(item.getConfigIds(), id -> ObjectUtil.equal(id, configId)) // 校验时段
 | 
			
		||||
                        && isBetween(item.getStartTime(), item.getEndTime())); // 追加当前日期是否处在活动日期之间的校验条件
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ public interface SeckillConfigService {
 | 
			
		||||
     */
 | 
			
		||||
    List<SeckillConfigDO> getSeckillConfigList();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 校验秒杀时段是否存在
 | 
			
		||||
     *
 | 
			
		||||
@@ -85,4 +86,12 @@ public interface SeckillConfigService {
 | 
			
		||||
     */
 | 
			
		||||
    void updateSeckillConfigStatus(Long id, Integer status);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取当前日期时间处于的秒杀时段且状态为 status
 | 
			
		||||
     *
 | 
			
		||||
     * @param status 状态
 | 
			
		||||
     * @return 时段
 | 
			
		||||
     */
 | 
			
		||||
    SeckillConfigDO getSeckillConfigListByStatusOnCurrentTime(Integer status);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,8 @@ import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
 | 
			
		||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -67,6 +69,12 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
 | 
			
		||||
        seckillConfigMapper.updateById(new SeckillConfigDO().setId(id).setStatus(status));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public SeckillConfigDO getSeckillConfigListByStatusOnCurrentTime(Integer status) {
 | 
			
		||||
        return findFirst(seckillConfigMapper.selectList(SeckillConfigDO::getStatus, status),
 | 
			
		||||
                config -> isBetween(config.getStartTime(), config.getEndTime()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteSeckillConfig(Long id) {
 | 
			
		||||
        // 校验存在
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
 | 
			
		||||
@@ -87,13 +87,13 @@ public class TradeAfterSaleController {
 | 
			
		||||
        // 拼接数据
 | 
			
		||||
        MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId());
 | 
			
		||||
        // 获取售后日志
 | 
			
		||||
        List<TradeAfterSaleLogRespDTO> logs = afterSaleLogService.getLog(afterSale.getId());
 | 
			
		||||
        List<TradeAfterSaleLogRespVO> logs = afterSaleLogService.getLog(afterSale.getId());
 | 
			
		||||
        // TODO 方便测试看效果,review 后移除
 | 
			
		||||
        if (logs == null) {
 | 
			
		||||
            logs = new ArrayList<>();
 | 
			
		||||
        }
 | 
			
		||||
        for (int i = 1; i <= 6; i++) {
 | 
			
		||||
            TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO();
 | 
			
		||||
            TradeAfterSaleLogRespVO respVO = new TradeAfterSaleLogRespVO();
 | 
			
		||||
            respVO.setId((long) i);
 | 
			
		||||
            respVO.setUserId((long) i);
 | 
			
		||||
            respVO.setUserType(i % 2 == 0 ? 2 : 1);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDetailRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRespPageItemVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO;
 | 
			
		||||
@@ -16,7 +15,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleLogDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.Mapping;
 | 
			
		||||
@@ -68,10 +67,10 @@ public interface TradeAfterSaleConvert {
 | 
			
		||||
 | 
			
		||||
    PageResult<AppTradeAfterSaleRespVO> convertPage02(PageResult<TradeAfterSaleDO> page);
 | 
			
		||||
 | 
			
		||||
    List<TradeAfterSaleLogRespDTO> convertList(List<TradeAfterSaleLogDO> list);
 | 
			
		||||
    List<TradeAfterSaleLogRespVO> convertList(List<TradeAfterSaleLogDO> list);
 | 
			
		||||
    
 | 
			
		||||
    default TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, TradeOrderDO order, List<TradeOrderItemDO> orderItems,
 | 
			
		||||
                                               MemberUserRespDTO user, List<TradeAfterSaleLogRespDTO> logs) {
 | 
			
		||||
                                               MemberUserRespDTO user, List<TradeAfterSaleLogRespVO> logs) {
 | 
			
		||||
        TradeAfterSaleDetailRespVO respVO = convert(afterSale, orderItems);
 | 
			
		||||
        // 处理用户信息
 | 
			
		||||
        respVO.setUser(convert(user));
 | 
			
		||||
@@ -81,7 +80,8 @@ public interface TradeAfterSaleConvert {
 | 
			
		||||
        respVO.setLogs(convertList1(logs));
 | 
			
		||||
        return respVO;
 | 
			
		||||
    }
 | 
			
		||||
    List<TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespDTO> list);
 | 
			
		||||
 | 
			
		||||
    List<cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.TradeAfterSaleLogRespVO> convertList1(List<TradeAfterSaleLogRespVO> list);
 | 
			
		||||
    @Mapping(target = "id", source = "afterSale.id")
 | 
			
		||||
    TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, List<TradeOrderItemDO> orderItems);
 | 
			
		||||
    TradeOrderBaseVO convert(TradeOrderDO order);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import lombok.NoArgsConstructor;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
// TODO @puhui999:这个是不是应该搞成 vo 啊?
 | 
			
		||||
/**
 | 
			
		||||
 * 贸易售后日志详情 DTO
 | 
			
		||||
 *
 | 
			
		||||
@@ -17,7 +16,7 @@ import java.time.LocalDateTime;
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class TradeAfterSaleLogRespDTO {
 | 
			
		||||
public class TradeAfterSaleLogRespVO {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669")
 | 
			
		||||
    private Long id;
 | 
			
		||||
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespVO;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,6 @@ public interface AfterSaleLogService {
 | 
			
		||||
     * @param afterSaleId 售后编号
 | 
			
		||||
     * @return 售后日志
 | 
			
		||||
     */
 | 
			
		||||
    List<TradeAfterSaleLogRespDTO> getLog(Long afterSaleId);
 | 
			
		||||
    List<TradeAfterSaleLogRespVO> getLog(Long afterSaleId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleWayEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.dto.TradeAfterSaleLogRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.aftersalelog.core.service.AfterSaleLogService;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 | 
			
		||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
 | 
			
		||||
@@ -450,7 +450,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<TradeAfterSaleLogRespDTO> getLog(Long afterSaleId) {
 | 
			
		||||
    public List<TradeAfterSaleLogRespVO> getLog(Long afterSaleId) {
 | 
			
		||||
        // TODO 不熟悉流程先这么滴
 | 
			
		||||
        List<TradeAfterSaleLogDO> saleLogDOs = tradeAfterSaleLogMapper.selectList(TradeAfterSaleLogDO::getAfterSaleId, afterSaleId);
 | 
			
		||||
        return TradeAfterSaleConvert.INSTANCE.convertList(saleLogDOs);
 | 
			
		||||
 
 | 
			
		||||
@@ -541,41 +541,49 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 | 
			
		||||
        tradeOrderMapper.updateById(update);
 | 
			
		||||
        // TODO @芋艿:改价时,赠送的积分,要不要做改动???
 | 
			
		||||
 | 
			
		||||
        // TODO @puhui999:应该是按照 payPrice 分配;并且要考虑取余问题;payPrice 也要考虑,item 里的
 | 
			
		||||
        // TODO:先按 adjustPrice 实现,没明白 payPrice 怎么搞哈哈哈
 | 
			
		||||
        // TODO @puhui999:就是对比新老 adjustPrice 的差值,然后计算补充的 adjustPrice 最终值;另外,可以不用区分 items.size 是不是 > 1 哈;应该是一致的逻辑;分摊的逻辑,有点类似 dividePrice 方法噢;
 | 
			
		||||
        // 5、更新 TradeOrderItem
 | 
			
		||||
        if (items.size() > 1) {
 | 
			
		||||
        // TradeOrderItemDO 需要做 adjustPrice 的分摊
 | 
			
		||||
            int price = reqVO.getAdjustPrice() / items.size();
 | 
			
		||||
            int remainderPrice = reqVO.getAdjustPrice() % items.size();
 | 
			
		||||
            List<TradeOrderItemDO> orders = new ArrayList<>();
 | 
			
		||||
        List<Integer> dividePrices = dividePrice(items, orderPayPrice);
 | 
			
		||||
        List<TradeOrderItemDO> updateItems = new ArrayList<>();
 | 
			
		||||
        for (int i = 0; i < items.size(); i++) {
 | 
			
		||||
                // 把平摊后剩余的金额加到第一个订单项
 | 
			
		||||
                if (remainderPrice != 0 && i == 0) {
 | 
			
		||||
                    orders.add(convertOrderItemPrice(items.get(i), price + remainderPrice));
 | 
			
		||||
                }
 | 
			
		||||
                orders.add(convertOrderItemPrice(items.get(i), price));
 | 
			
		||||
            }
 | 
			
		||||
            tradeOrderItemMapper.updateBatch(orders);
 | 
			
		||||
        } else {
 | 
			
		||||
            TradeOrderItemDO orderItem = items.get(0);
 | 
			
		||||
            TradeOrderItemDO updateItem = convertOrderItemPrice(orderItem, reqVO.getAdjustPrice());
 | 
			
		||||
            tradeOrderItemMapper.updateById(updateItem);
 | 
			
		||||
            TradeOrderItemDO item = items.get(i);
 | 
			
		||||
            Integer adjustPrice = item.getPrice() - dividePrices.get(i); // 计算调整的金额
 | 
			
		||||
            updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(adjustPrice)
 | 
			
		||||
                    .setPayPrice(item.getPayPrice() - adjustPrice));
 | 
			
		||||
        }
 | 
			
		||||
        tradeOrderItemMapper.updateBatch(updateItems);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // 6、更新支付订单
 | 
			
		||||
        payOrderApi.updatePayOrderPrice(order.getPayOrderId(), update.getPayPrice());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private TradeOrderItemDO convertOrderItemPrice(TradeOrderItemDO orderItem, Integer price) {
 | 
			
		||||
        TradeOrderItemDO newOrderItem = new TradeOrderItemDO();
 | 
			
		||||
        newOrderItem.setId(orderItem.getId());
 | 
			
		||||
        newOrderItem.setAdjustPrice(price);
 | 
			
		||||
        int payPrice = orderItem.getAdjustPrice() != null ? (orderItem.getPayPrice() - orderItem.getAdjustPrice())
 | 
			
		||||
                + price : orderItem.getPayPrice() + price;
 | 
			
		||||
        newOrderItem.setPayPrice(payPrice);
 | 
			
		||||
        return newOrderItem;
 | 
			
		||||
    /**
 | 
			
		||||
     * 计算订单调价价格分摊
 | 
			
		||||
     *
 | 
			
		||||
     * @param items         订单项
 | 
			
		||||
     * @param orderPayPrice 订单支付金额
 | 
			
		||||
     * @return 分摊金额数组,和传入的 orderItems 一一对应
 | 
			
		||||
     */
 | 
			
		||||
    private List<Integer> dividePrice(List<TradeOrderItemDO> items, Integer orderPayPrice) {
 | 
			
		||||
        Integer total = getSumValue(items, TradeOrderItemDO::getPrice, Integer::sum);
 | 
			
		||||
        assert total != null;
 | 
			
		||||
        // 遍历每一个,进行分摊
 | 
			
		||||
        List<Integer> prices = new ArrayList<>(items.size());
 | 
			
		||||
        int remainPrice = orderPayPrice;
 | 
			
		||||
        for (int i = 0; i < items.size(); i++) {
 | 
			
		||||
            TradeOrderItemDO orderItem = items.get(i);
 | 
			
		||||
            int partPrice;
 | 
			
		||||
            if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减
 | 
			
		||||
                partPrice = (int) (orderPayPrice * (1.0D * orderItem.getPayPrice() / total));
 | 
			
		||||
                remainPrice -= partPrice;
 | 
			
		||||
            } else {
 | 
			
		||||
                partPrice = remainPrice;
 | 
			
		||||
            }
 | 
			
		||||
            Assert.isTrue(partPrice >= 0, "分摊金额必须大于等于 0");
 | 
			
		||||
            prices.add(partPrice);
 | 
			
		||||
        }
 | 
			
		||||
        return prices;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.trade.service.order.bo;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
@@ -14,36 +15,73 @@ import javax.validation.constraints.NotNull;
 | 
			
		||||
@Data
 | 
			
		||||
public class TradeBeforeOrderCreateReqBO {
 | 
			
		||||
 | 
			
		||||
    // TODO @puhui999:注释也写下哈;bo 还是写注释噢
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 订单类型
 | 
			
		||||
     *
 | 
			
		||||
     * 枚举 {@link TradeOrderTypeEnum}
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "订单类型不能为空")
 | 
			
		||||
    private Integer orderType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户编号
 | 
			
		||||
     *
 | 
			
		||||
     * 关联 MemberUserDO 的 id 编号
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "用户编号不能为空")
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    // ========== 秒杀活动相关字段 ==========
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "秒杀活动编号", example = "1024")
 | 
			
		||||
    private Long seckillActivityId;
 | 
			
		||||
 | 
			
		||||
    // ========== 拼团活动相关字段 ==========
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 拼团活动编号
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "拼团活动编号", example = "1024")
 | 
			
		||||
    private Long combinationActivityId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 拼团团长编号
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "拼团团长编号", example = "2048")
 | 
			
		||||
    private Long combinationHeadId;
 | 
			
		||||
 | 
			
		||||
    // ========== 砍价活动相关字段 ==========
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 砍价活动编号
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "砍价活动编号", example = "123")
 | 
			
		||||
    private Long bargainActivityId;
 | 
			
		||||
 | 
			
		||||
    // ========== 活动购买商品相关字段 ==========
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 商品 SPU 编号
 | 
			
		||||
     *
 | 
			
		||||
     * 关联 ProductSkuDO 的 spuId 编号
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "SPU 编号不能为空")
 | 
			
		||||
    private Long spuId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 商品 SKU 编号
 | 
			
		||||
     *
 | 
			
		||||
     * 关联 ProductSkuDO 的 id 编号
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "SKU 编号活动商品不能为空")
 | 
			
		||||
    private Long skuId;
 | 
			
		||||
 | 
			
		||||
    @NotNull(message = "用户编号不能为空")
 | 
			
		||||
    private Long userId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 购买的商品数量
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "购买数量不能为空")
 | 
			
		||||
    private Integer count;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user