diff --git a/music-houduan/src/main/java/com/test/musichouduan/repository/CommentRepository.java b/music-houduan/src/main/java/com/test/musichouduan/repository/CommentRepository.java index ec77a74..9d554e9 100644 --- a/music-houduan/src/main/java/com/test/musichouduan/repository/CommentRepository.java +++ b/music-houduan/src/main/java/com/test/musichouduan/repository/CommentRepository.java @@ -34,6 +34,14 @@ public interface CommentRepository extends JpaRepository, JpaSpec */ List findByParentIdOrderByCreateTimeAsc(Long parentId); + /** + * 根据父评论ID列表查询所有子评论 + * + * @param parentIds 父评论ID列表 + * @return 子评论列表 + */ + List findByParentIdInOrderByCreateTimeAsc(List parentIds); + /** * 根据用户查询评论 * diff --git a/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java b/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java index 84286c1..9b2c8a2 100644 --- a/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java +++ b/music-houduan/src/main/java/com/test/musichouduan/service/impl/CommentServiceImpl.java @@ -74,16 +74,28 @@ public class CommentServiceImpl implements CommentService { .map(this::convertToDTO) .collect(Collectors.toList()); - // 获取子评论 - for (CommentDTO commentDTO : commentDTOs) { - List children = commentRepository.findByParentIdOrderByCreateTimeAsc(commentDTO.getId()); - if (!children.isEmpty()) { - commentDTO.setChildren(children.stream() - .map(this::convertToDTO) - .collect(Collectors.toList())); - } else { - commentDTO.setChildren(new ArrayList<>()); - } + // 优化:一次性获取所有子评论 + // 1. 获取所有父评论的ID + List parentIds = commentDTOs.stream() + .map(CommentDTO::getId) + .collect(Collectors.toList()); + + // 2. 如果有父评论,则一次性查询出它们所有的子评论 + if (!parentIds.isEmpty()) { + List allChildren = commentRepository.findByParentIdInOrderByCreateTimeAsc(parentIds); + + // 3. 将子评论按其父ID分组 + java.util.Map> childrenMap = allChildren.stream() + .map(this::convertToDTO) + .collect(Collectors.groupingBy(CommentDTO::getParentId)); + + // 4. 将子评论列表设置到对应的父评论DTO中 + commentDTOs.forEach(parentDTO -> parentDTO.setChildren( + childrenMap.getOrDefault(parentDTO.getId(), new ArrayList<>()) + )); + } else { + // 如果没有父评论,确保children字段不是null + commentDTOs.forEach(parentDTO -> parentDTO.setChildren(new ArrayList<>())); } return new PageResult<>( diff --git a/music-qianduan/src/views/MusicDetail.vue b/music-qianduan/src/views/MusicDetail.vue index 2ef7f1d..4f5745d 100644 --- a/music-qianduan/src/views/MusicDetail.vue +++ b/music-qianduan/src/views/MusicDetail.vue @@ -129,8 +129,9 @@
+
- +
@@ -150,19 +151,69 @@
{{ comment.content }}
-
+ + +
回复 取消
+ + +
+
+
+ +
+
+
+
{{ child.user.username }}
+
+ 回复 + + 删除 + +
+
+
+ @{{ child.parentCommentUser.username }} + {{ child.content }} +
+ + +
+ +
+ 回复 + 取消 +
+
+
+
+
@@ -210,6 +261,7 @@ import { getCommentList, addComment, deleteComment as apiDeleteComment } from '. import { connect, subscribe, unsubscribe, disconnect } from '../utils/websocket' import { ElMessage, ElMessageBox } from 'element-plus' import { VideoPlay, VideoPause, Star, StarFilled, Plus } from '@element-plus/icons-vue' +import { processImageUrl } from '../utils/imageUtils' const route = useRoute() const router = useRouter() @@ -226,6 +278,7 @@ const comments = ref([]) const commentContent = ref('') const replyContent = ref('') const replyingTo = ref(null) +const replyTo = ref(null) const expandedComments = ref([]) let commentSubscription = null; @@ -398,15 +451,34 @@ const deleteComment = async (commentId) => { // 设置回复对象 const setReplyTo = (comment) => { - replyingTo.value = comment; + replyingTo.value = comment.id; + replyTo.value = comment; + if (!expandedComments.value.includes(comment.id)) { + expandedComments.value.push(comment.id); + } }; // 取消回复 const cancelReply = () => { replyingTo.value = null; + replyTo.value = null; replyContent.value = ''; }; +// 切换回复可见性 +const toggleReplies = (comment) => { + const commentId = comment.id; + const index = expandedComments.value.indexOf(commentId); + if (index > -1) { + expandedComments.value.splice(index, 1); + if (replyingTo.value === commentId) { + cancelReply(); + } + } else { + expandedComments.value.push(commentId); + } +}; + // WebSocket 订阅 const setupWebSocket = () => { if (!music.value) return; @@ -414,10 +486,30 @@ const setupWebSocket = () => { const destination = `/topic/comments/1/${music.value.id}`; // 1 代表音乐类型 commentSubscription = subscribe(destination, (newComment) => { if (newComment && newComment.id) { - // 简单处理:直接重新拉取整个评论列表 - fetchComments(); + if (newComment.user && newComment.user.avatar) { + newComment.user.avatar = processImageUrl(newComment.user.avatar); + } + + if (newComment.parentId) { + const parentComment = comments.value.find(c => c.id === newComment.parentId); + if (parentComment) { + if (!parentComment.children) { + parentComment.children = []; + } + parentComment.children.push(newComment); + } + } else { + if (!comments.value.some(c => c.id === newComment.id)) { + comments.value.unshift(newComment); + } + } + } else { + console.warn("Received invalid comment data via WebSocket:", newComment); } }); + }, (error) => { + console.error("WebSocket connection error:", error); + // ElMessage.error('评论服务连接失败,实时更新不可用'); }); };