feat: 实现文章状态管理及分类标签展示功能

新增文章状态管理功能,支持草稿、已发表和已删除状态的显示与切换
重构分类和标签展示模块,添加点击跳转功能
优化文章列表页面,增加状态筛选和分页功能
完善疯言疯语模块,支持编辑和删除操作
修复路由跳转和页面刷新问题
This commit is contained in:
qingfeng1121
2025-11-08 11:16:15 +08:00
parent ad893b3e5c
commit 309aeaedc1
15 changed files with 840 additions and 325 deletions

View File

@@ -20,10 +20,15 @@
<p class="article-content-preview">{{ formatContentPreview(article.content, 150) }}</p>
<div class="article-meta-info">
<span class="article-publish-date">{{ formatRelativeTime(article.createdAt || article.createTime) }}</span>
<span v-if="article.categoryName" class="article-category-badge">{{ article.categoryName }} </span>
<span v-if="article.viewCount" class="article-views-count">{{ article.viewCount }} 阅读</span>
<span v-if="article.categoryName" class="article-category-badge"> {{ article.categoryName }} </span>
<span v-if="article.likes > 0" class="article-likes-count">{{ article.likes }} 点赞</span>
<span v-if="article.commentCount > 0" class="article-comments-count">{{ article.commentCount }} 评论</span>
<div class="article-status-badge-container" v-if="globalStore.Login">
<span v-if="article.status === 0" class="article-status-badge badge badge-warning">草稿</span>
<span v-if="article.status === 1" class="article-status-badge badge badge-success">已发表</span>
<span v-if="article.status === 2" class="article-status-badge badge badge-danger">已删除</span>
</div>
</div>
</div>
</transition-group>
@@ -36,7 +41,7 @@
<script setup>
import { useRouter, useRoute } from 'vue-router'
import { ref, onMounted } from 'vue'
import { ref, onMounted, watch } from 'vue'
import { formatDate, formatRelativeTime } from '@/utils/dateUtils'
import { formatContentPreview } from '@/utils/stringUtils'
import { ElMessage } from 'element-plus'
@@ -64,20 +69,35 @@ const fetchArticles = async () => {
// 检查URL参数确定获取文章的方式
const pathSegment = route.path.split('/')[2];
console.log(pathSegment)
// 根据不同路径获取不同文章
if (pathSegment === 'aericletype') {
// 按属性类型获取文章
const attributeData = globalStore.getValue('attribute')
response = await articleService.getArticlesByAttributeId(attributeData.id)
} else if (pathSegment === 'aericletitle') {
// 按标题搜索文章
const titleData = globalStore.getValue('articleserarch')
response = await articleService.getArticlesByTitle(titleData.name)
} else {
// 获取所有文章
console.log('获取所有文章列表')
response = await articleService.getAllArticles()
switch (pathSegment) {
case 'aericletype':
// 按属性类型获取文章
const attributeData = globalStore.getValue('attribute')
response = await articleService.getArticlesByAttributeId(attributeData.id)
break
case 'aericletitle':
// 按标题搜索文章
const titleData = globalStore.getValue('articleserarch')
response = await articleService.getArticlesByTitle(titleData.name)
break
case 'aericlestatus':
// 按状态获取文章
const statusData = globalStore.getValue('articlestatus')
response = await articleService.getArticlesByStatus(statusData.status)
break
default:
// 默认情况下,根据用户权限决定获取方式
if (globalStore.Login) {
// 获取所有文章(包含已删除)
console.log('管理员获取所有文章列表(包含已删除)')
response = await articleService.getAllArticlesWithDeleted()
} else {
// 获取所有文章
console.log('获取所有文章列表')
response = await articleService.getAllArticles()
}
}
// 为每个文章获取留言数量和分类名称
@@ -126,7 +146,10 @@ const fetchArticles = async () => {
* @param {Object} article - 文章对象
*/
const handleArticleClick = (article) => {
// 增加文章浏览量
articleService.incrementArticleViews(article.articleId)
// 清除之前的文章信息
globalStore.removeValue('articleInfo')
// 存储文章信息到全局状态
globalStore.setValue('articleInfo', article)
@@ -135,12 +158,24 @@ const handleArticleClick = (article) => {
path: '/article',
})
}
//刷新时挂载获取数据
// 组件挂载时获取数据
onMounted(() => {
fetchArticles()
})
// 监听路由变化,确保刷新时也能重新获取数据
watch(
// 监听路由路径和查询参数变化
() => [route.path, route.query],
// 路由变化时触发获取文章列表
() => {
fetchArticles()
console.log('路由变化,重新获取文章列表')
},
{ deep: true }
)
</script>
<style scoped>
@@ -261,69 +296,6 @@ onMounted(() => {
border-top: 1px solid rgba(0, 0, 0, 0.05);
}
/* 发布日期样式 */
.article-publish-date {
font-weight: 500;
color: #95a5a6;
}
/* 阅读数量样式 */
.article-views-count {
display: flex;
align-items: center;
color: #95a5a6;
}
.article-views-count::before {
content: '|';
margin-right: 12px;
color: #e0e0e0;
}
/* 分类标签样式 */
.article-category-badge {
display: flex;
align-items: center;
padding: 2px 10px;
background-color: rgba(52, 152, 219, 0.1);
color: #3498db;
border-radius: 4px;
font-size: 0.8rem;
font-weight: 500;
}
.article-category-badge::before {
content: '|';
margin-right: 12px;
color: #e0e0e0;
}
/* 点赞数量样式 */
.article-likes-count {
display: flex;
align-items: center;
color: #95a5a6;
}
.article-likes-count::before {
content: '|';
margin-right: 12px;
color: #e0e0e0;
}
/* 评论数量样式 */
.article-comments-count {
display: flex;
align-items: center;
color: #95a5a6;
}
.article-comments-count::before {
content: '|';
margin-right: 12px;
color: #e0e0e0;
}
/* 空状态容器样式 */
.empty-state-container {
text-align: center;