feat: 评论嵌套规则修复

This commit is contained in:
tim
2025-08-04 02:04:31 +08:00
parent 354cc7cd17
commit ba8babd68a
2 changed files with 47 additions and 22 deletions

View File

@@ -10,7 +10,11 @@
<div class="info-content"> <div class="info-content">
<div class="common-info-content-header"> <div class="common-info-content-header">
<div class="info-content-header-left"> <div class="info-content-header-left">
<div class="user-name">{{ comment.userName }}</div> <span class="user-name">{{ comment.userName }}</span>
<span v-if="level >= 2">
<i class="fas fa-reply reply-icon"></i>
<span class="user-name reply-user-name">{{ comment.parentUserName }}</span>
</span>
<div class="post-time">{{ comment.time }}</div> <div class="post-time">{{ comment.time }}</div>
</div> </div>
<div class="info-content-header-right"> <div class="info-content-header-right">
@@ -33,33 +37,23 @@
</ReactionsGroup> </ReactionsGroup>
</div> </div>
<div class="comment-editor-wrapper"> <div class="comment-editor-wrapper">
<CommentEditor v-if="showEditor" @submit="submitReply" :loading="isWaitingForReply" :disabled="!loggedIn" :show-login-overlay="!loggedIn" /> <CommentEditor v-if="showEditor" @submit="submitReply" :loading="isWaitingForReply" :disabled="!loggedIn"
:show-login-overlay="!loggedIn" />
</div> </div>
<div v-if="replyCount" class="reply-toggle" @click="toggleReplies"> <div v-if="replyCount && level < 2" class="reply-toggle" @click="toggleReplies">
<i v-if="showReplies" class="fas fa-chevron-up reply-toggle-icon"></i> <i v-if="showReplies" class="fas fa-chevron-up reply-toggle-icon"></i>
<i v-else class="fas fa-chevron-down reply-toggle-icon"></i> <i v-else class="fas fa-chevron-down reply-toggle-icon"></i>
{{ replyCount }}条回复 {{ replyCount }}条回复
</div> </div>
<div v-if="showReplies" class="reply-list"> <div v-if="showReplies && level < 2" class="reply-list">
<BaseTimeline :items="comment.reply"> <BaseTimeline :items="replyList">
<template #item="{ item }"> <template #item="{ item }">
<CommentItem :key="item.id" :comment="item" :level="level + 1" :default-show-replies="item.openReplies" /> <CommentItem :key="item.id" :comment="item" :level="level + 1" :default-show-replies="item.openReplies" />
</template> </template>
</BaseTimeline> </BaseTimeline>
<!-- <CommentItem
v-for="r in comment.reply"
:key="r.id"
:comment="r"
:level="level + 1"
:default-show-replies="r.openReplies"
/> -->
</div> </div>
<vue-easy-lightbox <vue-easy-lightbox :visible="lightboxVisible" :imgs="lightboxImgs" :index="lightboxIndex"
:visible="lightboxVisible" @hide="lightboxVisible = false" />
:imgs="lightboxImgs"
:index="lightboxIndex"
@hide="lightboxVisible = false"
/>
</div> </div>
</div> </div>
</template> </template>
@@ -118,6 +112,27 @@ const CommentItem = {
const toggleEditor = () => { const toggleEditor = () => {
showEditor.value = !showEditor.value showEditor.value = !showEditor.value
} }
// 合并所有子回复为一个扁平数组
const flattenReplies = (list) => {
let result = []
for (const r of list) {
result.push(r)
if (r.reply && r.reply.length > 0) {
result = result.concat(flattenReplies(r.reply))
}
}
return result
}
const replyList = computed(() => {
if (props.level < 1) {
return props.comment.reply
}
return flattenReplies(props.comment.reply || [])
})
const isAuthor = computed(() => authState.username === props.comment.userName) const isAuthor = computed(() => authState.username === props.comment.userName)
const isAdmin = computed(() => authState.role === 'ADMIN') const isAdmin = computed(() => authState.role === 'ADMIN')
const commentMenuItems = computed(() => const commentMenuItems = computed(() =>
@@ -208,7 +223,7 @@ const CommentItem = {
lightboxVisible.value = true lightboxVisible.value = true
} }
} }
return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply, copyCommentLink, renderMarkdown, isWaitingForReply, commentMenuItems, deleteComment, lightboxVisible, lightboxIndex, lightboxImgs, handleContentClick, loggedIn, replyCount } return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply, copyCommentLink, renderMarkdown, isWaitingForReply, commentMenuItems, deleteComment, lightboxVisible, lightboxIndex, lightboxImgs, handleContentClick, loggedIn, replyCount, replyList }
} }
} }
@@ -249,6 +264,15 @@ export default CommentItem
justify-content: space-between; justify-content: space-between;
} }
.reply-icon {
margin-right: 10px;
margin-left: 10px;
opacity: 0.5;
}
.reply-user-name {
opacity: 0.3;
}
@keyframes highlight { @keyframes highlight {
from { from {

View File

@@ -216,17 +216,18 @@ export default {
} }
} }
const mapComment = (c, level = 0) => ({ const mapComment = (c, parentUserName = '', level = 0) => ({
id: c.id, id: c.id,
userName: c.author.username, userName: c.author.username,
time: TimeManager.format(c.createdAt), time: TimeManager.format(c.createdAt),
avatar: c.author.avatar, avatar: c.author.avatar,
text: c.content, text: c.content,
reactions: c.reactions || [], reactions: c.reactions || [],
reply: (c.replies || []).map(r => mapComment(r, level + 1)), reply: (c.replies || []).map(r => mapComment(r, c.author.username, level + 1)),
openReplies: level === 0, openReplies: level === 0,
src: c.author.avatar, src: c.author.avatar,
iconClick: () => router.push(`/users/${c.author.id}`) iconClick: () => router.push(`/users/${c.author.id}`),
parentUserName: parentUserName
}) })
const getTopRelativeTo = (el, container) => { const getTopRelativeTo = (el, container) => {