|
|
@@ -21,10 +21,13 @@ 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.CommonCommentService;
|
|
|
import shop.alien.store.service.CommonRatingService;
|
|
|
import shop.alien.store.util.CommonConstant;
|
|
|
import shop.alien.util.common.constant.CommentSourceTypeEnum;
|
|
|
@@ -32,6 +35,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 +70,9 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
|
|
|
private final LifeLikeRecordMapper lifeLikeRecordMapper;
|
|
|
private final LifeCollectMapper lifeCollectMapper;
|
|
|
private final LifeFansMapper lifeFansMapper;
|
|
|
+ private final TagsSynonymMapper tagsSynonymMapper;
|
|
|
+ private final CommonCommentService commonCommentService;
|
|
|
+
|
|
|
|
|
|
|
|
|
public static final List<String> SERVICES_LIST = ImmutableList.of(
|
|
|
@@ -152,21 +159,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 +192,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 +293,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);
|
|
|
@@ -236,7 +341,7 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
|
|
|
List<Long> collect2 = commonRatings.stream().filter(i -> i.getScore() >= 4.5).map(CommonRating::getUserId).distinct().limit(6).collect(Collectors.toList());
|
|
|
if(!collect2.isEmpty()) {
|
|
|
List<LifeUser> lifeUsers = lifeUserMapper.selectList(new QueryWrapper<LifeUser>().lambda().in(LifeUser::getId, collect2));
|
|
|
- ratingCount.put("img", lifeUsers.stream().filter(x -> x.getUserImage() != null).map(LifeUser::getUserImage).collect(Collectors.toList()));
|
|
|
+ ratingCount.put("img", lifeUsers.stream().map(LifeUser::getUserImage).collect(Collectors.toList()));
|
|
|
} else {
|
|
|
ratingCount.put("img", new ArrayList<>());
|
|
|
}
|
|
|
@@ -333,62 +438,9 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
|
|
|
commonRatingVo.setIsCollect(0);
|
|
|
}
|
|
|
// 2查询一级评价
|
|
|
- QueryWrapper<CommonCommentVo> commentWrapper = new QueryWrapper<CommonCommentVo>()
|
|
|
- .eq("cc.source_type", CommentSourceTypeEnum.STORE_COMMENT.getType())
|
|
|
- .eq("cc.source_id", ratingId)
|
|
|
- .eq("cc.parent_id", 0);
|
|
|
- List<CommonCommentVo> commonComments = commonCommentMapper.selectALlComment(commentWrapper,CommonConstant.COMMENT_LIKE, userId);
|
|
|
-
|
|
|
- // 定义评论总数
|
|
|
- AtomicReference<Long> count = new AtomicReference<>(0L);
|
|
|
- count.updateAndGet(v -> v + commonComments.size());
|
|
|
- List<CommonCommentVo> commonCommentVos = new ArrayList<>();
|
|
|
- for (CommonCommentVo commonComment : commonComments) {
|
|
|
-// CommonCommentVo commonCommentVo = new CommonCommentVo();
|
|
|
-// BeanUtils.copyProperties(commonComment, commonCommentVo);
|
|
|
- // 递归获取所有子评论(扁平化)
|
|
|
- List<CommonCommentVo> allChildComments = getChildCommentsRecursively(commonComment.getId(), userId);
|
|
|
- count.updateAndGet(v -> v + allChildComments.size());
|
|
|
- // 一级评论本身的商家/用户标识和商家信息
|
|
|
- // setStoreUserInfo(first);
|
|
|
-
|
|
|
- // 按时间排序后绑定子评论列表
|
|
|
- allChildComments.sort(Comparator.comparing(CommonCommentVo::getCreatedTime));
|
|
|
-
|
|
|
- commonComment.setChildCommonComments(allChildComments);
|
|
|
- commonCommentVos.add(commonComment);
|
|
|
- }
|
|
|
- commonRatingVo.setCommentCount(count.get());
|
|
|
- commonRatingVo.setChildCommonComments(commonCommentVos);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private List<CommonCommentVo> getChildCommentsRecursively(Long id, Long userId) {
|
|
|
- List<CommonCommentVo> allChildComments = new ArrayList<>();
|
|
|
-
|
|
|
- // 查询直接回复当前评论的所有记录
|
|
|
- QueryWrapper<CommonCommentVo> wrapper = new QueryWrapper<>();
|
|
|
- wrapper.eq("cc.delete_flag", 0)
|
|
|
- .eq("cc.parent_id", id)
|
|
|
- .orderByAsc("cc.created_time");
|
|
|
- List<CommonCommentVo> directChildren = commonCommentMapper.selectALlComment(wrapper,CommonConstant.COMMENT_LIKE, userId);
|
|
|
-
|
|
|
- if (CollectionUtils.isEmpty(directChildren)) {
|
|
|
- return allChildComments;
|
|
|
+ List<CommonCommentVo> commonComments = commonCommentService.getFirstLevelComment(CommentSourceTypeEnum.STORE_COMMENT.getType(), ratingId,null,null, userId,CommonConstant.COMMENT_LIKE);
|
|
|
+ commonCommentService.getAllChildComment(userId, commonRatingVo, commonComments,CommonConstant.COMMENT_LIKE);
|
|
|
}
|
|
|
- // 处理每个直接子评论
|
|
|
- for (CommonCommentVo child : directChildren) {
|
|
|
- // 设置商家/用户标识
|
|
|
-// setStoreUserInfo(child);
|
|
|
- // 递归获取该子评论的所有子评论
|
|
|
- List<CommonCommentVo> grandChildren = getChildCommentsRecursively(child.getId(), userId);
|
|
|
- // 将当前子评论添加到结果列表
|
|
|
- allChildComments.add(child);
|
|
|
- // 将该子评论的所有子评论也添加到结果列表(扁平化)
|
|
|
- allChildComments.addAll(grandChildren);
|
|
|
- }
|
|
|
-
|
|
|
- return allChildComments;
|
|
|
}
|
|
|
|
|
|
@NotNull
|
|
|
@@ -403,19 +455,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 +486,109 @@ 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(
|
|
|
+ null,
|
|
|
+ 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 +617,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;
|
|
|
+ }
|
|
|
}
|
|
|
|