From 84ae421d800612d4dc5fcdeb35fce1701c4abba0 Mon Sep 17 00:00:00 2001 From: ikmkj <1@qq,com> Date: Fri, 25 Jul 2025 20:13:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(comment):=20=E6=B7=BB=E5=8A=A0=E6=AD=8C?= =?UTF-8?q?=E6=89=8B=E8=AF=A6=E6=83=85=E9=A1=B5=E8=AF=84=E8=AE=BA=E5=9B=9E?= =?UTF-8?q?=E5=A4=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增回复评论功能,支持嵌套回复 - 增加展开/收起子评论的功能 - 优化评论列表展示,支持子评论显示- 调整评论输入框和提交按钮布局 - 优化评论样式,区分主评论和子评论 --- music-qianduan/src/views/SingerDetail.vue | 169 +++++++++++++++++++--- 1 file changed, 146 insertions(+), 23 deletions(-) diff --git a/music-qianduan/src/views/SingerDetail.vue b/music-qianduan/src/views/SingerDetail.vue index 10da0d2..1459ffa 100644 --- a/music-qianduan/src/views/SingerDetail.vue +++ b/music-qianduan/src/views/SingerDetail.vue @@ -32,6 +32,18 @@ const comments = ref([]) // 评论内容 const commentContent = ref('') +// 回复内容 +const replyContent = ref('') + +// 回复对象 +const replyTo = ref(null) + +// 正在回复的评论 +const replyingTo = ref(null) + +// 展开的评论 +const expandedComments = ref([]) + // 加载状态 const loading = ref(false) @@ -178,15 +190,48 @@ const toggleCollect = async () => { } } +// 切换回复可见性 +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); + setReplyTo(comment); + } +}; + +// 设置回复 +const setReplyTo = (comment) => { + replyingTo.value = comment.id; + replyTo.value = comment; + replyContent.value = `@${comment.user.username} `; + if (!expandedComments.value.includes(comment.id)) { + expandedComments.value.push(comment.id); + } +} + +// 取消回复 +const cancelReply = () => { + replyingTo.value = null + replyTo.value = null + replyContent.value = '' +} + // 提交评论 -const submitComment = async () => { +const submitComment = async (isReply = false) => { if (!userStore.isLoggedIn) { ElMessage.warning('请先登录') router.push('/login') return } - if (!commentContent.value.trim()) { + const content = isReply ? replyContent.value : commentContent.value + if (!content.trim()) { ElMessage.warning('评论内容不能为空') return } @@ -195,14 +240,17 @@ const submitComment = async () => { const res = await addComment({ targetId: singerId.value, targetType: 3, // 3表示歌手 - content: commentContent.value + content: content, + parentId: isReply ? replyingTo.value : null }) if (res.code === 200) { - // 添加成功,评论将通过 WebSocket 推送,无需手动刷新 - // await fetchComments() // 移除手动刷新 - commentContent.value = '' - ElMessage.success('评论已发送') // 提示语可以调整 + if (isReply) { + replyContent.value = '' + } else { + commentContent.value = '' + } + ElMessage.success('评论已发送') } else { ElMessage.error(res.message || '评论失败') } @@ -283,19 +331,26 @@ onMounted(() => { connect(() => { const destination = `/topic/comments/3/${singerId.value}`; // 3 代表歌手类型 commentSubscription = subscribe(destination, (newComment) => { - // 收到新评论,添加到列表开头 if (newComment && newComment.id) { - // 处理新评论的用户头像 - if (newComment.user && newComment.user.avatar) { - newComment.user.avatar = processImageUrl(newComment.user.avatar); - } - // 检查是否已存在 - if (!comments.value.some(c => c.id === newComment.id)) { - comments.value.unshift(newComment); // 添加到开头 - console.log('New comment received via WebSocket:', newComment); - } + 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); + console.warn("Received invalid comment data via WebSocket:", newComment); } }); }, (error) => { @@ -431,10 +486,11 @@ onUnmounted(() => { :rows="3" placeholder="发表你的评论..." /> - 发表评论 +
+ 发表评论 +
-
@@ -445,6 +501,7 @@ onUnmounted(() => {
{{ comment.user.username }}
+ 回复 {
{{ comment.content }}
-
{{ comment.createTime }}
+ + + +
+ +
+ +
+ 回复 +
+
+
+
+ +
+
+
+
{{ child.user.username }}
+
+ + 删除 + +
+
+
{{ child.content }}
+
{{ child.createTime }}
+
+
+
@@ -578,7 +683,12 @@ onUnmounted(() => { display: flex; flex-direction: column; gap: 10px; - align-items: flex-end; +} + +.comment-submit-actions { + display: flex; + justify-content: flex-end; + gap: 10px; } .comment-list { @@ -611,13 +721,26 @@ onUnmounted(() => { font-weight: bold; } +.child-comment-list { + margin-top: 15px; + padding-left: 15px; + border-left: 2px solid #eee; +} + +.child-comment-input { + margin-top: 15px; +} + .comment-text { margin-bottom: 5px; color: #333; line-height: 1.5; } -.comment-time { +.comment-footer { + display: flex; + justify-content: space-between; + align-items: center; font-size: 0.8rem; color: #999; }