mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 17:21:53 +08:00
Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product
This commit is contained in:
commit
afaef0dfbb
@ -133,6 +133,11 @@
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -6,12 +6,11 @@ import cn.hutool.core.map.MapUtil;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Collection 工具类
|
||||
*
|
||||
@ -20,13 +19,14 @@ import java.util.stream.Collectors;
|
||||
public class CollectionUtils {
|
||||
|
||||
public static boolean containsAny(Object source, Object... targets) {
|
||||
return Arrays.asList(targets).contains(source);
|
||||
return asList(targets).contains(source);
|
||||
}
|
||||
|
||||
public static boolean isAnyEmpty(Collection<?>... collections) {
|
||||
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
|
||||
}
|
||||
|
||||
// TODO @puhui999:anyMatch 更统一点
|
||||
public static <T> boolean isAny(Collection<T> from, Predicate<T> predicate) {
|
||||
return from.stream().anyMatch(predicate);
|
||||
}
|
||||
@ -189,6 +189,46 @@ public class CollectionUtils {
|
||||
return func.apply(mapData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对比老、新两个列表,找出新增、修改、删除的数据
|
||||
*
|
||||
* @param oldList 老列表
|
||||
* @param newList 新列表
|
||||
* @param sameFunc 对比函数,返回 true 表示相同,返回 false 表示不同
|
||||
* 注意,same 是通过每个元素的“标识”,判断它们是不是同一个数据
|
||||
* @return [新增列表、修改列表、删除列表]
|
||||
*/
|
||||
public static <T> List<List<T>> diffList(Collection<T> oldList, Collection<T> newList,
|
||||
BiFunction<T, T, Boolean> sameFunc) {
|
||||
List<T> createList = new LinkedList<>(newList); // 默认都认为是新增的,后续会进行移除
|
||||
List<T> updateList = new ArrayList<>();
|
||||
List<T> deleteList = new ArrayList<>();
|
||||
|
||||
// 通过以 oldList 为主遍历,找出 updateList 和 deleteList
|
||||
for (T oldObj : oldList) {
|
||||
// 1. 寻找是否有匹配的
|
||||
T foundObj = null;
|
||||
for (Iterator<T> iterator = createList.iterator(); iterator.hasNext(); ) {
|
||||
T newObj = iterator.next();
|
||||
// 1.1 不匹配,则直接跳过
|
||||
if (!sameFunc.apply(oldObj, newObj)) {
|
||||
continue;
|
||||
}
|
||||
// 1.2 匹配,则移除,并结束寻找
|
||||
iterator.remove();
|
||||
foundObj = newObj;
|
||||
break;
|
||||
}
|
||||
// 2. 匹配添加到 updateList;不匹配则添加到 deleteList 中
|
||||
if (foundObj != null) {
|
||||
updateList.add(foundObj);
|
||||
} else {
|
||||
deleteList.add(oldObj);
|
||||
}
|
||||
}
|
||||
return asList(createList, updateList, deleteList);
|
||||
}
|
||||
|
||||
public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
|
||||
return org.springframework.util.CollectionUtils.containsAny(source, candidates);
|
||||
}
|
||||
|
@ -84,11 +84,11 @@ public class LocalDateTimeUtils {
|
||||
|
||||
public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
|
||||
// 日期部分使用了当前日期LocalDate.now()
|
||||
// TODO @puhui999:LocalDate.now() 抽一个变量,啊哈;然后注释写下;之后 4 个变量不用,直接调方法的时候,直接计算作为入参;
|
||||
LocalDateTime startDateTime1 = LocalDateTime.of(LocalDate.now(), startTime1);
|
||||
LocalDateTime endDateTime1 = LocalDateTime.of(LocalDate.now(), endTime1);
|
||||
LocalDateTime startDateTime2 = LocalDateTime.of(LocalDate.now(), startTime2);
|
||||
LocalDateTime endDateTime2 = LocalDateTime.of(LocalDate.now(), endTime2);
|
||||
|
||||
return LocalDateTimeUtil.isOverlap(startDateTime1, endDateTime1, startDateTime2, endDateTime2);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
package cn.iocoder.yudao.framework.common.util.collection;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link CollectionUtils} 的单元测试
|
||||
*/
|
||||
public class CollectionUtilsTest {
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
private static class Dog {
|
||||
|
||||
private Integer id;
|
||||
private String name;
|
||||
private String code;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffList() {
|
||||
// 准备参数
|
||||
Collection<Dog> oldList = Arrays.asList(
|
||||
new Dog(1, "花花", "hh"),
|
||||
new Dog(2, "旺财", "wc")
|
||||
);
|
||||
Collection<Dog> newList = Arrays.asList(
|
||||
new Dog(null, "花花2", "hh"),
|
||||
new Dog(null, "小白", "xb")
|
||||
);
|
||||
BiFunction<Dog, Dog, Boolean> sameFunc = (oldObj, newObj) -> {
|
||||
boolean same = oldObj.getCode().equals(newObj.getCode());
|
||||
// 如果相等的情况下,需要设置下 id,后续好更新
|
||||
if (same) {
|
||||
newObj.setId(oldObj.getId());
|
||||
}
|
||||
return same;
|
||||
};
|
||||
|
||||
// 调用
|
||||
List<List<Dog>> result = CollectionUtils.diffList(oldList, newList, sameFunc);
|
||||
// 断言
|
||||
assertEquals(result.size(), 3);
|
||||
// 断言 create
|
||||
assertEquals(result.get(0).size(), 1);
|
||||
assertEquals(result.get(0).get(0), new Dog(null, "小白", "xb"));
|
||||
// 断言 update
|
||||
assertEquals(result.get(1).size(), 1);
|
||||
assertEquals(result.get(1).get(0), new Dog(1, "花花2", "hh"));
|
||||
// 断言 delete
|
||||
assertEquals(result.get(2).size(), 1);
|
||||
assertEquals(result.get(2).get(0), new Dog(2, "旺财", "wc"));
|
||||
}
|
||||
|
||||
}
|
@ -17,20 +17,18 @@ import java.util.concurrent.TimeUnit;
|
||||
public class BannerApplicationRunner implements ApplicationRunner {
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
public void run(ApplicationArguments args) {
|
||||
ThreadUtil.execute(() -> {
|
||||
ThreadUtil.sleep(1, TimeUnit.SECONDS); // 延迟 1 秒,保证输出到结尾
|
||||
log.info("\n----------------------------------------------------------\n\t" +
|
||||
"项目启动成功!\n\t" +
|
||||
"接口文档: \t{} \n\t" +
|
||||
"开发文档: \t{} \n\t" +
|
||||
"视频教程: \t{} \n\t" +
|
||||
"源码解析: \t{} \n" +
|
||||
"视频教程: \t{} \n" +
|
||||
"----------------------------------------------------------",
|
||||
"https://doc.iocoder.cn/api-doc/",
|
||||
"https://doc.iocoder.cn",
|
||||
"https://t.zsxq.com/02Yf6M7Qn",
|
||||
"https://t.zsxq.com/02B6ujIee");
|
||||
"https://t.zsxq.com/02Yf6M7Qn");
|
||||
|
||||
// 数据报表
|
||||
if (isNotPresent("cn.iocoder.yudao.module.report.framework.security.config.SecurityConfiguration")) {
|
||||
@ -44,11 +42,11 @@ public class BannerApplicationRunner implements ApplicationRunner {
|
||||
if (isNotPresent("cn.iocoder.yudao.module.mp.framework.mp.config.MpConfiguration")) {
|
||||
System.out.println("[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]");
|
||||
}
|
||||
// 商城
|
||||
// 商城系统
|
||||
if (isNotPresent("cn.iocoder.yudao.module.trade.framework.web.config.TradeWebConfiguration")) {
|
||||
System.out.println("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
||||
}
|
||||
// 支付
|
||||
// 支付平台
|
||||
if (isNotPresent("cn.iocoder.yudao.module.pay.framework.pay.config.PayConfiguration")) {
|
||||
System.out.println("[支付系统 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
||||
}
|
||||
|
@ -44,6 +44,12 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
|
||||
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
|
||||
}
|
||||
|
||||
default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
|
||||
SFunction<T, ?> field3, Object value3) {
|
||||
return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
|
||||
.eq(field3, value3));
|
||||
}
|
||||
|
||||
default Long selectCount() {
|
||||
return selectCount(new QueryWrapper<T>());
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.web.core.handler;
|
||||
|
||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLog;
|
||||
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
@ -219,6 +220,13 @@ public class GlobalExceptionHandler {
|
||||
*/
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public CommonResult<?> defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
|
||||
// 情况一:处理表不存在的异常
|
||||
CommonResult<?> tableNotExistsResult = handleTableNotExists(ex);
|
||||
if (tableNotExistsResult != null) {
|
||||
return tableNotExistsResult;
|
||||
}
|
||||
|
||||
// 情况二:处理异常
|
||||
log.error("[defaultExceptionHandler]", ex);
|
||||
// 插入异常日志
|
||||
this.createExceptionLog(req, ex);
|
||||
@ -269,4 +277,48 @@ public class GlobalExceptionHandler {
|
||||
errorLog.setExceptionTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 Table 不存在的异常情况
|
||||
*
|
||||
* @param ex 异常
|
||||
* @return 如果是 Table 不存在的异常,则返回对应的 CommonResult
|
||||
*/
|
||||
private CommonResult<?> handleTableNotExists(Throwable ex) {
|
||||
String message = ExceptionUtil.getRootCauseMessage(ex);
|
||||
if (!message.contains("doesn't exist")) {
|
||||
return null;
|
||||
}
|
||||
// 1. 数据报表
|
||||
if (message.contains("report_")) {
|
||||
log.error("[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]");
|
||||
}
|
||||
// 2. 工作流
|
||||
if (message.contains("bpm_")) {
|
||||
log.error("[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]");
|
||||
}
|
||||
// 3. 微信公众号
|
||||
if (message.contains("mp_")) {
|
||||
log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
|
||||
}
|
||||
// 4. 商城系统
|
||||
if (StrUtil.containsAny(message, "product_", "promotion_", "trade_")) {
|
||||
log.error("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
|
||||
}
|
||||
// 5. 支付平台
|
||||
if (message.contains("pay_")) {
|
||||
log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
||||
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
|
||||
"[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package cn.iocoder.yudao.module.product.controller.app.comment;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
|
||||
@ -27,6 +27,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "用户 APP - 商品评价")
|
||||
@RestController
|
||||
@ -56,10 +57,17 @@ public class AppProductCommentController {
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得商品评价分页")
|
||||
public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
|
||||
PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
|
||||
Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId);
|
||||
PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, productSkuService.getSkuList(skuIds));
|
||||
return success(page);
|
||||
// 查询评论分页
|
||||
PageResult<ProductCommentDO> commentPageResult = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
|
||||
if (CollUtil.isEmpty(commentPageResult.getList())) {
|
||||
return success(PageResult.empty(commentPageResult.getTotal()));
|
||||
}
|
||||
|
||||
// 拼接返回
|
||||
Set<Long> skuIds = convertSet(commentPageResult.getList(), ProductCommentDO::getSkuId);
|
||||
PageResult<AppProductCommentRespVO> commentVOPageResult = ProductCommentConvert.INSTANCE.convertPage02(
|
||||
commentPageResult, productSkuService.getSkuList(skuIds));
|
||||
return success(commentVOPageResult);
|
||||
}
|
||||
|
||||
// TODO 芋艿:需要搞下
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.product.convert.comment;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
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
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
|
||||
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
@ -52,17 +50,16 @@ public interface ProductCommentConvert {
|
||||
|
||||
PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
|
||||
|
||||
default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult, List<ProductSkuDO> skuList) {
|
||||
Map<Long, ProductSkuDO> skuMap = Maps.newLinkedHashMapWithExpectedSize(skuList.size());
|
||||
if (CollUtil.isNotEmpty(skuList)) {
|
||||
skuMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId));
|
||||
}
|
||||
default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult,
|
||||
List<ProductSkuDO> skuList) {
|
||||
Map<Long, ProductSkuDO> skuMap = CollectionUtils.convertMap(skuList, ProductSkuDO::getId);
|
||||
PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
|
||||
page.getList().forEach(item -> {
|
||||
// 判断用户是否选择匿名
|
||||
if (ObjectUtil.equal(item.getAnonymous(), true)) {
|
||||
item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
|
||||
}
|
||||
// 设置 SKU 规格值
|
||||
MapUtils.findAndThen(skuMap, item.getSkuId(),
|
||||
sku -> item.setSkuProperties(convertList01(sku.getProperties())));
|
||||
});
|
||||
|
@ -112,10 +112,9 @@ public interface ProductSpuConvert {
|
||||
}
|
||||
|
||||
default List<ProductSpuDetailRespVO> convertForSpuDetailRespListVO(List<ProductSpuDO> spus, List<ProductSkuDO> skus) {
|
||||
List<ProductSpuDetailRespVO> vos = new ArrayList<>(spus.size());
|
||||
Map<Long, List<ProductSkuDO>> skuMultiMap = convertMultiMap(skus, ProductSkuDO::getSpuId);
|
||||
CollectionUtils.convertList(spus, spu -> vos.add(convert03(spu).setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId())))));
|
||||
return vos;
|
||||
return CollectionUtils.convertList(spus, spu -> convert03(spu)
|
||||
.setSkus(ProductSkuConvert.INSTANCE.convertList(skuMultiMap.get(spu.getId()))));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
// TODO @芋艿:后面也再撸撸这几个接口
|
||||
|
||||
// TODO @芋艿:后面也再撸撸这几个接口
|
||||
/**
|
||||
* 拼团记录 API 接口
|
||||
*
|
||||
@ -17,17 +17,18 @@ public interface CombinationRecordApi {
|
||||
*
|
||||
* @param reqDTO 请求 DTO
|
||||
*/
|
||||
void createRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
|
||||
void createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 校验拼团是否成功
|
||||
* 查询拼团记录是否成功
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param orderId 订单编号
|
||||
* @return 拼团是否成功
|
||||
*/
|
||||
boolean validateRecordStatusIsSuccess(Long userId, Long orderId);
|
||||
boolean isCombinationRecordSuccess(Long userId, Long orderId);
|
||||
|
||||
// TODO @puhui999:updateRecordStatus 和 updateRecordStatusAndStartTime 看看后续是不是可以统一掉;
|
||||
/**
|
||||
* 更新开团记录状态
|
||||
*
|
||||
@ -35,7 +36,7 @@ public interface CombinationRecordApi {
|
||||
* @param orderId 订单编号
|
||||
* @param status 状态值
|
||||
*/
|
||||
void updateRecordStatus(Long userId, Long orderId, Integer status);
|
||||
void updateCombinationRecordStatus(Long userId, Long orderId, Integer status);
|
||||
|
||||
/**
|
||||
* 更新开团记录状态和开始时间
|
||||
@ -44,6 +45,6 @@ public interface CombinationRecordApi {
|
||||
* @param orderId 订单编号
|
||||
* @param status 状态值
|
||||
*/
|
||||
void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status);
|
||||
void updateCombinationRecordStatusAndStartTime(Long userId, Long orderId, Integer status);
|
||||
|
||||
}
|
||||
|
@ -5,8 +5,9 @@ import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
// TODO @芋艿:这块要在看看
|
||||
/**
|
||||
* 拼团记录 Request DTO
|
||||
* 拼团记录的创建 Request DTO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
|
@ -20,23 +20,23 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
|
||||
private CombinationRecordService recordService;
|
||||
|
||||
@Override
|
||||
public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
recordService.createRecord(reqDTO);
|
||||
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
recordService.createCombinationRecord(reqDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateRecordStatusIsSuccess(Long userId, Long orderId) {
|
||||
return CombinationRecordStatusEnum.isSuccess(recordService.getRecord(userId, orderId).getStatus());
|
||||
public boolean isCombinationRecordSuccess(Long userId, Long orderId) {
|
||||
return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecordStatus(Long userId, Long orderId, Integer status) {
|
||||
recordService.updateRecordStatusByUserIdAndOrderId(userId, orderId, status);
|
||||
public void updateCombinationRecordStatus(Long userId, Long orderId, Integer status) {
|
||||
recordService.updateCombinationRecordStatusByUserIdAndOrderId(userId, orderId, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
|
||||
recordService.updateRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
|
||||
public void updateCombinationRecordStatusAndStartTime(Long userId, Long orderId, Integer status) {
|
||||
recordService.updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(userId, orderId, status, LocalDateTime.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.controller.admin.combination;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
|
||||
@ -23,9 +22,11 @@ import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.hutool.core.collection.CollectionUtil.newArrayList;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - 拼团活动")
|
||||
@RestController
|
||||
@ -35,6 +36,7 @@ public class CombinationActivityController {
|
||||
|
||||
@Resource
|
||||
private CombinationActivityService combinationActivityService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi spuApi;
|
||||
|
||||
@ -68,17 +70,18 @@ public class CombinationActivityController {
|
||||
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
|
||||
public CommonResult<CombinationActivityRespVO> getCombinationActivity(@RequestParam("id") Long id) {
|
||||
CombinationActivityDO activity = combinationActivityService.getCombinationActivity(id);
|
||||
List<CombinationProductDO> products = combinationActivityService.getProductsByActivityIds(newArrayList(id));
|
||||
List<CombinationProductDO> products = combinationActivityService.getCombinationProductsByActivityIds(newArrayList(id));
|
||||
return success(CombinationActivityConvert.INSTANCE.convert(activity, products));
|
||||
}
|
||||
|
||||
// TODO @puhui999:是不是可以删掉,貌似没用?
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得拼团活动列表")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
|
||||
public CommonResult<List<CombinationActivityRespVO>> getCombinationActivityList(@RequestParam("ids") Collection<Long> ids) {
|
||||
List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(ids);
|
||||
return success(CombinationActivityConvert.INSTANCE.complementList(list));
|
||||
return success(CombinationActivityConvert.INSTANCE.convertList(list));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@ -86,10 +89,14 @@ public class CombinationActivityController {
|
||||
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
|
||||
public CommonResult<PageResult<CombinationActivityRespVO>> getCombinationActivityPage(
|
||||
@Valid CombinationActivityPageReqVO pageVO) {
|
||||
// 查询拼团活动
|
||||
PageResult<CombinationActivityDO> pageResult = combinationActivityService.getCombinationActivityPage(pageVO);
|
||||
// 拼接数据
|
||||
Set<Long> activityIds = convertSet(pageResult.getList(), CombinationActivityDO::getId);
|
||||
Set<Long> spuIds = convertSet(pageResult.getList(), CombinationActivityDO::getSpuId);
|
||||
return success(CombinationActivityConvert.INSTANCE.convertPage(pageResult,
|
||||
combinationActivityService.getProductsByActivityIds(CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getId)),
|
||||
spuApi.getSpuList(CollectionUtils.convertSet(pageResult.getList(), CombinationActivityDO::getSpuId))));
|
||||
combinationActivityService.getCombinationProductsByActivityIds(activityIds),
|
||||
spuApi.getSpuList(spuIds)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ public class SeckillActivityController {
|
||||
return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts));
|
||||
}
|
||||
|
||||
// TODO @puhui999:是不是可以删掉,貌似没用?
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得秒杀活动列表")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.promotion.convert.combination;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
|
||||
@ -70,7 +71,7 @@ public interface CombinationActivityConvert {
|
||||
return respVO;
|
||||
}
|
||||
|
||||
List<CombinationActivityRespVO> complementList(List<CombinationActivityDO> list);
|
||||
List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list);
|
||||
|
||||
PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page);
|
||||
|
||||
@ -80,8 +81,10 @@ public interface CombinationActivityConvert {
|
||||
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
|
||||
PageResult<CombinationActivityRespVO> pageResult = convertPage(page);
|
||||
pageResult.getList().forEach(item -> {
|
||||
MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setSpuName(spu.getName()));
|
||||
MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setPicUrl(spu.getPicUrl()));
|
||||
MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
|
||||
item.setSpuName(spu.getName());
|
||||
item.setPicUrl(spu.getPicUrl());
|
||||
});
|
||||
item.setProducts(convertList2(productList));
|
||||
});
|
||||
return pageResult;
|
||||
@ -100,7 +103,7 @@ public interface CombinationActivityConvert {
|
||||
})
|
||||
CombinationProductDO convert(CombinationActivityDO activityDO, CombinationProductBaseVO vo);
|
||||
|
||||
default List<CombinationProductDO> complementList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
|
||||
default List<CombinationProductDO> convertList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
|
||||
List<CombinationProductDO> list = new ArrayList<>();
|
||||
products.forEach(sku -> {
|
||||
CombinationProductDO productDO = convert(activityDO, sku);
|
||||
@ -110,16 +113,12 @@ public interface CombinationActivityConvert {
|
||||
return list;
|
||||
}
|
||||
|
||||
default List<CombinationProductDO> complementList(List<CombinationProductDO> productDOs, List<CombinationProductUpdateReqVO> vos, CombinationActivityDO activityDO) {
|
||||
Map<Long, Long> longMap = convertMap(productDOs, CombinationProductDO::getSkuId, CombinationProductDO::getId);
|
||||
List<CombinationProductDO> list = new ArrayList<>();
|
||||
vos.forEach(sku -> {
|
||||
CombinationProductDO productDO = convert(activityDO, sku);
|
||||
productDO.setId(longMap.get(sku.getSkuId()));
|
||||
productDO.setActivityStatus(activityDO.getStatus());
|
||||
list.add(productDO);
|
||||
});
|
||||
return list;
|
||||
default List<CombinationProductDO> convertList(List<CombinationProductUpdateReqVO> updateProductVOs,
|
||||
List<CombinationProductDO> products, CombinationActivityDO activity) {
|
||||
Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId);
|
||||
return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
|
||||
.setId(productMap.get(updateProductVO.getSkuId()))
|
||||
.setActivityStatus(activity.getStatus()));
|
||||
}
|
||||
|
||||
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
|
||||
|
@ -21,6 +21,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
|
||||
/**
|
||||
* 秒杀活动 Convert
|
||||
*
|
||||
@ -37,6 +39,7 @@ public interface SeckillActivityConvert {
|
||||
|
||||
SeckillActivityRespVO convert(SeckillActivityDO bean);
|
||||
|
||||
// TODO @puhui999:这个是不是还是 convertList 好点?
|
||||
List<SeckillActivityRespVO> complementList(List<SeckillActivityDO> list);
|
||||
|
||||
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
|
||||
@ -73,7 +76,7 @@ public interface SeckillActivityConvert {
|
||||
})
|
||||
SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo);
|
||||
|
||||
default List<SeckillProductDO> complementList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
|
||||
default List<SeckillProductDO> convertList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
|
||||
List<SeckillProductDO> list = new ArrayList<>();
|
||||
products.forEach(sku -> {
|
||||
SeckillProductDO productDO = convert(activityDO, sku);
|
||||
@ -83,16 +86,12 @@ public interface SeckillActivityConvert {
|
||||
return list;
|
||||
}
|
||||
|
||||
default List<SeckillProductDO> complementList(List<SeckillProductDO> productDOs, List<SeckillProductUpdateReqVO> vos, SeckillActivityDO activityDO) {
|
||||
Map<Long, Long> longMap = CollectionUtils.convertMap(productDOs, SeckillProductDO::getSkuId, SeckillProductDO::getId);
|
||||
List<SeckillProductDO> list = new ArrayList<>();
|
||||
vos.forEach(sku -> {
|
||||
SeckillProductDO productDO = convert(activityDO, sku);
|
||||
productDO.setId(longMap.get(sku.getSkuId()));
|
||||
productDO.setActivityStatus(activityDO.getStatus());
|
||||
list.add(productDO);
|
||||
});
|
||||
return list;
|
||||
default List<SeckillProductDO> convertList(List<SeckillProductUpdateReqVO> updateProductVOs,
|
||||
List<SeckillProductDO> products, SeckillActivityDO activity) {
|
||||
Map<Long, Long> productMap = convertMap(products, SeckillProductDO::getSkuId, SeckillProductDO::getId);
|
||||
return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
|
||||
.setId(productMap.get(updateProductVO.getSkuId()))
|
||||
.setActivityStatus(activity.getStatus()));
|
||||
}
|
||||
|
||||
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> productDOs);
|
||||
|
@ -12,6 +12,9 @@ import java.time.LocalDateTime;
|
||||
/**
|
||||
* 拼团记录 DO
|
||||
*
|
||||
* 1. 用户参与拼团时,会创建一条记录
|
||||
* 2. 团长的拼团记录,和参团人的拼团记录,通过 {@link #headId} 关联
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@TableName("promotion_combination_record")
|
||||
|
@ -15,6 +15,7 @@ import java.util.List;
|
||||
@Mapper
|
||||
public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO> {
|
||||
|
||||
// TODO @puhui999:selectByUserIdAndOrderId
|
||||
default CombinationRecordDO selectRecord(Long userId, Long orderId) {
|
||||
return selectOne(CombinationRecordDO::getUserId, userId,
|
||||
CombinationRecordDO::getOrderId, orderId);
|
||||
@ -28,7 +29,8 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
|
||||
* @return 拼团记录
|
||||
*/
|
||||
default CombinationRecordDO selectRecordByHeadId(Long headId, Long activityId, Integer status) {
|
||||
return selectOne(CombinationRecordDO::getUserId, headId, CombinationRecordDO::getActivityId, activityId,
|
||||
return selectOne(CombinationRecordDO::getHeadId, headId,
|
||||
CombinationRecordDO::getActivityId, activityId,
|
||||
CombinationRecordDO::getStatus, status);
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,6 @@ public interface CombinationActivityService {
|
||||
* @param ids 拼团活动 ids
|
||||
* @return 拼团活动的商品列表
|
||||
*/
|
||||
List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids);
|
||||
List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids);
|
||||
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ public interface CombinationRecordService {
|
||||
* @param orderId 订单编号
|
||||
* @param status 状态
|
||||
*/
|
||||
void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
|
||||
void updateCombinationRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
|
||||
|
||||
/**
|
||||
* 创建拼团记录
|
||||
*
|
||||
* @param reqDTO 创建信息
|
||||
*/
|
||||
void createRecord(CombinationRecordCreateReqDTO reqDTO);
|
||||
void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 更新拼团状态和开始时间
|
||||
@ -36,7 +36,8 @@ public interface CombinationRecordService {
|
||||
* @param status 状态
|
||||
* @param startTime 开始时间
|
||||
*/
|
||||
void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime);
|
||||
void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId,
|
||||
Integer status, LocalDateTime startTime);
|
||||
|
||||
/**
|
||||
* 获得拼团状态
|
||||
@ -45,6 +46,6 @@ public interface CombinationRecordService {
|
||||
* @param orderId 订单编号
|
||||
* @return 拼团状态
|
||||
*/
|
||||
CombinationRecordDO getRecord(Long userId, Long orderId);
|
||||
CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import java.util.*;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
|
||||
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
|
||||
|
||||
/**
|
||||
* 拼团活动 Service 实现类
|
||||
@ -66,7 +66,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
// 获取所选 spu下的所有 sku
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(createReqVO.getSpuId()));
|
||||
// 校验商品 sku 是否存在
|
||||
validateProductSkuExistence(createReqVO.getProducts(), skus, CombinationProductCreateReqVO::getSkuId);
|
||||
validateProductSkuAllExists(createReqVO.getProducts(), skus, CombinationProductCreateReqVO::getSkuId);
|
||||
|
||||
// TODO 艿艿 有个小问题:现在有活动时间和限制时长,活动时间的结束时间早于设置的限制时间怎么算状态比如:
|
||||
// 活动时间 2023-08-05 15:00:00 - 2023-08-05 15:20:00 限制时长 2小时,那么活动时间结束就结束还是加时到满两小时
|
||||
@ -80,7 +80,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
combinationActivityMapper.insert(activityDO);
|
||||
// 插入商品
|
||||
List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.complementList(createReqVO.getProducts(), activityDO);
|
||||
List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activityDO);
|
||||
combinationProductMapper.insertBatch(productDOs);
|
||||
// 返回
|
||||
return activityDO.getId();
|
||||
@ -118,7 +118,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
// 获取所选 spu下的所有 sku
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId()));
|
||||
// 校验商品 sku 是否存在
|
||||
validateProductSkuExistence(updateReqVO.getProducts(), skus, CombinationProductUpdateReqVO::getSkuId);
|
||||
validateProductSkuAllExists(updateReqVO.getProducts(), skus, CombinationProductUpdateReqVO::getSkuId);
|
||||
|
||||
// 更新
|
||||
CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
|
||||
@ -140,18 +140,21 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
// 前端传过来的活动商品
|
||||
Set<Long> convertSet1 = CollectionUtils.convertSet(products, CombinationProductUpdateReqVO::getSkuId);
|
||||
// 分化数据
|
||||
// TODO @芋艿:看下这个实现
|
||||
Map<String, List<CombinationProductDO>> data = CollectionUtils.convertCDUMap(convertSet1, convertSet, mapData -> {
|
||||
HashMap<String, List<CombinationProductDO>> cdu = MapUtil.newHashMap(3);
|
||||
MapUtils.findAndThen(mapData, "create", list -> {
|
||||
cdu.put("create", CombinationActivityConvert.INSTANCE.complementList(CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
cdu.put("create", CombinationActivityConvert.INSTANCE.convertList(CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
});
|
||||
MapUtils.findAndThen(mapData, "delete", list -> {
|
||||
cdu.put("create", CollectionUtils.filterList(combinationProductDOs, item -> list.contains(item.getSkuId())));
|
||||
});
|
||||
MapUtils.findAndThen(mapData, "update", list -> {
|
||||
cdu.put("update", CombinationActivityConvert.INSTANCE.complementList(combinationProductDOs,
|
||||
CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
});
|
||||
// TODO @芋艿:临时注释,避免有问题
|
||||
// MapUtils.findAndThen(mapData, "update", list -> {
|
||||
// cdu.put("update", CombinationActivityConvert.INSTANCE.convertList(
|
||||
// combinationProductDOs,
|
||||
// CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
// });
|
||||
return cdu;
|
||||
});
|
||||
|
||||
@ -199,12 +202,12 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CombinationProductDO> getProductsByActivityIds(Collection<Long> ids) {
|
||||
public List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids) {
|
||||
return combinationProductMapper.selectListByActivityIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status) {
|
||||
public void updateCombinationRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status) {
|
||||
// 校验拼团是否存在
|
||||
CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
|
||||
|
||||
@ -215,7 +218,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime) {
|
||||
public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime) {
|
||||
CombinationRecordDO recordDO = validateCombinationRecord(userId, orderId);
|
||||
// 更新状态
|
||||
recordDO.setStatus(status);
|
||||
@ -247,15 +250,15 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
// 校验拼团活动
|
||||
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
// 1.1 校验拼团活动
|
||||
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
|
||||
// 需要校验下,它当前是不是已经参加了该拼团;
|
||||
// 1.2 需要校验下,他当前是不是已经参加了该拼团;
|
||||
CombinationRecordDO recordDO = recordMapper.selectRecord(reqDTO.getUserId(), reqDTO.getOrderId());
|
||||
if (recordDO != null) {
|
||||
throw exception(COMBINATION_RECORD_EXISTS);
|
||||
}
|
||||
// 父拼团是否存在,是否已经满了
|
||||
// 1.3 父拼团是否存在,是否已经满了
|
||||
if (reqDTO.getHeadId() != null) {
|
||||
CombinationRecordDO recordDO1 = recordMapper.selectRecordByHeadId(reqDTO.getHeadId(), reqDTO.getActivityId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
||||
if (recordDO1 == null) {
|
||||
@ -266,9 +269,12 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
throw exception(COMBINATION_RECORD_USER_FULL);
|
||||
}
|
||||
}
|
||||
// TODO @puhui999:应该还有一些校验,后续补噶;例如说,一个团,自己已经参与进去了,不能再参与进去;
|
||||
|
||||
// 2. 创建拼团记录
|
||||
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
|
||||
if (reqDTO.getHeadId() == null) {
|
||||
// TODO @puhui999:不是自己呀;headId 是父团长的 CombinationRecordDO.id 哈
|
||||
record.setHeadId(reqDTO.getUserId());
|
||||
}
|
||||
record.setVirtualGroup(false);
|
||||
@ -279,7 +285,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombinationRecordDO getRecord(Long userId, Long orderId) {
|
||||
public CombinationRecordDO getCombinationRecord(Long userId, Long orderId) {
|
||||
return validateCombinationRecord(userId, orderId);
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuExistence;
|
||||
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
|
||||
|
||||
/**
|
||||
* 秒杀活动 Service 实现类
|
||||
@ -74,7 +74,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
.setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
|
||||
seckillActivityMapper.insert(activity);
|
||||
// 插入商品
|
||||
List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.complementList(createReqVO.getProducts(), activity);
|
||||
List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
|
||||
seckillProductMapper.insertBatch(products);
|
||||
return activity.getId();
|
||||
}
|
||||
@ -121,7 +121,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
// 获取所选 spu下的所有 sku
|
||||
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
|
||||
// 校验商品 sku 是否存在
|
||||
validateProductSkuExistence(updateReqVO.getProducts(), skus, SeckillProductUpdateReqVO::getSkuId);
|
||||
validateProductSkuAllExists(updateReqVO.getProducts(), skus, SeckillProductUpdateReqVO::getSkuId);
|
||||
|
||||
// 更新活动
|
||||
SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
|
||||
@ -150,16 +150,17 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
||||
Map<String, List<SeckillProductDO>> data = CollectionUtils.convertCDUMap(voSkuIds, dbSkuIds, mapData -> {
|
||||
HashMap<String, List<SeckillProductDO>> cdu = MapUtil.newHashMap(3);
|
||||
MapUtils.findAndThen(mapData, "create", list -> {
|
||||
cdu.put("create", SeckillActivityConvert.INSTANCE.complementList(
|
||||
cdu.put("create", SeckillActivityConvert.INSTANCE.convertList(
|
||||
CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
});
|
||||
MapUtils.findAndThen(mapData, "delete", list -> {
|
||||
cdu.put("create", CollectionUtils.filterList(seckillProductDOs, item -> list.contains(item.getSkuId())));
|
||||
});
|
||||
MapUtils.findAndThen(mapData, "update", list -> {
|
||||
cdu.put("update", SeckillActivityConvert.INSTANCE.complementList(seckillProductDOs,
|
||||
CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
});
|
||||
// TODO @芋艿:临时注释
|
||||
// MapUtils.findAndThen(mapData, "update", list -> {
|
||||
// cdu.put("update", SeckillActivityConvert.INSTANCE.convertList(seckillProductDOs,
|
||||
// CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
|
||||
// });
|
||||
return cdu;
|
||||
});
|
||||
|
||||
|
@ -31,18 +31,20 @@ public class PromotionUtils {
|
||||
return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
|
||||
}
|
||||
|
||||
// TODO @puhui999:是不是第一个参数是 sku;然后是 products;这样关联性好点;
|
||||
/**
|
||||
* 校验商品 sku 是否存在
|
||||
* 校验商品 sku 是否都存在
|
||||
*
|
||||
* @param products 需要校验的商品
|
||||
* @param skus 数据库中的商品 skus
|
||||
* @param func 获取需要校验的商品的 skuId
|
||||
*/
|
||||
public static <T> void validateProductSkuExistence(List<T> products, List<ProductSkuRespDTO> skus, Function<T, Long> func) {
|
||||
public static <T> void validateProductSkuAllExists(List<T> products, List<ProductSkuRespDTO> skus, Function<T, Long> func) {
|
||||
// 校验 sku 个数是否一致
|
||||
Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
|
||||
Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
|
||||
// 校验 skuId 是否存在
|
||||
// TODO @puhui999:findFirst
|
||||
List<Long> f = CollectionUtils.filterList(skuIdsSet, s -> !skuIdsSet1.contains(s));
|
||||
if (CollUtil.isNotEmpty(f)) {
|
||||
throw exception(SKU_NOT_EXISTS);
|
||||
|
@ -332,6 +332,7 @@ public interface TradeOrderConvert {
|
||||
@Mapping(target = "avatar", source = "user.avatar"),
|
||||
@Mapping(target = "status", ignore = true)
|
||||
})
|
||||
CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem, AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
|
||||
CombinationRecordCreateReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem,
|
||||
AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
|
||||
|
||||
}
|
||||
|
@ -27,11 +27,13 @@ public class TradeMessageServiceImpl implements TradeMessageService {
|
||||
// 1、构造消息
|
||||
Map<String, Object> msgMap = new HashMap<>();
|
||||
msgMap.put("orderId", reqDTO.getOrderId());
|
||||
// TODO puhui999:应该不是 msg 哇,应该是涉及到的模版参数哈;msg 太大了
|
||||
msgMap.put("msg", reqDTO.getMessage());
|
||||
// 2、发送站内信
|
||||
notifyMessageSendApi.sendSingleMessageToMember(
|
||||
new NotifySendSingleToUserReqDTO()
|
||||
.setUserId(reqDTO.getUserId())
|
||||
// TODO puhui999:短信模版编号,枚举起来;
|
||||
.setTemplateCode("order_delivery")
|
||||
.setTemplateParams(msgMap));
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
// TODO @puhui999:改成 ReqBO 哈;包名也换了;service 我们还是同一用 bo 对象
|
||||
/**
|
||||
* 订单发货时 Req DTO
|
||||
*
|
||||
|
@ -174,7 +174,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
||||
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
|
||||
MemberUserRespDTO user = memberUserApi.getUser(userId);
|
||||
// TODO 拼团一次应该只能选择一种规格的商品
|
||||
combinationRecordApi.createRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
|
||||
// TODO @puhui999:应该是前置校验哈;然后不应该设置状态,而是交给拼团记录那处理;
|
||||
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
|
||||
.setStatus(CombinationRecordStatusEnum.WAITING.getStatus()));
|
||||
}
|
||||
// TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
|
||||
@ -311,7 +312,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
||||
// 1、拼团活动
|
||||
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
|
||||
// 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
|
||||
combinationRecordApi.updateRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
||||
combinationRecordApi.updateCombinationRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
||||
}
|
||||
// TODO 芋艿:发送订单变化的消息
|
||||
|
||||
@ -376,10 +377,11 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
||||
return new KeyValue<>(order, payOrder);
|
||||
}
|
||||
|
||||
// TODO @芋艿:后续在 review 下发货逻辑
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deliveryOrder(Long userId, TradeOrderDeliveryReqVO deliveryReqVO) {
|
||||
// 校验并获得交易订单(可发货)
|
||||
// 1.1 校验并获得交易订单(可发货)
|
||||
TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
|
||||
|
||||
/* TODO
|
||||
@ -388,35 +390,36 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
||||
* 2.如果店铺只支持到店自提那么下单后默认发货不需要物流
|
||||
* 3.如果店铺支持 物流-配送-自提 的情况下后台不需要选择配送方式按前端用户选择的配送方式发货即可
|
||||
*/
|
||||
TradeOrderDO tradeOrderDO = new TradeOrderDO();
|
||||
TradeOrderDO updateOrderObj = new TradeOrderDO();
|
||||
// 判断发货类型
|
||||
// 快递发货
|
||||
// 2.1 快递发货
|
||||
if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.EXPRESS.getMode())) {
|
||||
// 校验快递公司
|
||||
// TODO @puhui999:getDeliveryExpress 直接封装一个校验的,会不会好点;因为还有开启关闭啥的;
|
||||
DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
|
||||
if (deliveryExpress == null) {
|
||||
throw exception(EXPRESS_NOT_EXISTS);
|
||||
}
|
||||
tradeOrderDO.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
|
||||
updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
|
||||
}
|
||||
// 用户自提
|
||||
// 2.2 用户自提
|
||||
if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.PICK_UP.getMode())) {
|
||||
// TODO 校验自提门店是否存在
|
||||
// 重置一下确保快递公司和快递单号为空
|
||||
tradeOrderDO.setLogisticsId(null).setLogisticsNo("");
|
||||
updateOrderObj.setLogisticsId(null).setLogisticsNo("");
|
||||
}
|
||||
// TODO 芋艿:如果无需发货,需要怎么存储?
|
||||
// 2.3 TODO 芋艿:如果无需发货,需要怎么存储?回复:需要把 deliverType 设置为 DeliveryTypeEnum.NULL
|
||||
if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.NULL.getMode())) {
|
||||
// TODO 情况一:正常走发货逻辑和用户自提有点像 不同点:不需要自提门店只需要用户确认收货
|
||||
// TODO 情况二:用户下单付款后直接确认收货或等待用户确认收货
|
||||
// 重置一下确保快递公司和快递单号为空
|
||||
tradeOrderDO.setLogisticsId(null).setLogisticsNo("");
|
||||
updateOrderObj.setLogisticsId(null).setLogisticsNo("");
|
||||
}
|
||||
|
||||
// 更新 TradeOrderDO 状态为已发货,等待收货
|
||||
tradeOrderDO.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
|
||||
updateOrderObj.setStatus(TradeOrderStatusEnum.DELIVERED.getStatus())
|
||||
.setDeliveryStatus(TradeOrderDeliveryStatusEnum.DELIVERED.getStatus()).setDeliveryTime(LocalDateTime.now());
|
||||
int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), tradeOrderDO);
|
||||
int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), updateOrderObj);
|
||||
if (updateCount == 0) {
|
||||
throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
|
||||
}
|
||||
@ -457,7 +460,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|
||||
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
|
||||
// 校验订单拼团是否成功
|
||||
// TODO 用户 ID 使用当前登录用户的还是订单保存的?
|
||||
if (combinationRecordApi.validateRecordStatusIsSuccess(order.getUserId(), order.getId())) {
|
||||
if (combinationRecordApi.isCombinationRecordSuccess(order.getUserId(), order.getId())) {
|
||||
throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -68,7 +69,15 @@ public class MpAccountServiceImpl implements MpAccountService {
|
||||
// 注意:忽略自动多租户,因为要全局初始化缓存
|
||||
TenantUtils.executeIgnore(() -> {
|
||||
// 第一步:查询数据
|
||||
List<MpAccountDO> accounts = mpAccountMapper.selectList();
|
||||
List<MpAccountDO> accounts = Collections.emptyList();
|
||||
try {
|
||||
accounts = mpAccountMapper.selectList();
|
||||
} catch (Throwable ex) {
|
||||
if (!ex.getMessage().contains("doesn't exist")) {
|
||||
throw ex;
|
||||
}
|
||||
log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
|
||||
}
|
||||
log.info("[initLocalCacheIfUpdate][缓存公众号账号,数量为:{}]", accounts.size());
|
||||
|
||||
// 第二步:构建缓存。创建或更新支付 Client
|
||||
|
@ -27,6 +27,7 @@ import javax.annotation.Resource;
|
||||
import javax.validation.Validator;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -64,7 +65,15 @@ public class PayChannelServiceImpl implements PayChannelService {
|
||||
// 注意:忽略自动多租户,因为要全局初始化缓存
|
||||
TenantUtils.executeIgnore(() -> {
|
||||
// 第一步:查询数据
|
||||
List<PayChannelDO> channels = channelMapper.selectList();
|
||||
List<PayChannelDO> channels = Collections.emptyList();
|
||||
try {
|
||||
channels = channelMapper.selectList();
|
||||
} catch (Throwable ex) {
|
||||
if (!ex.getMessage().contains("doesn't exist")) {
|
||||
throw ex;
|
||||
}
|
||||
log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
|
||||
}
|
||||
log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size());
|
||||
|
||||
// 第二步:构建缓存:创建或更新支付 Client
|
||||
|
@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailAccountMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -46,7 +47,7 @@ public class MailAccountServiceImpl implements MailAccountService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id")
|
||||
@CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#updateReqVO.id")
|
||||
public void updateMailAccount(MailAccountUpdateReqVO updateReqVO) {
|
||||
// 校验是否存在
|
||||
validateMailAccountExists(updateReqVO.getId());
|
||||
@ -57,7 +58,7 @@ public class MailAccountServiceImpl implements MailAccountService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id")
|
||||
@CacheEvict(value = RedisKeyConstants.MAIL_ACCOUNT, key = "#id")
|
||||
public void deleteMailAccount(Long id) {
|
||||
// 校验是否存在账号
|
||||
validateMailAccountExists(id);
|
||||
|
@ -52,9 +52,9 @@
|
||||
<el-input v-model="formData.config.apiV3Key" placeholder="请输入 API V3 密钥" clearable
|
||||
:style="{width: '100%'}" type="textarea" :autosize="{minRows: 8, maxRows: 8}"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label-width="180px" label="apiclient_key.perm 证书" prop="config.privateKeyContent">
|
||||
<el-form-item label-width="180px" label="apiclient_key.pem 证书" prop="config.privateKeyContent">
|
||||
<el-input v-model="formData.config.privateKeyContent" type="textarea"
|
||||
placeholder="请上传 apiclient_key.perm 证书"
|
||||
placeholder="请上传 apiclient_key.pem 证书"
|
||||
readonly :autosize="{minRows: 8, maxRows: 8}" :style="{width: '100%'}"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label-width="180px" label="" prop="privateKeyContentFile">
|
||||
@ -132,7 +132,7 @@ export default {
|
||||
'config.apiVersion': [{ required: true, message: 'API版本不能为空', trigger: 'blur'}],
|
||||
'config.mchKey': [{ required: true, message: '请输入商户密钥', trigger: 'blur' }],
|
||||
'config.keyContent': [{ required: true, message: '请上传 apiclient_cert.p12 证书', trigger: 'blur' }],
|
||||
'config.privateKeyContent': [{ required: true, message: '请上传 apiclient_key.perm 证书', trigger: 'blur' }],
|
||||
'config.privateKeyContent': [{ required: true, message: '请上传 apiclient_key.pem 证书', trigger: 'blur' }],
|
||||
'config.privateCertContent': [{ required: true, message: '请上传 apiclient_cert.perm证 书', trigger: 'blur' }],
|
||||
'config.apiV3Key': [{ required: true, message: '请上传 api V3 密钥值', trigger: 'blur' }],
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user