|
|
@ -35,11 +35,25 @@
|
|
|
|
<img :src="comment.userAvatar || require('@/assets/default-avatar/boy_1.png')" alt="评论者头像" class="comment-avatar" />
|
|
|
|
<img :src="comment.userAvatar || require('@/assets/default-avatar/boy_1.png')" alt="评论者头像" class="comment-avatar" />
|
|
|
|
<div class="comment-content">
|
|
|
|
<div class="comment-content">
|
|
|
|
<p class="comment-name">{{ comment.userName }}</p>
|
|
|
|
<p class="comment-name">{{ comment.userName }}</p>
|
|
|
|
<p class="comment-text">{{ comment.content }}</p>
|
|
|
|
<p class="comment-text">{{ comment.content }}</p>
|
|
|
|
<div class="comment-meta">
|
|
|
|
<div class="comment-meta">
|
|
|
|
<span class="comment-time">{{ comment.createTime ? formatTime(comment.createTime) : '' }}</span>
|
|
|
|
<span class="comment-time">{{ comment.createTime ? formatTime(comment.createTime) : '' }}</span>
|
|
|
|
<span class="comment-likes">赞 {{ comment.likeCount ?? 0 }}</span>
|
|
|
|
<span class="comment-likes">赞 {{ comment.likeCount ?? 0 }}</span>
|
|
|
|
</div>
|
|
|
|
<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>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</li>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</ul>
|
|
|
@ -58,7 +72,7 @@
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="js" name="PostDetail">
|
|
|
|
<script setup lang="js" name="PostDetail">
|
|
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
import { ref, onMounted , onUnmounted} from 'vue';
|
|
|
|
import { useRoute } from 'vue-router';
|
|
|
|
import { useRoute } from 'vue-router';
|
|
|
|
import { usePostDetailStore } from '@/stores/postdetail.js';
|
|
|
|
import { usePostDetailStore } from '@/stores/postdetail.js';
|
|
|
|
import { useUserStore } from '@/stores/user.js';
|
|
|
|
import { useUserStore } from '@/stores/user.js';
|
|
|
@ -81,6 +95,25 @@ function formatTime(timeStr) {
|
|
|
|
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;
|
|
|
|
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 一级评论滚动加载
|
|
|
|
|
|
|
|
function handleScroll() {
|
|
|
|
|
|
|
|
const el = document.documentElement;
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
el.scrollTop + window.innerHeight >= el.scrollHeight - 100 &&
|
|
|
|
|
|
|
|
!postDetailStore.commentsLoading &&
|
|
|
|
|
|
|
|
!postDetailStore.commentsFinished
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
postDetailStore.fetchComments();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 子评论加载(点击“展开回复”时调用)
|
|
|
|
|
|
|
|
function loadReplies(comment) {
|
|
|
|
|
|
|
|
if (!comment.repliesLoading && !comment.repliesFinished) {
|
|
|
|
|
|
|
|
postDetailStore.fetchReplies(comment.id, comment);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送评论(这里只做前端追加,实际应调用后端接口)
|
|
|
|
// 发送评论(这里只做前端追加,实际应调用后端接口)
|
|
|
|
const sendComment = () => {
|
|
|
|
const sendComment = () => {
|
|
|
|
if (!userStore.isLoggedIn) {
|
|
|
|
if (!userStore.isLoggedIn) {
|
|
|
@ -89,7 +122,7 @@ const sendComment = () => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (newComment.value.trim()) {
|
|
|
|
if (newComment.value.trim()) {
|
|
|
|
postDetailStore.addComment({
|
|
|
|
postDetailStore.addComment({
|
|
|
|
userAvatar: userStore.userInfo.avatar || require('@/assets/default-avatar/boy_1.png'),
|
|
|
|
userAvatar: userStore.userInfo.avatar,
|
|
|
|
userName: userStore.userInfo.username,
|
|
|
|
userName: userStore.userInfo.username,
|
|
|
|
userId: userStore.userInfo.userid,
|
|
|
|
userId: userStore.userInfo.userid,
|
|
|
|
content: newComment.value,
|
|
|
|
content: newComment.value,
|
|
|
@ -102,6 +135,10 @@ const sendComment = () => {
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
onMounted(() => {
|
|
|
|
postDetailStore.fetchPostDetail(route.params.id);
|
|
|
|
postDetailStore.fetchPostDetail(route.params.id);
|
|
|
|
|
|
|
|
window.addEventListener('scroll', handleScroll);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
|
|
window.removeEventListener('scroll', handleScroll);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
@ -334,4 +371,38 @@ onMounted(() => {
|
|
|
|
text-align: left; /* 设置居左 */
|
|
|
|
text-align: left; /* 设置居左 */
|
|
|
|
color: #333;
|
|
|
|
color: #333;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.replies-list {
|
|
|
|
|
|
|
|
list-style: none;
|
|
|
|
|
|
|
|
padding-left: 40px; /* 缩进,区分主评论 */
|
|
|
|
|
|
|
|
margin: 8px 0 0 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.reply-item {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
|
|
padding: 6px 0;
|
|
|
|
|
|
|
|
border-bottom: 1px solid #f3f3f3;
|
|
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
|
|
color: #444;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.reply-user {
|
|
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
|
|
margin-right: 6px;
|
|
|
|
|
|
|
|
color: #5aa76f;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.reply-content {
|
|
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.reply-loading,
|
|
|
|
|
|
|
|
.reply-finished {
|
|
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
|
|
padding: 6px 0;
|
|
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</style>
|