<!-- views/PostDetail.vue - 帖子详情页组件 -->
<template>
<div class="post-detail">
<!-- 加载状态 -->
<div v-if="loading" class="loading-container">
<el-skeleton :rows="10" animated />
</div>
<!-- 帖子内容 -->
<template v-else-if="post">
<el-card class="post-card">
<!-- 帖子头部 -->
<div class="post-header">
<h1 class="post-title">{{ post.title }}</h1>
<div class="post-meta">
<div class="post-author">
<el-avatar :size="32" :src="post.author.avatar || ''">
{{ post.author.username.charAt(0).toUpperCase() }}
</el-avatar>
<span class="author-name">{{ post.author.username }}</span>
</div>
<div class="post-info">
<span class="post-category">{{ getCategoryName(post.categoryId) }}</span>
<span class="post-time">{{ formatDate(post.createTime) }}</span>
<span class="post-views">
<el-icon><View /></el-icon> {{ post.viewCount || 0 }}
</span>
</div>
</div>
</div>
<!-- 帖子内容 -->
<div class="post-content">
{{ post.content }}
</div>
<!-- 帖子操作 -->
<div class="post-actions">
<el-button type="primary" plain size="small" @click="handleLike">
<el-icon><Star /></el-icon> 点赞 ({{ post.likeCount || 0 }})
</el-button>
<!-- 仅帖子作者可见的操作 -->
<div v-if="isPostAuthor" class="author-actions">
<el-button type="primary" plain size="small" @click="handleEdit">
<el-icon><Edit /></el-icon> 编辑
</el-button>
<el-button type="danger" plain size="small" @click="handleDelete">
<el-icon><Delete /></el-icon> 删除
</el-button>
</div>
</div>
</el-card>
<!-- 评论区 -->
<el-card class="comment-card">
<template #header>
<div class="card-header">
<span>评论 ({{ post.comments?.length || 0 }})</span>
</div>
</template>
<!-- 评论列表 -->
<div class="comment-list">
<div v-if="post.comments && post.comments.length > 0">
<div v-for="comment in post.comments" :key="comment.id" class="comment-item">
<div class="comment-avatar">
<el-avatar :size="32" :src="comment.author.avatar || ''">
{{ comment.author.username.charAt(0).toUpperCase() }}
</el-avatar>
</div>
<div class="comment-content">
<div class="comment-header">
<span class="comment-author">{{ comment.author.username }}</span>
<span class="comment-time">{{ formatDate(comment.createTime) }}</span>
</div>
<div class="comment-text">{{ comment.content }}</div>
</div>
</div>
</div>
<el-empty v-else description="暂无评论" />
</div>
<!-- 发表评论 -->
<div class="comment-form">
<el-input
v-model="commentContent"
type="textarea"
:rows="3"
placeholder="发表你的评论..."
:disabled="!isAuthenticated"
/>
<div class="form-actions">
<el-button
type="primary"
@click="submitComment"
:disabled="!isAuthenticated || !commentContent.trim()"
>
发表评论
</el-button>
</div>
<div v-if="!isAuthenticated" class="login-tip">
请 <router-link to="/login">登录</router-link> 后发表评论
</div>
</div>
</el-card>
</template>
<!-- 帖子不存在 -->
<el-result v-else icon="error" title="帖子不存在" subtitle="该帖子可能已被删除或您没有权限查看">
<template #extra>
<el-button type="primary" @click="$router.push('/')">返回首页</el-button>
</template>
</el-result>
<!-- 删除确认对话框 -->
<el-dialog
v-model="deleteDialogVisible"
title="删除帖子"
width="30%"
>
<span>确定要删除这篇帖子吗?此操作不可恢复。</span>
<template #footer>
<span class="dialog-footer">
<el-button @click="deleteDialogVisible = false">取消</el-button>
<el-button type="danger" @click="confirmDelete">确定删除</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import { ref, computed, onMounted } from 'vue'
import { useStore } from 'vuex'
import { useRoute, useRouter } from 'vue-router'
import { View, Star, Edit, Delete } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
export default {
name: 'PostDetail',
components: {
View,
Star,
Edit,
Delete
},
setup() {
const store = useStore()
const route = useRoute()
const router = useRouter()
// 状态
const loading = ref(true)
const commentContent = ref('')
const deleteDialogVisible = ref(false)
// 从store获取数据
const post = computed(() => store.getters.getCurrentPost)
const categories = computed(() => store.getters.getCategories)
const isAuthenticated = computed(() => store.getters.isAuthenticated)
const currentUser = computed(() => store.getters.currentUser)
// 判断当前用户是否是帖子作者
const isPostAuthor = computed(() => {
if (!isAuthenticated.value || !post.value || !currentUser.value) return false
return post.value.author.id === currentUser.value.id
})
// 获取帖子详情
const fetchPostDetail = async () => {
loading.value = true
try {
const postId = route.params.id
await store.dispatch('fetchPostById', postId)
} catch (error) {
ElMessage.error('获取帖子详情失败')
console.error('获取帖子详情失败:', error)
} finally {
loading.value = false
}
}
// 获取分类名称
const getCategoryName = (categoryId) => {
const category = categories.value.find(c => c.id === categoryId)
return category ? category.name : '未分类'
}
// 格式化日期
const formatDate = (dateString) => {
if (!dateString) return ''
const date = new Date(dateString)
const now = new Date()
const diff = now - date
// 一分钟内
if (diff < 60 * 1000) {
return '刚刚'
}
// 一小时内
if (diff < 60 * 60 * 1000) {
return `${Math.floor(diff / (60 * 1000))}分钟前`
}
// 一天内
if (diff < 24 * 60 * 60 * 1000) {
return `${Math.floor(diff / (60 * 60 * 1000))}小时前`
}
// 一周内
if (diff < 7 * 24 * 60 * 60 * 1000) {
return `${Math.floor(diff / (24 * 60 * 60 * 1000))}天前`
}
// 其他
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}
// 点赞帖子
const handleLike = () => {
if (!isAuthenticated.value) {
ElMessage.warning('请先登录')
router.push('/login')
return
}
ElMessage.success('点赞成功')
// 这里应该调用API进行点赞操作
// 实际项目中需要实现后端API
}
// 编辑帖子
const handleEdit = () => {
if (!isPostAuthor.value) {
ElMessage.warning('只有作者才能编辑帖子')
return
}
router.push(`/edit-post/${post.value.id}`)
}
// 删除帖子
const handleDelete = () => {
if (!isPostAuthor.value) {
ElMessage.warning('只有作者才能删除帖子')
return
}
deleteDialogVisible.value = true
}
// 确认删除