Commit e7d86436650ba7850026d7ba760a4d512b8f6737

Authored by puhui999
1 parent 9cbd0fec

fix:修复 mall review @puhui999

Showing 38 changed files with 207 additions and 244 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.date.LocalDateTimeUtil;
4 4  
5 5 import java.time.Duration;
6 6 import java.time.LocalDateTime;
  7 +import java.time.LocalTime;
7 8  
8 9 /**
9 10 * 时间工具类,用于 {@link java.time.LocalDateTime}
... ... @@ -50,7 +51,7 @@ public class LocalDateTimeUtils {
50 51 * 判断当前时间是否在该时间范围内
51 52 *
52 53 * @param startTime 开始时间
53   - * @param endTime 结束时间
  54 + * @param endTime 结束时间
54 55 * @return 是否
55 56 */
56 57 public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
... ... @@ -60,4 +61,23 @@ public class LocalDateTimeUtils {
60 61 return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
61 62 }
62 63  
  64 + /**
  65 + * 检查时间重叠 不包含日期
  66 + *
  67 + * @param startTime1 需要校验的开始时间
  68 + * @param endTime1 需要校验的结束时间
  69 + * @param startTime2 校验所需的开始时间
  70 + * @param endTime2 校验所需的结束时间
  71 + * @return 是否重叠
  72 + */
  73 + public static boolean checkTimeOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
  74 + // 判断时间是否重叠
  75 + // 开始时间在已配置时段的结束时间之前 且 结束时间在已配置时段的开始时间之后 []
  76 + return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
  77 + // 开始时间在已配置时段的开始时间之前 且 结束时间在已配置时段的开始时间之后 (] 或 ()
  78 + || startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
  79 + // 开始时间在已配置时段的结束时间之前 且 结束时间在已配值时段的结束时间之后 [) 或 ()
  80 + || startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
  81 + }
  82 +
63 83 }
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
... ... @@ -46,7 +46,7 @@ public interface ErrorCodeConstants {
46 46  
47 47 // ========== 商品 评价 1008007000 ==========
48 48 ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1008007000, "商品 评价 不存在");
49   - ErrorCode ORDER_SPU_COMMENT_EXISTS = new ErrorCode(1008007001, "订单 商品评价 已存在");
  49 + ErrorCode ORDER_SKU_COMMENT_EXISTS = new ErrorCode(1008007001, "订单 商品评价 已存在");
50 50 ErrorCode COMMENT_ERROR_OPT = new ErrorCode(1008007002, "商品评价非法操作");
51 51 ErrorCode COMMENT_ADDITIONAL_EXISTS = new ErrorCode(1008007003, "商品追加评价已存在");
52 52  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentBaseVO.java
... ... @@ -26,23 +26,10 @@ public class ProductCommentBaseVO {
26 26 @NotNull(message = "评价人头像不能为空")
27 27 private String userAvatar;
28 28  
29   - // TODO @puhui:spuId、spuName 是不是只有 ProductCommentRespVO 有呀。
30   - @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
31   - @NotNull(message = "商品 SPU 编号不能为空")
32   - private Long spuId;
33   -
34   - @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
35   - @NotNull(message = "商品 SPU 名称不能为空")
36   - private String spuName;
37   -
38 29 @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
39 30 @NotNull(message = "商品 SKU 编号不能为空")
40 31 private Long skuId;
41 32  
42   - @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
43   - @NotNull(message = "评分星级不能为空")
44   - private Integer scores;
45   -
46 33 @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
47 34 @NotNull(message = "描述星级不能为空")
48 35 private Integer descriptionScores;
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java
... ... @@ -35,9 +35,8 @@ public class ProductCommentPageReqVO extends PageParam {
35 35 @InEnum(ProductCommentScoresEnum.class)
36 36 private Integer scores;
37 37  
38   - // TODO @puhui999:replyStatus 哈
39 38 @Schema(description = "商家是否回复", example = "true")
40   - private Boolean replied;
  39 + private Boolean replyStatus;
41 40  
42 41 @Schema(description = "创建时间")
43 42 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java
... ... @@ -5,6 +5,7 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import lombok.ToString;
7 7  
  8 +import javax.validation.constraints.NotNull;
8 9 import java.time.LocalDateTime;
9 10  
10 11 @Schema(description = "管理后台 - 商品评价 Response VO")
... ... @@ -40,4 +41,15 @@ public class ProductCommentRespVO extends ProductCommentBaseVO {
40 41 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
41 42 private LocalDateTime createTime;
42 43  
  44 + @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
  45 + private Integer scores;
  46 +
  47 + @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "清凉丝滑透气小短袖")
  48 + @NotNull(message = "商品 SPU 编号不能为空")
  49 + private Long spuId;
  50 +
  51 + @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
  52 + @NotNull(message = "商品 SPU 名称不能为空")
  53 + private String spuName;
  54 +
43 55 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
... ... @@ -30,11 +30,6 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
30 30 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
31 31 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
32 32  
33   -/**
34   - * 商品 SPU 相关接口
35   - *
36   - * @author HUIHUI
37   - */
38 33 @Tag(name = "管理后台 - 商品 SPU")
39 34 @RestController
40 35 @RequestMapping("/product/spu")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuCreateReqVO.java
... ... @@ -9,11 +9,6 @@ import lombok.ToString;
9 9 import javax.validation.Valid;
10 10 import java.util.List;
11 11  
12   -/**
13   - * 商品 SPU 创建 Request VO
14   - *
15   - * @author HUIHUI
16   - */
17 12 @Schema(description = "管理后台 - 商品 SPU 创建 Request VO")
18 13 @Data
19 14 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuDetailRespVO.java
... ... @@ -8,12 +8,6 @@ import lombok.ToString;
8 8  
9 9 import java.util.List;
10 10  
11   -/**
12   - * 商品 SPU 详细 Response VO
13   - * 包括关联的 SKU 等信息
14   - *
15   - * @author HUIHUI
16   - */
17 11 @Schema(description = "管理后台 - 商品 SPU 详细 Response VO")
18 12 @Data
19 13 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuExportReqVO.java
... ... @@ -10,11 +10,6 @@ import java.time.LocalDateTime;
10 10  
11 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
12 12  
13   -/**
14   - * 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的
15   - *
16   - * @author HUIHUI
17   - */
18 13 @Schema(description = "管理后台 - 商品Spu导出 Request VO,参数和 ProductSpuPageReqVO 是一致的")
19 14 @Data
20 15 @NoArgsConstructor
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java
... ... @@ -11,11 +11,6 @@ import java.time.LocalDateTime;
11 11  
12 12 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
13 13  
14   -/**
15   - * 商品 SPU 分页 Request VO
16   - *
17   - * @author HUIHUI
18   - */
19 14 @Schema(description = "管理后台 - 商品 SPU 分页 Request VO")
20 15 @Data
21 16 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuRespVO.java
... ... @@ -7,11 +7,6 @@ import lombok.ToString;
7 7  
8 8 import java.time.LocalDateTime;
9 9  
10   -/**
11   - * 商品 SPU Response VO
12   - *
13   - * @author HUIHUI
14   - */
15 10 @Schema(description = "管理后台 - 商品 SPU Response VO")
16 11 @Data
17 12 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java
... ... @@ -4,11 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5 import lombok.ToString;
6 6  
7   -/**
8   - * 商品 SPU 精简 Response VO
9   - * TODO 商品 SPU 精简 VO 暂时没有使用到,用到的时候再按需添加\修改属性
10   - * @author HUIHUI
11   - */
12 7 @Schema(description = "管理后台 - 商品 SPU 精简 Response VO")
13 8 @Data
14 9 @ToString(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateReqVO.java
... ... @@ -12,11 +12,6 @@ import javax.validation.Valid;
12 12 import javax.validation.constraints.NotNull;
13 13 import java.util.List;
14 14  
15   -/**
16   - * 商品 SPU 更新 Request VO
17   - *
18   - * @author HUIHUI
19   - */
20 15 @Schema(description = "管理后台 - 商品 SPU 更新 Request VO")
21 16 @Data
22 17 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuUpdateStatusReqVO.java
... ... @@ -7,11 +7,6 @@ import lombok.Data;
7 7  
8 8 import javax.validation.constraints.NotNull;
9 9  
10   -/**
11   - * 商品 SPU Status 更新 Request VO
12   - *
13   - * @author HUIHUI
14   - */
15 10 @Schema(description = "管理后台 - 商品 SPU Status 更新 Request VO")
16 11 @Data
17 12 public class ProductSpuUpdateStatusReqVO{
... ...
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 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.hutool.core.util.ObjectUtil;
5 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 7 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
8 8 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
9 9 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
10   -import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
11 10 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
12 11 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
13 12 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
14 13 import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
15 14 import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
  15 +import com.google.common.collect.Maps;
16 16 import io.swagger.v3.oas.annotations.Operation;
17 17 import io.swagger.v3.oas.annotations.Parameter;
18 18 import io.swagger.v3.oas.annotations.Parameters;
... ... @@ -26,11 +26,9 @@ import org.springframework.web.bind.annotation.RestController;
26 26  
27 27 import javax.annotation.Resource;
28 28 import javax.validation.Valid;
29   -import java.util.HashMap;
30 29 import java.util.List;
31 30 import java.util.Map;
32 31 import java.util.Set;
33   -import java.util.stream.Collectors;
34 32  
35 33 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
36 34  
... ... @@ -61,26 +59,14 @@ public class AppProductCommentController {
61 59 @GetMapping("/page")
62 60 @Operation(summary = "获得商品评价分页")
63 61 public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
64   - PageResult<AppProductCommentRespVO> page = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
65   - // TODO @puhui CollUtils 有简化 convertmap 和 list 的方法
66   - Set<Long> skuIds = page.getList().stream().map(AppProductCommentRespVO::getSkuId).collect(Collectors.toSet());
  62 + PageResult<ProductCommentDO> commentDOPage = productCommentService.getCommentPage(pageVO, Boolean.TRUE);
  63 + Set<Long> skuIds = CollectionUtils.convertSet(commentDOPage.getList(), ProductCommentDO::getSkuId);
67 64 List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds);
68   - Map<Long, ProductSkuDO> skuDOMap = new HashMap<>(skuIds.size());
  65 + Map<Long, ProductSkuDO> skuDOMap = Maps.newLinkedHashMapWithExpectedSize(skuIds.size());
69 66 if (CollUtil.isNotEmpty(skuList)) {
70   - skuDOMap.putAll(skuList.stream().collect(Collectors.toMap(ProductSkuDO::getId, c -> c)));
  67 + skuDOMap.putAll(CollectionUtils.convertMap(skuList, ProductSkuDO::getId, c -> c));
71 68 }
72   - // TODO @puihui999:下面也可以放到 convert 里哈
73   - page.getList().forEach(item -> {
74   - // 判断用户是否选择匿名
75   - if (ObjectUtil.equal(item.getAnonymous(), true)) {
76   - item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
77   - }
78   - ProductSkuDO productSkuDO = skuDOMap.get(item.getSkuId());
79   - if (productSkuDO != null) {
80   - List<AppProductPropertyValueDetailRespVO> skuProperties = ProductCommentConvert.INSTANCE.convertList01(productSkuDO.getProperties());
81   - item.setSkuProperties(skuProperties);
82   - }
83   - });
  69 + PageResult<AppProductCommentRespVO> page = ProductCommentConvert.INSTANCE.convertPage02(commentDOPage, skuDOMap);
84 70 return success(page);
85 71 }
86 72  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java
... ... @@ -10,11 +10,6 @@ import javax.validation.constraints.Size;
10 10 import java.time.LocalDateTime;
11 11 import java.util.List;
12 12  
13   -/**
14   - * 用户 App - 商品评价详情 Response VO
15   - *
16   - * @author HUIHUI
17   - */
18 13 @Schema(description = "用户 App - 商品评价详情 Response VO")
19 14 @Data
20 15 @ToString(callSuper = true)
... ...
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.util.ObjectUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
5 6 import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
... ... @@ -19,6 +20,7 @@ import org.mapstruct.factory.Mappers;
19 20 import java.math.BigDecimal;
20 21 import java.math.RoundingMode;
21 22 import java.util.List;
  23 +import java.util.Map;
22 24  
23 25 /**
24 26 * 商品评价 Convert
... ... @@ -32,10 +34,12 @@ public interface ProductCommentConvert {
32 34  
33 35 ProductCommentRespVO convert(ProductCommentDO bean);
34 36  
35   - // TODO @puhui999:这里貌似字段对上,就不用 mapping 了;可以测试下看看哈
36   - @Mapping(target = "goodCount", source = "goodCount")
37   - @Mapping(target = "mediocreCount", source = "mediocreCount")
38   - @Mapping(target = "negativeCount", source = "negativeCount")
  37 + @Named("calculateOverallScore")
  38 + default double calculateOverallScore(long goodCount, long mediocreCount, long negativeCount) {
  39 + return (goodCount * 5 + mediocreCount * 3 + negativeCount) / (double) (goodCount + mediocreCount + negativeCount);
  40 + }
  41 +
  42 + @Mapping(target = "scores", expression = "java(calculateOverallScore(goodCount, mediocreCount, negativeCount))")
39 43 AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount);
40 44  
41 45 List<ProductCommentRespVO> convertList(List<ProductCommentDO> list);
... ... @@ -44,7 +48,23 @@ public interface ProductCommentConvert {
44 48  
45 49 PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> page);
46 50  
47   - PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult);
  51 + PageResult<AppProductCommentRespVO> convertPage01(PageResult<ProductCommentDO> pageResult);
  52 +
  53 + default PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult, Map<Long, ProductSkuDO> skuDOMap) {
  54 + PageResult<AppProductCommentRespVO> page = convertPage01(pageResult);
  55 + page.getList().forEach(item -> {
  56 + // 判断用户是否选择匿名
  57 + if (ObjectUtil.equal(item.getAnonymous(), true)) {
  58 + item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
  59 + }
  60 + ProductSkuDO productSkuDO = skuDOMap.get(item.getSkuId());
  61 + if (productSkuDO != null) {
  62 + List<AppProductPropertyValueDetailRespVO> skuProperties = ProductCommentConvert.INSTANCE.convertList01(productSkuDO.getProperties());
  63 + item.setSkuProperties(skuProperties);
  64 + }
  65 + });
  66 + return page;
  67 + }
48 68  
49 69 /**
50 70 * 计算综合评分
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java
... ... @@ -51,11 +51,11 @@ public interface ProductCommentMapper extends BaseMapperX&lt;ProductCommentDO&gt; {
51 51 return selectPage(reqVO, queryWrapper);
52 52 }
53 53  
54   - default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long spuId) {
  54 + default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long skuId) {
55 55 return selectOne(new LambdaQueryWrapperX<ProductCommentDO>()
56 56 .eq(ProductCommentDO::getUserId, userId)
57 57 .eq(ProductCommentDO::getOrderItemId, orderItemId)
58   - .eq(ProductCommentDO::getSpuId, spuId));
  58 + .eq(ProductCommentDO::getSpuId, skuId));
59 59 }
60 60  
61 61 default Long selectCountBySpuId(Long spuId, Boolean visible, Integer type) {
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java
... ... @@ -54,7 +54,7 @@ public interface ProductCommentService {
54 54 * @param visible 是否可见
55 55 * @return 商品评价分页
56 56 */
57   - PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
  57 + PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
58 58  
59 59 /**
60 60 * 创建商品评论
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
... ... @@ -81,7 +81,7 @@ public class ProductCommentServiceImpl implements ProductCommentService {
81 81 @Transactional(rollbackFor = Exception.class)
82 82 public void createComment(ProductCommentCreateReqVO createReqVO) {
83 83 // 校验评论
84   - validateComment(createReqVO.getSpuId(), createReqVO.getUserId(), createReqVO.getOrderItemId());
  84 + validateComment(createReqVO.getSkuId(), createReqVO.getUserId(), createReqVO.getOrderItemId());
85 85  
86 86 ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqVO);
87 87 productCommentMapper.insert(commentDO);
... ... @@ -108,11 +108,11 @@ public class ProductCommentServiceImpl implements ProductCommentService {
108 108 return commentDO.getId();
109 109 }
110 110  
111   - private void validateComment(Long spuId, Long userId, Long orderItemId) {
  111 + private void validateComment(Long skuId, Long userId, Long orderItemId) {
112 112 // 判断当前订单的当前商品用户是否评价过
113   - ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, spuId);
  113 + ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, skuId);
114 114 if (null != exist) {
115   - throw exception(ORDER_SPU_COMMENT_EXISTS);
  115 + throw exception(ORDER_SKU_COMMENT_EXISTS);
116 116 }
117 117 }
118 118  
... ... @@ -141,23 +141,17 @@ public class ProductCommentServiceImpl implements ProductCommentService {
141 141 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT),
142 142 // 查询商品 id = spuId 的所有差评数量
143 143 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT)
144   - ).setScores(3.0); // TODO @puhui999:这里要实现下;;
  144 + );
145 145 }
146 146  
147 147 @Override
148 148 public List<AppProductCommentRespVO> getCommentList(Long spuId, Integer count) {
149   - // 校验商品 spu 是否存在
150   - // TODO @puhui 这里校验可以去掉哈。
151   - ProductSpuDO spuDO = validateSpu(spuId);
152   - return ProductCommentConvert.INSTANCE.convertList02(productCommentMapper.selectCommentList(spuDO.getId(), count).getList());
  149 + return ProductCommentConvert.INSTANCE.convertList02(productCommentMapper.selectCommentList(spuId, count).getList());
153 150 }
154 151  
155   - // TODO @puhui 可以放到 controller 去 convert 哈
156 152 @Override
157   - public PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
158   - // TODO @puhui 可以放到 controller 去 convert 哈
159   - return ProductCommentConvert.INSTANCE.convertPage02(
160   - productCommentMapper.selectPage(pageVO, visible));
  153 + public PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
  154 + return productCommentMapper.selectPage(pageVO, visible);
161 155 }
162 156  
163 157 @Override
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java
... ... @@ -10,7 +10,6 @@ import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommen
10 10 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO;
11 11 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
12 12 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
13   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
14 13 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
15 14 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
16 15 import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
... ... @@ -128,7 +127,7 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
128 127 productCommentPageReqVO.setSpuId(spuId);
129 128 productCommentPageReqVO.setSpuName("感冒药");
130 129 productCommentPageReqVO.setScores(ProductCommentScoresEnum.FOUR.getScores());
131   - productCommentPageReqVO.setReplied(Boolean.TRUE);
  130 + productCommentPageReqVO.setReplyStatus(Boolean.TRUE);
132 131  
133 132 PageResult<ProductCommentDO> commentPage = productCommentService.getCommentPage(productCommentPageReqVO);
134 133 PageResult<ProductCommentRespVO> result = ProductCommentConvert.INSTANCE.convertPage(productCommentMapper.selectPage(productCommentPageReqVO));
... ... @@ -138,15 +137,15 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
138 137 assertEquals(8, all.getTotal());
139 138  
140 139 // 测试获取所有商品分页评论数据
141   - PageResult<AppProductCommentRespVO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
  140 + PageResult<ProductCommentDO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
142 141 assertEquals(7, result1.getTotal());
143 142  
144 143 // 测试获取所有商品分页中评数据
145   - PageResult<AppProductCommentRespVO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
  144 + PageResult<ProductCommentDO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
146 145 assertEquals(2, result2.getTotal());
147 146  
148 147 // 测试获取指定 spuId 商品分页中评数据
149   - PageResult<AppProductCommentRespVO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
  148 + PageResult<ProductCommentDO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
150 149 assertEquals(2, result3.getTotal());
151 150  
152 151 // 测试分页 tab count
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/SeckillConfigController.java
... ... @@ -19,11 +19,6 @@ import java.util.List;
19 19  
20 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21 21  
22   -/**
23   - * 管理后台 - 秒杀时段相关接口
24   - *
25   - * @author HUIHUI
26   - */
27 22 @Tag(name = "管理后台 - 秒杀时段")
28 23 @RestController
29 24 @RequestMapping("/promotion/seckill-config")
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/activity/SeckillActivityRespVO.java
... ... @@ -9,11 +9,6 @@ import lombok.ToString;
9 9 import java.time.LocalDateTime;
10 10 import java.util.List;
11 11  
12   -/**
13   - * 管理后台 - 秒杀活动 Response VO
14   - *
15   - * @author HUIHUI
16   - */
17 12 @Schema(description = "管理后台 - 秒杀活动 Response VO")
18 13 @Data
19 14 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigBaseVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config;
2 2  
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 4 import io.swagger.v3.oas.annotations.media.Schema;
4 5 import lombok.Data;
5 6  
  7 +import javax.validation.constraints.AssertTrue;
6 8 import javax.validation.constraints.NotNull;
  9 +import java.time.LocalTime;
  10 +import java.util.List;
7 11  
8 12 /**
9 13 * 秒杀时段 Base VO,提供给添加、修改、详细的子 VO 使用
... ... @@ -26,12 +30,24 @@ public class SeckillConfigBaseVO {
26 30 @NotNull(message = "结束时间点不能为空")
27 31 private String endTime;
28 32  
29   - @Schema(description = "秒杀主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
30   - @NotNull(message = "秒杀主图不能为空")
31   - private String picUrl;
  33 + @Schema(description = "秒杀轮播图", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/xx.png]")
  34 + @NotNull(message = "秒杀轮播图不能为空")
  35 + private List<String> sliderPicUrls;
32 36  
33 37 @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
34 38 @NotNull(message = "状态不能为空")
35 39 private Integer status;
36 40  
  41 + @AssertTrue(message = "秒杀时段开始时间和结束时间不能相等")
  42 + @JsonIgnore
  43 + public boolean isValidStartTimeValid() {
  44 + return !LocalTime.parse(startTime).equals(LocalTime.parse(endTime));
  45 + }
  46 +
  47 + @AssertTrue(message = "秒杀时段开始时间不能在结束时间之后")
  48 + @JsonIgnore
  49 + public boolean isValidEndTimeValid() {
  50 + return !LocalTime.parse(startTime).isAfter(LocalTime.parse(endTime));
  51 + }
  52 +
37 53 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/config/SeckillConfigPageReqVO.java
... ... @@ -6,12 +6,6 @@ import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8 8  
9   -// TODO @puhui:VO 上不写注释,已经有注解啦。
10   -/**
11   - * 管理后台 - 秒杀时段分页 Request VO
12   - *
13   - * @author HUIHUI
14   - */
15 9 @Schema(description = "管理后台 - 秒杀时段分页 Request VO")
16 10 @Data
17 11 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductCreateReqVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
2 2  
3   -import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
4   -import lombok.*;
5   -import java.util.*;
6 3 import io.swagger.v3.oas.annotations.media.Schema;
7   -import javax.validation.constraints.*;
8   -
9   -/**
10   - * 管理后台 - 秒杀参与商品创建 Request VO
11   - *
12   - * @author HUIHUI
13   - */
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
14 7 @Schema(description = "管理后台 - 秒杀参与商品创建 Request VO")
15 8 @Data
16 9 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductRespVO.java
1 1 package cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
5 8 import java.time.LocalDateTime;
6 9  
7   -/**
8   - * 管理后台 - 秒杀参与商品 Response VO
9   - *
10   - * @author HUIHUI
11   - */
12 10 @Schema(description = "管理后台 - 秒杀参与商品 Response VO")
13 11 @Data
14 12 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/seckill/vo/product/SeckillProductUpdateReqVO.java
... ... @@ -5,11 +5,6 @@ import lombok.Data;
5 5 import lombok.EqualsAndHashCode;
6 6 import lombok.ToString;
7 7  
8   -/**
9   - * 管理后台 - 秒杀参与商品更新 Request VO
10   - *
11   - * @author HUIHUI
12   - */
13 8 @Schema(description = "管理后台 - 秒杀参与商品更新 Request VO")
14 9 @Data
15 10 @EqualsAndHashCode(callSuper = true)
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/seckill/seckillconfig/SeckillConfigDO.java
... ... @@ -3,22 +3,27 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig;
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import com.baomidou.mybatisplus.annotation.KeySequence;
  6 +import com.baomidou.mybatisplus.annotation.TableField;
6 7 import com.baomidou.mybatisplus.annotation.TableId;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
8   -import lombok.Data;
9   -import lombok.EqualsAndHashCode;
10   -import lombok.ToString;
  9 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  10 +import lombok.*;
  11 +
  12 +import java.util.List;
11 13  
12 14 /**
13 15 * 秒杀时段 DO
14 16 *
15 17 * @author 芋道源码
16 18 */
17   -@TableName("promotion_seckill_config")
  19 +@TableName(value = "promotion_seckill_config", autoResultMap = true)
18 20 @KeySequence("promotion_seckill_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
19 21 @Data
20 22 @EqualsAndHashCode(callSuper = true)
21 23 @ToString(callSuper = true)
  24 +@Builder
  25 +@NoArgsConstructor
  26 +@AllArgsConstructor
22 27 public class SeckillConfigDO extends BaseDO {
23 28  
24 29 /**
... ... @@ -38,14 +43,14 @@ public class SeckillConfigDO extends BaseDO {
38 43 * 结束时间点
39 44 */
40 45 private String endTime;
41   - // TODO puhui999:应该是轮播图; private List<String> sliderPicUrls;
42 46 /**
43   - * 秒杀主图
  47 + * 秒杀轮播图
44 48 */
45   - private String picUrl;
  49 + @TableField(typeHandler = JacksonTypeHandler.class)
  50 + private List<String> sliderPicUrls;
46 51 /**
47 52 * 状态
48   - *
  53 + * <p>
49 54 * 枚举 {@link CommonStatusEnum 对应的类}
50 55 */
51 56 private Integer status;
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/seckill/seckillconfig/SeckillConfigMapper.java
... ... @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
7 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
  10 +import java.util.List;
  11 +
10 12 @Mapper
11 13 public interface SeckillConfigMapper extends BaseMapperX<SeckillConfigDO> {
12 14  
... ... @@ -17,4 +19,9 @@ public interface SeckillConfigMapper extends BaseMapperX&lt;SeckillConfigDO&gt; {
17 19 .orderByDesc(SeckillConfigDO::getId));
18 20 }
19 21  
  22 + default List<SeckillConfigDO> selectListByStatus(Integer status) {
  23 + return selectList(SeckillConfigDO::getStatus, status);
  24 + }
  25 +
  26 +
20 27 }
... ...
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/seckillconfig/SeckillConfigServiceImpl.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
5 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
8 9 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
9 10 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
10 11 import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
... ... @@ -12,14 +13,13 @@ import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillCo
12 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
13 14 import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
14 15 import org.springframework.stereotype.Service;
  16 +import org.springframework.transaction.annotation.Transactional;
15 17 import org.springframework.validation.annotation.Validated;
16 18  
17 19 import javax.annotation.Resource;
18 20 import java.time.LocalTime;
19 21 import java.util.Collection;
20 22 import java.util.List;
21   -import java.util.Set;
22   -import java.util.stream.Collectors;
23 23  
24 24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 25 import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
... ... @@ -37,9 +37,10 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
37 37 private SeckillConfigMapper seckillConfigMapper;
38 38  
39 39 @Override
  40 + @Transactional(rollbackFor = Exception.class)
40 41 public Long createSeckillConfig(SeckillConfigCreateReqVO createReqVO) {
41 42 // 校验时间段是否冲突
42   - validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime());
  43 + validateSeckillConfigConflict(createReqVO.getStartTime(), createReqVO.getEndTime(), null);
43 44  
44 45 // 插入
45 46 SeckillConfigDO seckillConfig = SeckillConfigConvert.INSTANCE.convert(createReqVO);
... ... @@ -49,18 +50,30 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
49 50 }
50 51  
51 52 @Override
  53 + @Transactional(rollbackFor = Exception.class)
52 54 public void updateSeckillConfig(SeckillConfigUpdateReqVO updateReqVO) {
53 55 // 校验存在
54 56 validateSeckillConfigExists(updateReqVO.getId());
55 57 // 校验时间段是否冲突
56   - validateSeckillConfigConflict(updateReqVO.getStartTime(), updateReqVO.getEndTime());
  58 + validateSeckillConfigConflict(updateReqVO.getStartTime(), updateReqVO.getEndTime(), updateReqVO.getId());
57 59  
58 60 // 更新
59 61 SeckillConfigDO updateObj = SeckillConfigConvert.INSTANCE.convert(updateReqVO);
60 62 seckillConfigMapper.updateById(updateObj);
61 63 }
62 64  
  65 + // TODO @puhui999: 这个要不合并到更新操作里? 不单独有个操作咧; 更新状态不用那么多必须的参数,更新的时候需要校验时间段
63 66 @Override
  67 + public void updateSeckillConfigStatus(Long id, Integer status) {
  68 + // 校验秒杀时段是否存在
  69 + validateSeckillConfigExists(id);
  70 +
  71 + // 更新状态
  72 + seckillConfigMapper.updateById(new SeckillConfigDO().setId(id).setStatus(status));
  73 + }
  74 +
  75 + @Override
  76 + @Transactional(rollbackFor = Exception.class)
64 77 public void deleteSeckillConfig(Long id) {
65 78 // 校验存在
66 79 validateSeckillConfigExists(id);
... ... @@ -81,39 +94,29 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
81 94 * @param startTime 开始时间
82 95 * @param endTime 结束时间
83 96 */
84   - private void validateSeckillConfigConflict(String startTime, String endTime) {
  97 + private void validateSeckillConfigConflict(String startTime, String endTime, Long seckillConfigId) {
85 98 LocalTime startTime1 = LocalTime.parse(startTime);
86 99 LocalTime endTime1 = LocalTime.parse(endTime);
87   - // TODO @puhui999: 这个可以用 validator 里的 assertTrue 去做哈;
88   - // 检查选择的时间是否相等
89   - if (startTime1.equals(endTime1)) {
90   - throw exception(SECKILL_TIME_EQUAL);
91   - }
92   - // 检查开始时间是否在结束时间之前
93   - if (startTime1.isAfter(endTime1)) {
94   - throw exception(SECKILL_START_TIME_BEFORE_END_TIME);
95   - }
96 100 // 查询出所有的时段配置
97 101 List<SeckillConfigDO> configDOs = seckillConfigMapper.selectList();
  102 + // 更新时排除自己
  103 + if (seckillConfigId != null) {
  104 + configDOs.removeIf(item -> ObjectUtil.equal(item.getId(), seckillConfigId));
  105 + }
98 106 // 过滤出重叠的时段 ids
99   - // TODO @puhui999:感觉 findOne 就可以了?
100   - Set<Long> ids = configDOs.stream().filter((config) -> {
  107 + boolean hasConflict = configDOs.stream().anyMatch(config -> {
101 108 LocalTime startTime2 = LocalTime.parse(config.getStartTime());
102 109 LocalTime endTime2 = LocalTime.parse(config.getEndTime());
103 110 // 判断时间是否重叠
104   - // 开始时间在已配置时段的结束时间之前 且 结束时间在已配置时段的开始时间之后 []
105   - // todo @puhui999:LocalDateUtils 可以写个工具类?是否是有重叠的时间?感觉别的场景,可能也会有需要
106   - return startTime1.isBefore(endTime2) && endTime1.isAfter(startTime2)
107   - // 开始时间在已配置时段的开始时间之前 且 结束时间在已配置时段的开始时间之后 (] 或 ()
108   - || startTime1.isBefore(startTime2) && endTime1.isAfter(startTime2)
109   - // 开始时间在已配置时段的结束时间之前 且 结束时间在已配值时段的结束时间之后 [) 或 ()
110   - || startTime1.isBefore(endTime2) && endTime1.isAfter(endTime2);
111   - }).map(SeckillConfigDO::getId).collect(Collectors.toSet());
112   - if (CollUtil.isNotEmpty(ids)) {
  111 + return LocalDateTimeUtils.checkTimeOverlap(startTime1, endTime1, startTime2, endTime2);
  112 + });
  113 +
  114 + if (hasConflict) {
113 115 throw exception(SECKILL_TIME_CONFLICTS);
114 116 }
115 117 }
116 118  
  119 +
117 120 @Override
118 121 public SeckillConfigDO getSeckillConfig(Long id) {
119 122 return seckillConfigMapper.selectById(id);
... ... @@ -148,23 +151,9 @@ public class SeckillConfigServiceImpl implements SeckillConfigService {
148 151 return seckillConfigMapper.selectPage(pageVO);
149 152 }
150 153  
151   - // TODO @puhui999:写个查询状态的; 尽可能通用哈
152 154 @Override
153 155 public List<SeckillConfigDO> getListAllSimple() {
154   - return seckillConfigMapper.selectList(SeckillConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus());
155   - }
156   -
157   - // TODO @puhui999: 这个要不合并到更新操作里? 不单独有个操作咧;
158   - @Override
159   - public void updateSeckillConfigStatus(Long id, Integer status) {
160   - // 校验秒杀时段是否存在
161   - validateSeckillConfigExists(id);
162   -
163   - SeckillConfigDO seckillConfigDO = new SeckillConfigDO();
164   - seckillConfigDO.setId(id);
165   - seckillConfigDO.setStatus(status);
166   - // 更新状态
167   - seckillConfigMapper.updateById(seckillConfigDO);
  156 + return seckillConfigMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
168 157 }
169 158  
170 159 }
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
... ... @@ -27,6 +27,8 @@ public interface ErrorCodeConstants {
27 27 ErrorCode ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(1011000016, "交易订单更新支付状态失败,支付单金额不匹配");
28 28 ErrorCode ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED = new ErrorCode(1011000017, "交易订单发货失败,订单不是【待发货】状态");
29 29 ErrorCode ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(1011000018, "交易订单收货失败,订单不是【待收货】状态");
  30 + ErrorCode ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED = new ErrorCode(1011000019, "创建交易订单项的评价失败,订单不是【已完成】状态");
  31 + ErrorCode ORDER_COMMENT_STATUS_NOT_FALSE = new ErrorCode(1011000019, "创建交易订单项的评价失败,订单已评价");
30 32  
31 33 // ========== After Sale 模块 1011000100 ==========
32 34 ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
... ... @@ -4,8 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
6 6 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
7   -import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
8   -import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
9 7 import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
10 8 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
11 9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
... ... @@ -30,13 +28,10 @@ import javax.validation.Valid;
30 28 import java.util.List;
31 29 import java.util.Map;
32 30  
33   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 31 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
35 32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
36 33 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
37 34 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
38   -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
39   -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
40 35  
41 36 @Tag(name = "用户 App - 交易订单")
42 37 @RestController
... ... @@ -47,13 +42,9 @@ public class AppTradeOrderController {
47 42  
48 43 @Resource
49 44 private TradeOrderService tradeOrderService;
50   -
51 45 @Resource
52 46 private ProductPropertyValueApi productPropertyValueApi;
53 47 @Resource
54   - private ProductCommentApi productCommentApi;
55   -
56   - @Resource
57 48 private TradeOrderProperties tradeOrderProperties;
58 49  
59 50 @GetMapping("/settlement")
... ... @@ -121,7 +112,7 @@ public class AppTradeOrderController {
121 112 // 待发货
122 113 orderCount.put("undeliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.UNDELIVERED.getStatus(), null));
123 114 // 待收货
124   - orderCount.put("deliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.DELIVERED.getStatus(), null));
  115 + orderCount.put("deliveredCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.DELIVERED.getStatus(), null));
125 116 // 待评价
126 117 orderCount.put("uncommentedCount", tradeOrderService.getOrderCount(getLoginUserId(), TradeOrderStatusEnum.COMPLETED.getStatus(), false));
127 118 return success(orderCount);
... ... @@ -164,22 +155,7 @@ public class AppTradeOrderController {
164 155 @PostMapping("/item/create-comment")
165 156 @Operation(summary = "创建交易订单项的评价")
166 157 public CommonResult<Long> createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) {
167   - // TODO @puhui999:这个逻辑,最好写到 service 哈;
168   - Long loginUserId = getLoginUserId();
169   - // 先通过订单项 ID 查询订单项是否存在
170   - TradeOrderItemDO orderItemDO = tradeOrderService.getOrderItemByIdAndUserId(createReqVO.getOrderItemId(), loginUserId);
171   - if (orderItemDO == null) {
172   - throw exception(ORDER_ITEM_NOT_FOUND);
173   - }
174   - // 校验订单
175   - TradeOrderDO orderDO = tradeOrderService.getOrderByIdAndUserId(orderItemDO.getOrderId(), loginUserId);
176   - if (orderDO == null) {
177   - throw exception(ORDER_NOT_FOUND);
178   - }
179   - // TODO @puhui999:要校验订单已完成,但是未评价;
180   -
181   - ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItemDO);
182   - return success(productCommentApi.createComment(productCommentCreateReqDTO));
  158 + return success(tradeOrderService.createOrderItemComment(createReqVO));
183 159 }
184 160  
185 161 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java
... ... @@ -19,11 +19,6 @@ public class AppTradeOrderItemCommentCreateReqVO {
19 19 @NotNull(message = "交易订单项编号不能为空")
20 20 private Long orderItemId;
21 21  
22   - // TODO @puhui999:貌似不用这个字段哈;
23   - @Schema(description = "评分星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
24   - @NotNull(message = "评分星级 1-5 分不能为空")
25   - private Integer scores;
26   -
27 22 @Schema(description = "描述星级 1-5 分", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
28 23 @NotNull(message = "描述星级 1-5 分不能为空")
29 24 private Integer descriptionScores;
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -270,7 +270,6 @@ public interface TradeOrderConvert {
270 270 @Mapping(target = "skuId", source = "tradeOrderItemDO.skuId")
271 271 @Mapping(target = "orderId", source = "tradeOrderItemDO.orderId")
272 272 @Mapping(target = "orderItemId", source = "tradeOrderItemDO.id")
273   - @Mapping(target = "scores", source = "createReqVO.scores")
274 273 @Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores")
275 274 @Mapping(target = "benefitScores", source = "createReqVO.benefitScores")
276 275 @Mapping(target = "content", source = "createReqVO.content")
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate
7 7 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
8 8 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO;
9 9 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
  10 +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
10 11 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
11 12 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
12 13  
... ... @@ -177,4 +178,14 @@ public interface TradeOrderService {
177 178 * @return 得到订单
178 179 */
179 180 TradeOrderDO getOrderByIdAndUserId(Long orderId, Long loginUserId);
  181 +
  182 + /**
  183 + * 创建订单项评论
  184 + * 创建交易订单项的评价
  185 + *
  186 + * @param createReqVO 创建请求
  187 + * @return 得到评价 id
  188 + */
  189 + Long createOrderItemComment(AppTradeOrderItemCommentCreateReqVO createReqVO);
  190 +
180 191 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
... ... @@ -17,19 +17,21 @@ import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
17 17 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
18 18 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
19 19 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
  20 +import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
  21 +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
20 22 import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
21 23 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
22 24 import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
23 25 import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
24 26 import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
25 27 import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
26   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
27 28 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
28 29 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
29 30 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
30 31 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageReqVO;
31 32 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO;
32 33 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO;
  34 +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
33 35 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
34 36 import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
35 37 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
... ... @@ -57,6 +59,7 @@ import java.util.*;
57 59 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
58 60 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
59 61 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
  62 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
60 63 import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_ORDER_NOT_FOUND;
61 64 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
62 65  
... ... @@ -93,7 +96,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
93 96 @Resource
94 97 private MemberUserApi memberUserApi;
95 98 @Resource
96   - private AdminUserApi adminUserApi;
  99 + private ProductCommentApi productCommentApi;
97 100 @Resource
98 101 private NotifyMessageSendApi notifyMessageSendApi;
99 102  
... ... @@ -556,6 +559,30 @@ public class TradeOrderServiceImpl implements TradeOrderService {
556 559 return tradeOrderMapper.selectOrderByIdAndUserId(orderId, loginUserId);
557 560 }
558 561  
  562 + @Override
  563 + public Long createOrderItemComment(AppTradeOrderItemCommentCreateReqVO createReqVO) {
  564 + Long loginUserId = getLoginUserId();
  565 + // 先通过订单项 ID 查询订单项是否存在
  566 + TradeOrderItemDO orderItemDO = getOrderItemByIdAndUserId(createReqVO.getOrderItemId(), loginUserId);
  567 + if (orderItemDO == null) {
  568 + throw exception(ORDER_ITEM_NOT_FOUND);
  569 + }
  570 + // 校验订单
  571 + TradeOrderDO orderDO = getOrderByIdAndUserId(orderItemDO.getOrderId(), loginUserId);
  572 + if (orderDO == null) {
  573 + throw exception(ORDER_NOT_FOUND);
  574 + }
  575 + if (ObjectUtil.notEqual(orderDO.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) {
  576 + throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED);
  577 + }
  578 + if (ObjectUtil.notEqual(orderDO.getCommentStatus(), Boolean.FALSE)) {
  579 + throw exception(ORDER_COMMENT_STATUS_NOT_FALSE);
  580 + }
  581 +
  582 + ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItemDO);
  583 + return productCommentApi.createComment(productCommentCreateReqDTO);
  584 + }
  585 +
559 586 /**
560 587 * 判断指定订单的所有订单项,是不是都售后成功
561 588 *
... ...
yudao-module-member/yudao-module-member-biz/src/test/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImplTest.java
... ... @@ -19,10 +19,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
19 19 import static org.junit.jupiter.api.Assertions.assertNull;
20 20  
21 21 /**
22   -* {@link AddressServiceImpl} 的单元测试类
23   -*
24   -* @author 芋道源码
25   -*/
  22 + * {@link AddressServiceImpl} 的单元测试类
  23 + *
  24 + * @author 芋道源码
  25 + */
26 26 @Import(AddressServiceImpl.class)
27 27 public class AddressServiceImplTest extends BaseDbUnitTest {
28 28  
... ... @@ -82,8 +82,8 @@ public class AddressServiceImplTest extends BaseDbUnitTest {
82 82  
83 83 // 调用
84 84 addressService.deleteAddress(dbAddress.getUserId(), id);
85   - // 校验数据不存在了
86   - assertNull(addressMapper.selectById(id));
  85 + // 校验数据不存在了
  86 + assertNull(addressMapper.selectById(id));
87 87 }
88 88  
89 89 @Test
... ...