发送评论

main
lee-zt 20 hours ago
parent 2220f3f3e9
commit 0fc3a5e109

@ -169,5 +169,64 @@ export const usePostDetailStore = defineStore("postDetail", {
this.detailLoading = false;
}
},
// 发送评论或回复
async sendComment(newCommentData) {
if (!content || !this.post?.postId) return;
const RequestData = {
id: null,
postId: newCommentData.postId, // 帖子ID
content: newCommentData.content, // 评论内容
parentCommentId: newCommentData.parentCommentId, // 如果是一级评论则为0
};
try {
const res = await request.post('/comment', RequestData);
if (res.code === 200) {
const commentObj = {
id: res.data.id,
content: newCommentData.content,
userId: newCommentData.userId,
userName: newCommentData.userName,
userAvatar: newCommentData.userAvatar,
createTime: new Date().toISOString(),
likeCount: 0,
replyCount: 0,
postId: this.post.postId,
parentCommentId: newCommentData.parentCommentId,
topId: newCommentData.topId,
isLike: 0,
replies: [],
repliesLastVal: 0,
repliesOffset: 0,
repliesSize: 5,
repliesFinished: false,
repliesLoading: false,
};
// 新增评论后刷新评论列表或插入到对应位置
if (!parentCommentId) {
// 一级评论,插入到最前面
this.comments.unshift(commentObj);
this.post.commentCount = (this.post.commentCount || 0) + 1; // 更新帖子评论数
} else {
// 回复评论,插入到对应父评论的 replies
// 先找顶级父评论
let parent = this.comments.find(c => c.id === commentObj.parentCommentId || c.id === commentObj.topId);
// 如果是二级及以上回复,需递归查找
if (!parent && commentObj.topId) {
parent = this.comments.find(c => c.id === commentObj.topId);
}
if (parent) {
parent.replies.unshift(commentObj);
parent.replyCount = (parent.replyCount || 0) + 1;
}
}
console.log("评论成功:", res);
}else {
console.error("评论失败:", res);
ElMessage.error(res.message || '评论失败');
}
} catch (e) {
alert(e.response?.message || '发送评论失败,请稍后重试');
}
},
},
});

@ -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>
Loading…
Cancel
Save