diff --git a/.omc/ultrawork-state.json b/.omc/ultrawork-state.json index e4cc879..e91061a 100644 --- a/.omc/ultrawork-state.json +++ b/.omc/ultrawork-state.json @@ -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" } \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java b/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java index 439c34b..f4493d3 100644 --- a/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java +++ b/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java @@ -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 diff --git a/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java b/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java index c0e5a19..db224ab 100644 --- a/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java +++ b/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java @@ -34,9 +34,10 @@ public class AiCompanionController { private KeyboardAiCompanionLikeService aiCompanionLikeService; @PostMapping("/page") - @Operation(summary = "分页查询AI陪聊角色", description = "分页查询已上线的AI陪聊角色列表") + @Operation(summary = "分页查询AI陪聊角色", description = "分页查询已上线的AI陪聊角色列表,包含点赞数、评论数和当前用户点赞状态") public BaseResponse> pageList(@RequestBody PageDTO pageDTO) { - IPage result = aiCompanionService.pageList(pageDTO.getPageNum(), pageDTO.getPageSize()); + Long userId = StpUtil.getLoginIdAsLong(); + IPage result = aiCompanionService.pageListWithLikeStatus(userId, pageDTO.getPageNum(), pageDTO.getPageSize()); return ResultUtils.success(result); } diff --git a/src/main/java/com/yolo/keyborad/model/vo/AiCompanionVO.java b/src/main/java/com/yolo/keyborad/model/vo/AiCompanionVO.java index eb9a1f1..28c39d3 100644 --- a/src/main/java/com/yolo/keyborad/model/vo/AiCompanionVO.java +++ b/src/main/java/com/yolo/keyborad/model/vo/AiCompanionVO.java @@ -61,6 +61,9 @@ public class AiCompanionVO { @Schema(description = "评论总数") private Integer commentCount; + @Schema(description = "当前用户是否已点赞") + private Boolean liked; + @Schema(description = "创建时间") private Date createdAt; } diff --git a/src/main/java/com/yolo/keyborad/model/vo/CommentVO.java b/src/main/java/com/yolo/keyborad/model/vo/CommentVO.java index c67db8f..c9a48d8 100644 --- a/src/main/java/com/yolo/keyborad/model/vo/CommentVO.java +++ b/src/main/java/com/yolo/keyborad/model/vo/CommentVO.java @@ -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 replies; + + @Schema(description = "回复总数") + private Integer replyCount; } diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java b/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java index 7a76ff6..8e3d81b 100644 --- a/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java +++ b/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java @@ -20,6 +20,16 @@ public interface KeyboardAiCompanionService extends IService pageList(Integer pageNum, Integer pageSize); + /** + * 分页查询已上线的AI陪聊角色(带当前用户点赞状态) + * + * @param userId 当前用户ID + * @param pageNum 页码 + * @param pageSize 每页数量 + * @return 分页结果 + */ + IPage pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize); + /** * 根据AI人设ID获取系统提示词 * diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionCommentServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionCommentServiceImpl.java index f7d173e..f2aed85 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionCommentServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionCommentServiceImpl.java @@ -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 entityPage = this.page(page, queryWrapper); - // 获取所有用户ID - List userIds = entityPage.getRecords().stream() - .map(KeyboardAiCompanionComment::getUserId) - .distinct() + // 获取所有一级评论ID + List topCommentIds = entityPage.getRecords().stream() + .map(KeyboardAiCompanionComment::getId) .collect(Collectors.toList()); + // 批量查询回复(每条一级评论取前3条回复) + Map> repliesMap = Map.of(); + Map replyCountMap = Map.of(); + if (!topCommentIds.isEmpty()) { + // 查询所有回复 + LambdaQueryWrapper replyWrapper = new LambdaQueryWrapper<>(); + replyWrapper.in(KeyboardAiCompanionComment::getRootId, topCommentIds) + .eq(KeyboardAiCompanionComment::getStatus, 1) + .orderByAsc(KeyboardAiCompanionComment::getCreatedAt); + List 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 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 userMap = Map.of(); if (!userIds.isEmpty()) { @@ -117,33 +157,55 @@ public class KeyboardAiCompanionCommentServiceImpl extends ServiceImpl u)); } - // 获取当前用户已点赞的评论ID - List commentIds = entityPage.getRecords().stream() + // 收集所有评论ID用于查询点赞状态(一级评论 + 回复) + List allCommentIds = new ArrayList<>(topCommentIds); + repliesMap.values().stream() + .flatMap(List::stream) .map(KeyboardAiCompanionComment::getId) - .collect(Collectors.toList()); - Set likedCommentIds = commentLikeService.getLikedCommentIds(userId, commentIds); + .forEach(allCommentIds::add); + Set likedCommentIds = commentLikeService.getLikedCommentIds(userId, allCommentIds); // 转换为VO Map finalUserMap = userMap; - return entityPage.convert(entity -> { - CommentVO vo = new CommentVO(); - vo.setId(entity.getId()); - vo.setCompanionId(entity.getCompanionId()); - vo.setUserId(entity.getUserId()); - vo.setParentId(entity.getParentId()); - vo.setRootId(entity.getRootId()); - vo.setContent(entity.getContent()); - vo.setLikeCount(entity.getLikeCount()); - vo.setCreatedAt(entity.getCreatedAt()); - vo.setLiked(likedCommentIds.contains(entity.getId())); + Map> finalRepliesMap = repliesMap; + Map finalReplyCountMap = replyCountMap; + + return entityPage.convert(entity -> { + CommentVO vo = convertToVO(entity, finalUserMap, likedCommentIds); + + // 填充回复列表 + List replies = finalRepliesMap.getOrDefault(entity.getId(), List.of()); + List replyVOs = replies.stream() + .map(reply -> convertToVO(reply, finalUserMap, likedCommentIds)) + .collect(Collectors.toList()); + vo.setReplies(replyVOs); + vo.setReplyCount(finalReplyCountMap.getOrDefault(entity.getId(), 0L).intValue()); - // 填充用户信息 - KeyboardUser user = finalUserMap.get(entity.getUserId()); - if (user != null) { - vo.setUserName(user.getNickName()); - vo.setUserAvatar(user.getAvatarUrl()); - } return vo; }); } + + /** + * 将评论实体转换为VO + */ + private CommentVO convertToVO(KeyboardAiCompanionComment entity, Map userMap, Set likedCommentIds) { + CommentVO vo = new CommentVO(); + vo.setId(entity.getId()); + vo.setCompanionId(entity.getCompanionId()); + vo.setUserId(entity.getUserId()); + vo.setParentId(entity.getParentId()); + vo.setRootId(entity.getRootId()); + vo.setContent(entity.getContent()); + vo.setLikeCount(entity.getLikeCount()); + vo.setCreatedAt(entity.getCreatedAt()); + vo.setLiked(likedCommentIds.contains(entity.getId())); + + // 填充用户信息 + KeyboardUser user = userMap.get(entity.getUserId()); + if (user != null) { + vo.setUserName(user.getNickName()); + vo.setUserAvatar(user.getAvatarUrl()); + } + return vo; + } } diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java index 1079bc2..4a94b22 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java @@ -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 pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize) { + Page page = new Page<>(pageNum, pageSize); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(KeyboardAiCompanion::getStatus, 1) + .eq(KeyboardAiCompanion::getVisibility, 1) + .orderByDesc(KeyboardAiCompanion::getSortOrder) + .orderByDesc(KeyboardAiCompanion::getPopularityScore); + IPage entityPage = this.page(page, queryWrapper); + + // 获取所有角色ID + List companionIds = entityPage.getRecords().stream() + .map(KeyboardAiCompanion::getId) + .collect(Collectors.toList()); + + // 批量统计点赞数 + Map likeCountMap = Map.of(); + if (!companionIds.isEmpty()) { + LambdaQueryWrapper likeWrapper = new LambdaQueryWrapper<>(); + likeWrapper.in(KeyboardAiCompanionLike::getCompanionId, companionIds) + .eq(KeyboardAiCompanionLike::getStatus, (short) 1); + List likes = companionLikeService.list(likeWrapper); + likeCountMap = likes.stream() + .collect(Collectors.groupingBy(KeyboardAiCompanionLike::getCompanionId, Collectors.counting())); + } + + // 批量统计评论数 + Map commentCountMap = Map.of(); + if (!companionIds.isEmpty()) { + LambdaQueryWrapper commentWrapper = new LambdaQueryWrapper<>(); + commentWrapper.in(KeyboardAiCompanionComment::getCompanionId, companionIds) + .eq(KeyboardAiCompanionComment::getStatus, (short) 1); + List comments = companionCommentService.list(commentWrapper); + commentCountMap = comments.stream() + .collect(Collectors.groupingBy(KeyboardAiCompanionComment::getCompanionId, Collectors.counting())); + } + + // 获取当前用户已点赞的角色ID + Set likedCompanionIds = companionLikeService.getLikedCompanionIds(userId, companionIds); + + // 转换为VO并填充统计数据和点赞状态 + Map finalLikeCountMap = likeCountMap; + Map 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);