panzhilin 3 месяцев назад
Родитель
Сommit
2022d44a55

+ 50 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/RatingPercentVo.java

@@ -0,0 +1,50 @@
+package shop.alien.entity.store.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 评价回复率和评价比例VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@JsonInclude
+@ApiModel(value = "RatingPercentVo对象", description = "评价回复率和评价比例")
+public class RatingPercentVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "总评价数")
+    private Integer totalRatingCount;
+
+    @ApiModelProperty(value = "好评数")
+    private Integer goodCount;
+
+    @ApiModelProperty(value = "中评数")
+    private Integer midCount;
+
+    @ApiModelProperty(value = "差评数")
+    private Integer badCount;
+
+    @ApiModelProperty(value = "好评占比(%)")
+    private Double goodPercent;
+
+    @ApiModelProperty(value = "中评占比(%)")
+    private Double midPercent;
+
+    @ApiModelProperty(value = "差评占比(%)")
+    private Double badPercent;
+
+    @ApiModelProperty(value = "已回复的评价数")
+    private Integer repliedCount;
+
+    @ApiModelProperty(value = "回复率(%)")
+    private Double replyRate;
+}
+

+ 13 - 0
alien-store/src/main/java/shop/alien/store/controller/CommonRatingController.java

@@ -67,6 +67,19 @@ public class CommonRatingController {
         return R.data(commonRatingService.getRatingCount(businessId, businessType));
     }
 
+    @ApiOperation("获取回复率和评价比例(商户端)")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "businessId", value = "业务ID(店铺ID)", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "businessType", value = "业务类型:1-店铺评价", dataType = "Integer", paramType = "query", required = true)
+    })
+    @GetMapping("/getRatingPercent")
+    public R<shop.alien.entity.store.vo.RatingPercentVo> getRatingPercent(
+            @RequestParam Integer businessId,
+            @RequestParam Integer businessType) {
+        log.info("CommonRatingController.getRatingPercent?businessId={}&businessType={}", businessId, businessType);
+        return R.data(commonRatingService.getRatingPercent(businessId, businessType));
+    }
+
 //
 //    @ApiOperation("根据ID获取评价详情")
 //    @ApiImplicitParam(name = "id", value = "评价ID", dataType = "Long", paramType = "path", required = true)

+ 9 - 0
alien-store/src/main/java/shop/alien/store/service/CommonRatingService.java

@@ -54,6 +54,15 @@ public interface CommonRatingService extends IService<CommonRating> {
      */
     Object getRatingDetail(Integer ratingId, Long userId);
 
+    /**
+     * 获取回复率和评价比例
+     *
+     * @param businessId   业务ID(店铺ID)
+     * @param businessType 业务类型:1-店铺评价
+     * @return 回复率和评价比例信息
+     */
+    shop.alien.entity.store.vo.RatingPercentVo getRatingPercent(Integer businessId, Integer businessType);
+
 
   /*  /**
      * 根据业务类型和业务ID获取平均评分

+ 176 - 24
alien-store/src/main/java/shop/alien/store/service/impl/CommonRatingServiceImpl.java

@@ -21,6 +21,7 @@ import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.CommonCommentVo;
 import shop.alien.entity.store.vo.CommonRatingVo;
+import shop.alien.entity.store.vo.RatingPercentVo;
 import shop.alien.entity.store.vo.StoreInfoScoreVo;
 import shop.alien.entity.store.vo.WebSocketVo;
 import shop.alien.mapper.*;
@@ -155,22 +156,6 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
         }
 
     }
-
-    /**
-     * 分页查询评价列表
-     *
-     * @param pageNum      页数
-     * @param pageSize     页容
-     * @param businessType 业务类型:1-店铺评价
-     * @param businessId   业务关联ID
-     * @param userId       用户ID
-     * @param auditStatus  审核状态:0-待审核 1-通过 2-驳回
-     * @param searchScore  搜索评分:0-全部,1-好评 2-中评 3-差评,4-有图
-     * @param days         查询时间, 多少天前
-     * @param replyStatus  回复状态(0:全部, 1:已回复, 2:未回复)
-     * @param tagId        标签id
-     * @return R
-     */
     @Override
     public R getRatingList(Integer pageNum, Integer pageSize, Integer businessType, Long businessId, Long userId, Integer auditStatus, Integer searchScore, Integer days, Integer replyStatus, Integer tagId) {
         Page<CommonRating> page = new Page<>(pageNum, pageSize);
@@ -307,14 +292,10 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
         ratingCount = commonRatingMapper.getRatingCount(new QueryWrapper<CommonRating>().in("id", collect));
         
         // 计算好评、中评、差评占比
-        // 注意:数据库返回的 count 可能是 Long 类型,需要安全转换
-        Long goodCountLong = (Long) ratingCount.getOrDefault("goodCount", 0L);
-        Long midCountLong = (Long) ratingCount.getOrDefault("midCount", 0L);
-        Long badCountLong = (Long) ratingCount.getOrDefault("badCount", 0L);
-        
-        int goodCount = goodCountLong != null ? goodCountLong.intValue() : 0;
-        int midCount = midCountLong != null ? midCountLong.intValue() : 0;
-        int badCount = badCountLong != null ? badCountLong.intValue() : 0;
+        // 注意:数据库返回的 count 可能是 BigDecimal、Long 或 Integer 类型,需要安全转换
+        int goodCount = getIntValue(ratingCount.get("goodCount"));
+        int midCount = getIntValue(ratingCount.get("midCount"));
+        int badCount = getIntValue(ratingCount.get("badCount"));
         int totalCount = goodCount + midCount + badCount;
         
         if (totalCount > 0) {
@@ -585,6 +566,38 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
             Map<Long, Long> ratingCommentCountMap = allComments.stream()
                     .collect(Collectors.groupingBy(CommonComment::getSourceId, Collectors.counting()));
 
+            // 查询每个评价的最新一条商户回复(comment_type=2, parent_id=0)
+            Map<Long, CommonCommentVo> latestMerchantReplyMap = new HashMap<>();
+            if (!ratingIdSet.isEmpty()) {
+                QueryWrapper<CommonCommentVo> merchantReplyWrapper = new QueryWrapper<>();
+                merchantReplyWrapper.eq("cc.source_type", CommentSourceTypeEnum.STORE_COMMENT.getType())
+                                   .in("cc.source_id", ratingIdSet)
+                                   .eq("cc.comment_type", 2)  // 商户评论
+                                   .eq("cc.parent_id", 0)     // 直接回复评价的根评论
+                                   .eq("cc.is_show", 1)
+                                   .eq("cc.audit_status", 1)
+                                   .eq("cc.delete_flag", 0)
+                                   .orderByDesc("cc.created_time");
+                
+                // 查询所有商户回复(包含用户信息)
+                List<CommonCommentVo> merchantReplies = commonCommentMapper.selectALlComment(
+                    merchantReplyWrapper, 
+                    CommonConstant.COMMENT_LIKE, 
+                    userId != null ? userId : 0L
+                );
+                
+                // 按评价ID分组,每组只取最新的一条(已按时间倒序排序)
+                if (CollectionUtils.isNotEmpty(merchantReplies)) {
+                    for (CommonCommentVo reply : merchantReplies) {
+                        Long ratingId = reply.getSourceId();
+                        // 如果该评价还没有设置回复,则设置(因为已经按时间倒序,第一条就是最新的)
+                        if (ratingId != null && !latestMerchantReplyMap.containsKey(ratingId)) {
+                            latestMerchantReplyMap.put(ratingId, reply);
+                        }
+                    }
+                }
+            }
+
             // 4. 组装评价列表数据
             for (CommonRating record : page1.getRecords()) {
                 CommonRatingVo commonRatingVo = new CommonRatingVo();
@@ -606,6 +619,16 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
                 // 设置评论数
                 commonRatingVo.setCommentCount(ratingCommentCountMap.getOrDefault(record.getId(), 0L));
                 
+                // 设置商户最新回复(同一评价下,商家只显示最新的一条回复)
+                CommonCommentVo latestMerchantReply = latestMerchantReplyMap.get(record.getId());
+                if (latestMerchantReply != null) {
+                    // 只设置一条最新的商户回复
+                    commonRatingVo.setChildCommonComments(Collections.singletonList(latestMerchantReply));
+                } else {
+                    // 没有商户回复,设置为空列表
+                    commonRatingVo.setChildCommonComments(new ArrayList<>());
+                }
+                
                 resultList.add(commonRatingVo);
             }
             
@@ -643,5 +666,134 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
         
         return (long) this.count(wrapper);
     }*/
+    
+    /**
+     * 安全地将数据库返回的数值类型转换为 int
+     * 支持 BigDecimal、Long、Integer、Number 等类型
+     * 
+     * @param value 数据库返回的数值对象
+     * @return int 值,如果为 null 或无法转换则返回 0
+     */
+    private int getIntValue(Object value) {
+        if (value == null) {
+            return 0;
+        }
+        
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        
+        // 尝试字符串转换
+        try {
+            if (value instanceof String) {
+                return Integer.parseInt((String) value);
+            }
+        } catch (NumberFormatException e) {
+            log.warn("无法将值转换为 int: {}", value, e);
+        }
+        
+        return 0;
+    }
+
+    /**
+     * 获取回复率和评价比例
+     *
+     * @param businessId   业务ID(店铺ID)
+     * @param businessType 业务类型:1-店铺评价
+     * @return 回复率和评价比例信息
+     */
+    @Override
+    public RatingPercentVo getRatingPercent(Integer businessId, Integer businessType) {
+        log.info("CommonRatingServiceImpl.getRatingPercent?businessId={}&businessType={}", businessId, businessType);
+        
+        RatingPercentVo vo = new RatingPercentVo();
+        
+        // 1. 查询全部评价记录(仅展示的、审核通过的)
+        LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(CommonRating::getBusinessId, businessId);
+        wrapper.eq(CommonRating::getBusinessType, businessType);
+        wrapper.eq(CommonRating::getIsShow, 1);
+        wrapper.eq(CommonRating::getAuditStatus, 1);  // 仅统计审核通过的
+        List<CommonRating> commonRatings = commonRatingMapper.selectList(wrapper);
+        
+        // 如果为空,返回默认值
+        if (CollectionUtils.isEmpty(commonRatings)) {
+            vo.setTotalRatingCount(0);
+            vo.setGoodCount(0);
+            vo.setMidCount(0);
+            vo.setBadCount(0);
+            vo.setGoodPercent(0.0);
+            vo.setMidPercent(0.0);
+            vo.setBadPercent(0.0);
+            vo.setRepliedCount(0);
+            vo.setReplyRate(0.0);
+            return vo;
+        }
+        
+        List<Long> ratingIdList = commonRatings.stream()
+                .map(CommonRating::getId)
+                .collect(Collectors.toList());
+        
+        // 2. 获取评价统计信息(好评、中评、差评数量)
+        Map<String, Object> ratingCount = commonRatingMapper.getRatingCount(
+                new QueryWrapper<CommonRating>().in("id", ratingIdList));
+        
+        // 3. 计算好评、中评、差评数量和占比
+        int goodCount = getIntValue(ratingCount.get("goodCount"));
+        int midCount = getIntValue(ratingCount.get("midCount"));
+        int badCount = getIntValue(ratingCount.get("badCount"));
+        int totalCount = goodCount + midCount + badCount;
+        
+        vo.setTotalRatingCount(totalCount);
+        vo.setGoodCount(goodCount);
+        vo.setMidCount(midCount);
+        vo.setBadCount(badCount);
+        
+        // 计算占比(保留2位小数)
+        if (totalCount > 0) {
+            Double goodPercent = Math.round((goodCount * 100.0 / totalCount) * 100.0) / 100.0;
+            Double midPercent = Math.round((midCount * 100.0 / totalCount) * 100.0) / 100.0;
+            Double badPercent = Math.round((badCount * 100.0 / totalCount) * 100.0) / 100.0;
+            
+            vo.setGoodPercent(goodPercent);
+            vo.setMidPercent(midPercent);
+            vo.setBadPercent(badPercent);
+        } else {
+            vo.setGoodPercent(0.0);
+            vo.setMidPercent(0.0);
+            vo.setBadPercent(0.0);
+        }
+        
+        // 4. 计算回复率
+        // 查询已回复的评价数(存在商户评论 comment_type=2, parent_id=0)
+        LambdaQueryWrapper<CommonComment> repliedWrapper = new LambdaQueryWrapper<>();
+        repliedWrapper.eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())
+                     .in(CommonComment::getSourceId, ratingIdList)
+                     .eq(CommonComment::getCommentType, 2)  // 商户评论
+                     .eq(CommonComment::getParentId, 0)     // 根评论(直接回复评价)
+                     .eq(CommonComment::getIsShow, 1)
+                     .eq(CommonComment::getAuditStatus, 1);
+        
+        // 获取已回复的评价ID列表(去重)
+        Set<Long> repliedRatingIds = commonCommentMapper.selectList(repliedWrapper).stream()
+                .map(CommonComment::getSourceId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        
+        int repliedCount = repliedRatingIds.size();
+        vo.setRepliedCount(repliedCount);
+        
+        // 计算回复率(保留2位小数)
+        Double replyRate = 0.0;
+        if (totalCount > 0) {
+            replyRate = Math.round((repliedCount * 100.0 / totalCount) * 100.0) / 100.0;
+        }
+        vo.setReplyRate(replyRate);
+        
+        log.info("CommonRatingServiceImpl.getRatingPercent result: totalCount={}, goodCount={}, midCount={}, badCount={}, repliedCount={}, replyRate={}%",
+                totalCount, goodCount, midCount, badCount, repliedCount, replyRate);
+        
+        return vo;
+    }
 }