Commit 08535d60199ab9fa5dd3e544d1466d3368301710

Authored by 芋道源码
Committed by Gitee
2 parents fd072b7d 60172274

!509 完善商品评论

Merge pull request !509 from puhui999/feature/mall_product
Showing 28 changed files with 733 additions and 408 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.api.comment;
  2 +
  3 +import cn.iocoder.yudao.module.product.api.comment.dto.CommentCreateReqDTO;
  4 +
  5 +/**
  6 + * 产品评论 API 接口
  7 + *
  8 + * @author HUIHUI
  9 + */
  10 +public interface ProductCommentApi {
  11 +
  12 + /**
  13 + * 创建评论
  14 + *
  15 + * @param createReqDTO 评论参数
  16 + * @param orderId 订单 id
  17 + * @return 返回评论创建后的 id
  18 + */
  19 + Long createComment(CommentCreateReqDTO createReqDTO, Long orderId);
  20 +
  21 +}
... ...
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/comment/dto/CommentCreateReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.api.comment.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * 评论创建请求 DTO
  9 + *
  10 + * @author HUIHUI
  11 + */
  12 +@Data
  13 +public class CommentCreateReqDTO {
  14 +
  15 + /**
  16 + * 是否匿名
  17 + */
  18 + private Boolean anonymous;
  19 +
  20 + /**
  21 + * 交易订单项编号
  22 + */
  23 + private Long orderItemId;
  24 +
  25 + /**
  26 + * 商品 SPU 编号
  27 + */
  28 + private Long spuId;
  29 +
  30 + /**
  31 + * 商品 SPU 名称
  32 + */
  33 + private String spuName;
  34 +
  35 + /**
  36 + * 商品 SKU 编号
  37 + */
  38 + private Long skuId;
  39 +
  40 + /**
  41 + * 评分星级 1-5 分
  42 + */
  43 + private Integer scores;
  44 +
  45 + /**
  46 + * 描述星级 1-5 分
  47 + */
  48 + private Integer descriptionScores;
  49 +
  50 + /**
  51 + * 服务星级 1-5 分
  52 + */
  53 + private Integer benefitScores;
  54 +
  55 + /**
  56 + * 评论内容
  57 + */
  58 + private String content;
  59 +
  60 + /**
  61 + * 评论图片地址数组,以逗号分隔最多上传9张
  62 + */
  63 + private List<String> picUrls;
  64 +
  65 + /**
  66 + * 评价人名称
  67 + */
  68 + private String userNickname;
  69 +
  70 + /**
  71 + * 评价人头像
  72 + */
  73 + private String userAvatar;
  74 +
  75 + /**
  76 + * 评价人
  77 + */
  78 + private Long userId;
  79 +
  80 +}
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/comment/ProductCommentApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.api.comment;
  2 +
  3 +import cn.iocoder.yudao.module.product.api.comment.dto.CommentCreateReqDTO;
  4 +import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
  5 +import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
  6 +import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
  7 +import org.springframework.stereotype.Service;
  8 +import org.springframework.validation.annotation.Validated;
  9 +
  10 +import javax.annotation.Resource;
  11 +
  12 +/**
  13 + * 商品评论 API 实现类
  14 + *
  15 + * @author HUIHUI
  16 + */
  17 +@Service
  18 +@Validated
  19 +public class ProductCommentApiImpl implements ProductCommentApi {
  20 + @Resource
  21 + private ProductCommentService productCommentService;
  22 +
  23 + @Override
  24 + public Long createComment(CommentCreateReqDTO createReqDTO, Long orderId) {
  25 + ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqDTO, orderId);
  26 + return productCommentService.createComment(commentDO);
  27 + }
  28 +}
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/ProductCommentController.java
... ... @@ -35,8 +35,7 @@ public class ProductCommentController {
35 35 return success(ProductCommentConvert.INSTANCE.convertPage(pageResult));
36 36 }
37 37  
38   - // TODO @puhui999:update-visible
39   - @PutMapping("/update/visible")
  38 + @PutMapping("/update-visible")
40 39 @Operation(summary = "显示 / 隐藏评论")
41 40 @PreAuthorize("@ss.hasPermission('product:comment:update')")
42 41 public CommonResult<Boolean> updateCommentVisible(@Valid @RequestBody ProductCommentUpdateVisibleReqVO updateReqVO) {
... ... @@ -47,8 +46,8 @@ public class ProductCommentController {
47 46 @PutMapping("/reply")
48 47 @Operation(summary = "商家回复")
49 48 @PreAuthorize("@ss.hasPermission('product:comment:update')")
50   - public CommonResult<Boolean> commentReply(@Valid @RequestBody ProductCommentReplyVO replyVO) {
51   - productCommentService.commentReply(replyVO, getLoginUserId());
  49 + public CommonResult<Boolean> commentReply(@Valid @RequestBody ProductCommentReplyReqVO replyVO) {
  50 + productCommentService.replyComment(replyVO, getLoginUserId());
52 51 return success(true);
53 52 }
54 53  
... ... @@ -56,8 +55,7 @@ public class ProductCommentController {
56 55 @Operation(summary = "添加自评")
57 56 @PreAuthorize("@ss.hasPermission('product:comment:update')")
58 57 public CommonResult<Boolean> createComment(@Valid @RequestBody ProductCommentCreateReqVO createReqVO) {
59   - // TODO @puhui999:不用 ProductCommentConvert.INSTANCE.convert(createReqVO) 哈;多写一个 create 方法即可;
60   - productCommentService.createComment(ProductCommentConvert.INSTANCE.convert(createReqVO), Boolean.TRUE);
  58 + productCommentService.createComment(createReqVO);
61 59 return success(true);
62 60 }
63 61  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentBaseVO.java
... ... @@ -10,17 +10,15 @@ import java.util.List;
10 10 @Data
11 11 public class ProductCommentBaseVO {
12 12  
13   - // TODO @puhui999:把 example 补充下
14   -
15   - @Schema(description = "评价人名称", required = true, example = "张三")
  13 + @Schema(description = "评价人名称", required = true, example = "小姑凉")
16 14 @NotNull(message = "评价人名称不能为空")
17 15 private String userNickname;
18 16  
19   - @Schema(description = "评价人头像", required = true)
  17 + @Schema(description = "评价人头像", required = true, example = "https://www.iocoder.cn/xx.png")
20 18 @NotNull(message = "评价人头像不能为空")
21 19 private String userAvatar;
22 20  
23   - @Schema(description = "商品 SPU 编号", required = true, example = "29502")
  21 + @Schema(description = "商品 SPU 编号", required = true, example = "清凉丝滑透气小短袖")
24 22 @NotNull(message = "商品 SPU 编号不能为空")
25 23 private Long spuId;
26 24  
... ... @@ -28,27 +26,27 @@ public class ProductCommentBaseVO {
28 26 @NotNull(message = "商品 SPU 名称不能为空")
29 27 private String spuName;
30 28  
31   - @Schema(description = "商品 SKU 编号", required = true, example = "3082")
  29 + @Schema(description = "商品 SKU 编号", required = true, example = "1")
32 30 @NotNull(message = "商品 SKU 编号不能为空")
33 31 private Long skuId;
34 32  
35   - @Schema(description = "评分星级 1-5分", required = true)
  33 + @Schema(description = "评分星级 1-5分", required = true, example = "5")
36 34 @NotNull(message = "评分星级不能为空")
37 35 private Integer scores;
38 36  
39   - @Schema(description = "描述星级 1-5分", required = true)
  37 + @Schema(description = "描述星级 1-5分", required = true, example = "5")
40 38 @NotNull(message = "描述星级不能为空")
41 39 private Integer descriptionScores;
42 40  
43   - @Schema(description = "服务星级 1-5分", required = true)
  41 + @Schema(description = "服务星级 1-5分", required = true, example = "5")
44 42 @NotNull(message = "服务星级分不能为空")
45 43 private Integer benefitScores;
46 44  
47   - @Schema(description = "评论内容", required = true)
  45 + @Schema(description = "评论内容", required = true, example = "穿起来非常丝滑凉快")
48 46 @NotNull(message = "评论内容不能为空")
49 47 private String content;
50 48  
51   - @Schema(description = "评论图片地址数组,以逗号分隔最多上传9张", required = true)
  49 + @Schema(description = "评论图片地址数组,以逗号分隔最多上传9张", required = true, example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]")
52 50 @Size(max = 9, message = "评论图片地址数组长度不能超过9张")
53 51 private List<String> picUrls;
54 52  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentCreateReqVO.java
1 1 package cn.iocoder.yudao.module.product.controller.admin.comment.vo;
2 2  
3   -import lombok.*;
4 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import javax.validation.constraints.NotNull;
5 9  
6 10 @Schema(description = "管理后台 - 商品评价创建 Request VO")
7 11 @Data
... ... @@ -9,4 +13,12 @@ import io.swagger.v3.oas.annotations.media.Schema;
9 13 @ToString(callSuper = true)
10 14 public class ProductCommentCreateReqVO extends ProductCommentBaseVO {
11 15  
  16 + @Schema(description = "评价人", required = true, example = "16868")
  17 + @NotNull(message = "评价人不能为空")
  18 + private Long userId;
  19 +
  20 + @Schema(description = "评价订单项", required = true, example = "19292")
  21 + @NotNull(message = "评价订单项不能为空")
  22 + private Long orderItemId;
  23 +
12 24 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentPageReqVO.java
... ... @@ -31,11 +31,11 @@ public class ProductCommentPageReqVO extends PageParam {
31 31 @Schema(description = "商品SPU名称", example = "感冒药")
32 32 private String spuName;
33 33  
34   - @Schema(description = "评分星级 1-5分")
  34 + @Schema(description = "评分星级 1-5分", example = "5")
35 35 @InEnum(ProductCommentScoresEnum.class)
36 36 private Integer scores;
37 37  
38   - @Schema(description = "商家是否回复")
  38 + @Schema(description = "商家是否回复", example = "true")
39 39 private Boolean replied;
40 40  
41 41 @Schema(description = "创建时间")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentReplyVO.java renamed to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentReplyReqVO.java
... ... @@ -7,11 +7,10 @@ import lombok.ToString;
7 7 import javax.validation.constraints.NotEmpty;
8 8 import javax.validation.constraints.NotNull;
9 9  
10   -// TODO @puhui999:ReqVO
11 10 @Schema(description = "管理后台 - 商品评价可见修改 Request VO")
12 11 @Data
13 12 @ToString(callSuper = true)
14   -public class ProductCommentReplyVO {
  13 +public class ProductCommentReplyReqVO {
15 14  
16 15 @Schema(description = "评价编号", required = true, example = "15721")
17 16 @NotNull(message = "评价编号不能为空")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentRespVO.java
... ... @@ -16,7 +16,7 @@ public class ProductCommentRespVO extends ProductCommentBaseVO {
16 16 @Schema(description = "订单项编号", required = true, example = "24965")
17 17 private Long id;
18 18  
19   - @Schema(description = "是否匿名:[false:不匿名 true:匿名]", required = true)
  19 + @Schema(description = "是否匿名:[false:不匿名 true:匿名]", required = true, example = "false")
20 20 private Boolean anonymous;
21 21  
22 22 @Schema(description = "交易订单编号", required = true, example = "24428")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppCommentController.java renamed to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java
1 1 package cn.iocoder.yudao.module.product.controller.app.comment;
2 2  
3   -import cn.hutool.core.map.MapUtil;
4 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6   -import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
7   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
8   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentCreateReqVO;
9 5 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
10   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO;
  6 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
  7 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
11 8 import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
12   -import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
13 9 import cn.iocoder.yudao.module.product.service.comment.ProductCommentService;
14 10 import io.swagger.v3.oas.annotations.Operation;
15 11 import io.swagger.v3.oas.annotations.Parameter;
16 12 import io.swagger.v3.oas.annotations.Parameters;
17 13 import io.swagger.v3.oas.annotations.tags.Tag;
18 14 import org.springframework.validation.annotation.Validated;
19   -import org.springframework.web.bind.annotation.*;
  15 +import org.springframework.web.bind.annotation.GetMapping;
  16 +import org.springframework.web.bind.annotation.RequestMapping;
  17 +import org.springframework.web.bind.annotation.RequestParam;
  18 +import org.springframework.web.bind.annotation.RestController;
20 19  
21 20 import javax.annotation.Resource;
22 21 import javax.validation.Valid;
23 22 import java.time.LocalDateTime;
24   -import java.util.*;
  23 +import java.util.ArrayList;
  24 +import java.util.Arrays;
  25 +import java.util.List;
  26 +import java.util.Random;
25 27  
26 28 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27   -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
28 29  
29   -// TODO @puhui999:AppCommentController =》 AppProductCommentController
30 30 @Tag(name = "用户 APP - 商品评价")
31 31 @RestController
32 32 @RequestMapping("/product/comment")
33 33 @Validated
34   -public class AppCommentController {
  34 +public class AppProductCommentController {
35 35  
36 36 @Resource
37 37 private ProductCommentService productCommentService;
38 38  
39   - @Resource
40   - private MemberUserApi memberUserApi;
41   -
42 39 @GetMapping("/list")
43 40 @Operation(summary = "获得最近的 n 条商品评价")
44 41 @Parameters({
45 42 @Parameter(name = "spuId", description = "商品 SPU 编号", required = true, example = "1024"),
46 43 @Parameter(name = "count", description = "数量", required = true, example = "10")
47 44 })
48   - public CommonResult<List<AppCommentRespVO>> getCommentList(@RequestParam("spuId") Long spuId,
49   - @RequestParam(value = "count", defaultValue = "10") Integer count) {
  45 + public CommonResult<List<AppProductCommentRespVO>> getCommentList(@RequestParam("spuId") Long spuId,
  46 + @RequestParam(value = "count", defaultValue = "10") Integer count) {
50 47  
51 48 List<AppProductPropertyValueDetailRespVO> list = new ArrayList<>();
52 49  
... ... @@ -72,7 +69,7 @@ public class AppCommentController {
72 69 list.add(item3);
73 70  
74 71 // TODO 生成 mock 的数据
75   - AppCommentRespVO appCommentRespVO = new AppCommentRespVO();
  72 + AppProductCommentRespVO appCommentRespVO = new AppProductCommentRespVO();
76 73 appCommentRespVO.setUserId((long) (new Random().nextInt(100000) + 10000));
77 74 appCommentRespVO.setUserNickname("用户" + new Random().nextInt(100));
78 75 appCommentRespVO.setUserAvatar("https://demo26.crmeb.net/uploads/attach/2021/11/15/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
... ... @@ -85,7 +82,6 @@ public class AppCommentController {
85 82 appCommentRespVO.setReplyContent("回复内容" + new Random().nextInt(100));
86 83 appCommentRespVO.setReplyTime(LocalDateTime.now().minusDays(new Random().nextInt(30)));
87 84 appCommentRespVO.setCreateTime(LocalDateTime.now().minusDays(new Random().nextInt(30)));
88   - appCommentRespVO.setFinalScore(new Random().nextInt(5) + 1);
89 85 appCommentRespVO.setSpuId((long) (new Random().nextInt(100000) + 10000));
90 86 appCommentRespVO.setSpuName("商品" + new Random().nextInt(100));
91 87 appCommentRespVO.setSkuId((long) (new Random().nextInt(100000) + 10000));
... ... @@ -101,30 +97,14 @@ public class AppCommentController {
101 97  
102 98 @GetMapping("/page")
103 99 @Operation(summary = "获得商品评价分页")
104   - public CommonResult<PageResult<AppCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
  100 + public CommonResult<PageResult<AppProductCommentRespVO>> getCommentPage(@Valid AppCommentPageReqVO pageVO) {
105 101 return success(productCommentService.getCommentPage(pageVO, Boolean.TRUE));
106 102 }
107 103  
108   - // TODO @puhui999:方法名改成 getCommentStatistics?然后搞个对应的 vo?想了下,这样更优雅
109   - @GetMapping("/statistics")
110   - @Operation(summary = "获得商品的评价统计") // TODO @puhui999:@RequestParam 哈,针对 spuId
111   - public CommonResult<Map<String, Object>> getCommentStatistics(@Valid Long spuId) {
112   - // TODO 生成 mock 的数据
113   - if (true) {
114   - return success(MapUtil.<String, Object>builder("allCount", 10L).put("goodPercent", "10.33").build());
115   - }
116   - return null;
117   -// return success(productCommentService.getCommentPageTabsCount(spuId, Boolean.TRUE));
118   - }
119   -
120   - @PostMapping(value = "/create")
121   - @Operation(summary = "创建商品评价")
122   - public CommonResult<Boolean> createComment(@RequestBody AppCommentCreateReqVO createReqVO) {
123   - // TODO: 2023/3/20 要不要判断订单、商品是否存在
124   - // TODO @ouhui999:这个接口,搞到交易那比较合适;
125   - MemberUserRespDTO user = memberUserApi.getUser(getLoginUserId());
126   - productCommentService.createComment(ProductCommentConvert.INSTANCE.convert(user, createReqVO), Boolean.FALSE);
127   - return success(true);
  104 + @GetMapping("/getCommentStatistics")
  105 + @Operation(summary = "获得商品的评价统计")
  106 + public CommonResult<AppCommentStatisticsRespVO> getCommentPage(@Valid @RequestParam("spuId") Long spuId) {
  107 + return success(productCommentService.getCommentPageTabsCount(spuId, Boolean.TRUE));
128 108 }
129 109  
130 110 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentCreateReqVO.java deleted
1   -package cn.iocoder.yudao.module.product.controller.app.comment.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -
8   -import javax.validation.constraints.NotNull;
9   -
10   -// TODO @puhui999:不应该继承 AppCommentCreateReqVO
11   -@Schema(description = "用户APP - 商品评价创建 Request VO")
12   -@Data
13   -@EqualsAndHashCode(callSuper = true)
14   -@ToString(callSuper = true)
15   -public class AppCommentCreateReqVO extends AppCommentBaseVO {
16   -
17   - @Schema(description = "是否匿名", required = true, example = "true")
18   - @NotNull(message = "是否匿名不能为空")
19   - private Boolean anonymous;
20   -
21   - // TODO @puhui999:不应该传递 orderId
22   -
23   - @Schema(description = "交易订单编号", required = true, example = "12312")
24   - @NotNull(message = "交易订单编号不能为空")
25   - private Long orderId;
26   -
27   - @Schema(description = "交易订单项编号", required = true, example = "2312312")
28   - @NotNull(message = "交易订单项编号不能为空")
29   - private Long orderItemId;
30   -
31   -}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentPageReqVO.java
... ... @@ -8,34 +8,21 @@ import lombok.ToString;
8 8  
9 9 import javax.validation.constraints.NotNull;
10 10  
  11 +/**
  12 + * 用户 APP - 商品评价分页 Request VO
  13 + *
  14 + * @author HUIHUI
  15 + */
11 16 @Schema(description = "用户APP - 商品评价分页 Request VO")
12 17 @Data
13 18 @EqualsAndHashCode(callSuper = true)
14 19 @ToString(callSuper = true)
15 20 public class AppCommentPageReqVO extends PageParam {
16 21  
17   - // TODO @puhui999:不传递就是 all;
18   - /**
19   - * 所有
20   - */
21   - public static final Integer ALL = 0;
22   -
23   - /**
24   - * 所有数量 key
25   - */
26   - public static final String ALL_COUNT = "allCount";
27   -
28   - // TODO @puhui999:good 好评;
29 22 /**
30 23 * 好评
31 24 */
32   - public static final Integer FAVOURABLE_COMMENT = 1;
33   -
34   - // TODO @puhui999:medium 中评;然后 mediumCount 就好啦;
35   - /**
36   - * 好评数量 key
37   - */
38   - public static final String FAVOURABLE_COMMENT_COUNT = "favourableCommentCount";
  25 + public static final Integer GOOD_COMMENT = 1;
39 26  
40 27 /**
41 28 * 中评
... ... @@ -43,26 +30,10 @@ public class AppCommentPageReqVO extends PageParam {
43 30 public static final Integer MEDIOCRE_COMMENT = 2;
44 31  
45 32 /**
46   - * 中评数量 key
47   - */
48   - public static final String MEDIOCRE_COMMENT_COUNT = "mediocreCommentCount";
49   -
50   - /**
51 33 * 差评
52 34 */
53 35 public static final Integer NEGATIVE_COMMENT = 3;
54 36  
55   - /**
56   - * 差评数量 key
57   - */
58   - public static final String NEGATIVE_COMMENT_COUNT = "negativeCommentCount";
59   -
60   - // TODO @puhui999:这个挪到 DO 那没问题的哈;NICKNAME_ANONYMOUS
61   - /**
62   - * 默认匿名昵称
63   - */
64   - public static final String ANONYMOUS_NICKNAME = "匿名用户";
65   -
66 37 @Schema(description = "商品SPU编号", example = "29502")
67 38 @NotNull(message = "商品SPU编号不能为空")
68 39 private Long spuId;
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentRespVO.java deleted
1   -package cn.iocoder.yudao.module.product.controller.app.comment.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.ToString;
7   -
8   -import java.time.LocalDateTime;
9   -
10   -@Schema(description = "用户APP - 商品评价 Response VO")
11   -@Data
12   -@EqualsAndHashCode(callSuper = true)
13   -@ToString(callSuper = true)
14   -public class AppCommentRespVO extends AppCommentBaseVO {
15   -
16   - // TODO puhui999:把 example 也补充下哈
17   -
18   - @Schema(description = "评价人的用户编号", required = true, example = "15721")
19   - private Long userId;
20   -
21   - @Schema(description = "评价人名称", required = true, example = "张三")
22   - private String userNickname;
23   -
24   - @Schema(description = "评价人头像", required = true)
25   - private String userAvatar;
26   -
27   - @Schema(description = "订单项编号", required = true, example = "24965")
28   - private Long id;
29   -
30   - @Schema(description = "是否匿名", required = true)
31   - private Boolean anonymous;
32   -
33   - @Schema(description = "交易订单编号", required = true, example = "24428")
34   - private Long orderId;
35   -
36   - @Schema(description = "交易订单项编号", required = true, example = "8233")
37   - private Long orderItemId;
38   -
39   - @Schema(description = "商家是否回复", required = true)
40   - private Boolean replyStatus;
41   -
42   - @Schema(description = "回复管理员编号", example = "22212")
43   - private Long replyUserId;
44   -
45   - @Schema(description = "商家回复内容")
46   - private String replyContent;
47   -
48   - @Schema(description = "商家回复时间")
49   - private LocalDateTime replyTime;
50   -
51   - @Schema(description = "创建时间", required = true)
52   - private LocalDateTime createTime;
53   -
54   - @Schema(description = "最终评分", required = true)
55   - private Integer finalScore;
56   -
57   -}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentStatisticsRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.comment.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +
  7 +/**
  8 + * APP 商品评价页评论分类数统计 Response VO
  9 + *
  10 + * @author HUIHUI
  11 + */
  12 +@Schema(description = "APP - 商品评价页评论分类数统计 Response VO")
  13 +@Data
  14 +@ToString(callSuper = true)
  15 +public class AppCommentStatisticsRespVO {
  16 +
  17 + @Schema(description = "所有评论数量", required = true, example = "15721")
  18 + private Long allCount;
  19 +
  20 + @Schema(description = "好评数量", required = true, example = "15721")
  21 + private Long goodCount;
  22 +
  23 + @Schema(description = "中评数量", required = true, example = "15721")
  24 + private Long mediocreCount;
  25 +
  26 + @Schema(description = "差评数量", required = true, example = "15721")
  27 + private Long negativeCount;
  28 +
  29 +}
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentBaseVO.java renamed to yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentCreateReqVO.java
1 1 package cn.iocoder.yudao.module.product.controller.app.comment.vo;
2 2  
3   -import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
4 3 import io.swagger.v3.oas.annotations.media.Schema;
5 4 import lombok.Data;
  5 +import lombok.ToString;
6 6  
7 7 import javax.validation.constraints.NotNull;
8 8 import javax.validation.constraints.Size;
9 9 import java.util.List;
10 10  
11   -// TODO @puhui999:C 端可以不要 base 哈。
  11 +/**
  12 + * 用户APP - 商品评价创建 Request VO
  13 + *
  14 + * @author HUIHUI
  15 + */
  16 +@Schema(description = "用户APP - 商品评价创建 Request VO")
12 17 @Data
13   -public class AppCommentBaseVO {
  18 +@ToString(callSuper = true)
  19 +public class AppProductCommentCreateReqVO {
14 20  
15   - @Schema(description = "商品SPU编号", required = true, example = "29502")
  21 + @Schema(description = "是否匿名", required = true, example = "true")
  22 + @NotNull(message = "是否匿名不能为空")
  23 + private Boolean anonymous;
  24 +
  25 + @Schema(description = "交易订单项编号", required = true, example = "2312312")
  26 + @NotNull(message = "交易订单项编号不能为空")
  27 + private Long orderItemId;
  28 +
  29 + @Schema(description = "商品SPU编号", required = true, example = "91192")
16 30 @NotNull(message = "商品SPU编号不能为空")
17 31 private Long spuId;
18 32  
19   - @Schema(description = "商品SPU名称", required = true, example = "赵六")
  33 + @Schema(description = "商品SPU名称", required = true, example = "清凉丝滑小短袖")
20 34 @NotNull(message = "商品SPU名称不能为空")
21 35 private String spuName;
22 36  
23   - @Schema(description = "商品SKU编号", required = true, example = "3082")
  37 + @Schema(description = "商品SKU编号", required = true, example = "81192")
24 38 @NotNull(message = "商品SKU编号不能为空")
25 39 private Long skuId;
26 40  
27   - @Schema(description = "商品 SKU 属性", required = true)
28   - private List<AppProductPropertyValueDetailRespVO> skuProperties; // TODO puhui999:这个需要从数据库查询哈
29   -
30   - @Schema(description = "评分星级 1-5分", required = true)
  41 + @Schema(description = "评分星级 1-5分", required = true, example = "5")
31 42 @NotNull(message = "评分星级 1-5分不能为空")
32 43 private Integer scores;
33 44  
34   - @Schema(description = "描述星级 1-5分", required = true)
  45 + @Schema(description = "描述星级 1-5分", required = true, example = "5")
35 46 @NotNull(message = "描述星级 1-5分不能为空")
36 47 private Integer descriptionScores;
37 48  
38   - @Schema(description = "服务星级 1-5分", required = true)
  49 + @Schema(description = "服务星级 1-5分", required = true, example = "5")
39 50 @NotNull(message = "服务星级 1-5分不能为空")
40 51 private Integer benefitScores;
41 52  
42   - @Schema(description = "评论内容", required = true)
  53 + @Schema(description = "评论内容", required = true, example = "哇,真的很丝滑凉快诶,好评")
43 54 @NotNull(message = "评论内容不能为空")
44 55 private String content;
45 56  
46   - @Schema(description = "评论图片地址数组,以逗号分隔最多上传9张", required = true)
  57 + @Schema(description = "评论图片地址数组,以逗号分隔最多上传9张", required = true, example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]")
47 58 @Size(max = 9, message = "评论图片地址数组长度不能超过9张")
48 59 private List<String> picUrls;
49 60  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppProductCommentRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.app.comment.vo;
  2 +
  3 +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.ToString;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +import javax.validation.constraints.Size;
  11 +import java.time.LocalDateTime;
  12 +import java.util.List;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  15 +
  16 +/**
  17 + * 用户APP - 商品评价详情 Response VO
  18 + *
  19 + * @author HUIHUI
  20 + */
  21 +@Schema(description = "用户APP - 商品评价详情 Response VO")
  22 +@Data
  23 +@ToString(callSuper = true)
  24 +public class AppProductCommentRespVO {
  25 +
  26 + @Schema(description = "评价人的用户编号", required = true, example = "15721")
  27 + private Long userId;
  28 +
  29 + @Schema(description = "评价人名称", required = true, example = "张三")
  30 + private String userNickname;
  31 +
  32 + @Schema(description = "评价人头像", required = true, example = "https://www.iocoder.cn/xx.png")
  33 + private String userAvatar;
  34 +
  35 + @Schema(description = "订单项编号", required = true, example = "24965")
  36 + private Long id;
  37 +
  38 + @Schema(description = "是否匿名", required = true, example = "false")
  39 + private Boolean anonymous;
  40 +
  41 + @Schema(description = "交易订单编号", required = true, example = "24428")
  42 + private Long orderId;
  43 +
  44 + @Schema(description = "交易订单项编号", required = true, example = "8233")
  45 + private Long orderItemId;
  46 +
  47 + @Schema(description = "商家是否回复", required = true, example = "true")
  48 + private Boolean replyStatus;
  49 +
  50 + @Schema(description = "回复管理员编号", example = "22212")
  51 + private Long replyUserId;
  52 +
  53 + @Schema(description = "商家回复内容", example = "亲,你的好评就是我的动力(*^▽^*)")
  54 + private String replyContent;
  55 +
  56 + @Schema(description = "商家回复时间")
  57 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  58 + private LocalDateTime replyTime;
  59 +
  60 + @Schema(description = "追加评价内容", example = "穿了很久都很丝滑诶")
  61 + private String additionalContent;
  62 +
  63 + @Schema(description = "追评评价图片地址数组,以逗号分隔最多上传9张", example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]")
  64 + private List<String> additionalPicUrls;
  65 +
  66 + @Schema(description = "追加评价时间")
  67 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  68 + private LocalDateTime additionalTime;
  69 +
  70 + @Schema(description = "创建时间")
  71 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  72 + private LocalDateTime createTime;
  73 +
  74 + @Schema(description = "商品SPU编号", required = true, example = "91192")
  75 + @NotNull(message = "商品SPU编号不能为空")
  76 + private Long spuId;
  77 +
  78 + @Schema(description = "商品SPU名称", required = true, example = "清凉丝滑小短袖")
  79 + @NotNull(message = "商品SPU名称不能为空")
  80 + private String spuName;
  81 +
  82 + @Schema(description = "商品SKU编号", required = true, example = "81192")
  83 + @NotNull(message = "商品SKU编号不能为空")
  84 + private Long skuId;
  85 +
  86 + @Schema(description = "商品 SKU 属性", required = true)
  87 + private List<AppProductPropertyValueDetailRespVO> skuProperties;
  88 +
  89 + @Schema(description = "评分星级 1-5分", required = true, example = "5")
  90 + @NotNull(message = "评分星级 1-5分不能为空")
  91 + private Integer scores;
  92 +
  93 + @Schema(description = "描述星级 1-5分", required = true, example = "5")
  94 + @NotNull(message = "描述星级 1-5分不能为空")
  95 + private Integer descriptionScores;
  96 +
  97 + @Schema(description = "服务星级 1-5分", required = true, example = "5")
  98 + @NotNull(message = "服务星级 1-5分不能为空")
  99 + private Integer benefitScores;
  100 +
  101 + @Schema(description = "评论内容", required = true, example = "哇,真的很丝滑凉快诶,好评")
  102 + @NotNull(message = "评论内容不能为空")
  103 + private String content;
  104 +
  105 + @Schema(description = "评论图片地址数组,以逗号分隔最多上传9张", required = true, example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xxx.png]")
  106 + @Size(max = 9, message = "评论图片地址数组长度不能超过9张")
  107 + private List<String> picUrls;
  108 +
  109 +}
... ...
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 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
  4 +import cn.iocoder.yudao.module.product.api.comment.dto.CommentCreateReqDTO;
5 5 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO;
6 6 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentRespVO;
7   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentCreateReqVO;
8   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO;
  7 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
  8 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
  9 +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
9 10 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
  11 +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
10 12 import org.mapstruct.Mapper;
  13 +import org.mapstruct.Mapping;
  14 +import org.mapstruct.Named;
11 15 import org.mapstruct.factory.Mappers;
12 16  
  17 +import java.math.BigDecimal;
  18 +import java.math.RoundingMode;
13 19 import java.util.List;
14 20  
15 21 /**
... ... @@ -24,50 +30,44 @@ public interface ProductCommentConvert {
24 30  
25 31 ProductCommentRespVO convert(ProductCommentDO bean);
26 32  
  33 + @Mapping(target = "allCount", source = "allCount")
  34 + @Mapping(target = "goodCount", source = "goodCount")
  35 + @Mapping(target = "mediocreCount", source = "mediocreCount")
  36 + @Mapping(target = "negativeCount", source = "negativeCount")
  37 + AppCommentStatisticsRespVO convert(Long allCount, Long goodCount, Long mediocreCount, Long negativeCount);
  38 +
27 39 List<ProductCommentRespVO> convertList(List<ProductCommentDO> list);
28 40  
  41 + List<AppProductPropertyValueDetailRespVO> convertList01(List<ProductSkuDO.Property> properties);
  42 +
29 43 PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> page);
30 44  
31   - PageResult<AppCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult);
  45 + PageResult<AppProductCommentRespVO> convertPage02(PageResult<ProductCommentDO> pageResult);
32 46  
33   - // TODO @puhui999:用 mapstruct 的映射
34   - default ProductCommentDO convert(MemberUserRespDTO user, AppCommentCreateReqVO createReqVO) {
35   - ProductCommentDO productComment = new ProductCommentDO();
36   - productComment.setUserId(user.getId());
37   - productComment.setUserNickname(user.getNickname());
38   - productComment.setUserAvatar(user.getAvatar());
39   - productComment.setAnonymous(createReqVO.getAnonymous());
40   - productComment.setOrderId(createReqVO.getOrderId());
41   - productComment.setOrderItemId(createReqVO.getOrderItemId());
42   - productComment.setSpuId(createReqVO.getSpuId());
43   - productComment.setSpuName(createReqVO.getSpuName());
44   - productComment.setSkuId(createReqVO.getSkuId());
45   - productComment.setScores(createReqVO.getScores());
46   - productComment.setDescriptionScores(createReqVO.getDescriptionScores());
47   - productComment.setBenefitScores(createReqVO.getBenefitScores());
48   - productComment.setContent(createReqVO.getContent());
49   - productComment.setPicUrls(createReqVO.getPicUrls());
50   - return productComment;
  47 + /**
  48 + * 计算综合评分
  49 + *
  50 + * @param descriptionScores 描述星级
  51 + * @param benefitScores 服务星级
  52 + * @return {@link Integer}
  53 + */
  54 + @Named("convertScores")
  55 + default Integer convertScores(Integer descriptionScores, Integer benefitScores) {
  56 + // 计算评价最终综合评分 最终星数 = (商品评星 + 服务评星) / 2
  57 + BigDecimal sumScore = new BigDecimal(descriptionScores + benefitScores);
  58 + BigDecimal divide = sumScore.divide(BigDecimal.valueOf(2L), 0, RoundingMode.DOWN);
  59 + return divide.intValue();
51 60 }
52 61  
53   - // TODO @puhui999:用 mapstruct 的映射
54   - default ProductCommentDO convert(ProductCommentCreateReqVO createReq) {
55   - ProductCommentDO productComment = new ProductCommentDO();
56   - productComment.setUserId(0L);
57   - productComment.setUserNickname(createReq.getUserNickname());
58   - productComment.setUserAvatar(createReq.getUserAvatar());
59   - productComment.setAnonymous(Boolean.FALSE);
60   - productComment.setOrderId(0L);
61   - productComment.setOrderItemId(0L);
62   - productComment.setSpuId(createReq.getSpuId());
63   - productComment.setSpuName(createReq.getSpuName());
64   - productComment.setSkuId(createReq.getSkuId());
65   - productComment.setScores(createReq.getScores());
66   - productComment.setDescriptionScores(createReq.getDescriptionScores());
67   - productComment.setBenefitScores(createReq.getBenefitScores());
68   - productComment.setContent(createReq.getContent());
69   - productComment.setPicUrls(createReq.getPicUrls());
70   - return productComment;
71   - }
  62 + @Mapping(target = "orderId", source = "orderId")
  63 + @Mapping(target = "scores", expression = "java(convertScores(createReqDTO.getDescriptionScores(), createReqDTO.getBenefitScores()))")
  64 + ProductCommentDO convert(CommentCreateReqDTO createReqDTO, Long orderId);
  65 +
  66 + @Mapping(target = "userId", constant = "0L")
  67 + @Mapping(target = "orderId", constant = "0L")
  68 + @Mapping(target = "orderItemId", constant = "0L")
  69 + @Mapping(target = "anonymous", expression = "java(Boolean.FALSE)")
  70 + @Mapping(target = "scores", expression = "java(convertScores(createReq.getDescriptionScores(), createReq.getBenefitScores()))")
  71 + ProductCommentDO convert(ProductCommentCreateReqVO createReq);
72 72  
73 73 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/comment/ProductCommentDO.java
... ... @@ -29,6 +29,11 @@ import java.util.List;
29 29 public class ProductCommentDO extends BaseDO {
30 30  
31 31 /**
  32 + * 默认匿名昵称
  33 + */
  34 + public static final String NICKNAME_ANONYMOUS = "匿名用户";
  35 +
  36 + /**
32 37 * 评论编号,主键自增
33 38 */
34 39 @TableId
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/comment/ProductCommentMapper.java
... ... @@ -6,14 +6,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
7 7 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
8 8 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO;
9   -import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyVO;
10 9 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
11 10 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
12   -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
13 11 import org.apache.ibatis.annotations.Mapper;
14 12  
15   -import java.time.LocalDateTime;
16   -
17 13 @Mapper
18 14 public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
19 15  
... ... @@ -31,7 +27,7 @@ public interface ProductCommentMapper extends BaseMapperX&lt;ProductCommentDO&gt; {
31 27 // TODO 芋艿:在看看这块
32 28 static void appendTabQuery(LambdaQueryWrapperX<ProductCommentDO> queryWrapper, Integer type) {
33 29 // 构建好评查询语句:好评计算 (商品评分星级+服务评分星级) >= 8
34   - if (ObjectUtil.equal(type, AppCommentPageReqVO.FAVOURABLE_COMMENT)) {
  30 + if (ObjectUtil.equal(type, AppCommentPageReqVO.GOOD_COMMENT)) {
35 31 queryWrapper.apply("(scores + benefit_scores) >= 8");
36 32 }
37 33 // 构建中评查询语句:中评计算 (商品评分星级+服务评分星级) > 4 且 (商品评分星级+服务评分星级) < 8
... ... @@ -55,33 +51,14 @@ public interface ProductCommentMapper extends BaseMapperX&lt;ProductCommentDO&gt; {
55 51 return selectPage(reqVO, queryWrapper);
56 52 }
57 53  
58   - default void updateCommentVisible(Long id, Boolean visible) {
59   - LambdaUpdateWrapper<ProductCommentDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<ProductCommentDO>()
60   - .set(ProductCommentDO::getVisible, visible)
61   - .eq(ProductCommentDO::getId, id);
62   - update(null, lambdaUpdateWrapper);
63   - }
64   -
65   - default void commentReply(ProductCommentReplyVO replyVO, Long loginUserId) {
66   - LambdaUpdateWrapper<ProductCommentDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<ProductCommentDO>()
67   - .set(ProductCommentDO::getReplyStatus, Boolean.TRUE)
68   - .set(ProductCommentDO::getReplyTime, LocalDateTime.now())
69   - .set(ProductCommentDO::getReplyUserId, loginUserId)
70   - .set(ProductCommentDO::getReplyContent, replyVO.getReplyContent())
71   - .eq(ProductCommentDO::getId, replyVO.getId());
72   - update(null, lambdaUpdateWrapper);
73   - }
74   -
75   - // TODO @puhui999:使用 select 替代 find
76   - default ProductCommentDO findByUserIdAndOrderIdAndSpuId(Long userId, Long orderId, Long spuId) {
  54 + default ProductCommentDO selectByUserIdAndOrderIdAndSpuId(Long userId, Long orderId, Long spuId) {
77 55 return selectOne(new LambdaQueryWrapperX<ProductCommentDO>()
78 56 .eq(ProductCommentDO::getUserId, userId)
79 57 .eq(ProductCommentDO::getOrderId, orderId)
80 58 .eq(ProductCommentDO::getSpuId, spuId));
81 59 }
82 60  
83   - // TODO @puhui999:selectCountBySpuId 即可
84   - default Long selectTabCount(Long spuId, Boolean visible, Integer type) {
  61 + default Long selectCountBySpuId(Long spuId, Boolean visible, Integer type) {
85 62 LambdaQueryWrapperX<ProductCommentDO> queryWrapper = new LambdaQueryWrapperX<ProductCommentDO>()
86 63 .eqIfPresent(ProductCommentDO::getSpuId, spuId)
87 64 .eqIfPresent(ProductCommentDO::getVisible, visible);
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentService.java
1 1 package cn.iocoder.yudao.module.product.service.comment;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO;
4 5 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO;
5   -import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyVO;
  6 +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO;
6 7 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO;
7 8 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
8   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO;
  9 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
  10 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
9 11 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
10 12 import org.springframework.stereotype.Service;
11 13 import org.springframework.validation.annotation.Validated;
12 14  
13   -import java.util.Map;
14   -
15 15 /**
16 16 * 商品评论 Service 接口
17 17 *
... ... @@ -36,14 +36,13 @@ public interface ProductCommentService {
36 36 */
37 37 void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO);
38 38  
39   - // TODO @puhui999:replyComment
40 39 /**
41 40 * 商家回复
42 41 *
43 42 * @param replyVO 商家回复
44 43 * @param loginUserId 管理后台商家登陆人 ID
45 44 */
46   - void commentReply(ProductCommentReplyVO replyVO, Long loginUserId);
  45 + void replyComment(ProductCommentReplyReqVO replyVO, Long loginUserId);
47 46  
48 47 /**
49 48 * 获得商品评价分页
... ... @@ -52,15 +51,23 @@ public interface ProductCommentService {
52 51 * @param visible 是否可见
53 52 * @return 商品评价分页
54 53 */
55   - PageResult<AppCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
  54 + PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
  55 +
  56 + /**
  57 + * 创建商品评论 后台管理员创建评论使用
  58 + *
  59 + * @param createReqVO 商品评价创建 Request VO 对象
  60 + */
  61 + void createComment(ProductCommentCreateReqVO createReqVO);
56 62  
57 63 /**
58   - * 创建商品评论
  64 + * 创建评论
  65 + * 创建商品评论 APP 端创建商品评论使用
59 66 *
60   - * @param productComment 创建实体
61   - * @param system 是否系统评价
  67 + * @param commentDO 评论对象
  68 + * @return 返回评论 id
62 69 */
63   - void createComment(ProductCommentDO productComment, Boolean system);
  70 + Long createComment(ProductCommentDO commentDO);
64 71  
65 72 /**
66 73 * 获得商品的评价统计
... ... @@ -69,6 +76,6 @@ public interface ProductCommentService {
69 76 * @param visible 是否可见
70 77 * @return 评价统计
71 78 */
72   - Map<String, Long> getCommentPageTabsCount(Long spuId, Boolean visible);
  79 + AppCommentStatisticsRespVO getCommentPageTabsCount(Long spuId, Boolean visible);
73 80  
74 81 }
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
1 1 package cn.iocoder.yudao.module.product.service.comment;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.util.ObjectUtil;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO;
5 7 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO;
6   -import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyVO;
  8 +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO;
7 9 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO;
8 10 import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO;
9   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO;
  11 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
  12 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
  13 +import cn.iocoder.yudao.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
10 14 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
11 15 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
  16 +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
12 17 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
13 18 import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
  19 +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
14 20 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
15 21 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
16   -import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
  22 +import org.springframework.context.annotation.Lazy;
17 23 import org.springframework.stereotype.Service;
  24 +import org.springframework.transaction.annotation.Transactional;
18 25 import org.springframework.validation.annotation.Validated;
19 26  
20 27 import javax.annotation.Resource;
21   -import java.math.BigDecimal;
22   -import java.math.RoundingMode;
  28 +import java.time.LocalDateTime;
23 29 import java.util.HashMap;
  30 +import java.util.List;
24 31 import java.util.Map;
  32 +import java.util.Set;
  33 +import java.util.stream.Collectors;
25 34  
26 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
27 36 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*;
28   -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
29 37  
30 38 /**
31 39 * 商品评论 Service 实现类
... ... @@ -45,95 +53,120 @@ public class ProductCommentServiceImpl implements ProductCommentService {
45 53 @Resource
46 54 private ProductSpuService productSpuService;
47 55  
48   - @Override
49   - public PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO) {
50   - return productCommentMapper.selectPage(pageReqVO);
51   - }
  56 + @Resource
  57 + @Lazy
  58 + private ProductSkuService productSkuService;
52 59  
53 60 @Override
  61 + @Transactional(rollbackFor = Exception.class)
54 62 public void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO) {
55 63 // 校验评论是否存在
56   - validateCommentExists(updateReqVO.getId());
  64 + ProductCommentDO productCommentDO = validateCommentExists(updateReqVO.getId());
  65 + productCommentDO.setVisible(updateReqVO.getVisible());
57 66  
58 67 // 更新可见状态
59   - // TODO @puhui999:直接使用 update 操作
60   - productCommentMapper.updateCommentVisible(updateReqVO.getId(), updateReqVO.getVisible());
  68 + productCommentMapper.updateById(productCommentDO);
61 69 }
62 70  
63 71 @Override
64   - public void commentReply(ProductCommentReplyVO replyVO, Long loginUserId) {
  72 + @Transactional(rollbackFor = Exception.class)
  73 + public void replyComment(ProductCommentReplyReqVO replyVO, Long loginUserId) {
65 74 // 校验评论是否存在
66   - validateCommentExists(replyVO.getId());
  75 + ProductCommentDO productCommentDO = validateCommentExists(replyVO.getId());
  76 + productCommentDO.setReplyTime(LocalDateTime.now());
  77 + productCommentDO.setReplyUserId(loginUserId);
  78 + productCommentDO.setReplyStatus(Boolean.TRUE);
  79 + productCommentDO.setReplyContent(replyVO.getReplyContent());
67 80  
68 81 // 回复评论
69   - // TODO @puhui999:直接使用 update 操作
70   - productCommentMapper.commentReply(replyVO, loginUserId);
  82 + productCommentMapper.updateById(productCommentDO);
71 83 }
72 84  
73 85 @Override
74   - public Map<String, Long> getCommentPageTabsCount(Long spuId, Boolean visible) {
75   - Map<String, Long> countMap = new HashMap<>(4);
76   - // 查询商品 id = spuId 的所有评论数量
77   - countMap.put(AppCommentPageReqVO.ALL_COUNT,
78   - productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.ALL));
79   - // 查询商品 id = spuId 的所有好评数量
80   - countMap.put(AppCommentPageReqVO.FAVOURABLE_COMMENT_COUNT,
81   - productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.FAVOURABLE_COMMENT));
82   - // 查询商品 id = spuId 的所有中评数量
83   - countMap.put(AppCommentPageReqVO.MEDIOCRE_COMMENT_COUNT,
84   - productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT));
85   - // 查询商品 id = spuId 的所有差评数量
86   - countMap.put(AppCommentPageReqVO.NEGATIVE_COMMENT_COUNT,
87   - productCommentMapper.selectTabCount(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT));
88   - return countMap;
  86 + @Transactional(rollbackFor = Exception.class)
  87 + public void createComment(ProductCommentCreateReqVO createReqVO) {
  88 + // 校验订单
  89 + Long orderId = tradeOrderApi.validateOrder(createReqVO.getUserId(), createReqVO.getOrderItemId());
  90 + // 校验评论
  91 + validateComment(createReqVO.getSpuId(), createReqVO.getUserId(), orderId);
  92 +
  93 + ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqVO);
  94 + productCommentMapper.insert(commentDO);
89 95 }
90 96  
91 97 @Override
92   - public PageResult<AppCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
93   - // TODO @puhui999:逻辑可以在 controller 做哈。让 service 简介一点;因为是 view 需要不展示昵称
94   - PageResult<AppCommentRespVO> result = ProductCommentConvert.INSTANCE.convertPage02(productCommentMapper.selectPage(pageVO, visible));
95   - result.getList().forEach(item -> {
96   - // 判断用户是否选择匿名
97   - if (ObjectUtil.equal(item.getAnonymous(), true)) {
98   - item.setUserNickname(AppCommentPageReqVO.ANONYMOUS_NICKNAME);
99   - }
100   - // TODO @puhui999:直接插入的时候,计算到 scores 字段里;这样就去掉 finalScore 字段哈
101   - // 计算评价最终综合评分 最终星数 = (商品评星 + 服务评星) / 2
102   - BigDecimal sumScore = new BigDecimal(item.getScores() + item.getBenefitScores());
103   - BigDecimal divide = sumScore.divide(BigDecimal.valueOf(2L), 0, RoundingMode.DOWN);
104   - item.setFinalScore(divide.intValue());
105   - });
106   - return result;
  98 + @Transactional(rollbackFor = Exception.class)
  99 + public Long createComment(ProductCommentDO commentDO) {
  100 + // 校验评论
  101 + validateComment(commentDO.getSpuId(), commentDO.getUserId(), commentDO.getOrderId());
  102 +
  103 + productCommentMapper.insert(commentDO);
  104 + return commentDO.getId();
107 105 }
108 106  
109   - @Override
110   - public void createComment(ProductCommentDO productComment, Boolean system) {
111   - // TODO @puhui999:这里不区分是否为 system;直接都校验
112   - if (!system) {
113   - // TODO 判断订单是否存在 fix;
114   - // TODO @puhui999:改成 order 那有个 comment 接口,哪里校验下;商品评论这里不校验订单是否存在哈
115   - TradeOrderRespDTO order = tradeOrderApi.getOrder(productComment.getOrderId());
116   - if (null == order) {
117   - throw exception(ORDER_NOT_FOUND);
118   - }
119   - ProductSpuDO spu = productSpuService.getSpu(productComment.getSpuId());
120   - if (null == spu) {
121   - throw exception(SPU_NOT_EXISTS);
122   - }
123   - // 判断当前订单的当前商品用户是否评价过
124   - ProductCommentDO exist = productCommentMapper.findByUserIdAndOrderIdAndSpuId(productComment.getId(), productComment.getOrderId(), productComment.getSpuId());
125   - if (null != exist) {
126   - throw exception(ORDER_SPU_COMMENT_EXISTS);
127   - }
  107 + // TODO 只有创建和更新诶 要不要删除接口
  108 +
  109 + private void validateComment(Long spuId, Long userId, Long orderId) {
  110 + ProductSpuDO spu = productSpuService.getSpu(spuId);
  111 + if (null == spu) {
  112 + throw exception(SPU_NOT_EXISTS);
  113 + }
  114 + // 判断当前订单的当前商品用户是否评价过
  115 + ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderIdAndSpuId(userId, orderId, spuId);
  116 + if (null != exist) {
  117 + throw exception(ORDER_SPU_COMMENT_EXISTS);
128 118 }
129   - productCommentMapper.insert(productComment);
130 119 }
131 120  
132   - private void validateCommentExists(Long id) {
  121 + private ProductCommentDO validateCommentExists(Long id) {
133 122 ProductCommentDO productComment = productCommentMapper.selectById(id);
134 123 if (productComment == null) {
135 124 throw exception(COMMENT_NOT_EXISTS);
136 125 }
  126 + return productComment;
  127 + }
  128 +
  129 + @Override
  130 + public AppCommentStatisticsRespVO getCommentPageTabsCount(Long spuId, Boolean visible) {
  131 + return ProductCommentConvert.INSTANCE.convert(
  132 + // 查询商品 id = spuId 的所有评论数量
  133 + productCommentMapper.selectCountBySpuId(spuId, visible, null),
  134 + // 查询商品 id = spuId 的所有好评数量
  135 + productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.GOOD_COMMENT),
  136 + // 查询商品 id = spuId 的所有中评数量
  137 + productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT),
  138 + // 查询商品 id = spuId 的所有差评数量
  139 + productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT)
  140 + );
  141 + }
  142 +
  143 + @Override
  144 + public PageResult<AppProductCommentRespVO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible) {
  145 + PageResult<AppProductCommentRespVO> result = ProductCommentConvert.INSTANCE.convertPage02(
  146 + productCommentMapper.selectPage(pageVO, visible));
  147 + Set<Long> skuIds = result.getList().stream().map(AppProductCommentRespVO::getSkuId).collect(Collectors.toSet());
  148 + List<ProductSkuDO> skuList = productSkuService.getSkuList(skuIds);
  149 + Map<Long, ProductSkuDO> skuDOMap = new HashMap<>(skuIds.size());
  150 + if (CollUtil.isNotEmpty(skuList)) {
  151 + skuDOMap.putAll(skuList.stream().collect(Collectors.toMap(ProductSkuDO::getId, c -> c)));
  152 + }
  153 + result.getList().forEach(item -> {
  154 + // 判断用户是否选择匿名
  155 + if (ObjectUtil.equal(item.getAnonymous(), true)) {
  156 + item.setUserNickname(ProductCommentDO.NICKNAME_ANONYMOUS);
  157 + }
  158 + ProductSkuDO productSkuDO = skuDOMap.get(item.getSkuId());
  159 + if (productSkuDO != null) {
  160 + List<AppProductPropertyValueDetailRespVO> skuProperties = ProductCommentConvert.INSTANCE.convertList01(productSkuDO.getProperties());
  161 + item.setSkuProperties(skuProperties);
  162 + }
  163 + });
  164 + return result;
  165 + }
  166 +
  167 + @Override
  168 + public PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO) {
  169 + return productCommentMapper.selectPage(pageReqVO);
137 170 }
138 171  
139 172 }
... ...
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java
... ... @@ -5,15 +5,17 @@ import cn.hutool.core.util.RandomUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7 7 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO;
8   -import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyVO;
  8 +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO;
9 9 import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentRespVO;
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   -import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentRespVO;
  12 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentStatisticsRespVO;
  13 +import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppProductCommentRespVO;
13 14 import cn.iocoder.yudao.module.product.convert.comment.ProductCommentConvert;
14 15 import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO;
15 16 import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper;
16 17 import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum;
  18 +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
17 19 import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
18 20 import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
19 21 import org.junit.jupiter.api.Test;
... ... @@ -24,7 +26,6 @@ import org.springframework.context.annotation.Lazy;
24 26 import javax.annotation.Resource;
25 27 import java.time.LocalDateTime;
26 28 import java.util.Date;
27   -import java.util.Map;
28 29  
29 30 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
30 31 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
... ... @@ -52,6 +53,8 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
52 53 private TradeOrderApi tradeOrderApi;
53 54 @MockBean
54 55 private ProductSpuService productSpuService;
  56 + @MockBean
  57 + private ProductSkuService productSkuService;
55 58  
56 59 public String generateNo() {
57 60 return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999);
... ... @@ -135,23 +138,23 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
135 138 assertEquals(8, all.getTotal());
136 139  
137 140 // 测试获取所有商品分页评论数据
138   - PageResult<AppCommentRespVO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
  141 + PageResult<AppProductCommentRespVO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE);
139 142 assertEquals(7, result1.getTotal());
140 143  
141 144 // 测试获取所有商品分页中评数据
142   - PageResult<AppCommentRespVO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
  145 + PageResult<AppProductCommentRespVO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
143 146 assertEquals(2, result2.getTotal());
144 147  
145 148 // 测试获取指定 spuId 商品分页中评数据
146   - PageResult<AppCommentRespVO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
  149 + PageResult<AppProductCommentRespVO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE);
147 150 assertEquals(2, result3.getTotal());
148 151  
149 152 // 测试分页 tab count
150   - Map<String, Long> tabsCount = productCommentService.getCommentPageTabsCount(spuId, Boolean.TRUE);
151   - assertEquals(6, tabsCount.get(AppCommentPageReqVO.ALL_COUNT));
152   - assertEquals(4, tabsCount.get(AppCommentPageReqVO.FAVOURABLE_COMMENT_COUNT));
153   - assertEquals(2, tabsCount.get(AppCommentPageReqVO.MEDIOCRE_COMMENT_COUNT));
154   - assertEquals(0, tabsCount.get(AppCommentPageReqVO.NEGATIVE_COMMENT_COUNT));
  153 + AppCommentStatisticsRespVO tabsCount = productCommentService.getCommentPageTabsCount(spuId, Boolean.TRUE);
  154 + assertEquals(6, tabsCount.getAllCount());
  155 + assertEquals(4, tabsCount.getGoodCount());
  156 + assertEquals(2, tabsCount.getMediocreCount());
  157 + assertEquals(0, tabsCount.getNegativeCount());
155 158  
156 159 }
157 160  
... ... @@ -183,10 +186,10 @@ public class ProductCommentServiceImplTest extends BaseDbUnitTest {
183 186  
184 187 Long productCommentId = productComment.getId();
185 188  
186   - ProductCommentReplyVO replyVO = new ProductCommentReplyVO();
  189 + ProductCommentReplyReqVO replyVO = new ProductCommentReplyReqVO();
187 190 replyVO.setId(productCommentId);
188 191 replyVO.setReplyContent("测试");
189   - productCommentService.commentReply(replyVO, 1L);
  192 + productCommentService.replyComment(replyVO, 1L);
190 193  
191 194 ProductCommentDO productCommentDO = productCommentMapper.selectById(productCommentId);
192 195 assertEquals("测试", productCommentDO.getReplyContent());
... ...
yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql
... ... @@ -126,36 +126,81 @@ CREATE TABLE IF NOT EXISTS `product_property_value` (
126 126 PRIMARY KEY("id")
127 127 ) COMMENT '规格值';
128 128  
129   -CREATE TABLE IF NOT EXISTS `product_comment` (
130   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '评价编号',
131   - `user_id` bigint NOT NULL COMMENT ' 评价ID 用户编号',
132   - `user_nickname` varchar(128) NOT NULL COMMENT '评价人名称',
133   - `user_avatar` varchar(255) NOT NULL COMMENT '评价人头像',
134   - `anonymous` bit(1) NOT NULL DEFAULT 0 COMMENT '是否匿名 0:不匿名 1:匿名',
135   - `order_id` bigint NOT NULL COMMENT '交易订单编号',
136   - `order_item_id` bigint NOT NULL COMMENT '交易订单项编号',
137   - `spu_id` bigint NOT NULL COMMENT '商品SPU编号',
138   - `spu_name` varchar NOT NULL COMMENT '商品SPU名称',
139   - `sku_id` bigint NOT NULL COMMENT '商品SKU编号',
140   - `visible` bit(1) NOT NULL DEFAULT 1 COMMENT '是否可见 true:显示 false:隐藏',
141   - `scores` int NOT NULL COMMENT '评分星级 1-5分',
142   - `description_scores` int NOT NULL COMMENT '描述星级 1-5分',
143   - `benefit_scores` int NOT NULL COMMENT '服务星级 1-5分',
144   - `delivery_scores` int NOT NULL COMMENT '配送星级 1-5分',
145   - `content` varchar(2000) NOT NULL COMMENT '评论内容',
146   - `pic_urls` varchar(1024) DEFAULT '' COMMENT '评论图片地址数组,以逗号分隔最多上传9张',
147   - `replied` bit(1) NOT NULL DEFAULT 0 COMMENT '商家是否回复 1:回复 0:未回复',
148   - `reply_user_id` bigint COMMENT '回复管理员编号',
149   - `reply_content` varchar(2000) COMMENT '商家回复内容',
150   - `reply_time` datetime COMMENT '商家回复时间',
151   - `additional_content` varchar(2000) COMMENT '追加评价内容',
152   - `additional_pic_urls` varchar(1024) COMMENT '追评评价图片地址数组,以逗号分隔最多上传9张',
153   - `additional_time` datetime COMMENT '追加评价时间',
154   - "creator" varchar(64) DEFAULT '',
155   - "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
156   - "updater" varchar(64) DEFAULT '',
157   - "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  129 +CREATE TABLE IF NOT EXISTS `product_comment`
  130 +(
  131 + `id`
  132 + bigint
  133 + NOT
  134 + NULL
  135 + AUTO_INCREMENT
  136 + COMMENT
  137 + '评论编号,主键自增',
  138 + `user_id`
  139 + bigint
  140 + DEFAULT
  141 + NULL
  142 + COMMENT
  143 + '评价人的用户编号关联 MemberUserDO 的 id 编号',
  144 + `user_nickname`
  145 + varchar
  146 +(
  147 + 255
  148 +) DEFAULT NULL COMMENT '评价人名称',
  149 + `user_avatar` varchar
  150 +(
  151 + 1024
  152 +) DEFAULT NULL COMMENT '评价人头像',
  153 + `anonymous` bit
  154 +(
  155 + 1
  156 +) DEFAULT NULL COMMENT '是否匿名',
  157 + `order_id` bigint DEFAULT NULL COMMENT '交易订单编号关联 TradeOrderDO 的 id 编号',
  158 + `order_item_id` bigint DEFAULT NULL COMMENT '交易订单项编号关联 TradeOrderItemDO 的 id 编号',
  159 + `spu_id` bigint DEFAULT NULL COMMENT '商品 SPU 编号关联 ProductSpuDO 的 id',
  160 + `spu_name` varchar
  161 +(
  162 + 255
  163 +) DEFAULT NULL COMMENT '商品 SPU 名称',
  164 + `sku_id` bigint DEFAULT NULL COMMENT '商品 SKU 编号关联 ProductSkuDO 的 id 编号',
  165 + `visible` bit
  166 +(
  167 + 1
  168 +) DEFAULT NULL COMMENT '是否可见true:显示false:隐藏',
  169 + `scores` tinyint DEFAULT NULL COMMENT '评分星级1-5分',
  170 + `description_scores` tinyint DEFAULT NULL COMMENT '描述星级1-5 星',
  171 + `benefit_scores` tinyint DEFAULT NULL COMMENT '服务星级1-5 星',
  172 + `content` varchar
  173 +(
  174 + 1024
  175 +) DEFAULT NULL COMMENT '评论内容',
  176 + `pic_urls` varchar
  177 +(
  178 + 4096
  179 +) DEFAULT NULL COMMENT '评论图片地址数组',
  180 + `reply_status` bit
  181 +(
  182 + 1
  183 +) DEFAULT NULL COMMENT '商家是否回复',
  184 + `reply_user_id` bigint DEFAULT NULL COMMENT '回复管理员编号关联 AdminUserDO 的 id 编号',
  185 + `reply_content` varchar
  186 +(
  187 + 1024
  188 +) DEFAULT NULL COMMENT '商家回复内容',
  189 + `reply_time` datetime DEFAULT NULL COMMENT '商家回复时间',
  190 + `creator` varchar
  191 +(
  192 + 64
  193 +) DEFAULT '' COMMENT '创建者',
  194 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  195 + `updater` varchar
  196 +(
  197 + 64
  198 +) DEFAULT '' COMMENT '更新者',
  199 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
158 200 "deleted" bit NOT NULL DEFAULT FALSE,
159   - "tenant_id" bigint not null default '0',
160   - PRIMARY KEY (`id`)
161   -) COMMENT '商品评价';
162 201 \ No newline at end of file
  202 + "tenant_id" bigint not null default '0',
  203 + PRIMARY KEY
  204 +(
  205 + `id`
  206 +)
  207 + ) COMMENT '产品评论表';
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApi.java
1 1 package cn.iocoder.yudao.module.trade.api.order;
2 2  
3   -import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
4   -
5 3 /**
6 4 * 订单 API 接口
7 5 *
... ... @@ -10,11 +8,12 @@ import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
10 8 public interface TradeOrderApi {
11 9  
12 10 /**
13   - * 获取订单通过订单 id
  11 + * 验证订单
14 12 *
15   - * @param id id
16   - * @return 订单信息 Response DTO
  13 + * @param userId 用户 id
  14 + * @param orderItemId 订单项 id
  15 + * @return 校验通过返回订单 id
17 16 */
18   - TradeOrderRespDTO getOrder(Long id);
  17 + Long validateOrder(Long userId, Long orderItemId);
19 18  
20 19 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
1 1 package cn.iocoder.yudao.module.trade.api.order;
2 2  
3   -import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
4   -import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
  3 +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
5 4 import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
6 5 import org.springframework.stereotype.Service;
7 6 import org.springframework.validation.annotation.Validated;
8 7  
9 8 import javax.annotation.Resource;
10 9  
  10 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  11 +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
  12 +
11 13 /**
12 14 * 订单 API 接口实现类
13 15 *
... ... @@ -21,8 +23,14 @@ public class TradeOrderApiImpl implements TradeOrderApi {
21 23 private TradeOrderService tradeOrderService;
22 24  
23 25 @Override
24   - public TradeOrderRespDTO getOrder(Long id) {
25   - return TradeOrderConvert.INSTANCE.convert(tradeOrderService.getOrder(id));
  26 + public Long validateOrder(Long userId, Long orderItemId) {
  27 + // 校验订单项,订单项存在订单就存在
  28 + TradeOrderItemDO item = tradeOrderService.getOrderItem(userId, orderItemId);
  29 + if (item == null) {
  30 + throw exception(ORDER_ITEM_NOT_FOUND);
  31 + }
  32 +
  33 + return item.getOrderId();
26 34 }
27 35  
28 36 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
... ... @@ -5,9 +5,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
6 6 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
7 7 import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
  8 +import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
8 9 import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
9 10 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
10 11 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
  12 +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
11 13 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
12 14 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
13 15 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
... ... @@ -15,6 +17,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
15 17 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
16 18 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
17 19 import cn.iocoder.yudao.module.trade.service.order.TradeOrderService;
  20 +import com.google.common.collect.Maps;
18 21 import io.swagger.v3.oas.annotations.Operation;
19 22 import io.swagger.v3.oas.annotations.Parameter;
20 23 import io.swagger.v3.oas.annotations.tags.Tag;
... ... @@ -24,14 +27,15 @@ import org.springframework.web.bind.annotation.*;
24 27  
25 28 import javax.annotation.Resource;
26 29 import javax.validation.Valid;
27   -import java.util.HashMap;
28 30 import java.util.List;
29 31 import java.util.Map;
30 32  
  33 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 34 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
32 35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
33 36 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
34 37 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;
35 39  
36 40 @Tag(name = "用户 App - 交易订单")
37 41 @RestController
... ... @@ -49,6 +53,9 @@ public class AppTradeOrderController {
49 53 @Resource
50 54 private TradeOrderProperties tradeOrderProperties;
51 55  
  56 + @Resource
  57 + private ProductCommentApi productCommentApi;
  58 +
52 59 @GetMapping("/settlement")
53 60 @Operation(summary = "获得订单结算信息")
54 61 @PreAuthenticated
... ... @@ -106,7 +113,7 @@ public class AppTradeOrderController {
106 113 @GetMapping("/get-count")
107 114 @Operation(summary = "获得交易订单数量")
108 115 public CommonResult<Map<String, Long>> getOrderCount() {
109   - Map<String, Long> orderCount = new HashMap<>();
  116 + Map<String, Long> orderCount = Maps.newLinkedHashMapWithExpectedSize(5);
110 117 // 全部
111 118 orderCount.put("allCount", tradeOrderService.getOrderCount(getLoginUserId(), null, null));
112 119 // 待付款(未支付)
... ... @@ -130,11 +137,18 @@ public class AppTradeOrderController {
130 137 return success(TradeOrderConvert.INSTANCE.convert03(item));
131 138 }
132 139  
133   - // TODO 芋艿:待实现
134 140 @PostMapping("/item/create-comment")
135 141 @Operation(summary = "创建交易订单项的评价")
136   - public CommonResult<Long> createOrderItemComment() {
137   - return success(0L);
  142 + public CommonResult<Long> createOrderItemComment(@RequestBody AppTradeOrderItemCommentCreateReqVO createReqVO) {
  143 + // 校验订单项,订单项存在订单就存在
  144 + TradeOrderItemDO item = tradeOrderService.getOrderItem(createReqVO.getUserId(), createReqVO.getOrderItemId());
  145 + if (item == null) {
  146 + throw exception(ORDER_ITEM_NOT_FOUND);
  147 + }
  148 +
  149 + return success(productCommentApi.createComment(TradeOrderConvert.INSTANCE.convert04(createReqVO), item.getOrderId()));
138 150 }
139 151  
  152 + // TODO 合并代码后发现只有商家回复功能 用户追评不要了吗?
  153 +
140 154 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/item/AppTradeOrderItemCommentCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.controller.app.order.vo.item;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotNull;
  7 +import javax.validation.constraints.Size;
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 商品评价创建 Request VO
  12 + *
  13 + * @author HUIHUI
  14 + */
  15 +@Schema(description = "用户APP - 商品评价创建 Request VO")
  16 +@Data
  17 +public class AppTradeOrderItemCommentCreateReqVO {
  18 +
  19 + @Schema(description = "是否匿名", required = true, example = "true")
  20 + @NotNull(message = "是否匿名不能为空")
  21 + private Boolean anonymous;
  22 +
  23 + @Schema(description = "交易订单项编号", required = true, example = "2312312")
  24 + @NotNull(message = "交易订单项编号不能为空")
  25 + private Long orderItemId;
  26 +
  27 + @Schema(description = "商品SPU编号", required = true, example = "29502")
  28 + @NotNull(message = "商品SPU编号不能为空")
  29 + private Long spuId;
  30 +
  31 + @Schema(description = "商品SPU名称", required = true, example = "丝滑飘逸小短裙")
  32 + @NotNull(message = "商品SPU名称不能为空")
  33 + private String spuName;
  34 +
  35 + @Schema(description = "商品SKU编号", required = true, example = "3082")
  36 + @NotNull(message = "商品SKU编号不能为空")
  37 + private Long skuId;
  38 +
  39 + @Schema(description = "评分星级 1-5分", required = true, example = "5")
  40 + @NotNull(message = "评分星级 1-5分不能为空")
  41 + private Integer scores;
  42 +
  43 + @Schema(description = "描述星级 1-5分", required = true, example = "5")
  44 + @NotNull(message = "描述星级 1-5分不能为空")
  45 + private Integer descriptionScores;
  46 +
  47 + @Schema(description = "服务星级 1-5分", required = true, example = "5")
  48 + @NotNull(message = "服务星级 1-5分不能为空")
  49 + private Integer benefitScores;
  50 +
  51 + @Schema(description = "评论内容", required = true, example = "穿身上很漂亮诶(*^▽^*)")
  52 + @NotNull(message = "评论内容不能为空")
  53 + private String content;
  54 +
  55 + @Schema(description = "评论图片地址数组,以逗号分隔最多上传9张", required = true, example = "[https://www.iocoder.cn/xx.png, https://www.iocoder.cn/xx.png]")
  56 + @Size(max = 9, message = "评论图片地址数组长度不能超过9张")
  57 + private List<String> picUrls;
  58 +
  59 + @Schema(description = "评价人名称", required = true, example = "小姑凉")
  60 + @NotNull(message = "评价人名称不能为空")
  61 + private String userNickname;
  62 +
  63 + @Schema(description = "评价人头像", required = true, example = "https://www.iocoder.cn/xx.png")
  64 + @NotNull(message = "评价人头像不能为空")
  65 + private String userAvatar;
  66 +
  67 + @Schema(description = "评价人", required = true, example = "16868")
  68 + @NotNull(message = "评价人不能为空")
  69 + private Long userId;
  70 +
  71 +}
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
8 8 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
9 9 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
10 10 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
  11 +import cn.iocoder.yudao.module.product.api.comment.dto.CommentCreateReqDTO;
11 12 import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
12 13 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
13 14 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
... ... @@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailR
18 19 import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO;
19 20 import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO;
20 21 import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
  22 +import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
21 23 import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
22 24 import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO;
23 25 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
... ... @@ -75,9 +77,10 @@ public interface TradeOrderConvert {
75 77 return orderItem;
76 78 });
77 79 }
  80 +
78 81 TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item);
79 82  
80   - @Mapping(source = "userId" , target = "userId")
  83 + @Mapping(source = "userId", target = "userId")
81 84 PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId);
82 85  
83 86 @Mappings({
... ... @@ -85,6 +88,7 @@ public interface TradeOrderConvert {
85 88 @Mapping(source = "count", target = "incrCount"),
86 89 })
87 90 ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean);
  91 +
88 92 List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list);
89 93  
90 94 default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
... ... @@ -136,7 +140,7 @@ public interface TradeOrderConvert {
136 140 properties.forEach(property -> {
137 141 ProductPropertyValueDetailRespDTO propertyValueDetail = propertyValueDetailMap.get(property.getValueId());
138 142 if (propertyValueDetail == null) {
139   - return;
  143 + return;
140 144 }
141 145 item.getProperties().add(convert(propertyValueDetail));
142 146 });
... ... @@ -148,7 +152,9 @@ public interface TradeOrderConvert {
148 152 });
149 153 return new PageResult<>(orderVOs, pageResult.getTotal());
150 154 }
  155 +
151 156 TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items);
  157 +
152 158 ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean);
153 159  
154 160 // TODO 芋艿:可简化
... ... @@ -179,7 +185,9 @@ public interface TradeOrderConvert {
179 185 orderVO.setUser(convert(user));
180 186 return orderVO;
181 187 }
  188 +
182 189 TradeOrderDetailRespVO convert2(TradeOrderDO order, List<TradeOrderItemDO> items);
  190 +
183 191 MemberUserRespVO convert(MemberUserRespDTO bean);
184 192  
185 193 // TODO 芋艿:可简化
... ... @@ -214,7 +222,9 @@ public interface TradeOrderConvert {
214 222 });
215 223 return new PageResult<>(orderVOs, pageResult.getTotal());
216 224 }
  225 +
217 226 AppTradeOrderPageItemRespVO convert02(TradeOrderDO order, List<TradeOrderItemDO> items);
  227 +
218 228 AppProductPropertyValueDetailRespVO convert02(ProductPropertyValueDetailRespDTO bean);
219 229  
220 230 default AppTradeOrderDetailRespVO convert02(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
... ... @@ -243,10 +253,13 @@ public interface TradeOrderConvert {
243 253 orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId()));
244 254 return orderVO;
245 255 }
  256 +
246 257 AppTradeOrderDetailRespVO convert3(TradeOrderDO order, List<TradeOrderItemDO> items);
247 258  
248 259 AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean);
249 260  
  261 + CommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO);
  262 +
250 263 default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
251 264 List<TradeCartDO> cartList) {
252 265 TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();
... ... @@ -286,6 +299,8 @@ public interface TradeOrderConvert {
286 299 }
287 300 return respVO;
288 301 }
  302 +
289 303 AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
290 304  
  305 +
291 306 }
... ...