|
|
@@ -24,6 +24,7 @@ import shop.alien.entity.store.vo.CommonRatingVo;
|
|
|
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 +33,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 +68,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(
|
|
|
@@ -153,20 +156,39 @@ 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) {
|
|
|
+ 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 +204,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 +305,33 @@ 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;
|
|
|
+ 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 +524,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 +555,66 @@ 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()));
|
|
|
|
|
|
+ // 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));
|
|
|
+
|
|
|
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
|