|
|
|
@ -35,25 +35,34 @@
|
|
|
|
|
<img :src="comment.userAvatar || require('@/assets/default-avatar/boy_1.png')" alt="评论者头像" class="comment-avatar" />
|
|
|
|
|
<div class="comment-content">
|
|
|
|
|
<p class="comment-name">{{ comment.userName }}</p>
|
|
|
|
|
<p class="comment-text">{{ comment.content }}</p>
|
|
|
|
|
<div class="comment-meta">
|
|
|
|
|
<span class="comment-time">{{ comment.createTime ? formatTime(comment.createTime) : '' }}</span>
|
|
|
|
|
<span class="comment-likes">赞 {{ comment.likeCount ?? 0 }}</span>
|
|
|
|
|
<span v-if="comment.replyCount > 0">
|
|
|
|
|
<button @click="loadReplies(comment)">
|
|
|
|
|
{{ comment.replies.length > 0 ? '收起回复' : '展开回复' }} ({{ comment.replyCount }})
|
|
|
|
|
</button>
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 子评论列表 -->
|
|
|
|
|
<ul v-if="comment.replies.length > 0" class="replies-list">
|
|
|
|
|
<li v-for="reply in comment.replies" :key="reply.id" class="reply-item">
|
|
|
|
|
<span class="reply-user">{{ reply.userName }}:</span>
|
|
|
|
|
<span class="reply-content">{{ reply.content }}</span>
|
|
|
|
|
</li>
|
|
|
|
|
<li v-if="comment.repliesLoading" class="reply-loading">加载中...</li>
|
|
|
|
|
<li v-if="comment.repliesFinished" class="reply-finished">没有更多回复了</li>
|
|
|
|
|
</ul>
|
|
|
|
|
<p class="comment-text">{{ comment.content }}</p>
|
|
|
|
|
<div class="comment-meta">
|
|
|
|
|
<span class="comment-time">{{ comment.createTime ? formatTime(comment.createTime) : '' }}</span>
|
|
|
|
|
<span class="comment-likes">赞 {{ comment.likeCount ?? 0 }}</span>
|
|
|
|
|
<span v-if="comment.replyCount > 0">
|
|
|
|
|
<button @click="loadReplies(comment)">
|
|
|
|
|
{{ comment.replies.length > 0 ? '收起回复' : '展开回复' }} ({{ comment.replyCount }})
|
|
|
|
|
</button>
|
|
|
|
|
</span>
|
|
|
|
|
<button class="reply-btn" @click="startReply(comment)">回复</button>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 子评论列表 -->
|
|
|
|
|
<ul v-if="comment.replies.length > 0" class="replies-list">
|
|
|
|
|
<li v-for="reply in comment.replies" :key="reply.id" class="comment-item reply-item">
|
|
|
|
|
<img :src="reply.userAvatar" alt="评论者头像" class="comment-avatar" />
|
|
|
|
|
<div class="comment-content">
|
|
|
|
|
<p class="comment-name">{{ reply.userName }}</p>
|
|
|
|
|
<p class="comment-text">{{ reply.content }}</p>
|
|
|
|
|
<div class="comment-meta">
|
|
|
|
|
<span class="comment-time">{{ reply.createTime ? formatTime(reply.createTime) : '' }}</span>
|
|
|
|
|
<span class="comment-likes">赞 {{ reply.likeCount ?? 0 }}</span>
|
|
|
|
|
<button class="reply-btn" @click="startReply(reply)">回复</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
<li v-if="comment.repliesLoading" class="reply-loading">加载中...</li>
|
|
|
|
|
<li v-if="comment.repliesFinished" class="reply-finished">没有更多回复了</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
@ -61,6 +70,10 @@
|
|
|
|
|
|
|
|
|
|
<!-- 发送评论 -->
|
|
|
|
|
<div class="comment-box">
|
|
|
|
|
<div v-if="replyingComment" class="replying-tip">
|
|
|
|
|
正在回复 @{{ replyingComment.userName }}
|
|
|
|
|
<button class="cancel-reply-btn" @click="cancelReply">取消回复</button>
|
|
|
|
|
</div>
|
|
|
|
|
<textarea
|
|
|
|
|
v-model="newComment"
|
|
|
|
|
placeholder="写下你的评论..."
|
|
|
|
@ -81,14 +94,23 @@ const route = useRoute();
|
|
|
|
|
const postDetailStore = usePostDetailStore();
|
|
|
|
|
const userStore = useUserStore(); // 如果需要用户信息
|
|
|
|
|
const newComment = ref('');
|
|
|
|
|
const replyingComment = ref(null); // 当前正在回复的评论对象,null 表示发一级评论
|
|
|
|
|
|
|
|
|
|
// 作者信息(如不需要可移除)
|
|
|
|
|
//
|
|
|
|
|
const author = postDetailStore.post?.author ;
|
|
|
|
|
const isFollowing = ref(false);
|
|
|
|
|
const toggleFollow = () => {
|
|
|
|
|
isFollowing.value = !isFollowing.value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 点击“回复”按钮时调用
|
|
|
|
|
function startReply(comment) {
|
|
|
|
|
replyingComment.value = comment;
|
|
|
|
|
}
|
|
|
|
|
// 取消回复
|
|
|
|
|
function cancelReply() {
|
|
|
|
|
replyingComment.value = null;
|
|
|
|
|
}
|
|
|
|
|
// 时间格式化
|
|
|
|
|
function formatTime(timeStr) {
|
|
|
|
|
const date = new Date(timeStr);
|
|
|
|
@ -106,7 +128,6 @@ function handleScroll() {
|
|
|
|
|
postDetailStore.fetchComments();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 子评论加载(点击“展开回复”时调用)
|
|
|
|
|
function loadReplies(comment) {
|
|
|
|
|
if (!comment.repliesLoading && !comment.repliesFinished) {
|
|
|
|
@ -114,21 +135,27 @@ function loadReplies(comment) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发送评论(这里只做前端追加,实际应调用后端接口)
|
|
|
|
|
// 发送评论
|
|
|
|
|
const sendComment = () => {
|
|
|
|
|
if (!userStore.isLoggedIn) {
|
|
|
|
|
alert('请先登录后再评论');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (newComment.value.trim()) {
|
|
|
|
|
postDetailStore.addComment({
|
|
|
|
|
const newCommentData = {
|
|
|
|
|
content: newComment.value,
|
|
|
|
|
userAvatar: userStore.userInfo.avatar,
|
|
|
|
|
userName: userStore.userInfo.username,
|
|
|
|
|
userId: userStore.userInfo.userid,
|
|
|
|
|
content: newComment.value,
|
|
|
|
|
createTime: new Date().toISOString(),
|
|
|
|
|
likeCount: 0,
|
|
|
|
|
});
|
|
|
|
|
replyCount: 0,
|
|
|
|
|
postId: postDetailStore.post.id,
|
|
|
|
|
parentCommentId: replyingComment.value ? replyingComment.value.id : null, // 如果是回复评论,则设置 parentCommentId
|
|
|
|
|
topId: null,
|
|
|
|
|
isLike: false,
|
|
|
|
|
}
|
|
|
|
|
postDetailStore.addComment(newCommentData);
|
|
|
|
|
newComment.value = '';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
@ -405,4 +432,28 @@ onUnmounted(() => {
|
|
|
|
|
padding: 6px 0;
|
|
|
|
|
text-align: left;
|
|
|
|
|
}
|
|
|
|
|
.replying-tip {
|
|
|
|
|
color: #409eff;
|
|
|
|
|
margin-bottom: 6px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
.cancel-reply-btn {
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
margin-left: 8px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
}
|
|
|
|
|
.reply-btn {
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: #409eff;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
}
|
|
|
|
|
.reply-btn:hover {
|
|
|
|
|
text-decoration: underline;
|
|
|
|
|
}
|
|
|
|
|
</style>
|