Commit a4613f0af9eaedaba79e9b22e17ca3b6ca91fe6d

Authored by puhui999
1 parent 2e207019

拼团活动: 完善 review 提到的问题

Showing 13 changed files with 135 additions and 94 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
1 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2  
3   -import cn.iocoder.yudao.framework.common.core.KeyValue;
4 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO;
5 5 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
6 6  
7 7 import javax.validation.Valid;
... ... @@ -28,9 +28,9 @@ public interface CombinationRecordApi {
28 28 * 创建开团记录
29 29 *
30 30 * @param reqDTO 请求 DTO
31   - * @return key 开团记录编号、value 团长编号
  31 + * @return 团信息
32 32 */
33   - KeyValue<Long, Long> createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
  33 + CombinationRecordCreateRespDTO createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
34 34  
35 35 /**
36 36 * 查询拼团记录是否成功
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateRespDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.api.combination.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 拼团记录的创建 Response DTO
  7 + *
  8 + * @author HUIHUI
  9 + */
  10 +@Data
  11 +public class CombinationRecordCreateRespDTO {
  12 +
  13 + /**
  14 + * 拼团活动编号
  15 + *
  16 + * 关联 CombinationActivityDO 的 id 字段
  17 + */
  18 + private Long combinationActivityId;
  19 + /**
  20 + * 拼团团长编号
  21 + *
  22 + * 关联 CombinationRecordDO 的 headId 字段
  23 + */
  24 + private Long combinationHeadId;
  25 + /**
  26 + * 拼团记录编号
  27 + *
  28 + * 关联 CombinationRecordDO 的 id 字段
  29 + */
  30 + private Long combinationRecordId;
  31 +
  32 +}
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
1 1 package cn.iocoder.yudao.module.promotion.api.combination;
2 2  
3   -import cn.iocoder.yudao.framework.common.core.KeyValue;
4 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  4 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO;
5 5 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
  6 +import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
6 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
7 8 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
8 9 import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
... ... @@ -29,10 +30,9 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
29 30 recordService.validateCombinationRecord(userId, activityId, headId, skuId, count);
30 31 }
31 32  
32   - // TODO @puhui999:搞个创建的 RespDTO 哈;
33 33 @Override
34   - public KeyValue<Long, Long> createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
35   - return recordService.createCombinationRecord(reqDTO);
  34 + public CombinationRecordCreateRespDTO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
  35 + return CombinationActivityConvert.INSTANCE.convert4(recordService.createCombinationRecord(reqDTO));
36 36 }
37 37  
38 38 @Override
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationRecordController.java
... ... @@ -3,11 +3,11 @@ package cn.iocoder.yudao.module.promotion.controller.admin.combination;
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordPageItemRespVO;
6   -import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPage2VO;
7 6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO;
8 7 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordSummaryVO;
9 8 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
10 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
11 11 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
12 12 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
13 13 import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
... ... @@ -40,7 +40,6 @@ public class CombinationRecordController {
40 40 @Lazy
41 41 private CombinationRecordService combinationRecordService;
42 42  
43   - // TODO @puhui999:getBargainRecordPage 和 getBargainRecordPage 是不是可以合并;然后 CombinationRecordReqPageVO 加一个 headId;
44 43 // 然后如果 headId 非空,并且第一页,单独多查询一条 head ;放到第 0 个位置;相当于说,第一页特殊一点;
45 44  
46 45 @GetMapping("/page")
... ... @@ -48,21 +47,12 @@ public class CombinationRecordController {
48 47 @PreAuthorize("@ss.hasPermission('promotion:combination-record:query')")
49 48 public CommonResult<PageResult<CombinationRecordPageItemRespVO>> getBargainRecordPage(@Valid CombinationRecordReqPageVO pageVO) {
50 49 PageResult<CombinationRecordDO> recordPage = combinationRecordService.getCombinationRecordPage(pageVO);
  50 + // 拼接数据
51 51 List<CombinationActivityDO> activities = combinationActivityService.getCombinationActivityListByIds(
52 52 convertSet(recordPage.getList(), CombinationRecordDO::getActivityId));
53   - // TODO @puhui999:商品没读取
54   - return success(CombinationActivityConvert.INSTANCE.convert(recordPage, activities));
55   - }
56   -
57   - @GetMapping("/page-by-headId")
58   - @Operation(summary = "获得拼团记录分页")
59   - @PreAuthorize("@ss.hasPermission('promotion:combination-record:query')")
60   - public CommonResult<PageResult<CombinationRecordPageItemRespVO>> getBargainRecordPage(@Valid CombinationRecordReqPage2VO pageVO) {
61   - // 包含团长和团员的分页记录
62   - PageResult<CombinationRecordDO> recordPage = combinationRecordService.getCombinationRecordPage2(pageVO);
63   - List<CombinationActivityDO> activities = combinationActivityService.getCombinationActivityListByIds(
  53 + List<CombinationProductDO> products = combinationActivityService.getCombinationProductListByActivityIds(
64 54 convertSet(recordPage.getList(), CombinationRecordDO::getActivityId));
65   - return success(CombinationActivityConvert.INSTANCE.convert(recordPage, activities));
  55 + return success(CombinationActivityConvert.INSTANCE.convert(recordPage, activities, products));
66 56 }
67 57  
68 58 @GetMapping("/get-summary")
... ... @@ -70,7 +60,7 @@ public class CombinationRecordController {
70 60 @PreAuthorize("@ss.hasPermission('promotion:combination-record:query')")
71 61 public CommonResult<CombinationRecordSummaryVO> getCombinationRecordSummary() {
72 62 CombinationRecordSummaryVO summaryVO = new CombinationRecordSummaryVO();
73   - summaryVO.setUserCount(combinationRecordService.getCombinationRecordCount(null, null, null)); // 获取拼团用户参与数量
  63 + summaryVO.setUserCount(combinationRecordService.getCombinationUserCount()); // 获取拼团用户参与数量
74 64 summaryVO.setSuccessCount(combinationRecordService.getCombinationRecordCount( // 获取成团记录
75 65 CombinationRecordStatusEnum.SUCCESS.getStatus(), null, CombinationRecordDO.HEAD_ID_GROUP));
76 66 summaryVO.setVirtualGroupCount(combinationRecordService.getCombinationRecordCount(// 获取虚拟成团记录
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/vo/recrod/CombinationRecordReqPageVO.java
... ... @@ -23,6 +23,9 @@ public class CombinationRecordReqPageVO extends PageParam {
23 23 @InEnum(BargainRecordStatusEnum.class)
24 24 private Integer status;
25 25  
  26 + @Schema(description = "团长编号", example = "1024")
  27 + private Long headId;
  28 +
26 29 @Schema(description = "创建时间")
27 30 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
28 31 private LocalDateTime[] createTime;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/combination/AppCombinationRecordController.java
... ... @@ -47,7 +47,7 @@ public class AppCombinationRecordController {
47 47 public CommonResult<AppCombinationRecordSummaryRespVO> getCombinationRecordSummary() {
48 48 AppCombinationRecordSummaryRespVO summary = new AppCombinationRecordSummaryRespVO();
49 49 // 1. 获得拼团参与用户数量
50   - Long count = combinationRecordService.getCombinationRecordCount(null, null, null);
  50 + Long count = combinationRecordService.getCombinationUserCount();
51 51 if (count == 0) {
52 52 summary.setAvatars(Collections.emptyList());
53 53 summary.setUserCount(count);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
8 8 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
9 9 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
10 10 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
  11 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO;
11 12 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
12 13 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageItemRespVO;
13 14 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
... ... @@ -109,6 +110,11 @@ public interface CombinationActivityConvert {
109 110  
110 111 CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
111 112  
  113 + default CombinationRecordCreateRespDTO convert4(CombinationRecordDO combinationRecord) {
  114 + return new CombinationRecordCreateRespDTO().setCombinationActivityId(combinationRecord.getActivityId())
  115 + .setCombinationRecordId(combinationRecord.getId()).setCombinationHeadId(combinationRecord.getHeadId());
  116 + }
  117 +
112 118 default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
113 119 CombinationActivityDO activity, MemberUserRespDTO user,
114 120 ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
... ... @@ -172,12 +178,14 @@ public interface CombinationActivityConvert {
172 178  
173 179 PageResult<CombinationRecordPageItemRespVO> convert(PageResult<CombinationRecordDO> result);
174 180  
175   - default PageResult<CombinationRecordPageItemRespVO> convert(PageResult<CombinationRecordDO> recordPage, List<CombinationActivityDO> activities) {
  181 + default PageResult<CombinationRecordPageItemRespVO> convert(PageResult<CombinationRecordDO> recordPage, List<CombinationActivityDO> activities, List<CombinationProductDO> products) {
176 182 PageResult<CombinationRecordPageItemRespVO> result = convert(recordPage);
  183 + // 拼接关联属性
177 184 Map<Long, CombinationActivityDO> activityMap = convertMap(activities, CombinationActivityDO::getId);
  185 + Map<Long, List<CombinationProductDO>> productsMap = convertMultiMap(products, CombinationProductDO::getActivityId);
178 186 result.setList(CollectionUtils.convertList(result.getList(), item -> {
179 187 findAndThen(activityMap, item.getActivityId(), activity -> {
180   - item.setActivity(convert(activity));
  188 + item.setActivity(convert(activity).setProducts(convertList2(productsMap.get(item.getActivityId()))));
181 189 });
182 190 return item;
183 191 }));
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/bargain/BargainActivityMapper.java
... ... @@ -86,7 +86,7 @@ public interface BargainActivityMapper extends BaseMapperX&lt;BargainActivityDO&gt; {
86 86 .last("LIMIT " + count));
87 87 }
88 88  
89   - // TODO @puhui999:是不是返回 BargainActivityDO 更干净哈?
  89 + // TODO @puhui999:是不是返回 BargainActivityDO 更干净哈?分组后返回 DO 的话需要联表查询
90 90 /**
91 91 * 查询出指定 spuId 的 spu 参加的活动最接近现在的一条记录。多个的话,一个 spuId 对应一个最近的活动编号
92 92 *
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
... ... @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 7 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
8 8 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
9   -import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPage2VO;
10 9 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO;
11 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
12 11 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
... ... @@ -97,21 +96,19 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
97 96 }
98 97  
99 98 default PageResult<CombinationRecordDO> selectPage(CombinationRecordReqPageVO pageVO) {
100   - return selectPage(pageVO, new LambdaQueryWrapperX<CombinationRecordDO>()
  99 + LambdaQueryWrapperX<CombinationRecordDO> queryWrapper = new LambdaQueryWrapperX<CombinationRecordDO>()
101 100 .eqIfPresent(CombinationRecordDO::getStatus, pageVO.getStatus())
102   - .betweenIfPresent(CombinationRecordDO::getCreateTime, pageVO.getCreateTime()));
103   - }
104   -
105   - default PageResult<CombinationRecordDO> selectPage(CombinationRecordReqPage2VO pageVO) {
106   - return selectPage(pageVO, new LambdaQueryWrapperX<CombinationRecordDO>()
107   - .eq(CombinationRecordDO::getId, pageVO.getHeadId())
108   - .or()
109   - .eq(CombinationRecordDO::getHeadId, pageVO.getHeadId()));
  101 + .betweenIfPresent(CombinationRecordDO::getCreateTime, pageVO.getCreateTime());
  102 + if (pageVO.getHeadId() != null) {
  103 + queryWrapper.eq(CombinationRecordDO::getId, pageVO.getHeadId())
  104 + .or()
  105 + .eq(CombinationRecordDO::getHeadId, pageVO.getHeadId());
  106 + }
  107 + return selectPage(pageVO, queryWrapper);
110 108 }
111 109  
112 110 /**
113 111 * 查询指定条件的记录数
114   - * 如果参数都为 null 时则查询用户拼团记录(DISTINCT 去重),也就是说查询会员表中的用户有多少人参与过拼团活动每个人只统计一次
115 112 *
116 113 * @param status 状态,可为 null
117 114 * @param virtualGroup 是否虚拟成团,可为 null
... ... @@ -119,12 +116,20 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
119 116 * @return 记录数
120 117 */
121 118 default Long selectCountByHeadAndStatusAndVirtualGroup(Integer status, Boolean virtualGroup, Long headId) {
  119 + return selectCount(new LambdaQueryWrapperX<CombinationRecordDO>()
  120 + .eqIfPresent(CombinationRecordDO::getStatus, status)
  121 + .eqIfPresent(CombinationRecordDO::getVirtualGroup, virtualGroup)
  122 + .eqIfPresent(CombinationRecordDO::getHeadId, headId));
  123 + }
  124 +
  125 + /**
  126 + * 查询用户拼团记录(DISTINCT 去重),也就是说查询会员表中的用户有多少人参与过拼团活动每个人只统计一次
  127 + *
  128 + * @return 参加过拼团的用户数
  129 + */
  130 + default Long selectUserDistinctCount() {
122 131 return selectCount(new QueryWrapper<CombinationRecordDO>()
123   - // TODO @puhui999:这种偏逻辑性的,不要给 mapper 哈;可以考虑拆成 2 个 mapper,上层也是 2 个 service;
124   - .select(status == null && virtualGroup == null && headId == null, "DISTINCT (user_id)")
125   - .eq(status != null, "status", status)
126   - .eq(virtualGroup != null, "virtual_group", virtualGroup)
127   - .eq(headId != null, "head_id", headId)
  132 + .select("DISTINCT (user_id)")
128 133 .groupBy("user_id"));
129 134 }
130 135  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
... ... @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
6 6 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
7   -import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPage2VO;
8 7 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO;
9 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
10 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
... ... @@ -50,9 +49,9 @@ public interface CombinationRecordService {
50 49 * 创建拼团记录
51 50 *
52 51 * @param reqDTO 创建信息
53   - * @return key 开团记录编号 value 团长编号
  52 + * @return 团信息
54 53 */
55   - KeyValue<Long, Long> createCombinationRecord(CombinationRecordCreateReqDTO reqDTO);
  54 + CombinationRecordDO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO);
56 55  
57 56 /**
58 57 * 获得拼团记录
... ... @@ -94,7 +93,14 @@ public interface CombinationRecordService {
94 93 * @param headId 团长编号,允许空。目的 headId 设置为 {@link CombinationRecordDO#HEAD_ID_GROUP} 时,可以设置
95 94 * @return 记录数
96 95 */
97   - Long getCombinationRecordCount(@Nullable Integer status, @Nullable Boolean virtualGroup, @Nullable Long headId);
  96 + Long getCombinationRecordCount(@Nullable Integer status, @Nullable Boolean virtualGroup, Long headId);
  97 +
  98 + /**
  99 + * 查询用户拼团记录(DISTINCT 去重),也就是说查询会员表中的用户有多少人参与过拼团活动每个人只统计一次
  100 + *
  101 + * @return 参加过拼团的用户数
  102 + */
  103 + Long getCombinationUserCount();
98 104  
99 105 /**
100 106 * 获取最近的 count 条拼团记录
... ... @@ -139,14 +145,6 @@ public interface CombinationRecordService {
139 145 PageResult<CombinationRecordDO> getCombinationRecordPage(CombinationRecordReqPageVO pageVO);
140 146  
141 147 /**
142   - * 获取拼团记录分页数据(通过团长查询)
143   - *
144   - * @param pageVO 分页请求
145   - * @return 拼团记录分页数据(包括团长的)
146   - */
147   - PageResult<CombinationRecordDO> getCombinationRecordPage2(CombinationRecordReqPage2VO pageVO);
148   -
149   - /**
150 148 * 【拼团活动】获得拼团记录数量 Map
151 149 *
152 150 * @param activityIds 活动记录编号数组
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
... ... @@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
14 14 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
15 15 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
16 16 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationValidateJoinRespDTO;
17   -import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPage2VO;
18 17 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.recrod.CombinationRecordReqPageVO;
19 18 import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
20 19 import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
... ... @@ -23,7 +22,6 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
23 22 import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
24 23 import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
25 24 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
26   -import org.springframework.scheduling.annotation.Async;
27 25 import org.springframework.stereotype.Service;
28 26 import org.springframework.transaction.annotation.Transactional;
29 27 import org.springframework.validation.annotation.Validated;
... ... @@ -72,9 +70,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
72 70 CombinationRecordDO record = validateCombinationRecord(userId, orderId);
73 71  
74 72 // 更新状态
75   - // TODO @puhui999:不要整个更新,new 一个出来;why?例如说,两个线程都去更新,这样存在相互覆盖的问题
76   - record.setStatus(status);
77   - combinationRecordMapper.updateById(record);
  73 + combinationRecordMapper.updateById(new CombinationRecordDO().setId(record.getId()).setStatus(status));
78 74 }
79 75  
80 76 private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
... ... @@ -164,7 +160,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
164 160  
165 161 @Override
166 162 @Transactional(rollbackFor = Exception.class)
167   - public KeyValue<Long, Long> createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
  163 + public CombinationRecordDO createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
168 164 // 1. 校验拼团活动
169 165 KeyValue<CombinationActivityDO, CombinationProductDO> keyValue = validateCombinationRecord(reqDTO.getUserId(),
170 166 reqDTO.getActivityId(), reqDTO.getHeadId(), reqDTO.getSkuId(), reqDTO.getCount());
... ... @@ -191,7 +187,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
191 187 if (ObjUtil.notEqual(CombinationRecordDO.HEAD_ID_GROUP, record.getHeadId())) {
192 188 updateCombinationRecordWhenCreate(reqDTO.getHeadId(), keyValue.getKey());
193 189 }
194   - return new KeyValue<>(record.getId(), record.getHeadId());
  190 + return record;
195 191 }
196 192  
197 193 /**
... ... @@ -250,6 +246,11 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
250 246 }
251 247  
252 248 @Override
  249 + public Long getCombinationUserCount() {
  250 + return combinationRecordMapper.selectUserDistinctCount();
  251 + }
  252 +
  253 + @Override
253 254 public List<CombinationRecordDO> getLatestCombinationRecordList(int count) {
254 255 return combinationRecordMapper.selectLatestList(count);
255 256 }
... ... @@ -276,11 +277,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
276 277 }
277 278  
278 279 @Override
279   - public PageResult<CombinationRecordDO> getCombinationRecordPage2(CombinationRecordReqPage2VO pageVO) {
280   - return combinationRecordMapper.selectPage(pageVO);
281   - }
282   -
283   - @Override
284 280 public Map<Long, Integer> getCombinationRecordCountMapByActivity(Collection<Long> activityIds,
285 281 @Nullable Integer status, @Nullable Long headId) {
286 282 return combinationRecordMapper.selectCombinationRecordCountMapByActivityIdAndStatusAndHeadId(activityIds, status, headId);
... ... @@ -343,32 +339,28 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
343 339  
344 340 @Override
345 341 public KeyValue<Integer, Integer> expireCombinationRecord() {
346   - // TODO @puhui999:数字一般是 1. 2. 这种格式哈
347   - // 1。获取所有正在进行中的过期的父拼团
  342 + // 1.获取所有正在进行中的过期的父拼团
348 343 List<CombinationRecordDO> headExpireRecords = combinationRecordMapper.selectListByHeadIdAndStatusAndExpireTimeLt(
349 344 CombinationRecordDO.HEAD_ID_GROUP, CombinationRecordStatusEnum.IN_PROGRESS.getStatus(), LocalDateTime.now());
350 345 if (CollUtil.isEmpty(headExpireRecords)) {
351 346 return new KeyValue<>(0, 0);
352 347 }
353 348  
354   - // 2. 获取拼团活动
355   - // TODO @puhui999:在自己模块里,变量可以简略点;例如说 activityList
356   - List<CombinationActivityDO> combinationActivities = combinationActivityService.getCombinationActivityListByIds(
  349 + // 2.获取拼团活动
  350 + List<CombinationActivityDO> activities = combinationActivityService.getCombinationActivityListByIds(
357 351 convertSet(headExpireRecords, CombinationRecordDO::getActivityId));
358   - Map<Long, CombinationActivityDO> activityMap = convertMap(combinationActivities, CombinationActivityDO::getId);
  352 + Map<Long, CombinationActivityDO> activityMap = convertMap(activities, CombinationActivityDO::getId);
359 353  
360   - // TODO @puhui999:job 一般不建议异步跑;因为可能下次跑,结果上次还没跑完;
361   - // TODO 这里,我们可以每个 record 处理下;然后按照是否需要虚拟拼团,各搞一个方法逻辑 + 事务;这样,保证 job 里面尽量不要大事务,而是 n 个独立小事务的处理。
362   - // 3. 校验是否虚拟成团
  354 + // 3.校验是否虚拟成团
363 355 List<CombinationRecordDO> virtualGroupHeadRecords = new ArrayList<>(); // 虚拟成团
364 356 for (Iterator<CombinationRecordDO> iterator = headExpireRecords.iterator(); iterator.hasNext(); ) {
365 357 CombinationRecordDO record = iterator.next();
366   - // 3.1 不匹配,则直接跳过
  358 + // 3.1.不匹配,则直接跳过
367 359 CombinationActivityDO activity = activityMap.get(record.getActivityId());
368 360 if (activity == null || !activity.getVirtualGroup()) { // 取不到活动的或者不是虚拟拼团的
369 361 continue;
370 362 }
371   - // 3.2 匹配,则移除,添加到虚拟成团中,并结束寻找
  363 + // 3.2.匹配,则移除,添加到虚拟成团中,并结束寻找
372 364 virtualGroupHeadRecords.add(record);
373 365 iterator.remove();
374 366 break;
... ... @@ -381,8 +373,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
381 373 return new KeyValue<>(headExpireRecords.size(), virtualGroupHeadRecords.size());
382 374 }
383 375  
384   - @Async
385   - protected void handleExpireRecord(List<CombinationRecordDO> headExpireRecords) {
  376 + /**
  377 + * 处理过期拼团
  378 + *
  379 + * @param headExpireRecords 过期拼团团长记录列表
  380 + */
  381 + @Transactional(rollbackFor = Exception.class)
  382 + public void handleExpireRecord(List<CombinationRecordDO> headExpireRecords) {
386 383 if (CollUtil.isEmpty(headExpireRecords)) {
387 384 return;
388 385 }
... ... @@ -400,8 +397,13 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
400 397 });
401 398 }
402 399  
403   - @Async
404   - protected void handleVirtualGroupRecord(List<CombinationRecordDO> virtualGroupHeadRecords) {
  400 + /**
  401 + * 处理虚拟拼团
  402 + *
  403 + * @param virtualGroupHeadRecords 虚拟成团团长记录列表
  404 + */
  405 + @Transactional(rollbackFor = Exception.class)
  406 + public void handleVirtualGroupRecord(List<CombinationRecordDO> virtualGroupHeadRecords) {
405 407 if (CollUtil.isEmpty(virtualGroupHeadRecords)) {
406 408 return;
407 409 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
... ... @@ -93,16 +93,19 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
93 93 return selectOne(TradeOrderDO::getPickUpVerifyCode, pickUpVerifyCode);
94 94 }
95 95  
96   - // TODO @hui999:是不是只针对 combinationActivityId 的查询呀?
  96 + /**
  97 + * 只针对 combinationActivityId 的查询
  98 + *
  99 + * @param userId 用户编号
  100 + * @param activityId 拼团活动编号
  101 + * @param status 订单状态
  102 + * @return 交易订单
  103 + */
97 104 default TradeOrderDO selectByUserIdAndActivityIdAndStatus(Long userId, Long activityId, Integer status) {
98 105 return selectOne(new LambdaQueryWrapperX<TradeOrderDO>()
99   - .and(q -> q.eq(TradeOrderDO::getUserId, userId)
100   - .eq(TradeOrderDO::getStatus, status))
101   - .and(q -> q.eq(TradeOrderDO::getCombinationActivityId, activityId)
102   - .or()
103   - .eq(TradeOrderDO::getSeckillActivityId, activityId)
104   - .or()
105   - .eq(TradeOrderDO::getBargainActivityId, activityId))
  106 + .eq(TradeOrderDO::getUserId, userId)
  107 + .eq(TradeOrderDO::getStatus, status)
  108 + .eq(TradeOrderDO::getCombinationActivityId, activityId)
106 109 );
107 110 }
108 111  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java
1 1 package cn.iocoder.yudao.module.trade.service.order.handler;
2 2  
3 3 import cn.hutool.core.lang.Assert;
4   -import cn.iocoder.yudao.framework.common.core.KeyValue;
5 4 import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
  5 +import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateRespDTO;
6 6 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
7 7 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
8 8 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
... ... @@ -49,7 +49,6 @@ public class TradeCombinationOrderHandler implements TradeOrderHandler {
49 49 order.getCombinationHeadId(), item.getSkuId(), item.getCount());
50 50  
51 51 // 2. 校验该用户是否存在未支付的拼团活动订单,避免一个拼团可以下多个单子了
52   - // TODO @puhui999:只校验未支付的拼团订单噢
53 52 TradeOrderDO activityOrder = orderQueryService.getActivityOrderByUserIdAndActivityIdAndStatus(
54 53 order.getUserId(), order.getCombinationActivityId(), TradeOrderStatusEnum.UNPAID.getStatus());
55 54 if (activityOrder != null) {
... ... @@ -67,13 +66,14 @@ public class TradeCombinationOrderHandler implements TradeOrderHandler {
67 66  
68 67 // 2. 创建拼团记录
69 68 TradeOrderItemDO item = orderItems.get(0);
70   - KeyValue<Long, Long> recordIdAndHeadId = combinationRecordApi.createCombinationRecord(
  69 + CombinationRecordCreateRespDTO combinationRecord = combinationRecordApi.createCombinationRecord(
71 70 TradeOrderConvert.INSTANCE.convert(order, item));
72 71  
73 72 // 3. 更新拼团相关信息到订单
74   - // TODO 芋艿,只需要更新 record
  73 + // TODO 芋艿,只需要更新 record。 如果创建订单时自己是团长的情况下 combinationHeadId 是为 null 的,
  74 + // 设置团长编号这个操作时在订单是否后创建拼团记录时才设置的,所以支付完创建拼团记录后需要设置一下记录编号和团长编号
75 75 orderUpdateService.updateOrderCombinationInfo(order.getId(), order.getCombinationActivityId(),
76   - recordIdAndHeadId.getKey(), recordIdAndHeadId.getValue());
  76 + combinationRecord.getCombinationRecordId(), combinationRecord.getCombinationHeadId());
77 77 }
78 78  
79 79 @Override
... ...