Commit afaef0dfbbcf67a1e7016bf78e8c4eb1e5402670

Authored by puhui999
2 parents a82898ca 222d1cf6

Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product

Showing 32 changed files with 345 additions and 127 deletions
yudao-framework/yudao-common/pom.xml
... ... @@ -133,6 +133,11 @@
133 133 <artifactId>transmittable-thread-local</artifactId>
134 134 </dependency>
135 135  
  136 + <!-- Test 测试相关 -->
  137 + <dependency>
  138 + <groupId>org.springframework.boot</groupId>
  139 + <artifactId>spring-boot-starter-test</artifactId>
  140 + </dependency>
136 141 </dependencies>
137 142  
138 143 </project>
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -6,12 +6,11 @@ import cn.hutool.core.map.MapUtil;
6 6 import com.google.common.collect.ImmutableMap;
7 7  
8 8 import java.util.*;
9   -import java.util.function.BinaryOperator;
10   -import java.util.function.Function;
11   -import java.util.function.Predicate;
12   -import java.util.function.Supplier;
  9 +import java.util.function.*;
13 10 import java.util.stream.Collectors;
14 11  
  12 +import static java.util.Arrays.asList;
  13 +
15 14 /**
16 15 * Collection 工具类
17 16 *
... ... @@ -20,13 +19,14 @@ import java.util.stream.Collectors;
20 19 public class CollectionUtils {
21 20  
22 21 public static boolean containsAny(Object source, Object... targets) {
23   - return Arrays.asList(targets).contains(source);
  22 + return asList(targets).contains(source);
24 23 }
25 24  
26 25 public static boolean isAnyEmpty(Collection<?>... collections) {
27 26 return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
28 27 }
29 28  
  29 + // TODO @puhui999:anyMatch 更统一点
30 30 public static <T> boolean isAny(Collection<T> from, Predicate<T> predicate) {
31 31 return from.stream().anyMatch(predicate);
32 32 }
... ... @@ -189,6 +189,46 @@ public class CollectionUtils {
189 189 return func.apply(mapData);
190 190 }
191 191  
  192 + /**
  193 + * 对比老、新两个列表,找出新增、修改、删除的数据
  194 + *
  195 + * @param oldList 老列表
  196 + * @param newList 新列表
  197 + * @param sameFunc 对比函数,返回 true 表示相同,返回 false 表示不同
  198 + * 注意,same 是通过每个元素的“标识”,判断它们是不是同一个数据
  199 + * @return [新增列表、修改列表、删除列表]
  200 + */
  201 + public static <T> List<List<T>> diffList(Collection<T> oldList, Collection<T> newList,
  202 + BiFunction<T, T, Boolean> sameFunc) {
  203 + List<T> createList = new LinkedList<>(newList); // 默认都认为是新增的,后续会进行移除
  204 + List<T> updateList = new ArrayList<>();
  205 + List<T> deleteList = new ArrayList<>();
  206 +
  207 + // 通过以 oldList 为主遍历,找出 updateList 和 deleteList
  208 + for (T oldObj : oldList) {
  209 + // 1. 寻找是否有匹配的
  210 + T foundObj = null;
  211 + for (Iterator<T> iterator = createList.iterator(); iterator.hasNext(); ) {
  212 + T newObj = iterator.next();
  213 + // 1.1 不匹配,则直接跳过
  214 + if (!sameFunc.apply(oldObj, newObj)) {
  215 + continue;
  216 + }
  217 + // 1.2 匹配,则移除,并结束寻找
  218 + iterator.remove();
  219 + foundObj = newObj;
  220 + break;
  221 + }
  222 + // 2. 匹配添加到 updateList;不匹配则添加到 deleteList 中
  223 + if (foundObj != null) {
  224 + updateList.add(foundObj);
  225 + } else {
  226 + deleteList.add(oldObj);
  227 + }
  228 + }
  229 + return asList(createList, updateList, deleteList);
  230 + }
  231 +
192 232 public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
193 233 return org.springframework.util.CollectionUtils.containsAny(source, candidates);
194 234 }
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
... ... @@ -84,11 +84,11 @@ public class LocalDateTimeUtils {
84 84  
85 85 public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
86 86 // 日期部分使用了当前日期LocalDate.now()
  87 + // TODO @puhui999:LocalDate.now() 抽一个变量,啊哈;然后注释写下;之后 4 个变量不用,直接调方法的时候,直接计算作为入参;
87 88 LocalDateTime startDateTime1 = LocalDateTime.of(LocalDate.now(), startTime1);
88 89 LocalDateTime endDateTime1 = LocalDateTime.of(LocalDate.now(), endTime1);
89 90 LocalDateTime startDateTime2 = LocalDateTime.of(LocalDate.now(), startTime2);
90 91 LocalDateTime endDateTime2 = LocalDateTime.of(LocalDate.now(), endTime2);
91   -
92 92 return LocalDateTimeUtil.isOverlap(startDateTime1, endDateTime1, startDateTime2, endDateTime2);
93 93 }
94 94  
... ...
yudao-framework/yudao-common/src/test/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtilsTest.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.util.collection;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import org.junit.jupiter.api.Test;
  6 +
  7 +import java.util.Arrays;
  8 +import java.util.Collection;
  9 +import java.util.List;
  10 +import java.util.function.BiFunction;
  11 +
  12 +import static org.junit.jupiter.api.Assertions.assertEquals;
  13 +
  14 +/**
  15 + * {@link CollectionUtils} 的单元测试
  16 + */
  17 +public class CollectionUtilsTest {
  18 +
  19 + @Data
  20 + @AllArgsConstructor
  21 + private static class Dog {
  22 +
  23 + private Integer id;
  24 + private String name;
  25 + private String code;
  26 +
  27 + }
  28 +
  29 + @Test
  30 + public void testDiffList() {
  31 + // 准备参数
  32 + Collection<Dog> oldList = Arrays.asList(
  33 + new Dog(1, "花花", "hh"),
  34 + new Dog(2, "旺财", "wc")
  35 + );
  36 + Collection<Dog> newList = Arrays.asList(
  37 + new Dog(null, "花花2", "hh"),
  38 + new Dog(null, "小白", "xb")
  39 + );
  40 + BiFunction<Dog, Dog, Boolean> sameFunc = (oldObj, newObj) -> {
  41 + boolean same = oldObj.getCode().equals(newObj.getCode());
  42 + // 如果相等的情况下,需要设置下 id,后续好更新
  43 + if (same) {
  44 + newObj.setId(oldObj.getId());
  45 + }
  46 + return same;
  47 + };
  48 +
  49 + // 调用
  50 + List<List<Dog>> result = CollectionUtils.diffList(oldList, newList, sameFunc);
  51 + // 断言
  52 + assertEquals(result.size(), 3);
  53 + // 断言 create
  54 + assertEquals(result.get(0).size(), 1);
  55 + assertEquals(result.get(0).get(0), new Dog(null, "小白", "xb"));
  56 + // 断言 update
  57 + assertEquals(result.get(1).size(), 1);
  58 + assertEquals(result.get(1).get(0), new Dog(1, "花花2", "hh"));
  59 + // 断言 delete
  60 + assertEquals(result.get(2).size(), 1);
  61 + assertEquals(result.get(2).get(0), new Dog(2, "旺财", "wc"));
  62 + }
  63 +
  64 +}
... ...
yudao-framework/yudao-spring-boot-starter-banner/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
... ... @@ -17,20 +17,18 @@ import java.util.concurrent.TimeUnit;
17 17 public class BannerApplicationRunner implements ApplicationRunner {
18 18  
19 19 @Override
20   - public void run(ApplicationArguments args) throws Exception {
  20 + public void run(ApplicationArguments args) {
21 21 ThreadUtil.execute(() -> {
22 22 ThreadUtil.sleep(1, TimeUnit.SECONDS); // 延迟 1 秒,保证输出到结尾
23 23 log.info("\n----------------------------------------------------------\n\t" +
24 24 "项目启动成功!\n\t" +
25 25 "接口文档: \t{} \n\t" +
26 26 "开发文档: \t{} \n\t" +
27   - "视频教程: \t{} \n\t" +
28   - "源码解析: \t{} \n" +
  27 + "视频教程: \t{} \n" +
29 28 "----------------------------------------------------------",
30 29 "https://doc.iocoder.cn/api-doc/",
31 30 "https://doc.iocoder.cn",
32   - "https://t.zsxq.com/02Yf6M7Qn",
33   - "https://t.zsxq.com/02B6ujIee");
  31 + "https://t.zsxq.com/02Yf6M7Qn");
34 32  
35 33 // 数据报表
36 34 if (isNotPresent("cn.iocoder.yudao.module.report.framework.security.config.SecurityConfiguration")) {
... ... @@ -44,11 +42,11 @@ public class BannerApplicationRunner implements ApplicationRunner {
44 42 if (isNotPresent("cn.iocoder.yudao.module.mp.framework.mp.config.MpConfiguration")) {
45 43 System.out.println("[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]");
46 44 }
47   - // 商城
  45 + // 商城系统
48 46 if (isNotPresent("cn.iocoder.yudao.module.trade.framework.web.config.TradeWebConfiguration")) {
49 47 System.out.println("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
50 48 }
51   - // 支付
  49 + // 支付平台
52 50 if (isNotPresent("cn.iocoder.yudao.module.pay.framework.pay.config.PayConfiguration")) {
53 51 System.out.println("[支付系统 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
54 52 }
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
... ... @@ -44,6 +44,12 @@ public interface BaseMapperX&lt;T&gt; extends BaseMapper&lt;T&gt; {
44 44 return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
45 45 }
46 46  
  47 + default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
  48 + SFunction<T, ?> field3, Object value3) {
  49 + return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
  50 + .eq(field3, value3));
  51 + }
  52 +
47 53 default Long selectCount() {
48 54 return selectCount(new QueryWrapper<T>());
49 55 }
... ...
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.web.core.handler;
2 2  
3 3 import cn.hutool.core.exceptions.ExceptionUtil;
4 4 import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.StrUtil;
5 6 import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLog;
6 7 import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
7 8 import cn.iocoder.yudao.framework.common.exception.ServiceException;
... ... @@ -219,6 +220,13 @@ public class GlobalExceptionHandler {
219 220 */
220 221 @ExceptionHandler(value = Exception.class)
221 222 public CommonResult<?> defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
  223 + // 情况一:处理表不存在的异常
  224 + CommonResult<?> tableNotExistsResult = handleTableNotExists(ex);
  225 + if (tableNotExistsResult != null) {
  226 + return tableNotExistsResult;
  227 + }
  228 +
  229 + // 情况二:处理异常
222 230 log.error("[defaultExceptionHandler]", ex);
223 231 // 插入异常日志
224 232 this.createExceptionLog(req, ex);
... ... @@ -269,4 +277,48 @@ public class GlobalExceptionHandler {
269 277 errorLog.setExceptionTime(LocalDateTime.now());
270 278 }
271 279  
  280 + /**
  281 + * 处理 Table 不存在的异常情况
  282 + *
  283 + * @param ex 异常
  284 + * @return 如果是 Table 不存在的异常,则返回对应的 CommonResult
  285 + */
  286 + private CommonResult<?> handleTableNotExists(Throwable ex) {
  287 + String message = ExceptionUtil.getRootCauseMessage(ex);
  288 + if (!message.contains("doesn't exist")) {
  289 + return null;
  290 + }
  291 + // 1. 数据报表
  292 + if (message.contains("report_")) {
  293 + log.error("[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]");
  294 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  295 + "[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]");
  296 + }
  297 + // 2. 工作流
  298 + if (message.contains("bpm_")) {
  299 + log.error("[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]");
  300 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  301 + "[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]");
  302 + }
  303 + // 3. 微信公众号
  304 + if (message.contains("mp_")) {
  305 + log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
  306 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  307 + "[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
  308 + }
  309 + // 4. 商城系统
  310 + if (StrUtil.containsAny(message, "product_", "promotion_", "trade_")) {
  311 + log.error("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
  312 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  313 + "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
  314 + }
  315 + // 5. 支付平台
  316 + if (message.contains("pay_")) {
  317 + log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
  318 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  319 + "[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
  320 + }
  321 + return null;
  322 + }
  323 +
272 324 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java
1 1 package cn.iocoder.yudao.module.product.controller.app.comment;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 6 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
7 7 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
8 8 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
... ... @@ -27,6 +27,7 @@ import java.util.List;
27 27 import java.util.Set;
28 28  
29 29 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  30 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
30 31  
31 32 @Tag(name = "用户 APP - 商品评价")
32 33 @RestController
... ... @@ -56,10 +57,17 @@ public class AppProductCommentController {
56 57 @GetMapping("/page")
57 58 @Operation(summary = "获得商品评价分页")
58 59 public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
59   - PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
60   - Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId);
61   - PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, productSkuService.getSkuList(skuIds));
62   - return success(page);
  60 + // 查询评论分页
  61 + PageResult<ProductCommentDO> commentPageResult = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
  62 + if (CollUtil.isEmpty(commentPageResult.getList())) {
  63 + return success(PageResult.empty(commentPageResult.getTotal()));
  64 + }
  65 +
  66 + // 拼接返回
  67 + Set<Long> skuIds = convertSet(commentPageResult.getList(), ProductCommentDO::getSkuId);
  68 + PageResult<AppProductCommentRespVO> commentVOPageResult = ProductCommentConvert.INSTANCE.convertPage02(
  69 + commentPageResult, productSkuService.getSkuList(skuIds));
  70 + return success(commentVOPageResult);
63 71 }
64 72  
65 73 // TODO 芋艿:需要搞下
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java
1 1 package cn.iocoder.yudao.module.product.convert.comment;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.ObjectUtil;
5 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
... ... @@ -15,7 +14,6 @@ import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProdu
15 14 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
16 15 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
17 16 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
18   -import com.google.common.collect.Maps;
19 17 import org.mapstruct.Mapper;
20 18 import org.mapstruct.Mapping;
21 19 import org.mapstruct.Named;
... ... @@ -52,17 +50,16 @@ public interface ProductCommentConvert {
52 50  
53 51 PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
54 52  
55   - default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult, List<ProductSkuDO> skuList) {
56   - Map<Long, ProductSkuDO> skuMap = Maps.newLinkedHashMapWithExpectedSize(skuList.size());
57   - if (CollUtil.isNotEmpty(skuList)) {
58   - skuMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId));
59   - }
  53 + default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult,
  54 + List<ProductSkuDO> skuList) {
  55 + Map<Long, ProductSkuDO> skuMap = CollectionUtils.convertMap(skuList, ProductSkuDO::getId);
60 56 PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
61 57 page.getList().forEach(item -> {
62 58 // 判断用户是否选择匿名
63 59 if (ObjectUtil.equal(item.getAnonymous(), true)) {
64 60 item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
65 61 }
  62 + // 设置 SKU 规格值
66 63 MapUtils.findAndThen(skuMap, item.getSkuId(),
67 64 sku -> item.setSkuProperties(convertList01(sku.getProperties())));
68 65 });
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
... ... @@ -112,10 +112,9 @@ public interface ProductSpuConvert {
112 112 }
113 113  
114 114 default List<ProductSpuDetailRespVO> convertForSpuDetailRespListVO(List<ProductSpuDO> spus, List<ProductSkuDO> skus) {
115   - List<ProductSpuDetailRespVO> vos = new ArrayList<>(spus.size());
116 115 Map<Long, List<ProductSkuDO>> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId);
117   - CollectionUtils.convertList(spus, spu -> vos.add(convert03(spu).setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId())))));
118   - return vos;
  116 + return CollectionUtils.convertList(spus, spu -> convert03(spu)
  117 + .setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId()))));
119 118 }
120 119  
121 120 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApi.java
... ... @@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.promotion.api.combination;
3 3 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
4 4  
5 5 import javax.validation.Valid;
6   -// TODO @芋艿:后面也再撸撸这几个接口
7 6  
  7 +// TODO @芋艿:后面也再撸撸这几个接口
8 8 /**
9 9 * 拼团记录 API 接口
10 10 *
... ... @@ -17,17 +17,18 @@ public interface CombinationRecordApi {
17 17 *
18 18 * @param reqDTO 请求 DTO
19 19 */
20   - void createRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
  20 + void createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
21 21  
22 22 /**
23   - * 校验拼团是否成功
  23 + * 查询拼团记录是否成功
24 24 *
25 25 * @param userId 用户编号
26 26 * @param orderId 订单编号
27 27 * @return 拼团是否成功
28 28 */
29   - boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
  29 + boolean isCombinationRecordSuccess(Long userId, Long orderId);
30 30  
  31 + // TODO @puhui999:updateRecordStatus 和 updateRecordStatusAndStartTime 看看后续是不是可以统一掉;
31 32 /**
32 33 * 更新开团记录状态
33 34 *
... ... @@ -35,7 +36,7 @@ public interface CombinationRecordApi {
35 36 * @param orderId 订单编号
36 37 * @param status 状态值
37 38 */
38   - void updateRecordStatus(Long userId, Long orderId, Integer status);
  39 + void updateCombinationRecordStatus(Long userId, Long orderId, Integer status);
39 40  
40 41 /**
41 42 * 更新开团记录状态和开始时间
... ... @@ -44,6 +45,6 @@ public interface CombinationRecordApi {
44 45 * @param orderId 订单编号
45 46 * @param status 状态值
46 47 */
47   - void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status);
  48 + void updateCombinationRecordStatusAndStartTime(Long userId, Long orderId, Integer status);
48 49  
49 50 }
... ...
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/dto/CombinationRecordCreateReqDTO.java
... ... @@ -5,8 +5,9 @@ import lombok.Data;
5 5 import javax.validation.constraints.NotEmpty;
6 6 import javax.validation.constraints.NotNull;
7 7  
  8 +// TODO @芋艿:这块要在看看
8 9 /**
9   - * 拼团记录 Request DTO
  10 + * 拼团记录的创建 Request DTO
10 11 *
11 12 * @author HUIHUI
12 13 */
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/combination/CombinationRecordApiImpl.java
... ... @@ -20,23 +20,23 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
20 20 private CombinationRecordService recordService;
21 21  
22 22 @Override
23   - public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
24   - recordService.createRecord(reqDTO);
  23 + public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
  24 + recordService.createCombinationRecord(reqDTO);
25 25 }
26 26  
27 27 @Override
28   - public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
29   - return CombinationRecordStatusEnum.isSuccess(recordService.getRecord(userId, orderId).getStatus());
  28 + public boolean isCombinationRecordSuccess(Long userId, Long orderId) {
  29 + return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus());
30 30 }
31 31  
32 32 @Override
33   - public void updateRecordStatus(Long userId, Long orderId, Integer status) {
34   - recordService.updateRecordStatusByUserIdAndOrderId(userId, orderId, status);
  33 + public void updateCombinationRecordStatus(Long userId, Long orderId, Integer status) {
  34 + recordService.updateCombinationRecordStatusByUserIdAndOrderId(userId, orderId, status);
35 35 }
36 36  
37 37 @Override
38   - public void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
39   - recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
  38 + public void updateCombinationRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
  39 + recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
40 40 }
41 41  
42 42 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/combination/CombinationActivityController.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.controller.admin.combination;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6 5 import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
7 6 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
8 7 import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
... ... @@ -23,9 +22,11 @@ import javax.annotation.Resource;
23 22 import javax.validation.Valid;
24 23 import java.util.Collection;
25 24 import java.util.List;
  25 +import java.util.Set;
26 26  
27 27 import static cn.hutool.core.collection.CollectionUtil.newArrayList;
28 28 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
29 30  
30 31 @Tag(name = "管理后台 - 拼团活动")
31 32 @RestController
... ... @@ -35,6 +36,7 @@ public class CombinationActivityController {
35 36  
36 37 @Resource
37 38 private CombinationActivityService combinationActivityService;
  39 +
38 40 @Resource
39 41 private ProductSpuApi spuApi;
40 42  
... ... @@ -68,17 +70,18 @@ public class CombinationActivityController {
68 70 @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
69 71 public CommonResult<CombinationActivityRespVO> getCombinationActivity(@RequestParam("id") Long id) {
70 72 CombinationActivityDO activity = combinationActivityService.getCombinationActivity(id);
71   - List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(newArrayList(id));
  73 + List<CombinationProductDO> products = combinationActivityService.getCombinationProductsByActivityIds(newArrayList(id));
72 74 return success(CombinationActivityConvert.INSTANCE.convert(activity, products));
73 75 }
74 76  
  77 + // TODO @puhui999:是不是可以删掉,貌似没用?
75 78 @GetMapping("/list")
76 79 @Operation(summary = "获得拼团活动列表")
77 80 @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
78 81 @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
79 82 public CommonResult<List<CombinationActivityRespVO>> getCombinationActivityList(@RequestParam("ids") Collection<Long> ids) {
80 83 List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(ids);
81   - return success(CombinationActivityConvert.INSTANCE.complementList(list));
  84 + return success(CombinationActivityConvert.INSTANCE.convertList(list));
82 85 }
83 86  
84 87 @GetMapping("/page")
... ... @@ -86,10 +89,14 @@ public class CombinationActivityController {
86 89 @PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
87 90 public CommonResult<PageResult<CombinationActivityRespVO>> getCombinationActivityPage(
88 91 @Valid CombinationActivityPageReqVO pageVO) {
  92 + // 查询拼团活动
89 93 PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
  94 + // 拼接数据
  95 + Set<Long> activityIds = convertSet(pageResult.getList(), CombinationActivityDO::getId);
  96 + Set<Long> spuIds = convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
90 97 return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult,
91   - combinationActivityService.getProductsByActivityIds(CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getId)),
92   - spuApi.getSpuList(CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getSpuId))));
  98 + combinationActivityService.getCombinationProductsByActivityIds(activityIds),
  99 + spuApi.getSpuList(spuIds)));
93 100 }
94 101  
95 102 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillActivityController.java
... ... @@ -79,6 +79,7 @@ public class SeckillActivityController {
79 79 return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts));
80 80 }
81 81  
  82 + // TODO @puhui999:是不是可以删掉,貌似没用?
82 83 @GetMapping("/list")
83 84 @Operation(summary = "获得秒杀活动列表")
84 85 @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/combination/CombinationActivityConvert.java
1 1 package cn.iocoder.yudao.module.promotion.convert.combination;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 5 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
5 6 import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
6 7 import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
... ... @@ -70,7 +71,7 @@ public interface CombinationActivityConvert {
70 71 return respVO;
71 72 }
72 73  
73   - List<CombinationActivityRespVO> complementList(List<CombinationActivityDO> list);
  74 + List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list);
74 75  
75 76 PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page);
76 77  
... ... @@ -80,8 +81,10 @@ public interface CombinationActivityConvert {
80 81 Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
81 82 PageResult<CombinationActivityRespVO> pageResult = convertPage(page);
82 83 pageResult.getList().forEach(item -> {
83   - MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setSpuName(spu.getName()));
84   - MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()));
  84 + MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
  85 + item.setSpuName(spu.getName());
  86 + item.setPicUrl(spu.getPicUrl());
  87 + });
85 88 item.setProducts(convertList2(productList));
86 89 });
87 90 return pageResult;
... ... @@ -100,7 +103,7 @@ public interface CombinationActivityConvert {
100 103 })
101 104 CombinationProductDO convert(CombinationActivityDO activityDO, CombinationProductBaseVO vo);
102 105  
103   - default List<CombinationProductDO> complementList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
  106 + default List<CombinationProductDO> convertList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
104 107 List<CombinationProductDO> list = new ArrayList<>();
105 108 products.forEach(sku -> {
106 109 CombinationProductDO productDO = convert(activityDO, sku);
... ... @@ -110,16 +113,12 @@ public interface CombinationActivityConvert {
110 113 return list;
111 114 }
112 115  
113   - default List<CombinationProductDO> complementList(List<CombinationProductDO> productDOs, List<CombinationProductUpdateReqVO> vos, CombinationActivityDO activityDO) {
114   - Map<Long, Long> longMap = convertMap(productDOs, CombinationProductDO::getSkuId, CombinationProductDO::getId);
115   - List<CombinationProductDO> list = new ArrayList<>();
116   - vos.forEach(sku -> {
117   - CombinationProductDO productDO = convert(activityDO, sku);
118   - productDO.setId(longMap.get(sku.getSkuId()));
119   - productDO.setActivityStatus(activityDO.getStatus());
120   - list.add(productDO);
121   - });
122   - return list;
  116 + default List<CombinationProductDO> convertList(List<CombinationProductUpdateReqVO> updateProductVOs,
  117 + List<CombinationProductDO> products, CombinationActivityDO activity) {
  118 + Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId);
  119 + return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
  120 + .setId(productMap.get(updateProductVO.getSkuId()))
  121 + .setActivityStatus(activity.getStatus()));
123 122 }
124 123  
125 124 CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/seckill/seckillactivity/SeckillActivityConvert.java
... ... @@ -21,6 +21,8 @@ import java.util.ArrayList;
21 21 import java.util.List;
22 22 import java.util.Map;
23 23  
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  25 +
24 26 /**
25 27 * 秒杀活动 Convert
26 28 *
... ... @@ -37,6 +39,7 @@ public interface SeckillActivityConvert {
37 39  
38 40 SeckillActivityRespVO convert(SeckillActivityDO bean);
39 41  
  42 + // TODO @puhui999:这个是不是还是 convertList 好点?
40 43 List<SeckillActivityRespVO> complementList(List<SeckillActivityDO> list);
41 44  
42 45 PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
... ... @@ -73,7 +76,7 @@ public interface SeckillActivityConvert {
73 76 })
74 77 SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo);
75 78  
76   - default List<SeckillProductDO> complementList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
  79 + default List<SeckillProductDO> convertList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
77 80 List<SeckillProductDO> list = new ArrayList<>();
78 81 products.forEach(sku -> {
79 82 SeckillProductDO productDO = convert(activityDO, sku);
... ... @@ -83,16 +86,12 @@ public interface SeckillActivityConvert {
83 86 return list;
84 87 }
85 88  
86   - default List<SeckillProductDO> complementList(List<SeckillProductDO> productDOs, List<SeckillProductUpdateReqVO> vos, SeckillActivityDO activityDO) {
87   - Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
88   - List<SeckillProductDO> list = new ArrayList<>();
89   - vos.forEach(sku -> {
90   - SeckillProductDO productDO = convert(activityDO, sku);
91   - productDO.setId(longMap.get(sku.getSkuId()));
92   - productDO.setActivityStatus(activityDO.getStatus());
93   - list.add(productDO);
94   - });
95   - return list;
  89 + default List<SeckillProductDO> convertList(List<SeckillProductUpdateReqVO> updateProductVOs,
  90 + List<SeckillProductDO> products, SeckillActivityDO activity) {
  91 + Map<Long, Long> productMap = convertMap(products, SeckillProductDO::getSkuId, SeckillProductDO::getId);
  92 + return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
  93 + .setId(productMap.get(updateProductVO.getSkuId()))
  94 + .setActivityStatus(activity.getStatus()));
96 95 }
97 96  
98 97 List<SeckillProductRespVO> convertList2(List<SeckillProductDO> productDOs);
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/combination/CombinationRecordDO.java
... ... @@ -12,6 +12,9 @@ import java.time.LocalDateTime;
12 12 /**
13 13 * 拼团记录 DO
14 14 *
  15 + * 1. 用户参与拼团时,会创建一条记录
  16 + * 2. 团长的拼团记录,和参团人的拼团记录,通过 {@link #headId} 关联
  17 + *
15 18 * @author HUIHUI
16 19 */
17 20 @TableName("promotion_combination_record")
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/combination/CombinationRecordMapper.java
... ... @@ -15,6 +15,7 @@ import java.util.List;
15 15 @Mapper
16 16 public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO> {
17 17  
  18 + // TODO @puhui999:selectByUserIdAndOrderId
18 19 default CombinationRecordDO selectRecord(Long userId, Long orderId) {
19 20 return selectOne(CombinationRecordDO::getUserId, userId,
20 21 CombinationRecordDO::getOrderId, orderId);
... ... @@ -28,7 +29,8 @@ public interface CombinationRecordMapper extends BaseMapperX&lt;CombinationRecordDO
28 29 * @return 拼团记录
29 30 */
30 31 default CombinationRecordDO selectRecordByHeadId(Long headId, Long activityId, Integer status) {
31   - return selectOne(CombinationRecordDO::getUserId, headId, CombinationRecordDO::getActivityId, activityId,
  32 + return selectOne(CombinationRecordDO::getHeadId, headId,
  33 + CombinationRecordDO::getActivityId, activityId,
32 34 CombinationRecordDO::getStatus, status);
33 35 }
34 36  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationActivityService.java
... ... @@ -70,6 +70,6 @@ public interface CombinationActivityService {
70 70 * @param ids 拼团活动 ids
71 71 * @return 拼团活动的商品列表
72 72 */
73   - List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids);
  73 + List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids);
74 74  
75 75 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordService.java
... ... @@ -19,14 +19,14 @@ public interface CombinationRecordService {
19 19 * @param orderId 订单编号
20 20 * @param status 状态
21 21 */
22   - void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
  22 + void updateCombinationRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
23 23  
24 24 /**
25 25 * 创建拼团记录
26 26 *
27 27 * @param reqDTO 创建信息
28 28 */
29   - void createRecord(CombinationRecordCreateReqDTO reqDTO);
  29 + void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO);
30 30  
31 31 /**
32 32 * 更新拼团状态和开始时间
... ... @@ -36,7 +36,8 @@ public interface CombinationRecordService {
36 36 * @param status 状态
37 37 * @param startTime 开始时间
38 38 */
39   - void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime);
  39 + void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId,
  40 + Integer status, LocalDateTime startTime);
40 41  
41 42 /**
42 43 * 获得拼团状态
... ... @@ -45,6 +46,6 @@ public interface CombinationRecordService {
45 46 * @param orderId 订单编号
46 47 * @return 拼团状态
47 48 */
48   - CombinationRecordDO getRecord(Long userId, Long orderId);
  49 + CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
49 50  
50 51 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationServiceImpl.java
... ... @@ -37,7 +37,7 @@ import java.util.*;
37 37 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
38 38 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
39 39 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
40   -import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
  40 +import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
41 41  
42 42 /**
43 43 * 拼团活动 Service 实现类
... ... @@ -66,7 +66,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
66 66 // 获取所选 spu下的所有 sku
67 67 List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(createReqVO.getSpuId()));
68 68 // 校验商品 sku 是否存在
69   - validateProductSkuExistence(createReqVO.getProducts(), skus, CombinationProductCreateReqVO::getSkuId);
  69 + validateProductSkuAllExists(createReqVO.getProducts(), skus, CombinationProductCreateReqVO::getSkuId);
70 70  
71 71 // TODO 艿艿 有个小问题:现在有活动时间和限制时长,活动时间的结束时间早于设置的限制时间怎么算状态比如:
72 72 // 活动时间 2023-08-05 15:00:00 - 2023-08-05 15:20:00 限制时长 2小时,那么活动时间结束就结束还是加时到满两小时
... ... @@ -80,7 +80,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
80 80 activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
81 81 combinationActivityMapper.insert(activityDO);
82 82 // 插入商品
83   - List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.complementList(createReqVO.getProducts(), activityDO);
  83 + List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activityDO);
84 84 combinationProductMapper.insertBatch(productDOs);
85 85 // 返回
86 86 return activityDO.getId();
... ... @@ -118,7 +118,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
118 118 // 获取所选 spu下的所有 sku
119 119 List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId()));
120 120 // 校验商品 sku 是否存在
121   - validateProductSkuExistence(updateReqVO.getProducts(), skus, CombinationProductUpdateReqVO::getSkuId);
  121 + validateProductSkuAllExists(updateReqVO.getProducts(), skus, CombinationProductUpdateReqVO::getSkuId);
122 122  
123 123 // 更新
124 124 CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
... ... @@ -140,18 +140,21 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
140 140 // 前端传过来的活动商品
141 141 Set<Long> convertSet1 = CollectionUtils.convertSet(products, CombinationProductUpdateReqVO::getSkuId);
142 142 // 分化数据
  143 + // TODO @芋艿:看下这个实现
143 144 Map<String, List<CombinationProductDO>> data = CollectionUtils.convertCDUMap(convertSet1, convertSet, mapData -> {
144 145 HashMap<String, List<CombinationProductDO>> cdu = MapUtil.newHashMap(3);
145 146 MapUtils.findAndThen(mapData, "create", list -> {
146   - cdu.put("create", CombinationActivityConvert.INSTANCE.complementList(CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
  147 + cdu.put("create", CombinationActivityConvert.INSTANCE.convertList(CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
147 148 });
148 149 MapUtils.findAndThen(mapData, "delete", list -> {
149 150 cdu.put("create", CollectionUtils.filterList(combinationProductDOs, item -> list.contains(item.getSkuId())));
150 151 });
151   - MapUtils.findAndThen(mapData, "update", list -> {
152   - cdu.put("update", CombinationActivityConvert.INSTANCE.complementList(combinationProductDOs,
153   - CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
154   - });
  152 + // TODO @芋艿:临时注释,避免有问题
  153 +// MapUtils.findAndThen(mapData, "update", list -> {
  154 +// cdu.put("update", CombinationActivityConvert.INSTANCE.convertList(
  155 +// combinationProductDOs,
  156 +// CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
  157 +// });
155 158 return cdu;
156 159 });
157 160  
... ... @@ -199,12 +202,12 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
199 202 }
200 203  
201 204 @Override
202   - public List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids) {
  205 + public List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids) {
203 206 return combinationProductMapper.selectListByActivityIds(ids);
204 207 }
205 208  
206 209 @Override
207   - public void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status) {
  210 + public void updateCombinationRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status) {
208 211 // 校验拼团是否存在
209 212 CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
210 213  
... ... @@ -215,7 +218,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
215 218  
216 219 @Override
217 220 @Transactional(rollbackFor = Exception.class)
218   - public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime) {
  221 + public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime) {
219 222 CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
220 223 // 更新状态
221 224 recordDO.setStatus(status);
... ... @@ -247,15 +250,15 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
247 250 }
248 251  
249 252 @Override
250   - public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
251   - // 校验拼团活动
  253 + public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
  254 + // 1.1 校验拼团活动
252 255 CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
253   - // 需要校验下,它当前是不是已经参加了该拼团;
  256 + // 1.2 需要校验下,他当前是不是已经参加了该拼团;
254 257 CombinationRecordDO recordDO = recordMapper.selectRecord(reqDTO.getUserId(), reqDTO.getOrderId());
255 258 if (recordDO != null) {
256 259 throw exception(COMBINATION_RECORD_EXISTS);
257 260 }
258   - // 父拼团是否存在,是否已经满了
  261 + // 1.3 父拼团是否存在,是否已经满了
259 262 if (reqDTO.getHeadId() != null) {
260 263 CombinationRecordDO recordDO1 = recordMapper.selectRecordByHeadId(reqDTO.getHeadId(), reqDTO.getActivityId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
261 264 if (recordDO1 == null) {
... ... @@ -266,9 +269,12 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
266 269 throw exception(COMBINATION_RECORD_USER_FULL);
267 270 }
268 271 }
  272 + // TODO @puhui999:应该还有一些校验,后续补噶;例如说,一个团,自己已经参与进去了,不能再参与进去;
269 273  
  274 + // 2. 创建拼团记录
270 275 CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
271 276 if (reqDTO.getHeadId() == null) {
  277 + // TODO @puhui999:不是自己呀;headId 是父团长的 CombinationRecordDO.id 哈
272 278 record.setHeadId(reqDTO.getUserId());
273 279 }
274 280 record.setVirtualGroup(false);
... ... @@ -279,7 +285,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
279 285 }
280 286  
281 287 @Override
282   - public CombinationRecordDO getRecord(Long userId, Long orderId) {
  288 + public CombinationRecordDO getCombinationRecord(Long userId, Long orderId) {
283 289 return validateCombinationRecord(userId, orderId);
284 290 }
285 291  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillactivity/SeckillActivityServiceImpl.java
... ... @@ -34,7 +34,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
34 34 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
35 35 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
36 36 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
37   -import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
  37 +import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
38 38  
39 39 /**
40 40 * 秒杀活动 Service 实现类
... ... @@ -74,7 +74,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
74 74 .setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
75 75 seckillActivityMapper.insert(activity);
76 76 // 插入商品
77   - List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.complementList(createReqVO.getProducts(), activity);
  77 + List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
78 78 seckillProductMapper.insertBatch(products);
79 79 return activity.getId();
80 80 }
... ... @@ -121,7 +121,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
121 121 // 获取所选 spu下的所有 sku
122 122 List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
123 123 // 校验商品 sku 是否存在
124   - validateProductSkuExistence(updateReqVO.getProducts(), skus, SeckillProductUpdateReqVO::getSkuId);
  124 + validateProductSkuAllExists(updateReqVO.getProducts(), skus, SeckillProductUpdateReqVO::getSkuId);
125 125  
126 126 // 更新活动
127 127 SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
... ... @@ -150,16 +150,17 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
150 150 Map<String, List<SeckillProductDO>> data = CollectionUtils.convertCDUMap(voSkuIds, dbSkuIds, mapData -> {
151 151 HashMap<String, List<SeckillProductDO>> cdu = MapUtil.newHashMap(3);
152 152 MapUtils.findAndThen(mapData, "create", list -> {
153   - cdu.put("create", SeckillActivityConvert.INSTANCE.complementList(
  153 + cdu.put("create", SeckillActivityConvert.INSTANCE.convertList(
154 154 CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
155 155 });
156 156 MapUtils.findAndThen(mapData, "delete", list -> {
157 157 cdu.put("create", CollectionUtils.filterList(seckillProductDOs, item -> list.contains(item.getSkuId())));
158 158 });
159   - MapUtils.findAndThen(mapData, "update", list -> {
160   - cdu.put("update", SeckillActivityConvert.INSTANCE.complementList(seckillProductDOs,
161   - CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
162   - });
  159 + // TODO @芋艿:临时注释
  160 +// MapUtils.findAndThen(mapData, "update", list -> {
  161 +// cdu.put("update", SeckillActivityConvert.INSTANCE.convertList(seckillProductDOs,
  162 +// CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
  163 +// });
163 164 return cdu;
164 165 });
165 166  
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java
... ... @@ -31,18 +31,20 @@ public class PromotionUtils {
31 31 return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
32 32 }
33 33  
  34 + // TODO @puhui999:是不是第一个参数是 sku;然后是 products;这样关联性好点;
34 35 /**
35   - * 校验商品 sku 是否存在
  36 + * 校验商品 sku 是否都存在
36 37 *
37 38 * @param products 需要校验的商品
38 39 * @param skus 数据库中的商品 skus
39 40 * @param func 获取需要校验的商品的 skuId
40 41 */
41   - public static <T> void validateProductSkuExistence(List<T> products, List<ProductSkuRespDTO> skus, Function<T, Long> func) {
  42 + public static <T> void validateProductSkuAllExists(List<T> products, List<ProductSkuRespDTO> skus, Function<T, Long> func) {
42 43 // 校验 sku 个数是否一致
43 44 Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
44 45 Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
45 46 // 校验 skuId 是否存在
  47 + // TODO @puhui999:findFirst
46 48 List<Long> f = CollectionUtils.filterList(skuIdsSet, s -> !skuIdsSet1.contains(s));
47 49 if (CollUtil.isNotEmpty(f)) {
48 50 throw exception(SKU_NOT_EXISTS);
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -332,6 +332,7 @@ public interface TradeOrderConvert {
332 332 @Mapping(target = "avatar", source = "user.avatar"),
333 333 @Mapping(target = "status", ignore = true)
334 334 })
335   - CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem, AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
  335 + CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,
  336 + AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
336 337  
337 338 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java
... ... @@ -27,11 +27,13 @@ public class TradeMessageServiceImpl implements TradeMessageService {
27 27 // 1、构造消息
28 28 Map<String, Object> msgMap = new HashMap<>();
29 29 msgMap.put("orderId", reqDTO.getOrderId());
  30 + // TODO puhui999:应该不是 msg 哇,应该是涉及到的模版参数哈;msg 太大了
30 31 msgMap.put("msg", reqDTO.getMessage());
31 32 // 2、发送站内信
32 33 notifyMessageSendApi.sendSingleMessageToMember(
33 34 new NotifySendSingleToUserReqDTO()
34 35 .setUserId(reqDTO.getUserId())
  36 + // TODO puhui999:短信模版编号,枚举起来;
35 37 .setTemplateCode("order_delivery")
36 38 .setTemplateParams(msgMap));
37 39 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/dto/TradeOrderMessageWhenDeliveryOrderReqDTO.java
... ... @@ -5,6 +5,7 @@ import lombok.Data;
5 5 import javax.validation.constraints.NotEmpty;
6 6 import javax.validation.constraints.NotNull;
7 7  
  8 +// TODO @puhui999:改成 ReqBO 哈;包名也换了;service 我们还是同一用 bo 对象
8 9 /**
9 10 * 订单发货时 Req DTO
10 11 *
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
... ... @@ -174,7 +174,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
174 174 if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
175 175 MemberUserRespDTO user = memberUserApi.getUser(userId);
176 176 // TODO 拼团一次应该只能选择一种规格的商品
177   - combinationRecordApi.createRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
  177 + // TODO @puhui999:应该是前置校验哈;然后不应该设置状态,而是交给拼团记录那处理;
  178 + combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
178 179 .setStatus(CombinationRecordStatusEnum.WAITING.getStatus()));
179 180 }
180 181 // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
... ... @@ -311,7 +312,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
311 312 // 1、拼团活动
312 313 if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
313 314 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
314   - combinationRecordApi.updateRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
  315 + combinationRecordApi.updateCombinationRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
315 316 }
316 317 // TODO 芋艿:发送订单变化的消息
317 318  
... ... @@ -376,10 +377,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
376 377 return new KeyValue<>(order, payOrder);
377 378 }
378 379  
  380 + // TODO @芋艿:后续在 review 下发货逻辑
379 381 @Override
380 382 @Transactional(rollbackFor = Exception.class)
381 383 public void deliveryOrder(Long userId, TradeOrderDeliveryReqVO deliveryReqVO) {
382   - // 校验并获得交易订单(可发货)
  384 + // 1.1 校验并获得交易订单(可发货)
383 385 TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
384 386  
385 387 /* TODO
... ... @@ -388,35 +390,36 @@ public class TradeOrderServiceImpl implements TradeOrderService {
388 390 * 2.如果店铺只支持到店自提那么下单后默认发货不需要物流
389 391 * 3.如果店铺支持 物流-配送-自提 的情况下后台不需要选择配送方式按前端用户选择的配送方式发货即可
390 392 */
391   - TradeOrderDO tradeOrderDO = new TradeOrderDO();
  393 + TradeOrderDO updateOrderObj = new TradeOrderDO();
392 394 // 判断发货类型
393   - // 快递发货
  395 + // 2.1 快递发货
394 396 if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.EXPRESS.getMode())) {
395 397 // 校验快递公司
  398 + // TODO @puhui999:getDeliveryExpress 直接封装一个校验的,会不会好点;因为还有开启关闭啥的;
396 399 DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
397 400 if (deliveryExpress == null) {
398 401 throw exception(EXPRESS_NOT_EXISTS);
399 402 }
400   - tradeOrderDO.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
  403 + updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
401 404 }
402   - // 用户自提
  405 + // 2.2 用户自提
403 406 if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.PICK_UP.getMode())) {
404 407 // TODO 校验自提门店是否存在
405 408 // 重置一下确保快递公司和快递单号为空
406   - tradeOrderDO.setLogisticsId(null).setLogisticsNo("");
  409 + updateOrderObj.setLogisticsId(null).setLogisticsNo("");
407 410 }
408   - // TODO 芋艿:如果无需发货,需要怎么存储?
  411 + // 2.3 TODO 芋艿:如果无需发货,需要怎么存储?回复:需要把 deliverType 设置为 DeliveryTypeEnum.NULL
409 412 if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.NULL.getMode())) {
410 413 // TODO 情况一:正常走发货逻辑和用户自提有点像 不同点:不需要自提门店只需要用户确认收货
411 414 // TODO 情况二:用户下单付款后直接确认收货或等待用户确认收货
412 415 // 重置一下确保快递公司和快递单号为空
413   - tradeOrderDO.setLogisticsId(null).setLogisticsNo("");
  416 + updateOrderObj.setLogisticsId(null).setLogisticsNo("");
414 417 }
415 418  
416 419 // 更新 TradeOrderDO 状态为已发货,等待收货
417   - tradeOrderDO.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
  420 + updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
418 421 .setDeliveryStatus(TradeOrderDeliveryStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now());
419   - int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), tradeOrderDO);
  422 + int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
420 423 if (updateCount == 0) {
421 424 throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
422 425 }
... ... @@ -457,7 +460,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
457 460 if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
458 461 // 校验订单拼团是否成功
459 462 // TODO 用户 ID 使用当前登录用户的还是订单保存的?
460   - if (combinationRecordApi.validateRecordStatusIsSuccess(order.getUserId(), order.getId())) {
  463 + if (combinationRecordApi.isCombinationRecordSuccess(order.getUserId(), order.getId())) {
461 464 throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
462 465 }
463 466 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java
... ... @@ -27,6 +27,7 @@ import org.springframework.validation.annotation.Validated;
27 27 import javax.annotation.PostConstruct;
28 28 import javax.annotation.Resource;
29 29 import java.time.LocalDateTime;
  30 +import java.util.Collections;
30 31 import java.util.List;
31 32 import java.util.Map;
32 33 import java.util.concurrent.TimeUnit;
... ... @@ -68,7 +69,15 @@ public class MpAccountServiceImpl implements MpAccountService {
68 69 // 注意:忽略自动多租户,因为要全局初始化缓存
69 70 TenantUtils.executeIgnore(() -> {
70 71 // 第一步:查询数据
71   - List<MpAccountDO> accounts = mpAccountMapper.selectList();
  72 + List<MpAccountDO> accounts = Collections.emptyList();
  73 + try {
  74 + accounts = mpAccountMapper.selectList();
  75 + } catch (Throwable ex) {
  76 + if (!ex.getMessage().contains("doesn't exist")) {
  77 + throw ex;
  78 + }
  79 + log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
  80 + }
72 81 log.info("[initLocalCacheIfUpdate][缓存公众号账号,数量为:{}]", accounts.size());
73 82  
74 83 // 第二步:构建缓存。创建或更新支付 Client
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
... ... @@ -27,6 +27,7 @@ import javax.annotation.Resource;
27 27 import javax.validation.Validator;
28 28 import java.time.LocalDateTime;
29 29 import java.util.Collection;
  30 +import java.util.Collections;
30 31 import java.util.List;
31 32 import java.util.concurrent.TimeUnit;
32 33  
... ... @@ -64,7 +65,15 @@ public class PayChannelServiceImpl implements PayChannelService {
64 65 // 注意:忽略自动多租户,因为要全局初始化缓存
65 66 TenantUtils.executeIgnore(() -> {
66 67 // 第一步:查询数据
67   - List<PayChannelDO> channels = channelMapper.selectList();
  68 + List<PayChannelDO> channels = Collections.emptyList();
  69 + try {
  70 + channels = channelMapper.selectList();
  71 + } catch (Throwable ex) {
  72 + if (!ex.getMessage().contains("doesn't exist")) {
  73 + throw ex;
  74 + }
  75 + log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
  76 + }
68 77 log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size());
69 78  
70 79 // 第二步:构建缓存:创建或更新支付 Client
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailAccountServiceImpl.java
... ... @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
9 9 import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
10 10 import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
11 11 import lombok.extern.slf4j.Slf4j;
  12 +import org.springframework.cache.annotation.CacheEvict;
12 13 import org.springframework.cache.annotation.Cacheable;
13 14 import org.springframework.stereotype.Service;
14 15 import org.springframework.validation.annotation.Validated;
... ... @@ -46,7 +47,7 @@ public class MailAccountServiceImpl implements MailAccountService {
46 47 }
47 48  
48 49 @Override
49   - @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id")
  50 + @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id")
50 51 public void updateMailAccount(MailAccountUpdateReqVO updateReqVO) {
51 52 // 校验是否存在
52 53 validateMailAccountExists(updateReqVO.getId());
... ... @@ -57,7 +58,7 @@ public class MailAccountServiceImpl implements MailAccountService {
57 58 }
58 59  
59 60 @Override
60   - @Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id")
  61 + @CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id")
61 62 public void deleteMailAccount(Long id) {
62 63 // 校验是否存在账号
63 64 validateMailAccountExists(id);
... ...
yudao-ui-admin/src/views/pay/app/components/weixinChannelForm.vue
... ... @@ -52,9 +52,9 @@
52 52 <el-input v-model="formData.config.apiV3Key" placeholder="请输入 API V3 密钥" clearable
53 53 :style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input>
54 54 </el-form-item>
55   - <el-form-item label-width="180px" label="apiclient_key.perm 证书" prop="config.privateKeyContent">
  55 + <el-form-item label-width="180px" label="apiclient_key.pem 证书" prop="config.privateKeyContent">
56 56 <el-input v-model="formData.config.privateKeyContent" type="textarea"
57   - placeholder="请上传 apiclient_key.perm 证书"
  57 + placeholder="请上传 apiclient_key.pem 证书"
58 58 readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
59 59 </el-form-item>
60 60 <el-form-item label-width="180px" label="" prop="privateKeyContentFile">
... ... @@ -132,7 +132,7 @@ export default {
132 132 'config.apiVersion': [{ required: true, message: 'API版本不能为空', trigger: 'blur'}],
133 133 'config.mchKey': [{ required: true, message: '请输入商户密钥', trigger: 'blur' }],
134 134 'config.keyContent': [{ required: true, message: '请上传 apiclient_cert.p12 证书', trigger: 'blur' }],
135   - 'config.privateKeyContent': [{ required: true, message: '请上传 apiclient_key.perm 证书', trigger: 'blur' }],
  135 + 'config.privateKeyContent': [{ required: true, message: '请上传 apiclient_key.pem 证书', trigger: 'blur' }],
136 136 'config.privateCertContent': [{ required: true, message: '请上传 apiclient_cert.perm证 书', trigger: 'blur' }],
137 137 'config.apiV3Key': [{ required: true, message: '请上传 api V3 密钥值', trigger: 'blur' }],
138 138 },
... ...