Commit 4273b8f09cff3d6e20e6d83bc28b6ffd95700b7e

Authored by puhui999
1 parent 01ef5f79

营销活动:完善 review 提到的问题

Showing 14 changed files with 167 additions and 154 deletions
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
... ... @@ -111,9 +111,10 @@ public interface ErrorCodeConstants {
111 111 ErrorCode BARGAIN_HELP_CREATE_FAIL_HELP_EXISTS = new ErrorCode(1_013_014_004, "助力失败,您已经助力过了");
112 112  
113 113 // ========== 文章分类 1-013-015-000 ==========
114   - ErrorCode ARTICLE_CATEGORY_NOT_EXISTS = new ErrorCode(1_013_015_000, "分类不存在");
  114 + ErrorCode ARTICLE_CATEGORY_NOT_EXISTS = new ErrorCode(1_013_015_000, "文章分类不存在");
  115 + ErrorCode ARTICLE_CATEGORY_DELETE_FAIL_HAVE_ARTICLES = new ErrorCode(1_013_015_001, "文章分类删除失败,存在关联文章");
115 116  
116 117 // ========== 文章管理 1-013-016-000 ==========
117   - ErrorCode ARTICLE_NOT_EXISTS = new ErrorCode(1_013_016_000, "文章管理不存在");
  118 + ErrorCode ARTICLE_NOT_EXISTS = new ErrorCode(1_013_016_000, "文章不存在");
118 119  
119 120 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/article/ArticleConvert.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO;
5 5 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleRespVO;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticleRespVO;
7 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO;
8 9 import org.mapstruct.Mapper;
9 10 import org.mapstruct.factory.Mappers;
... ... @@ -30,4 +31,10 @@ public interface ArticleConvert {
30 31  
31 32 PageResult<ArticleRespVO> convertPage(PageResult<ArticleDO> page);
32 33  
  34 + AppArticleRespVO convert01(ArticleDO article);
  35 +
  36 + PageResult<AppArticleRespVO> convertPage02(PageResult<ArticleDO> articlePage);
  37 +
  38 + List<AppArticleRespVO> convertList03(List<ArticleDO> articleCategoryListByRecommendHotAndRecommendBanner);
  39 +
33 40 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
... ... @@ -207,31 +207,29 @@ public interface CombinationActivityConvert {
207 207 /**
208 208 * 转换生成虚拟成团虚拟记录
209 209 *
210   - * @param virtualGroupHeadRecords 虚拟成团团长记录列表
  210 + * @param virtualGroupHeadRecord 虚拟成团团长记录
211 211 * @return 虚拟记录列表
212 212 */
213   - default List<CombinationRecordDO> convertVirtualGroupList(List<CombinationRecordDO> virtualGroupHeadRecords) {
  213 + default List<CombinationRecordDO> convertVirtualGroupList(CombinationRecordDO virtualGroupHeadRecord) {
214 214 List<CombinationRecordDO> createRecords = new ArrayList<>();
215   - virtualGroupHeadRecords.forEach(headRecord -> {
216   - // 计算需要创建的虚拟成团记录数量
217   - int count = headRecord.getUserSize() - headRecord.getUserCount();
218   - for (int i = 0; i < count; i++) {
219   - // 基础信息和团长保持一致
220   - CombinationRecordDO newRecord = new CombinationRecordDO().setActivityId(headRecord.getActivityId())
221   - .setCombinationPrice(headRecord.getCombinationPrice()).setSpuId(headRecord.getSpuId()).setSpuName(headRecord.getSpuName())
222   - .setPicUrl(headRecord.getPicUrl()).setSkuId(headRecord.getSkuId()).setHeadId(headRecord.getId())
223   - .setStatus(headRecord.getStatus()) // 状态保持和创建时一致,创建完成后会接着处理
224   - .setVirtualGroup(headRecord.getVirtualGroup()).setExpireTime(headRecord.getExpireTime())
225   - .setStartTime(headRecord.getStartTime()).setUserSize(headRecord.getUserSize()).setUserCount(headRecord.getUserCount());
226   - // 虚拟信息
227   - newRecord.setCount(0);
228   - newRecord.setUserId(0L);
229   - newRecord.setNickname("");
230   - newRecord.setAvatar("");
231   - newRecord.setOrderId(0L);
232   - createRecords.add(newRecord);
233   - }
234   - });
  215 + // 计算需要创建的虚拟成团记录数量
  216 + int count = virtualGroupHeadRecord.getUserSize() - virtualGroupHeadRecord.getUserCount();
  217 + for (int i = 0; i < count; i++) {
  218 + // 基础信息和团长保持一致
  219 + CombinationRecordDO newRecord = new CombinationRecordDO().setActivityId(virtualGroupHeadRecord.getActivityId())
  220 + .setCombinationPrice(virtualGroupHeadRecord.getCombinationPrice()).setSpuId(virtualGroupHeadRecord.getSpuId()).setSpuName(virtualGroupHeadRecord.getSpuName())
  221 + .setPicUrl(virtualGroupHeadRecord.getPicUrl()).setSkuId(virtualGroupHeadRecord.getSkuId()).setHeadId(virtualGroupHeadRecord.getId())
  222 + .setStatus(virtualGroupHeadRecord.getStatus()) // 状态保持和创建时一致,创建完成后会接着处理
  223 + .setVirtualGroup(virtualGroupHeadRecord.getVirtualGroup()).setExpireTime(virtualGroupHeadRecord.getExpireTime())
  224 + .setStartTime(virtualGroupHeadRecord.getStartTime()).setUserSize(virtualGroupHeadRecord.getUserSize()).setUserCount(virtualGroupHeadRecord.getUserCount());
  225 + // 虚拟信息
  226 + newRecord.setCount(0);
  227 + newRecord.setUserId(0L);
  228 + newRecord.setNickname("");
  229 + newRecord.setAvatar("");
  230 + newRecord.setOrderId(0L);
  231 + createRecords.add(newRecord);
  232 + }
235 233 return createRecords;
236 234 }
237 235  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/article/ArticleMapper.java
... ... @@ -4,9 +4,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO;
7 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
  11 +import java.util.List;
  12 +
10 13 /**
11 14 * 文章管理 Mapper
12 15 *
... ... @@ -28,4 +31,16 @@ public interface ArticleMapper extends BaseMapperX&lt;ArticleDO&gt; {
28 31 .orderByDesc(ArticleDO::getId));
29 32 }
30 33  
  34 + default List<ArticleDO> selectList(Boolean recommendHot, Boolean recommendBanner) {
  35 + return selectList(new LambdaQueryWrapperX<ArticleDO>()
  36 + .eqIfPresent(ArticleDO::getRecommendHot, recommendHot)
  37 + .eqIfPresent(ArticleDO::getRecommendBanner, recommendBanner));
  38 + }
  39 +
  40 + default PageResult<ArticleDO> selectPage(AppArticlePageReqVO pageReqVO) {
  41 + return selectPage(pageReqVO, new LambdaQueryWrapperX<ArticleDO>()
  42 + .eqIfPresent(ArticleDO::getCategoryId, pageReqVO.getCategoryId()));
  43 + }
  44 +
  45 +
31 46 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
... ... @@ -127,11 +127,9 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
127 127 *
128 128 * @return 参加过拼团的用户数
129 129 */
130   - // TODO @puhui999:1)方法名,直接 selectUserCount;2)COUNT(DISTINCT(user_id)) 就可以啦,不用 group by 哈
131   - default Long selectUserDistinctCount() {
  130 + default Long selectUserCount() {
132 131 return selectCount(new QueryWrapper<CombinationRecordDO>()
133   - .select("DISTINCT (user_id)")
134   - .groupBy("user_id"));
  132 + .select("DISTINCT (user_id)"));
135 133 }
136 134  
137 135 default List<CombinationRecordDO> selectListByHeadIdAndStatusAndExpireTimeLt(Long headId, Integer status, LocalDateTime dateTime) {
... ... @@ -141,8 +139,8 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
141 139 .lt(CombinationRecordDO::getExpireTime, dateTime));
142 140 }
143 141  
144   - default List<CombinationRecordDO> selectListByHeadIds(Collection<Long> headIds) {
145   - return selectList(new LambdaQueryWrapperX<CombinationRecordDO>().in(CombinationRecordDO::getHeadId, headIds));
  142 + default List<CombinationRecordDO> selectListByHeadId(Long headId) {
  143 + return selectList(new LambdaQueryWrapperX<CombinationRecordDO>().eq(CombinationRecordDO::getHeadId, headId));
146 144 }
147 145  
148 146 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleCategoryServiceImpl.java
1 1 package cn.iocoder.yudao.module.promotion.service.article;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryCreateReqVO;
5 6 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryPageReqVO;
6 7 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.category.ArticleCategoryUpdateReqVO;
7 8 import cn.iocoder.yudao.module.promotion.convert.article.ArticleCategoryConvert;
8 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO;
9 11 import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleCategoryMapper;
10 12 import org.springframework.stereotype.Service;
11 13 import org.springframework.validation.annotation.Validated;
... ... @@ -14,6 +16,7 @@ import javax.annotation.Resource;
14 16 import java.util.List;
15 17  
16 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_DELETE_FAIL_HAVE_ARTICLES;
17 20 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_NOT_EXISTS;
18 21  
19 22 /**
... ... @@ -27,6 +30,8 @@ public class ArticleCategoryServiceImpl implements ArticleCategoryService {
27 30  
28 31 @Resource
29 32 private ArticleCategoryMapper articleCategoryMapper;
  33 + @Resource
  34 + private ArticleService articleService;
30 35  
31 36 @Override
32 37 public Long createArticleCategory(ArticleCategoryCreateReqVO createReqVO) {
... ... @@ -50,7 +55,11 @@ public class ArticleCategoryServiceImpl implements ArticleCategoryService {
50 55 public void deleteArticleCategory(Long id) {
51 56 // 校验存在
52 57 validateArticleCategoryExists(id);
53   - // TODO @puhui999:需要校验下,是不是存在文章
  58 + // 校验是不是存在关联文章
  59 + List<ArticleDO> articleList = articleService.getArticleByCategoryId(id);
  60 + if (CollUtil.isNotEmpty(articleList)) {
  61 + throw exception(ARTICLE_CATEGORY_DELETE_FAIL_HAVE_ARTICLES);
  62 + }
54 63  
55 64 // 删除
56 65 articleCategoryMapper.deleteById(id);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleService.java
... ... @@ -4,19 +4,21 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO;
5 5 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO;
7 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO;
8 9  
9 10 import javax.validation.Valid;
  11 +import java.util.List;
10 12  
11 13 /**
12   - * 文章管理 Service 接口
  14 + * 文章详情 Service 接口
13 15 *
14 16 * @author HUIHUI
15 17 */
16 18 public interface ArticleService {
17 19  
18 20 /**
19   - * 创建文章管理
  21 + * 创建文章详情
20 22 *
21 23 * @param createReqVO 创建信息
22 24 * @return 编号
... ... @@ -24,33 +26,58 @@ public interface ArticleService {
24 26 Long createArticle(@Valid ArticleCreateReqVO createReqVO);
25 27  
26 28 /**
27   - * 更新文章管理
  29 + * 更新文章详情
28 30 *
29 31 * @param updateReqVO 更新信息
30 32 */
31 33 void updateArticle(@Valid ArticleUpdateReqVO updateReqVO);
32 34  
33 35 /**
34   - * 删除文章管理
  36 + * 删除文章详情
35 37 *
36 38 * @param id 编号
37 39 */
38 40 void deleteArticle(Long id);
39 41  
40 42 /**
41   - * 获得文章管理
  43 + * 获得文章详情
42 44 *
43 45 * @param id 编号
44   - * @return 文章管理
  46 + * @return 文章详情
45 47 */
46 48 ArticleDO getArticle(Long id);
47 49  
48 50 /**
49   - * 获得文章管理分页
  51 + * 获得文章详情分页
50 52 *
51 53 * @param pageReqVO 分页查询
52   - * @return 文章管理分页
  54 + * @return 文章详情分页
53 55 */
54 56 PageResult<ArticleDO> getArticlePage(ArticlePageReqVO pageReqVO);
55 57  
  58 + /**
  59 + * 获得文章详情列表
  60 + *
  61 + * @param recommendHot 是否热门
  62 + * @param recommendBanner 是否轮播图
  63 + * @return 文章详情列表
  64 + */
  65 + List<ArticleDO> getArticleCategoryListByRecommendHotAndRecommendBanner(Boolean recommendHot, Boolean recommendBanner);
  66 +
  67 + /**
  68 + * 获得文章详情分页
  69 + *
  70 + * @param pageReqVO 分页查询
  71 + * @return 文章详情分页
  72 + */
  73 + PageResult<ArticleDO> getArticlePage(AppArticlePageReqVO pageReqVO);
  74 +
  75 + /**
  76 + * 获得指定分类的文章列表
  77 + *
  78 + * @param categoryId 文章分类编号
  79 + * @return 文章列表
  80 + */
  81 + List<ArticleDO> getArticleByCategoryId(Long categoryId);
  82 +
56 83 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImpl.java
... ... @@ -4,15 +4,19 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO;
5 5 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO;
6 6 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO;
7 8 import cn.iocoder.yudao.module.promotion.convert.article.ArticleConvert;
  9 +import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleCategoryDO;
8 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO;
9 11 import cn.iocoder.yudao.module.promotion.dal.mysql.article.ArticleMapper;
10 12 import org.springframework.stereotype.Service;
11 13 import org.springframework.validation.annotation.Validated;
12 14  
13 15 import javax.annotation.Resource;
  16 +import java.util.List;
14 17  
15 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_CATEGORY_NOT_EXISTS;
16 20 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.ARTICLE_NOT_EXISTS;
17 21  
18 22 /**
... ... @@ -26,10 +30,14 @@ public class ArticleServiceImpl implements ArticleService {
26 30  
27 31 @Resource
28 32 private ArticleMapper articleMapper;
  33 + @Resource
  34 + private ArticleCategoryService articleCategoryService;
29 35  
30 36 @Override
31 37 public Long createArticle(ArticleCreateReqVO createReqVO) {
32   - // TODO @puhui999:需要校验分类存在
  38 + // 校验分类存在
  39 + validateArticleCategoryExists(createReqVO.getCategoryId());
  40 +
33 41 // 插入
34 42 ArticleDO article = ArticleConvert.INSTANCE.convert(createReqVO);
35 43 articleMapper.insert(article);
... ... @@ -41,7 +49,8 @@ public class ArticleServiceImpl implements ArticleService {
41 49 public void updateArticle(ArticleUpdateReqVO updateReqVO) {
42 50 // 校验存在
43 51 validateArticleExists(updateReqVO.getId());
44   - // TODO @puhui999:需要校验分类存在
  52 + // 校验分类存在
  53 + validateArticleCategoryExists(updateReqVO.getCategoryId());
45 54  
46 55 // 更新
47 56 ArticleDO updateObj = ArticleConvert.INSTANCE.convert(updateReqVO);
... ... @@ -62,6 +71,13 @@ public class ArticleServiceImpl implements ArticleService {
62 71 }
63 72 }
64 73  
  74 + private void validateArticleCategoryExists(Long categoryId) {
  75 + ArticleCategoryDO articleCategory = articleCategoryService.getArticleCategory(categoryId);
  76 + if (articleCategory == null) {
  77 + throw exception(ARTICLE_CATEGORY_NOT_EXISTS);
  78 + }
  79 + }
  80 +
65 81 @Override
66 82 public ArticleDO getArticle(Long id) {
67 83 return articleMapper.selectById(id);
... ... @@ -72,4 +88,19 @@ public class ArticleServiceImpl implements ArticleService {
72 88 return articleMapper.selectPage(pageReqVO);
73 89 }
74 90  
  91 + @Override
  92 + public List<ArticleDO> getArticleCategoryListByRecommendHotAndRecommendBanner(Boolean recommendHot, Boolean recommendBanner) {
  93 + return articleMapper.selectList(recommendHot, recommendBanner);
  94 + }
  95 +
  96 + @Override
  97 + public PageResult<ArticleDO> getArticlePage(AppArticlePageReqVO pageReqVO) {
  98 + return articleMapper.selectPage(pageReqVO);
  99 + }
  100 +
  101 + @Override
  102 + public List<ArticleDO> getArticleByCategoryId(Long categoryId) {
  103 + return articleMapper.selectList(ArticleDO::getCategoryId, categoryId);
  104 + }
  105 +
75 106 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java
... ... @@ -247,7 +247,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
247 247  
248 248 @Override
249 249 public Long getCombinationUserCount() {
250   - return combinationRecordMapper.selectUserDistinctCount();
  250 + return combinationRecordMapper.selectUserCount();
251 251 }
252 252  
253 253 @Override
... ... @@ -351,48 +351,46 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
351 351 convertSet(headExpireRecords, CombinationRecordDO::getActivityId));
352 352 Map<Long, CombinationActivityDO> activityMap = convertMap(activities, CombinationActivityDO::getId);
353 353  
354   - // TODO @puhui999:这里可以改成“每个团”,处理一次哈;这样 handleExpireRecord、handleVirtualGroupRecord 都改成按团处理,每个是一个小事务;
355   - // 3. 校验是否虚拟成团
356   - List<CombinationRecordDO> virtualGroupHeadRecords = new ArrayList<>(); // 虚拟成团
357   - for (Iterator<CombinationRecordDO> iterator = headExpireRecords.iterator(); iterator.hasNext(); ) {
358   - CombinationRecordDO record = iterator.next();
359   - // 3.1.不匹配,则直接跳过
360   - CombinationActivityDO activity = activityMap.get(record.getActivityId());
361   - if (activity == null || !activity.getVirtualGroup()) { // 取不到活动的或者不是虚拟拼团的
362   - continue;
  354 + // 3. 改成“每个团”,处理一次哈;这样 handleExpireRecord、handleVirtualGroupRecord 都改成按团处理,每个是一个小事务;
  355 + KeyValue<Integer, Integer> keyValue = new KeyValue<>(0, 0); // 统计过期拼团和虚拟成团
  356 + for (CombinationRecordDO recordDO : headExpireRecords) {
  357 + try {
  358 + CombinationActivityDO activity = activityMap.get(recordDO.getActivityId());
  359 + if (activity == null || !activity.getVirtualGroup()) { // 取不到活动的或者不是虚拟拼团的
  360 + // 3.1. 处理过期的拼团
  361 + getSelf().handleExpireRecord(recordDO);
  362 + keyValue.setKey(keyValue.getKey() + 1);
  363 + } else {
  364 + // 3.2. 处理虚拟成团
  365 + getSelf().handleVirtualGroupRecord(recordDO);
  366 + keyValue.setValue(keyValue.getValue() + 1);
  367 + }
  368 + } catch (Exception ignored) { // 处理异常继续循环
363 369 }
364   - // 3.2.匹配,则移除,添加到虚拟成团中,并结束寻找
365   - virtualGroupHeadRecords.add(record);
366   - iterator.remove();
367   - break;
368 370 }
369 371  
370   - // 4.处理过期的拼团
371   - getSelf().handleExpireRecord(headExpireRecords);
372   - // 5.虚拟成团
373   - getSelf().handleVirtualGroupRecord(virtualGroupHeadRecords);
374   - return new KeyValue<>(headExpireRecords.size(), virtualGroupHeadRecords.size());
  372 + return keyValue;
375 373 }
376 374  
377 375 /**
378 376 * 处理过期拼团
379 377 *
380   - * @param headExpireRecords 过期拼团团长记录列表
  378 + * @param headExpireRecord 过期拼团团长记录列表
381 379 */
382 380 @Transactional(rollbackFor = Exception.class)
383   - public void handleExpireRecord(List<CombinationRecordDO> headExpireRecords) {
384   - if (CollUtil.isEmpty(headExpireRecords)) {
  381 + public void handleExpireRecord(CombinationRecordDO headExpireRecord) {
  382 + if (headExpireRecord == null) {
385 383 return;
386 384 }
387 385  
388 386 // 1.更新拼团记录
389   - List<CombinationRecordDO> headsAndRecords = updateBatchCombinationRecords(headExpireRecords,
  387 + List<CombinationRecordDO> headsAndRecords = updateBatchCombinationRecords(headExpireRecord,
390 388 CombinationRecordStatusEnum.FAILED);
391 389 if (headsAndRecords == null) {
392 390 return;
393 391 }
394 392  
395   - // 2.订单取消 TODO 以现在的取消回滚逻辑好像只能循环了
  393 + // 2.订单取消
396 394 headsAndRecords.forEach(item -> {
397 395 tradeOrderApi.cancelPaidOrder(item.getUserId(), item.getOrderId());
398 396 });
... ... @@ -401,36 +399,32 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
401 399 /**
402 400 * 处理虚拟拼团
403 401 *
404   - * @param virtualGroupHeadRecords 虚拟成团团长记录列表
  402 + * @param virtualGroupHeadRecord 虚拟成团团长记录列表
405 403 */
406 404 @Transactional(rollbackFor = Exception.class)
407   - public void handleVirtualGroupRecord(List<CombinationRecordDO> virtualGroupHeadRecords) {
408   - if (CollUtil.isEmpty(virtualGroupHeadRecords)) {
  405 + public void handleVirtualGroupRecord(CombinationRecordDO virtualGroupHeadRecord) {
  406 + if (virtualGroupHeadRecord == null) {
409 407 return;
410 408 }
411 409  
412 410 // 1. 团员补齐
413   - combinationRecordMapper.insertBatch(CombinationActivityConvert.INSTANCE.convertVirtualGroupList(virtualGroupHeadRecords));
  411 + combinationRecordMapper.insertBatch(CombinationActivityConvert.INSTANCE.convertVirtualGroupList(virtualGroupHeadRecord));
414 412 // 2. 更新拼团记录
415   - updateBatchCombinationRecords(virtualGroupHeadRecords, CombinationRecordStatusEnum.SUCCESS);
  413 + updateBatchCombinationRecords(virtualGroupHeadRecord, CombinationRecordStatusEnum.SUCCESS);
416 414 }
417 415  
418   - private List<CombinationRecordDO> updateBatchCombinationRecords(List<CombinationRecordDO> headRecords, CombinationRecordStatusEnum status) {
419   - // 1. 查询团成员
420   - List<CombinationRecordDO> records = combinationRecordMapper.selectListByHeadIds(
421   - convertSet(headRecords, CombinationRecordDO::getId));
  416 + private List<CombinationRecordDO> updateBatchCombinationRecords(CombinationRecordDO headRecord, CombinationRecordStatusEnum status) {
  417 + // 1. 查询团成员(包含团长)
  418 + List<CombinationRecordDO> records = combinationRecordMapper.selectListByHeadId(headRecord.getId());
422 419 if (CollUtil.isEmpty(records)) {
423 420 return null;
424 421 }
425   - Map<Long, List<CombinationRecordDO>> recordsMap = convertMultiMap(records, CombinationRecordDO::getHeadId);
426   - headRecords.forEach(item -> {
427   - recordsMap.get(item.getId()).add(item); // 把团长加进团里
428   - });
  422 + records.add(headRecord);// 把团长加进去
  423 +
429 424 // 2.批量更新拼团记录 status 和 失败/成团时间
430   - List<CombinationRecordDO> headsAndRecords = mergeValuesFromMap(recordsMap);
431   - List<CombinationRecordDO> updateRecords = new ArrayList<>(headsAndRecords.size());
  425 + List<CombinationRecordDO> updateRecords = new ArrayList<>(records.size());
432 426 LocalDateTime now = LocalDateTime.now();
433   - headsAndRecords.forEach(item -> {
  427 + records.forEach(item -> {
434 428 CombinationRecordDO record = new CombinationRecordDO().setId(item.getId())
435 429 .setStatus(status.getStatus()).setEndTime(now);
436 430 if (CombinationRecordStatusEnum.isSuccess(status.getStatus())) { // 虚拟成团完事更改状态成功后还需要把参与人数修改为成团需要人数
... ... @@ -439,7 +433,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
439 433 updateRecords.add(record);
440 434 });
441 435 combinationRecordMapper.updateBatch(updateRecords);
442   - return headsAndRecords;
  436 + return records;
443 437 }
444 438  
445 439 /**
... ...
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/article/ArticleServiceImplTest.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.promotion.service.article;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 5 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleCreateReqVO;
6   -import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.ArticleExportReqVO;
7 6 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticlePageReqVO;
8 7 import cn.iocoder.yudao.module.promotion.controller.admin.article.vo.article.ArticleUpdateReqVO;
9 8 import cn.iocoder.yudao.module.promotion.dal.dataobject.article.ArticleDO;
... ... @@ -13,7 +12,6 @@ import org.junit.jupiter.api.Test;
13 12 import org.springframework.context.annotation.Import;
14 13  
15 14 import javax.annotation.Resource;
16   -import java.util.List;
17 15  
18 16 import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
19 17 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
... ... @@ -166,68 +164,4 @@ public class ArticleServiceImplTest extends BaseDbUnitTest {
166 164 assertPojoEquals(dbArticle, pageResult.getList().get(0));
167 165 }
168 166  
169   - @Test
170   - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
171   - public void testGetArticleList() {
172   - // mock 数据
173   - ArticleDO dbArticle = randomPojo(ArticleDO.class, o -> { // 等会查询到
174   - o.setCategoryId(null);
175   - o.setTitle(null);
176   - o.setAuthor(null);
177   - o.setPicUrl(null);
178   - o.setIntroduction(null);
179   - o.setBrowseCount(null);
180   - o.setSort(null);
181   - o.setStatus(null);
182   - o.setSpuId(null);
183   - o.setRecommendHot(null);
184   - o.setRecommendBanner(null);
185   - o.setContent(null);
186   - o.setCreateTime(null);
187   - });
188   - articleMapper.insert(dbArticle);
189   - // 测试 categoryId 不匹配
190   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setCategoryId(null)));
191   - // 测试 title 不匹配
192   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setTitle(null)));
193   - // 测试 author 不匹配
194   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setAuthor(null)));
195   - // 测试 picUrl 不匹配
196   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setPicUrl(null)));
197   - // 测试 introduction 不匹配
198   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setIntroduction(null)));
199   - // 测试 browseCount 不匹配
200   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setBrowseCount(null)));
201   - // 测试 sort 不匹配
202   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setSort(null)));
203   - // 测试 status 不匹配
204   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setStatus(null)));
205   - // 测试 spuId 不匹配
206   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setSpuId(null)));
207   - // 测试 recommendHot 不匹配
208   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setRecommendHot(null)));
209   - // 测试 recommendBanner 不匹配
210   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setRecommendBanner(null)));
211   - // 测试 content 不匹配
212   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setContent(null)));
213   - // 测试 createTime 不匹配
214   - articleMapper.insert(cloneIgnoreId(dbArticle, o -> o.setCreateTime(null)));
215   - // 准备参数
216   - ArticleExportReqVO reqVO = new ArticleExportReqVO();
217   - reqVO.setCategoryId(null);
218   - reqVO.setTitle(null);
219   - reqVO.setAuthor(null);
220   - reqVO.setStatus(null);
221   - reqVO.setSpuId(null);
222   - reqVO.setRecommendHot(null);
223   - reqVO.setRecommendBanner(null);
224   - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
225   -
226   - // 调用
227   - List<ArticleDO> list = articleService.getArticleList(reqVO);
228   - // 断言
229   - assertEquals(1, list.size());
230   - assertPojoEquals(dbArticle, list.get(0));
231   - }
232   -
233 167 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
... ... @@ -93,7 +93,6 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
93 93 return selectOne(TradeOrderDO::getPickUpVerifyCode, pickUpVerifyCode);
94 94 }
95 95  
96   - // TODO @puhui999:selectByUserIdAndCombinationActivityIdAndStatus,这样更容易理解哈。
97 96 /**
98 97 * 只针对 combinationActivityId 的查询
99 98 *
... ... @@ -102,7 +101,7 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
102 101 * @param status 订单状态
103 102 * @return 交易订单
104 103 */
105   - default TradeOrderDO selectByUserIdAndActivityIdAndStatus(Long userId, Long activityId, Integer status) {
  104 + default TradeOrderDO selectByUserIdAndCombinationActivityIdAndStatus(Long userId, Long activityId, Integer status) {
106 105 return selectOne(new LambdaQueryWrapperX<TradeOrderDO>()
107 106 .eq(TradeOrderDO::getUserId, userId)
108 107 .eq(TradeOrderDO::getStatus, status)
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java
... ... @@ -46,7 +46,7 @@ public interface TradeOrderQueryService {
46 46 * @param status 订单状态
47 47 * @return 交易订单
48 48 */
49   - TradeOrderDO getActivityOrderByUserIdAndActivityIdAndStatus(Long userId, Long activityId, Integer status);
  49 + TradeOrderDO getCombinationActivityOrderByUserIdAndCombinationActivityIdAndStatus(Long userId, Long activityId, Integer status);
50 50  
51 51 /**
52 52 * 获得订单列表
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java
... ... @@ -71,8 +71,8 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
71 71 }
72 72  
73 73 @Override
74   - public TradeOrderDO getActivityOrderByUserIdAndActivityIdAndStatus(Long userId, Long activityId, Integer status) {
75   - return tradeOrderMapper.selectByUserIdAndActivityIdAndStatus(userId, activityId, status);
  74 + public TradeOrderDO getCombinationActivityOrderByUserIdAndCombinationActivityIdAndStatus(Long userId, Long activityId, Integer status) {
  75 + return tradeOrderMapper.selectByUserIdAndCombinationActivityIdAndStatus(userId, activityId, status);
76 76 }
77 77  
78 78 @Override
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java
... ... @@ -49,7 +49,7 @@ public class TradeCombinationOrderHandler implements TradeOrderHandler {
49 49 order.getCombinationHeadId(), item.getSkuId(), item.getCount());
50 50  
51 51 // 2. 校验该用户是否存在未支付的拼团活动订单,避免一个拼团可以下多个单子了
52   - TradeOrderDO activityOrder = orderQueryService.getActivityOrderByUserIdAndActivityIdAndStatus(
  52 + TradeOrderDO activityOrder = orderQueryService.getCombinationActivityOrderByUserIdAndCombinationActivityIdAndStatus(
53 53 order.getUserId(), order.getCombinationActivityId(), TradeOrderStatusEnum.UNPAID.getStatus());
54 54 if (activityOrder != null) {
55 55 throw exception(ORDER_CREATE_FAIL_EXIST_UNPAID);
... ...