fix(ai-companion): 修复点赞状态与评论回复展示逻辑
- 分页查询接口新增当前用户点赞状态返回 - CommentVO 新增 replies 与 replyCount 字段支持嵌套回复 - 评论服务支持查询一级评论及其前 999 条回复 - 免登录白名单新增 /ai-companion/comment/page 接口
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
"active": true,
|
||||
"started_at": "2026-01-26T13:01:18.447Z",
|
||||
"original_prompt": "刚刚回滚了代码,现在AI陪聊角色评论需要使用KeyboardAiCompanionCommentLikeService添加一个评论点赞接口,用来记录点赞和取消点赞。 ulw",
|
||||
"reinforcement_count": 8,
|
||||
"last_checked_at": "2026-01-27T10:35:42.226Z"
|
||||
"reinforcement_count": 10,
|
||||
"last_checked_at": "2026-01-27T11:00:42.142Z"
|
||||
}
|
||||
@@ -115,7 +115,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
"/ai-companion/page",
|
||||
"/chat/history",
|
||||
"/ai-companion/comment/add",
|
||||
"/speech/transcribe"
|
||||
"/speech/transcribe",
|
||||
"/ai-companion/comment/page"
|
||||
};
|
||||
}
|
||||
@Bean
|
||||
|
||||
@@ -34,9 +34,10 @@ public class AiCompanionController {
|
||||
private KeyboardAiCompanionLikeService aiCompanionLikeService;
|
||||
|
||||
@PostMapping("/page")
|
||||
@Operation(summary = "分页查询AI陪聊角色", description = "分页查询已上线的AI陪聊角色列表")
|
||||
@Operation(summary = "分页查询AI陪聊角色", description = "分页查询已上线的AI陪聊角色列表,包含点赞数、评论数和当前用户点赞状态")
|
||||
public BaseResponse<IPage<AiCompanionVO>> pageList(@RequestBody PageDTO pageDTO) {
|
||||
IPage<AiCompanionVO> result = aiCompanionService.pageList(pageDTO.getPageNum(), pageDTO.getPageSize());
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
IPage<AiCompanionVO> result = aiCompanionService.pageListWithLikeStatus(userId, pageDTO.getPageNum(), pageDTO.getPageSize());
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ public class AiCompanionVO {
|
||||
@Schema(description = "评论总数")
|
||||
private Integer commentCount;
|
||||
|
||||
@Schema(description = "当前用户是否已点赞")
|
||||
private Boolean liked;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
@@ -45,4 +46,10 @@ public class CommentVO {
|
||||
|
||||
@Schema(description = "评论创建时间")
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "回复列表(仅一级评论有值,默认返回前3条)")
|
||||
private List<CommentVO> replies;
|
||||
|
||||
@Schema(description = "回复总数")
|
||||
private Integer replyCount;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@ public interface KeyboardAiCompanionService extends IService<KeyboardAiCompanion
|
||||
*/
|
||||
IPage<AiCompanionVO> pageList(Integer pageNum, Integer pageSize);
|
||||
|
||||
/**
|
||||
* 分页查询已上线的AI陪聊角色(带当前用户点赞状态)
|
||||
*
|
||||
* @param userId 当前用户ID
|
||||
* @param pageNum 页码
|
||||
* @param pageSize 每页数量
|
||||
* @return 分页结果
|
||||
*/
|
||||
IPage<AiCompanionVO> pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize);
|
||||
|
||||
/**
|
||||
* 根据AI人设ID获取系统提示词
|
||||
*
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.yolo.keyborad.service.UserService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -104,12 +105,51 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
|
||||
.orderByDesc(KeyboardAiCompanionComment::getCreatedAt);
|
||||
IPage<KeyboardAiCompanionComment> entityPage = this.page(page, queryWrapper);
|
||||
|
||||
// 获取所有用户ID
|
||||
List<Long> userIds = entityPage.getRecords().stream()
|
||||
.map(KeyboardAiCompanionComment::getUserId)
|
||||
.distinct()
|
||||
// 获取所有一级评论ID
|
||||
List<Long> topCommentIds = entityPage.getRecords().stream()
|
||||
.map(KeyboardAiCompanionComment::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 批量查询回复(每条一级评论取前3条回复)
|
||||
Map<Long, List<KeyboardAiCompanionComment>> repliesMap = Map.of();
|
||||
Map<Long, Long> replyCountMap = Map.of();
|
||||
if (!topCommentIds.isEmpty()) {
|
||||
// 查询所有回复
|
||||
LambdaQueryWrapper<KeyboardAiCompanionComment> replyWrapper = new LambdaQueryWrapper<>();
|
||||
replyWrapper.in(KeyboardAiCompanionComment::getRootId, topCommentIds)
|
||||
.eq(KeyboardAiCompanionComment::getStatus, 1)
|
||||
.orderByAsc(KeyboardAiCompanionComment::getCreatedAt);
|
||||
List<KeyboardAiCompanionComment> allReplies = this.list(replyWrapper);
|
||||
|
||||
// 按rootId分组,每组取前3条
|
||||
repliesMap = allReplies.stream()
|
||||
.collect(Collectors.groupingBy(KeyboardAiCompanionComment::getRootId));
|
||||
|
||||
// 统计回复数量
|
||||
replyCountMap = repliesMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> (long) e.getValue().size()));
|
||||
|
||||
// 每组只保留前3条
|
||||
repliesMap = repliesMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> e.getValue().stream().limit(999).collect(Collectors.toList())
|
||||
));
|
||||
}
|
||||
|
||||
// 收集所有需要查询的用户ID(一级评论 + 回复)
|
||||
List<Long> userIds = new ArrayList<>(entityPage.getRecords().stream()
|
||||
.map(KeyboardAiCompanionComment::getUserId)
|
||||
.collect(Collectors.toSet()));
|
||||
repliesMap.values().stream()
|
||||
.flatMap(List::stream)
|
||||
.map(KeyboardAiCompanionComment::getUserId)
|
||||
.forEach(uid -> {
|
||||
if (!userIds.contains(uid)) {
|
||||
userIds.add(uid);
|
||||
}
|
||||
});
|
||||
|
||||
// 批量查询用户信息
|
||||
Map<Long, KeyboardUser> userMap = Map.of();
|
||||
if (!userIds.isEmpty()) {
|
||||
@@ -117,15 +157,38 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
|
||||
userMap = users.stream().collect(Collectors.toMap(KeyboardUser::getId, u -> u));
|
||||
}
|
||||
|
||||
// 获取当前用户已点赞的评论ID
|
||||
List<Long> commentIds = entityPage.getRecords().stream()
|
||||
// 收集所有评论ID用于查询点赞状态(一级评论 + 回复)
|
||||
List<Long> allCommentIds = new ArrayList<>(topCommentIds);
|
||||
repliesMap.values().stream()
|
||||
.flatMap(List::stream)
|
||||
.map(KeyboardAiCompanionComment::getId)
|
||||
.collect(Collectors.toList());
|
||||
Set<Long> likedCommentIds = commentLikeService.getLikedCommentIds(userId, commentIds);
|
||||
.forEach(allCommentIds::add);
|
||||
Set<Long> likedCommentIds = commentLikeService.getLikedCommentIds(userId, allCommentIds);
|
||||
|
||||
// 转换为VO
|
||||
Map<Long, KeyboardUser> finalUserMap = userMap;
|
||||
Map<Long, List<KeyboardAiCompanionComment>> finalRepliesMap = repliesMap;
|
||||
Map<Long, Long> finalReplyCountMap = replyCountMap;
|
||||
|
||||
return entityPage.convert(entity -> {
|
||||
CommentVO vo = convertToVO(entity, finalUserMap, likedCommentIds);
|
||||
|
||||
// 填充回复列表
|
||||
List<KeyboardAiCompanionComment> replies = finalRepliesMap.getOrDefault(entity.getId(), List.of());
|
||||
List<CommentVO> replyVOs = replies.stream()
|
||||
.map(reply -> convertToVO(reply, finalUserMap, likedCommentIds))
|
||||
.collect(Collectors.toList());
|
||||
vo.setReplies(replyVOs);
|
||||
vo.setReplyCount(finalReplyCountMap.getOrDefault(entity.getId(), 0L).intValue());
|
||||
|
||||
return vo;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将评论实体转换为VO
|
||||
*/
|
||||
private CommentVO convertToVO(KeyboardAiCompanionComment entity, Map<Long, KeyboardUser> userMap, Set<Long> likedCommentIds) {
|
||||
CommentVO vo = new CommentVO();
|
||||
vo.setId(entity.getId());
|
||||
vo.setCompanionId(entity.getCompanionId());
|
||||
@@ -138,12 +201,11 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl<KeyboardA
|
||||
vo.setLiked(likedCommentIds.contains(entity.getId()));
|
||||
|
||||
// 填充用户信息
|
||||
KeyboardUser user = finalUserMap.get(entity.getUserId());
|
||||
KeyboardUser user = userMap.get(entity.getUserId());
|
||||
if (user != null) {
|
||||
vo.setUserName(user.getNickName());
|
||||
vo.setUserAvatar(user.getAvatarUrl());
|
||||
}
|
||||
return vo;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.yolo.keyborad.service.KeyboardAiCompanionService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
@@ -83,6 +84,58 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl<KeyboardAiCompan
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<AiCompanionVO> pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize) {
|
||||
Page<KeyboardAiCompanion> page = new Page<>(pageNum, pageSize);
|
||||
LambdaQueryWrapper<KeyboardAiCompanion> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(KeyboardAiCompanion::getStatus, 1)
|
||||
.eq(KeyboardAiCompanion::getVisibility, 1)
|
||||
.orderByDesc(KeyboardAiCompanion::getSortOrder)
|
||||
.orderByDesc(KeyboardAiCompanion::getPopularityScore);
|
||||
IPage<KeyboardAiCompanion> entityPage = this.page(page, queryWrapper);
|
||||
|
||||
// 获取所有角色ID
|
||||
List<Long> companionIds = entityPage.getRecords().stream()
|
||||
.map(KeyboardAiCompanion::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 批量统计点赞数
|
||||
Map<Long, Long> likeCountMap = Map.of();
|
||||
if (!companionIds.isEmpty()) {
|
||||
LambdaQueryWrapper<KeyboardAiCompanionLike> likeWrapper = new LambdaQueryWrapper<>();
|
||||
likeWrapper.in(KeyboardAiCompanionLike::getCompanionId, companionIds)
|
||||
.eq(KeyboardAiCompanionLike::getStatus, (short) 1);
|
||||
List<KeyboardAiCompanionLike> likes = companionLikeService.list(likeWrapper);
|
||||
likeCountMap = likes.stream()
|
||||
.collect(Collectors.groupingBy(KeyboardAiCompanionLike::getCompanionId, Collectors.counting()));
|
||||
}
|
||||
|
||||
// 批量统计评论数
|
||||
Map<Long, Long> commentCountMap = Map.of();
|
||||
if (!companionIds.isEmpty()) {
|
||||
LambdaQueryWrapper<KeyboardAiCompanionComment> commentWrapper = new LambdaQueryWrapper<>();
|
||||
commentWrapper.in(KeyboardAiCompanionComment::getCompanionId, companionIds)
|
||||
.eq(KeyboardAiCompanionComment::getStatus, (short) 1);
|
||||
List<KeyboardAiCompanionComment> comments = companionCommentService.list(commentWrapper);
|
||||
commentCountMap = comments.stream()
|
||||
.collect(Collectors.groupingBy(KeyboardAiCompanionComment::getCompanionId, Collectors.counting()));
|
||||
}
|
||||
|
||||
// 获取当前用户已点赞的角色ID
|
||||
Set<Long> likedCompanionIds = companionLikeService.getLikedCompanionIds(userId, companionIds);
|
||||
|
||||
// 转换为VO并填充统计数据和点赞状态
|
||||
Map<Long, Long> finalLikeCountMap = likeCountMap;
|
||||
Map<Long, Long> finalCommentCountMap = commentCountMap;
|
||||
return entityPage.convert(entity -> {
|
||||
AiCompanionVO vo = BeanUtil.copyProperties(entity, AiCompanionVO.class);
|
||||
vo.setLikeCount(finalLikeCountMap.getOrDefault(entity.getId(), 0L).intValue());
|
||||
vo.setCommentCount(finalCommentCountMap.getOrDefault(entity.getId(), 0L).intValue());
|
||||
vo.setLiked(likedCompanionIds.contains(entity.getId()));
|
||||
return vo;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSystemPromptById(Long companionId) {
|
||||
KeyboardAiCompanion companion = this.getById(companionId);
|
||||
|
||||
Reference in New Issue
Block a user