|
|
|
@ -158,26 +158,293 @@
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 其他管理模块的占位符 -->
|
|
|
|
|
<!-- 帖子管理 -->
|
|
|
|
|
<div v-if="activeMenu === 'posts'" class="posts-content">
|
|
|
|
|
<h2>帖子管理</h2>
|
|
|
|
|
<p>帖子管理功能开发中...</p>
|
|
|
|
|
<div class="table-toolbar">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="postSearch"
|
|
|
|
|
placeholder="搜索帖子..."
|
|
|
|
|
style="width: 300px"
|
|
|
|
|
@input="searchPosts"
|
|
|
|
|
/>
|
|
|
|
|
<el-select v-model="postCategoryFilter" placeholder="分类筛选" @change="searchPosts">
|
|
|
|
|
<el-option label="全部" :value="null" />
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="category in categories"
|
|
|
|
|
:key="category.id"
|
|
|
|
|
:label="category.name"
|
|
|
|
|
:value="category.id"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
<el-select v-model="postStatusFilter" placeholder="状态筛选" @change="searchPosts">
|
|
|
|
|
<el-option label="全部" :value="null" />
|
|
|
|
|
<el-option label="正常" :value="1" />
|
|
|
|
|
<el-option label="置顶" :value="2" />
|
|
|
|
|
<el-option label="已删除" :value="0" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="posts" style="width: 100%">
|
|
|
|
|
<el-table-column prop="id" label="ID" width="80" />
|
|
|
|
|
<el-table-column prop="title" label="标题" width="200" show-overflow-tooltip />
|
|
|
|
|
<el-table-column prop="nickname" label="作者" width="120" />
|
|
|
|
|
<el-table-column prop="categoryName" label="分类" width="100" />
|
|
|
|
|
<el-table-column prop="viewCount" label="浏览" width="80" />
|
|
|
|
|
<el-table-column prop="likeCount" label="点赞" width="80" />
|
|
|
|
|
<el-table-column prop="commentCount" label="评论" width="80" />
|
|
|
|
|
<el-table-column prop="status" label="状态" width="100">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-tag :type="getPostStatusType(scope.row.status)">
|
|
|
|
|
{{ getPostStatusText(scope.row.status) }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="createdAt" label="发布时间" width="180" />
|
|
|
|
|
<el-table-column label="操作" width="250">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<!-- 已删除的帖子显示恢复按钮 -->
|
|
|
|
|
<template v-if="scope.row.status === 0">
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="success"
|
|
|
|
|
@click="restorePost(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
恢复
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="danger"
|
|
|
|
|
@click="permanentDeletePost(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
永久删除
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
<!-- 正常和置顶的帖子显示置顶和删除按钮 -->
|
|
|
|
|
<template v-else>
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
:type="scope.row.status === 2 ? 'warning' : 'primary'"
|
|
|
|
|
@click="togglePostTop(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
{{ scope.row.status === 2 ? '取消置顶' : '置顶' }}
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="danger"
|
|
|
|
|
@click="deletePost(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-pagination
|
|
|
|
|
v-model:current-page="postPage"
|
|
|
|
|
v-model:page-size="postPageSize"
|
|
|
|
|
:total="postTotal"
|
|
|
|
|
@current-change="loadPosts"
|
|
|
|
|
layout="total, prev, pager, next"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 评论管理 -->
|
|
|
|
|
<div v-if="activeMenu === 'comments'" class="comments-content">
|
|
|
|
|
<h2>评论管理</h2>
|
|
|
|
|
<p>评论管理功能开发中...</p>
|
|
|
|
|
<div class="table-toolbar">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="commentSearch"
|
|
|
|
|
placeholder="搜索评论..."
|
|
|
|
|
style="width: 300px"
|
|
|
|
|
@input="searchComments"
|
|
|
|
|
/>
|
|
|
|
|
<el-select v-model="commentStatusFilter" placeholder="状态筛选" @change="searchComments">
|
|
|
|
|
<el-option label="全部" :value="null" />
|
|
|
|
|
<el-option label="正常" :value="1" />
|
|
|
|
|
<el-option label="已删除" :value="0" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="comments" style="width: 100%">
|
|
|
|
|
<el-table-column prop="id" label="ID" width="80" />
|
|
|
|
|
<el-table-column prop="content" label="内容" width="300" show-overflow-tooltip />
|
|
|
|
|
<el-table-column prop="nickname" label="评论者" width="120" />
|
|
|
|
|
<el-table-column prop="postTitle" label="所属帖子" width="200" show-overflow-tooltip />
|
|
|
|
|
<el-table-column prop="likeCount" label="点赞" width="80" />
|
|
|
|
|
<el-table-column prop="status" label="状态" width="100">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
|
|
|
|
|
{{ scope.row.status === 1 ? '正常' : '已删除' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="createdAt" label="发布时间" width="180" />
|
|
|
|
|
<el-table-column label="操作" width="120">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="danger"
|
|
|
|
|
@click="deleteComment(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-pagination
|
|
|
|
|
v-model:current-page="commentPage"
|
|
|
|
|
v-model:page-size="commentPageSize"
|
|
|
|
|
:total="commentTotal"
|
|
|
|
|
@current-change="loadComments"
|
|
|
|
|
layout="total, prev, pager, next"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 分类管理 -->
|
|
|
|
|
<div v-if="activeMenu === 'categories'" class="categories-content">
|
|
|
|
|
<h2>分类管理</h2>
|
|
|
|
|
<p>分类管理功能开发中...</p>
|
|
|
|
|
<div class="table-toolbar">
|
|
|
|
|
<el-button type="primary" @click="showCreateCategoryDialog">
|
|
|
|
|
<el-icon><Plus /></el-icon>
|
|
|
|
|
新增分类
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="categories" style="width: 100%">
|
|
|
|
|
<el-table-column prop="id" label="ID" width="80" />
|
|
|
|
|
<el-table-column prop="name" label="分类名称" width="150" />
|
|
|
|
|
<el-table-column prop="description" label="描述" width="200" show-overflow-tooltip />
|
|
|
|
|
<el-table-column prop="icon" label="图标" width="80" />
|
|
|
|
|
<el-table-column prop="sort" label="排序" width="80" />
|
|
|
|
|
<el-table-column prop="status" label="状态" width="100">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
|
|
|
|
|
{{ scope.row.status === 1 ? '启用' : '禁用' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="createdAt" label="创建时间" width="180" />
|
|
|
|
|
<el-table-column label="操作" width="200">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="primary"
|
|
|
|
|
@click="editCategory(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
编辑
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="danger"
|
|
|
|
|
@click="deleteCategory(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 资源管理 -->
|
|
|
|
|
<div v-if="activeMenu === 'resources'" class="resources-content">
|
|
|
|
|
<h2>资源管理</h2>
|
|
|
|
|
<p>资源管理功能开发中...</p>
|
|
|
|
|
<div class="table-toolbar">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="resourceSearch"
|
|
|
|
|
placeholder="搜索资源..."
|
|
|
|
|
style="width: 300px"
|
|
|
|
|
@input="searchResources"
|
|
|
|
|
/>
|
|
|
|
|
<el-select v-model="resourceCategoryFilter" placeholder="分类筛选" @change="searchResources">
|
|
|
|
|
<el-option label="全部" :value="null" />
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="category in categories"
|
|
|
|
|
:key="category.id"
|
|
|
|
|
:label="category.name"
|
|
|
|
|
:value="category.id"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
<el-select v-model="resourceStatusFilter" placeholder="状态筛选" @change="searchResources">
|
|
|
|
|
<el-option label="全部" :value="null" />
|
|
|
|
|
<el-option label="正常" :value="1" />
|
|
|
|
|
<el-option label="已删除" :value="0" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
<el-table :data="resources" style="width: 100%">
|
|
|
|
|
<el-table-column prop="id" label="ID" width="80" />
|
|
|
|
|
<el-table-column prop="title" label="标题" width="200" show-overflow-tooltip />
|
|
|
|
|
<el-table-column prop="nickname" label="上传者" width="120" />
|
|
|
|
|
<el-table-column prop="categoryName" label="分类" width="100" />
|
|
|
|
|
<el-table-column prop="fileType" label="文件类型" width="120" />
|
|
|
|
|
<el-table-column prop="fileSize" label="文件大小" width="100">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
{{ formatFileSize(scope.row.fileSize) }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="downloadCount" label="下载" width="80" />
|
|
|
|
|
<el-table-column prop="likeCount" label="点赞" width="80" />
|
|
|
|
|
<el-table-column prop="status" label="状态" width="100">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
|
|
|
|
|
{{ scope.row.status === 1 ? '正常' : '已删除' }}
|
|
|
|
|
</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column prop="createdAt" label="上传时间" width="180" />
|
|
|
|
|
<el-table-column label="操作" width="120">
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
<el-button
|
|
|
|
|
size="small"
|
|
|
|
|
type="danger"
|
|
|
|
|
@click="deleteResource(scope.row)"
|
|
|
|
|
>
|
|
|
|
|
删除
|
|
|
|
|
</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
<el-pagination
|
|
|
|
|
v-model:current-page="resourcePage"
|
|
|
|
|
v-model:page-size="resourcePageSize"
|
|
|
|
|
:total="resourceTotal"
|
|
|
|
|
@current-change="loadResources"
|
|
|
|
|
layout="total, prev, pager, next"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 分类编辑对话框 -->
|
|
|
|
|
<el-dialog
|
|
|
|
|
v-model="categoryDialogVisible"
|
|
|
|
|
:title="isEditingCategory ? '编辑分类' : '新增分类'"
|
|
|
|
|
width="500px"
|
|
|
|
|
>
|
|
|
|
|
<el-form :model="categoryForm" :rules="categoryRules" ref="categoryFormRef" label-width="80px">
|
|
|
|
|
<el-form-item label="分类名称" prop="name">
|
|
|
|
|
<el-input v-model="categoryForm.name" placeholder="请输入分类名称" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="描述" prop="description">
|
|
|
|
|
<el-input v-model="categoryForm.description" type="textarea" placeholder="请输入分类描述" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="图标" prop="icon">
|
|
|
|
|
<el-input v-model="categoryForm.icon" placeholder="请输入图标(如:📚)" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="排序" prop="sort">
|
|
|
|
|
<el-input-number v-model="categoryForm.sort" :min="1" :max="100" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item label="状态" prop="status">
|
|
|
|
|
<el-radio-group v-model="categoryForm.status">
|
|
|
|
|
<el-radio :label="1">启用</el-radio>
|
|
|
|
|
<el-radio :label="0">禁用</el-radio>
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<span class="dialog-footer">
|
|
|
|
|
<el-button @click="categoryDialogVisible = false">取消</el-button>
|
|
|
|
|
<el-button type="primary" @click="saveCategoryForm" :loading="isSavingCategory">
|
|
|
|
|
{{ isEditingCategory ? '更新' : '创建' }}
|
|
|
|
|
</el-button>
|
|
|
|
|
</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
@ -193,7 +460,8 @@ import {
|
|
|
|
|
Document,
|
|
|
|
|
ChatDotRound,
|
|
|
|
|
FolderOpened,
|
|
|
|
|
Files
|
|
|
|
|
Files,
|
|
|
|
|
Plus
|
|
|
|
|
} from '@element-plus/icons-vue'
|
|
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
|
|
import { adminApi } from '@/api/admin'
|
|
|
|
@ -206,6 +474,28 @@ interface SystemStats {
|
|
|
|
|
totalResources?: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定义分类接口
|
|
|
|
|
interface Category {
|
|
|
|
|
id: number
|
|
|
|
|
name: string
|
|
|
|
|
description?: string
|
|
|
|
|
icon?: string
|
|
|
|
|
sort: number
|
|
|
|
|
status: number
|
|
|
|
|
createdAt?: string
|
|
|
|
|
updatedAt?: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定义分类表单接口
|
|
|
|
|
interface CategoryForm {
|
|
|
|
|
id: number | null
|
|
|
|
|
name: string
|
|
|
|
|
description: string
|
|
|
|
|
icon: string
|
|
|
|
|
sort: number
|
|
|
|
|
status: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const userStore = useUserStore()
|
|
|
|
|
|
|
|
|
@ -216,13 +506,58 @@ const activeMenu = ref('dashboard')
|
|
|
|
|
const stats = ref<SystemStats>({})
|
|
|
|
|
|
|
|
|
|
// 用户管理相关
|
|
|
|
|
const users = ref([])
|
|
|
|
|
const users = ref<any[]>([])
|
|
|
|
|
const userSearch = ref('')
|
|
|
|
|
const userRoleFilter = ref(null)
|
|
|
|
|
const userPage = ref(1)
|
|
|
|
|
const userPageSize = ref(10)
|
|
|
|
|
const userTotal = ref(0)
|
|
|
|
|
|
|
|
|
|
// 帖子管理相关
|
|
|
|
|
const posts = ref<any[]>([])
|
|
|
|
|
const postSearch = ref('')
|
|
|
|
|
const postCategoryFilter = ref<number | null>(null)
|
|
|
|
|
const postStatusFilter = ref<number | null>(null)
|
|
|
|
|
const postPage = ref(1)
|
|
|
|
|
const postPageSize = ref(10)
|
|
|
|
|
const postTotal = ref(0)
|
|
|
|
|
|
|
|
|
|
// 评论管理相关
|
|
|
|
|
const comments = ref<any[]>([])
|
|
|
|
|
const commentSearch = ref('')
|
|
|
|
|
const commentStatusFilter = ref<number | null>(null)
|
|
|
|
|
const commentPage = ref(1)
|
|
|
|
|
const commentPageSize = ref(10)
|
|
|
|
|
const commentTotal = ref(0)
|
|
|
|
|
|
|
|
|
|
// 分类管理相关
|
|
|
|
|
const categories = ref<Category[]>([])
|
|
|
|
|
const categoryDialogVisible = ref(false)
|
|
|
|
|
const isEditingCategory = ref(false)
|
|
|
|
|
const categoryForm = ref<CategoryForm>({
|
|
|
|
|
id: null,
|
|
|
|
|
name: '',
|
|
|
|
|
description: '',
|
|
|
|
|
icon: '',
|
|
|
|
|
sort: 1,
|
|
|
|
|
status: 1
|
|
|
|
|
})
|
|
|
|
|
const categoryRules = ref({
|
|
|
|
|
name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }],
|
|
|
|
|
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }]
|
|
|
|
|
})
|
|
|
|
|
const categoryFormRef = ref(null)
|
|
|
|
|
const isSavingCategory = ref(false)
|
|
|
|
|
|
|
|
|
|
// 资源管理相关
|
|
|
|
|
const resources = ref<any[]>([])
|
|
|
|
|
const resourceSearch = ref('')
|
|
|
|
|
const resourceCategoryFilter = ref<number | null>(null)
|
|
|
|
|
const resourceStatusFilter = ref<number | null>(null)
|
|
|
|
|
const resourcePage = ref(1)
|
|
|
|
|
const resourcePageSize = ref(10)
|
|
|
|
|
const resourceTotal = ref(0)
|
|
|
|
|
|
|
|
|
|
// 菜单选择处理
|
|
|
|
|
const handleMenuSelect = (index: string) => {
|
|
|
|
|
activeMenu.value = index
|
|
|
|
@ -230,6 +565,14 @@ const handleMenuSelect = (index: string) => {
|
|
|
|
|
loadStats()
|
|
|
|
|
} else if (index === 'users') {
|
|
|
|
|
loadUsers()
|
|
|
|
|
} else if (index === 'posts') {
|
|
|
|
|
loadPosts()
|
|
|
|
|
} else if (index === 'comments') {
|
|
|
|
|
loadComments()
|
|
|
|
|
} else if (index === 'categories') {
|
|
|
|
|
loadCategories()
|
|
|
|
|
} else if (index === 'resources') {
|
|
|
|
|
loadResources()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -263,12 +606,98 @@ const loadUsers = async () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载帖子列表
|
|
|
|
|
const loadPosts = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await adminApi.getPostList({
|
|
|
|
|
page: postPage.value,
|
|
|
|
|
size: postPageSize.value,
|
|
|
|
|
keyword: postSearch.value || undefined,
|
|
|
|
|
categoryId: postCategoryFilter.value || undefined,
|
|
|
|
|
status: postStatusFilter.value || undefined
|
|
|
|
|
})
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
posts.value = response.data.list
|
|
|
|
|
postTotal.value = response.data.total
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('加载帖子列表失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载评论列表
|
|
|
|
|
const loadComments = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await adminApi.getCommentList({
|
|
|
|
|
page: commentPage.value,
|
|
|
|
|
size: commentPageSize.value,
|
|
|
|
|
keyword: commentSearch.value || undefined,
|
|
|
|
|
status: commentStatusFilter.value || undefined
|
|
|
|
|
})
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
comments.value = response.data.list
|
|
|
|
|
commentTotal.value = response.data.total
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('加载评论列表失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载分类列表
|
|
|
|
|
const loadCategories = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await adminApi.getCategoryList()
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
categories.value = response.data
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('加载分类列表失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载资源列表
|
|
|
|
|
const loadResources = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await adminApi.getResourceList({
|
|
|
|
|
page: resourcePage.value,
|
|
|
|
|
size: resourcePageSize.value,
|
|
|
|
|
keyword: resourceSearch.value || undefined,
|
|
|
|
|
categoryId: resourceCategoryFilter.value || undefined,
|
|
|
|
|
status: resourceStatusFilter.value || undefined
|
|
|
|
|
})
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
resources.value = response.data.list
|
|
|
|
|
resourceTotal.value = response.data.total
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('加载资源列表失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 搜索用户
|
|
|
|
|
const searchUsers = () => {
|
|
|
|
|
userPage.value = 1
|
|
|
|
|
loadUsers()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 搜索帖子
|
|
|
|
|
const searchPosts = () => {
|
|
|
|
|
postPage.value = 1
|
|
|
|
|
loadPosts()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 搜索评论
|
|
|
|
|
const searchComments = () => {
|
|
|
|
|
commentPage.value = 1
|
|
|
|
|
loadComments()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 搜索资源
|
|
|
|
|
const searchResources = () => {
|
|
|
|
|
resourcePage.value = 1
|
|
|
|
|
loadResources()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 切换用户状态
|
|
|
|
|
const toggleUserStatus = async (user: any) => {
|
|
|
|
|
try {
|
|
|
|
@ -304,6 +733,197 @@ const deleteUser = async (user: any) => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 切换帖子状态
|
|
|
|
|
const togglePostTop = async (post: any) => {
|
|
|
|
|
try {
|
|
|
|
|
const newStatus = post.status === 2 ? 1 : 2
|
|
|
|
|
const response = await adminApi.updatePostStatus(post.id, { status: newStatus })
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
post.status = newStatus
|
|
|
|
|
ElMessage.success('帖子状态更新成功')
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('更新帖子状态失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除帖子
|
|
|
|
|
const deletePost = async (post: any) => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm('确定要删除该帖子吗?此操作不可恢复!', '警告', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await adminApi.deletePost(post.id)
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('帖子删除成功')
|
|
|
|
|
loadPosts()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
ElMessage.error('删除帖子失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 恢复帖子
|
|
|
|
|
const restorePost = async (post: any) => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm('确定要恢复该帖子吗?', '确认', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'info'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await adminApi.updatePostStatus(post.id, { status: 1 })
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('帖子恢复成功')
|
|
|
|
|
loadPosts()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
ElMessage.error('恢复帖子失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 永久删除帖子
|
|
|
|
|
const permanentDeletePost = async (post: any) => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm('确定要永久删除该帖子吗?此操作不可恢复!', '危险操作', {
|
|
|
|
|
confirmButtonText: '永久删除',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'error',
|
|
|
|
|
confirmButtonClass: 'el-button--danger'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await adminApi.permanentDeletePost(post.id)
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('帖子永久删除成功')
|
|
|
|
|
loadPosts()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
ElMessage.error('永久删除帖子失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除评论
|
|
|
|
|
const deleteComment = async (comment: any) => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm('确定要删除该评论吗?此操作不可恢复!', '警告', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await adminApi.deleteComment(comment.id)
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('评论删除成功')
|
|
|
|
|
loadComments()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
ElMessage.error('删除评论失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 显示创建分类对话框
|
|
|
|
|
const showCreateCategoryDialog = () => {
|
|
|
|
|
isEditingCategory.value = false
|
|
|
|
|
categoryForm.value = {
|
|
|
|
|
id: null,
|
|
|
|
|
name: '',
|
|
|
|
|
description: '',
|
|
|
|
|
icon: '',
|
|
|
|
|
sort: 1,
|
|
|
|
|
status: 1
|
|
|
|
|
}
|
|
|
|
|
categoryDialogVisible.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 编辑分类
|
|
|
|
|
const editCategory = (category: any) => {
|
|
|
|
|
isEditingCategory.value = true
|
|
|
|
|
categoryForm.value = {
|
|
|
|
|
id: category.id,
|
|
|
|
|
name: category.name,
|
|
|
|
|
description: category.description,
|
|
|
|
|
icon: category.icon,
|
|
|
|
|
sort: category.sort,
|
|
|
|
|
status: category.status
|
|
|
|
|
}
|
|
|
|
|
categoryDialogVisible.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存分类
|
|
|
|
|
const saveCategoryForm = async () => {
|
|
|
|
|
try {
|
|
|
|
|
isSavingCategory.value = true
|
|
|
|
|
let response
|
|
|
|
|
if (isEditingCategory.value && categoryForm.value.id) {
|
|
|
|
|
response = await adminApi.updateCategory(categoryForm.value.id, categoryForm.value)
|
|
|
|
|
} else {
|
|
|
|
|
response = await adminApi.createCategory(categoryForm.value)
|
|
|
|
|
}
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('分类保存成功')
|
|
|
|
|
categoryDialogVisible.value = false
|
|
|
|
|
loadCategories()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
ElMessage.error('保存分类失败')
|
|
|
|
|
} finally {
|
|
|
|
|
isSavingCategory.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除分类
|
|
|
|
|
const deleteCategory = async (category: any) => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm('确定要删除该分类吗?此操作不可恢复!', '警告', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await adminApi.deleteCategory(category.id)
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('分类删除成功')
|
|
|
|
|
loadCategories()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
ElMessage.error('删除分类失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除资源
|
|
|
|
|
const deleteResource = async (resource: any) => {
|
|
|
|
|
try {
|
|
|
|
|
await ElMessageBox.confirm('确定要删除该资源吗?此操作不可恢复!', '警告', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await adminApi.deleteResource(resource.id)
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
ElMessage.success('资源删除成功')
|
|
|
|
|
loadResources()
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error !== 'cancel') {
|
|
|
|
|
ElMessage.error('删除资源失败')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取角色类型
|
|
|
|
|
const getRoleType = (role: number) => {
|
|
|
|
|
switch (role) {
|
|
|
|
@ -324,6 +944,34 @@ const getRoleText = (role: number) => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取帖子状态类型
|
|
|
|
|
const getPostStatusType = (status: number) => {
|
|
|
|
|
switch (status) {
|
|
|
|
|
case 1: return ''
|
|
|
|
|
case 2: return 'warning'
|
|
|
|
|
case 0: return 'danger'
|
|
|
|
|
default: return ''
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取帖子状态文本
|
|
|
|
|
const getPostStatusText = (status: number) => {
|
|
|
|
|
switch (status) {
|
|
|
|
|
case 1: return '正常'
|
|
|
|
|
case 2: return '置顶'
|
|
|
|
|
case 0: return '已删除'
|
|
|
|
|
default: return '未知'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 格式化文件大小
|
|
|
|
|
const formatFileSize = (size: number) => {
|
|
|
|
|
if (size < 1024) return size + ' B'
|
|
|
|
|
if (size < 1024 * 1024) return (size / 1024).toFixed(1) + ' KB'
|
|
|
|
|
if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(1) + ' MB'
|
|
|
|
|
return (size / (1024 * 1024 * 1024)).toFixed(1) + ' GB'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 退出登录
|
|
|
|
|
const logout = () => {
|
|
|
|
|
userStore.logout()
|
|
|
|
|