Ver código fonte

Merge branch 'Fix-panzhilin' into release_20260123

panzhilin 2 meses atrás
pai
commit
349803c6e5

+ 1 - 1
alien-entity/src/main/java/shop/alien/entity/store/TagsSynonym.java

@@ -27,7 +27,7 @@ public class TagsSynonym {
     @TableField("main_tag_id")
     private Integer mainTagId;
 
-    @ApiModelProperty(value = "评论ID")
+    @ApiModelProperty(value = "评论ID(关联common_comment.id)")
     @TableField("comment_id")
     private Integer commentId;
 

+ 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;
+}
+

+ 10 - 2
alien-store/src/main/java/shop/alien/store/controller/CommonCommentController.java

@@ -1,4 +1,4 @@
-package shop.alien.store.controller;
+  package shop.alien.store.controller;
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -59,7 +59,12 @@ public class CommonCommentController {
      //   "merchantId": 10086, 为2商户评论需要填
      }
      */
-    @ApiOperation(value = "新增评论", notes = "0:成功, 1:失败, 2:文本内容异常, 3:图片内容异常")
+    /**
+     * 新增评论
+     * @param commonComment 评论对象
+     * @return 0:成功, 1:失败, 2:文本内容异常, 4:字数超限(超过300字)
+     */
+    @ApiOperation(value = "新增评论", notes = "0:成功, 1:失败, 2:文本内容异常, 4:字数超限(超过300字)")
     @PostMapping("/addComment")
     public R addComment(@RequestBody CommonComment commonComment) {
         Integer addComment = commonCommentService.addComment(commonComment);
@@ -69,6 +74,9 @@ public class CommonCommentController {
         if (addComment == 2) {
             return R.fail("新增评论失败,评论内容包含敏感字符");
         }
+        if (addComment == 4) {
+            return R.fail("新增评论失败,评论内容超过300字限制");
+        }
         return R.fail("新增评论失败");
     }
 

+ 24 - 5
alien-store/src/main/java/shop/alien/store/controller/CommonRatingController.java

@@ -36,7 +36,10 @@ public class CommonRatingController {
             @ApiImplicitParam(name = "businessId", value = "业务关联ID", dataType = "Long", paramType = "query"),
             @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Long", paramType = "query"),
             @ApiImplicitParam(name = "auditStatus", value = "审核状态:0-待审核 1-通过 2-驳回", dataType = "Integer", paramType = "query"),
-            @ApiImplicitParam(name = "searchScore", value = "搜索评分:0-全部,1-好评 2-中评 3-差评,4-有图", dataType = "Integer", paramType = "query")
+            @ApiImplicitParam(name = "searchScore", value = "搜索评分:0-全部,1-好评 2-中评 3-差评,4-有图", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "days", value = "查询时间, 多少天前", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "replyStatus", value = "回复状态(0:全部, 1:已回复, 2:未回复)", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "tagId", value = "标签id", dataType = "Integer", paramType = "query")
     })
     @GetMapping("/getList")
     public R getList(
@@ -46,10 +49,13 @@ public class CommonRatingController {
             @RequestParam(required = false) Long businessId,
             @RequestParam(required = false) Long userId,
             @RequestParam(required = false) Integer auditStatus,
-            @RequestParam(defaultValue = "0") Integer searchScore) {
-        log.info("CommonRatingController.getList?pageNum={}&pageSize={}&businessType={}&businessId={}&userId={}&auditStatus={}&searchScore={}",
-                pageNum, pageSize, businessType, businessId, userId, auditStatus, searchScore);
-        return commonRatingService.getRatingList(pageNum, pageSize, businessType, businessId, userId, auditStatus, searchScore);
+            @RequestParam(defaultValue = "0") Integer searchScore,
+            @RequestParam(required = false) Integer days,
+            @RequestParam(required = false) Integer replyStatus,
+            @RequestParam(required = false) Integer tagId) {
+        log.info("CommonRatingController.getList?pageNum={}&pageSize={}&businessType={}&businessId={}&userId={}&auditStatus={}&searchScore={}&days={}&replyStatus={}&tagId={}",
+                pageNum, pageSize, businessType, businessId, userId, auditStatus, searchScore, days, replyStatus, tagId);
+        return commonRatingService.getRatingList(pageNum, pageSize, businessType, businessId, userId, auditStatus, searchScore, days, replyStatus, tagId);
     }
 
     @ApiOperation("获取全部评价数量(好评,中评,差评)")
@@ -62,6 +68,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)

+ 14 - 2
alien-store/src/main/java/shop/alien/store/service/CommonRatingService.java

@@ -20,7 +20,7 @@ public interface CommonRatingService extends IService<CommonRating> {
      */
     Integer saveCommonRating(CommonRating commonRating);
 
-/*        *
+    /**
      * 分页查询评价列表
      *
      * @param pageNum      页数
@@ -30,9 +30,12 @@ public interface CommonRatingService extends IService<CommonRating> {
      * @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 IPage<CommonRating>
      */
-    R getRatingList(Integer pageNum, Integer pageSize, Integer businessType, Long businessId, Long userId, Integer auditStatus, Integer searchScore);
+    R getRatingList(Integer pageNum, Integer pageSize, Integer businessType, Long businessId, Long userId, Integer auditStatus, Integer searchScore, Integer days, Integer replyStatus, Integer tagId);
 
      /**
      * 获取店铺评价数量(好评,中评,差评)
@@ -51,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获取平均评分

+ 10 - 3
alien-store/src/main/java/shop/alien/store/service/impl/CommentAppealServiceImpl.java

@@ -197,7 +197,7 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
             lawyerUser.eq(LawyerUser::getId, appeal.getLawyerUserId());
             LawyerUser lifeUser = lawyerUserMapper.selectOne(lawyerUser);
             if (lifeUser == null) {
-                log.warn("评价用户不存在,userId={}", lifeUser.getId());
+                log.warn("律师用户不存在,lawyerUserId={}", appeal.getLawyerUserId());
                 return;
             }
             LambdaQueryWrapper<OrderReview> orderReviewLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -547,16 +547,23 @@ public class CommentAppealServiceImpl extends ServiceImpl<CommentAppealMapper, C
                 pageNum, pageSize, status, lawyerUserId);
         List<CommentAppealVo> appealList = new ArrayList<>();
         //status 3 查全部
-        if (status == 3) {
+        if (status != null && status == 3) {
             appealList = baseMapper.getAppealHistoryList(null, lawyerUserId);
         } else {
             // 查询申诉历史列表
             appealList = baseMapper.getAppealHistoryList(status, lawyerUserId);
         }
 
+        // 防止空指针异常:如果查询结果为null,初始化为空列表
+        if (appealList == null) {
+            appealList = new ArrayList<>();
+        }
+
         // 处理数据转换(图片列表等)
         for (CommentAppealVo vo : appealList) {
-            processAppealVo(vo);
+            if (vo != null) {
+                processAppealVo(vo);
+            }
         }
 
         ListToPage.setPage(appealList, pageNum, pageSize);

+ 15 - 1
alien-store/src/main/java/shop/alien/store/service/impl/CommonCommentServiceImpl.java

@@ -27,16 +27,30 @@ public class CommonCommentServiceImpl extends ServiceImpl<CommonCommentMapper, C
     @Autowired
     private TextModerationUtil textModerationUtil;
 
+    /**
+     * 新增评论
+     * 
+     * @param commonComment 评论对象
+     * @return 0:成功, 1:失败, 2:文本内容异常, 4:字数超限(超过300字)
+     */
     @Override
     public Integer addComment(CommonComment commonComment) {
+        // 校验评论内容字数限制(300字)
+        if (commonComment.getContent() != null && commonComment.getContent().length() > 300) {
+            log.warn("评论内容超过300字限制,content length={}", commonComment.getContent().length());
+            return 4; // 字数超限
+        }
+        
+        // 文本内容审核
         TextModerationResultVO textCheckResult = null;
         try {
             textCheckResult = textModerationUtil.invokeFunction(commonComment.getContent(), CommonRatingServiceImpl.SERVICES_LIST);
             if ("high".equals(textCheckResult.getRiskLevel())) {
-                return 2;
+                return 2; // 文本内容异常(包含敏感词)
             }
             return this.save(commonComment) ? 0 : 1;
         } catch (Exception e) {
+            log.error("新增评论失败", e);
             return 1;
         }
     }

+ 329 - 29
alien-store/src/main/java/shop/alien/store/service/impl/CommonRatingServiceImpl.java

@@ -21,9 +21,11 @@ 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.*;
+import shop.alien.entity.store.TagsSynonym;
 import shop.alien.store.config.WebSocketProcess;
 import shop.alien.store.service.CommonRatingService;
 import shop.alien.store.util.CommonConstant;
@@ -32,6 +34,7 @@ import shop.alien.util.common.constant.RatingBusinessTypeEnum;
 import shop.alien.util.common.safe.TextModerationResultVO;
 import shop.alien.util.common.safe.TextModerationUtil;
 import shop.alien.util.common.safe.TextReviewServiceEnum;
+import shop.alien.util.common.DateUtils;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -66,6 +69,7 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
     private final LifeLikeRecordMapper lifeLikeRecordMapper;
     private final LifeCollectMapper lifeCollectMapper;
     private final LifeFansMapper lifeFansMapper;
+    private final TagsSynonymMapper tagsSynonymMapper;
 
 
     public static final List<String> SERVICES_LIST = ImmutableList.of(
@@ -152,21 +156,24 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
         }
 
     }
-
     @Override
-    public R getRatingList(Integer pageNum, Integer pageSize, Integer businessType, Long businessId, Long userId, Integer auditStatus, Integer searchScore) {
+    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);
         LambdaQueryWrapper<CommonRating> wrapper = new LambdaQueryWrapper<>();
         
+        // 业务类型筛选
         if (businessType != null) {
             wrapper.eq(CommonRating::getBusinessType, businessType);
         }
+        // 业务ID筛选
         if (businessId != null) {
             wrapper.eq(CommonRating::getBusinessId, businessId);
         }
+        // 审核状态筛选
         if (auditStatus != null) {
             wrapper.eq(CommonRating::getAuditStatus, auditStatus);
         }
+        // 评分等级筛选
         if (searchScore != null) {
             if(searchScore == 1){
                 // 1-好评
@@ -182,17 +189,89 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
             }else if(searchScore == 4){
                 // 4-有图
                 wrapper.isNotNull(CommonRating::getImageUrls);
-                // 2. 排除 空字符串 ""
                 wrapper.ne(CommonRating::getImageUrls, "");
-                // 3. 排除 纯空格字符串(如"   ")—— 用 TRIM 函数去掉首尾空格后判断非空
                 wrapper.apply("TRIM({0}) <> ''", "image_urls");
             }
         }
+        // 时间范围筛选
+        if (days != null && days > 0) {
+            Date date = DateUtils.calcDays(new Date(), -days);
+            wrapper.ge(CommonRating::getCreatedTime, date);
+        }
+        // 回复状态筛选(使用EXISTS子查询在数据库层面筛选)
+        if (replyStatus != null && (replyStatus == 1 || replyStatus == 2)) {
+            if (replyStatus == 1) {
+                // 已回复:存在商户评论
+                wrapper.apply("EXISTS (SELECT 1 FROM common_comment cc WHERE cc.source_type = 1 " +
+                             "AND cc.source_id = common_rating.id AND cc.comment_type = 2 " +
+                             "AND cc.is_show = 1 AND cc.audit_status = 1 AND cc.delete_flag = 0)");
+            } else if (replyStatus == 2) {
+                // 未回复:不存在商户评论
+                wrapper.apply("NOT EXISTS (SELECT 1 FROM common_comment cc WHERE cc.source_type = 1 " +
+                             "AND cc.source_id = common_rating.id AND cc.comment_type = 2 " +
+                             "AND cc.is_show = 1 AND cc.audit_status = 1 AND cc.delete_flag = 0)");
+            }
+        }
+        // 标签筛选
+        if (tagId != null) {
+            // 1. 查询标签关联的评论ID列表(tags_synonym.comment_id 关联 common_comment.id)
+            LambdaQueryWrapper<TagsSynonym> tagWrapper = new LambdaQueryWrapper<>();
+            tagWrapper.eq(TagsSynonym::getMainTagId, tagId)
+                     .eq(TagsSynonym::getDeleteFlag, 0)
+                     .isNotNull(TagsSynonym::getCommentId);  // 确保comment_id不为空
+            List<TagsSynonym> tagsSynonymList = tagsSynonymMapper.selectList(tagWrapper);
+            
+            if (CollectionUtils.isNotEmpty(tagsSynonymList)) {
+                // 2. 提取评论ID列表(common_comment.id)
+                List<Long> commentIdList = tagsSynonymList.stream()
+                        .filter(synonym -> synonym != null && synonym.getCommentId() != null)
+                        .map(synonym -> synonym.getCommentId().longValue())
+                        .distinct()
+                        .collect(Collectors.toList());
+                
+                if (CollectionUtils.isNotEmpty(commentIdList)) {
+                    // 3. 通过评论ID查询common_comment表,获取source_id(评价ID)
+                    LambdaQueryWrapper<CommonComment> commentWrapper = new LambdaQueryWrapper<>();
+                    commentWrapper.in(CommonComment::getId, commentIdList)
+                                 .eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())  // source_type=1表示评价的评论
+                                 .eq(CommonComment::getIsShow, 1)
+                                 .eq(CommonComment::getAuditStatus, 1);
+                    List<CommonComment> comments = commonCommentMapper.selectList(commentWrapper);
+                    
+                    if (CollectionUtils.isNotEmpty(comments)) {
+                        // 4. 提取评价ID列表(common_comment.source_id = common_rating.id)
+                        List<Long> ratingIdList = comments.stream()
+                                .filter(comment -> comment.getSourceId() != null)
+                                .map(CommonComment::getSourceId)
+                                .distinct()
+                                .collect(Collectors.toList());
+                        
+                        if (CollectionUtils.isNotEmpty(ratingIdList)) {
+                            wrapper.in(CommonRating::getId, ratingIdList);
+                        } else {
+                            // 如果没有匹配的评价ID,返回空结果
+                            wrapper.eq(CommonRating::getId, -1);
+                        }
+                    } else {
+                        // 如果没有匹配的评论,返回空结果
+                        wrapper.eq(CommonRating::getId, -1);
+                    }
+                } else {
+                    // 如果没有评论ID,返回空结果
+                    wrapper.eq(CommonRating::getId, -1);
+                }
+            } else {
+                // 如果没有标签关联,返回空结果
+                wrapper.eq(CommonRating::getId, -1);
+            }
+        }
         
         wrapper.eq(CommonRating::getIsShow, 1);
         wrapper.orderByDesc(CommonRating::getId);
         IPage<CommonRating> page1 = this.page(page, wrapper);
-        return doListBusinessWithType(page1, businessType,userId);
+        
+        // 处理回复状态筛选
+        return doListBusinessWithType(page1, businessType, userId, replyStatus);
     }
 
     @Override
@@ -211,6 +290,29 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
         }
         // 获取评价统计信息(总评论数、有图评论数、好评数、中评数、差评数)
         ratingCount = commonRatingMapper.getRatingCount(new QueryWrapper<CommonRating>().in("id", collect));
+        
+        // 计算好评、中评、差评占比
+        // 注意:数据库返回的 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) {
+            // 计算占比(保留2位小数)
+            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;
+            
+            ratingCount.put("goodPercent", goodPercent);
+            ratingCount.put("midPercent", midPercent);
+            ratingCount.put("badPercent", badPercent);
+        } else {
+            ratingCount.put("goodPercent", 0.0);
+            ratingCount.put("midPercent", 0.0);
+            ratingCount.put("badPercent", 0.0);
+        }
+        
         if(RatingBusinessTypeEnum.STORE_RATING.getBusinessType() == businessType){
             // 1店铺评分
             StoreInfo storeInfo = storeInfoMapper.selectById(businessId);
@@ -403,19 +505,29 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
         }
     }
 
-    private R doListBusinessWithType(IPage<CommonRating> page1, Integer businessType, Long userId) {
+    /**
+     * 根据业务类型处理评价列表
+     *
+     * @param page1       评价分页数据
+     * @param businessType 业务类型
+     * @param userId      用户ID
+     * @param replyStatus 回复状态(0:全部, 1:已回复, 2:未回复)
+     * @return R<IPage<CommonRatingVo>>
+     */
+    private R<IPage<CommonRatingVo>> doListBusinessWithType(IPage<CommonRating> page1, Integer businessType, Long userId, Integer replyStatus) {
         if(businessType == RatingBusinessTypeEnum.STORE_RATING.getBusinessType()){
-            IPage<CommonRatingVo> result = new Page<>(page1.getPages(), page1.getSize(), page1.getTotal());
-            List resultList = new ArrayList();
+            IPage<CommonRatingVo> result = new Page<>(page1.getCurrent(), page1.getSize(), page1.getTotal());
+            List<CommonRatingVo> resultList = new ArrayList<>();
             if(page1.getRecords().isEmpty()){
                 result.setRecords(resultList);
                 return R.data(result);
             }
-            // 1查询评价用户信息
+            
+            // 1. 查询评价用户信息
             Set<Long> userIdSet = page1.getRecords().stream()
                     .map(CommonRating::getUserId)
                     .collect(Collectors.toSet());
-            List<LifeUser> lifeUsers = new  ArrayList<>();
+            List<LifeUser> lifeUsers = new ArrayList<>();
             Map<Integer, LifeUser> lifeUserMap = new HashMap<>();
             if (!userIdSet.isEmpty()){
                 lifeUsers = lifeUserMapper.selectList(
@@ -424,49 +536,108 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
                 lifeUserMap = lifeUsers.stream()
                         .collect(Collectors.toMap(LifeUser::getId, Function.identity()));
             }
-            // 2查询当前用户点赞列表(仅评价)
-            List<LifeLikeRecord> lifeLikeRecords = lifeLikeRecordMapper.selectList(
-                    new QueryWrapper<LifeLikeRecord>().lambda()
-                    .eq(LifeLikeRecord::getDianzanId, userId)
-                    .eq(LifeLikeRecord::getType, CommonConstant.RATING_LIKE));
-            Map<String, LifeLikeRecord> likeRecordMap = lifeLikeRecords.stream()
-                    .collect(Collectors.toMap(LifeLikeRecord::getHuifuId, Function.identity()));
-
+            
+            // 2. 查询当前用户点赞列表(仅评价)
+            List<LifeLikeRecord> lifeLikeRecords = new ArrayList<>();
+            Map<String, LifeLikeRecord> likeRecordMap = new HashMap<>();
+            if (userId != null) {
+                lifeLikeRecords = lifeLikeRecordMapper.selectList(
+                        new QueryWrapper<LifeLikeRecord>().lambda()
+                        .eq(LifeLikeRecord::getDianzanId, userId)
+                        .eq(LifeLikeRecord::getType, CommonConstant.RATING_LIKE));
+                likeRecordMap = lifeLikeRecords.stream()
+                        .collect(Collectors.toMap(LifeLikeRecord::getHuifuId, Function.identity()));
+            }
 
-            // 1.查询评价的评论的记录个数
+            // 3. 查询评价的评论记录个数和商户回复状态
             Set<Long> ratingIdSet = page1.getRecords().stream()
                     .map(CommonRating::getId)
                     .collect(Collectors.toSet());
-            LambdaQueryWrapper<CommonComment> commentWrapper = new LambdaQueryWrapper<CommonComment>()
-                    .eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())
-                    .in(CommonComment::getSourceId, ratingIdSet);
-            // 评价id对应的所有评论 定义Map存储「评价ID -> 该评价下的总评论数」
-            Map<Long, Long> ratingCommentCountMap = commonCommentMapper.selectList(commentWrapper).stream()
+            
+            // 查询所有评论(用于统计评论数)
+            LambdaQueryWrapper<CommonComment> commentWrapper = new LambdaQueryWrapper<>();
+            commentWrapper.eq(CommonComment::getSourceType, CommentSourceTypeEnum.STORE_COMMENT.getType())
+                         .in(CommonComment::getSourceId, ratingIdSet)
+                         .eq(CommonComment::getIsShow, 1)
+                         .eq(CommonComment::getAuditStatus, 1);
+            List<CommonComment> allComments = commonCommentMapper.selectList(commentWrapper);
+            
+            // 评价ID -> 该评价下的总评论数
+            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();
                 BeanUtil.copyProperties(record, commonRatingVo);
-                // 判断用户信息
+                
+                // 设置用户信息
                 if(lifeUserMap.containsKey(Integer.parseInt(record.getUserId().toString()))){
                     LifeUser lifeUser = lifeUserMap.get(Integer.parseInt(record.getUserId().toString()));
-                    // 设置评论用户信息
                     commonRatingVo.setUserImage(lifeUser.getUserImage());
                     commonRatingVo.setUserName(lifeUser.getUserName());
                 }
-                // 判断当前登录人是否点赞过
+                
+                // 设置点赞状态
                 commonRatingVo.setIsLike(0);
                 if(likeRecordMap.containsKey(record.getId().toString())){
                     commonRatingVo.setIsLike(1);
                 }
-                // 3.1 从映射中获取该评价的总评论数(默认0)
+                
+                // 设置评论数
                 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);
             }
+            
             result.setRecords(resultList);
             return R.data(result);
         }
-        return null;
+        // 如果不是店铺评价类型,返回空结果
+        IPage<CommonRatingVo> emptyResult = new Page<>(page1.getCurrent(), page1.getSize(), 0);
+        return R.data(emptyResult);
     }
 /*
     @Override
@@ -495,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;
+    }
 }