修复权限验证问题:普通用户无法访问后台管理页面

This commit is contained in:
AIGC Developer
2025-10-23 09:59:54 +08:00
parent a294f61f3c
commit 08b737b1ef
59 changed files with 3586 additions and 607 deletions

View File

@@ -1,6 +1,74 @@
<template>
<div class="works-page">
<div class="toolbar">
<!-- 左侧导航栏 -->
<aside class="sidebar">
<!-- Logo -->
<div class="logo">logo</div>
<!-- 导航菜单 -->
<nav class="nav-menu">
<div class="nav-item" @click="goToProfile">
<el-icon><User /></el-icon>
<span>个人主页</span>
</div>
<div class="nav-item" @click="goToSubscription">
<el-icon><Compass /></el-icon>
<span>会员订阅</span>
</div>
<div class="nav-item active">
<el-icon><Document /></el-icon>
<span>我的作品</span>
</div>
</nav>
<!-- 工具分隔线 -->
<div class="divider">
<span>工具</span>
</div>
<!-- 工具菜单 -->
<nav class="tools-menu">
<div class="nav-item" @click="goToTextToVideo">
<el-icon><VideoPlay /></el-icon>
<span>文生视频</span>
</div>
<div class="nav-item" @click="goToImageToVideo">
<el-icon><Picture /></el-icon>
<span>图生视频</span>
</div>
<div class="nav-item" @click="goToStoryboardVideo">
<el-icon><Film /></el-icon>
<span>分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
</nav>
</aside>
<!-- 主内容区域 -->
<main class="main-content">
<!-- 顶部栏 -->
<header class="top-header">
<div class="header-right">
<div class="discount-badge">
<span class="discount-icon">+ 25</span>
<span class="discount-text">首购优惠</span>
</div>
<div class="notification-bell">
<el-icon><Bell /></el-icon>
<span class="notification-badge">5</span>
</div>
<div class="user-avatar">
<el-icon><User /></el-icon>
</div>
<div class="settings-icon">
<el-icon><Setting /></el-icon>
</div>
</div>
</header>
<!-- 内容区域 -->
<div class="content-area">
<div class="toolbar">
<el-radio-group v-model="activeTab" size="small" class="seg-control">
<el-radio-button label="all">全部</el-radio-button>
<el-radio-button label="video">视频</el-radio-button>
@@ -8,44 +76,55 @@
</el-radio-group>
</div>
<div class="filters-bar">
<el-space wrap size="small" class="filters">
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" size="small" />
<el-select v-model="category" placeholder="任务类型" size="small" style="width: 120px" @change="onFilterChange">
<el-option label="全部" value="all" />
<el-option label="文生视频" value="text2video" />
<el-option label="图生视频" value="image2video" />
<el-option label="分镜视频" value="storyboard" />
<el-option label="参考图" value="reference" />
</el-select>
<el-select v-model="resolution" placeholder="清晰度" clearable size="small" style="width: 120px">
<el-option label="标清" value="sd" />
<el-option label="高清" value="hd" />
<el-option label="超清" value="uhd" />
</el-select>
<el-select v-model="sortBy" size="small" style="width: 120px">
<el-option label="比例" value="ratio" />
<el-option label="时间" value="date" />
<el-option label="热门" value="hot" />
</el-select>
<el-select v-model="order" size="small" style="width: 100px">
<el-option label="升序" value="asc" />
<el-option label="降序" value="desc" />
</el-select>
</el-space>
<div class="right">
<el-input v-model="keyword" placeholder="名字/提示词/ID" size="small" clearable style="width: 220px" @keyup.enter.native="reload" />
</div>
</div>
<div class="filters-bar">
<div class="filters-left">
<el-select v-model="dateFilter" placeholder="日期" size="small" style="width: 100px">
<el-option label="今天" value="today" />
<el-option label="本周" value="week" />
<el-option label="本月" value="month" />
</el-select>
<el-select v-model="category" placeholder="任务类型" size="small" style="width: 100px" @change="onFilterChange">
<el-option label="全部" value="all" />
<el-option label="文生视频" value="text2video" />
<el-option label="图生视频" value="image2video" />
<el-option label="分镜视频" value="storyboard" />
</el-select>
<el-select v-model="resolution" placeholder="清晰度" clearable size="small" style="width: 100px">
<el-option label="标清" value="sd" />
<el-option label="高清" value="hd" />
<el-option label="超清" value="uhd" />
</el-select>
<el-select v-model="sortBy" placeholder="比例" size="small" style="width: 100px">
<el-option label="比例" value="ratio" />
<el-option label="时间" value="date" />
<el-option label="热门" value="hot" />
</el-select>
<el-button size="small" @click="resetFilters">重置</el-button>
</div>
<div class="filters-right">
<el-input
v-model="keyword"
placeholder="名字/提示词/ID"
size="small"
clearable
style="width: 220px"
@keyup.enter.native="reload"
>
<template #prefix>
<el-icon><Search /></el-icon>
</template>
</el-input>
</div>
</div>
<div class="select-row">
<el-checkbox v-model="multiSelect" size="small">选择多个</el-checkbox>
<template v-if="multiSelect && selectedIds.size">
<el-tag type="success" size="small">已选 {{ selectedIds.size }} 个项目</el-tag>
<el-button size="small" type="primary" @click="bulkDownload" plain>下载</el-button>
<el-button size="small" type="danger" @click="bulkDelete" plain>删除</el-button>
</template>
</div>
<div class="select-row">
<el-checkbox v-model="multiSelect" size="small">选择{{ selectedIds.size || 6 }}个项目</el-checkbox>
<template v-if="multiSelect && selectedIds.size">
<el-tag type="success" size="small">已选 {{ selectedIds.size }} 个项目</el-tag>
<el-button size="small" type="primary" @click="bulkDownload" plain>下载</el-button>
<el-button size="small" type="danger" @click="bulkDelete" plain>删除</el-button>
</template>
</div>
<el-row :gutter="16" class="works-grid">
<el-col v-for="item in filteredItems" :key="item.id" :xs="24" :sm="12" :md="8" :lg="6">
@@ -223,9 +302,11 @@
</div>
</el-dialog>
<div class="finished" v-if="!hasMore && filteredItems.length>0">已加载全部内容</div>
<el-empty v-if="!loading && filteredItems.length===0" description="没有找到相关内容" />
</div>
<div class="finished" v-if="!hasMore && filteredItems.length>0">已加载全部内容</div>
<el-empty v-if="!loading && filteredItems.length===0" description="没有找到相关内容" />
</div>
</main>
</div>
</template>
@@ -233,12 +314,13 @@
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Star, MoreFilled, User } from '@element-plus/icons-vue'
import { Star, User, Compass, Document, VideoPlay, Picture, Film, Bell, Setting, Search } from '@element-plus/icons-vue'
const router = useRouter()
const activeTab = ref('all')
const dateRange = ref([])
const dateFilter = ref('')
const category = ref('all')
const resolution = ref('')
const sortBy = ref('date')
@@ -443,6 +525,42 @@ const bulkDelete = async () => {
} catch (_) {}
}
// 导航方法
const goToProfile = () => {
console.log('导航到个人主页')
router.push('/profile')
}
const goToSubscription = () => {
console.log('导航到会员订阅')
router.push('/subscription')
}
const goToTextToVideo = () => {
console.log('导航到文生视频')
router.push('/text-to-video')
}
const goToImageToVideo = () => {
console.log('导航到图生视频')
router.push('/image-to-video')
}
const goToStoryboardVideo = () => {
console.log('导航到分镜视频')
router.push('/storyboard-video')
}
// 重置筛选器
const resetFilters = () => {
dateFilter.value = ''
category.value = 'all'
resolution.value = ''
sortBy.value = 'date'
keyword.value = ''
ElMessage.success('筛选器已重置')
}
onMounted(() => {
loadList()
})
@@ -450,8 +568,189 @@ onMounted(() => {
<style scoped>
.works-page {
padding: 16px 20px;
min-height: 100vh;
background: #0a0a0a;
color: white;
display: flex;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
position: relative;
}
/* 页面特殊效果 */
.works-page::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 10% 20%, rgba(64, 158, 255, 0.1) 0%, transparent 50%),
radial-gradient(circle at 90% 80%, rgba(103, 194, 58, 0.1) 0%, transparent 50%),
radial-gradient(circle at 50% 50%, rgba(230, 162, 60, 0.05) 0%, transparent 50%);
animation: profileGlow 6s ease-in-out infinite alternate;
pointer-events: none;
z-index: 1;
}
@keyframes profileGlow {
0% { opacity: 0.3; }
100% { opacity: 0.6; }
}
.works-page > * {
position: relative;
z-index: 2;
}
/* 左侧导航栏 */
.sidebar {
width: 280px !important;
background: #1a1a1a !important;
padding: 24px 0 !important;
border-right: 1px solid #1a1a1a !important;
flex-shrink: 0 !important;
z-index: 100 !important;
display: block !important;
position: relative !important;
}
.logo {
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu, .tools-menu {
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.nav-item:hover {
background: #2a2a2a;
}
.nav-item.active {
background: #1e3a8a;
}
.nav-item .el-icon {
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 15px;
flex: 1;
}
.sora-tag {
margin-left: 8px;
font-size: 10px;
padding: 2px 6px;
}
.divider {
margin: 30px 20px 20px;
padding: 0 16px;
color: #666;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 1px;
}
/* 主内容区域 */
.main-content {
flex: 1;
padding: 0;
}
/* 顶部导航栏 */
.top-header {
padding: 20px 30px;
border-bottom: 1px solid #333;
display: flex;
justify-content: flex-end;
}
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.discount-badge {
display: flex;
align-items: center;
background: #3b82f6;
color: white;
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
}
.discount-icon {
background: #1e40af;
padding: 2px 6px;
border-radius: 10px;
margin-right: 6px;
}
.notification-bell {
position: relative;
cursor: pointer;
color: #9ca3af;
font-size: 20px;
}
.notification-badge {
position: absolute;
top: -8px;
right: -8px;
background: #ef4444;
color: white;
font-size: 10px;
padding: 2px 6px;
border-radius: 10px;
min-width: 16px;
text-align: center;
}
.user-avatar, .settings-icon {
cursor: pointer;
color: #9ca3af;
font-size: 20px;
}
.user-avatar:hover, .settings-icon:hover, .notification-bell:hover {
color: white;
}
/* 内容区域 */
.content-area {
flex: 1;
padding: 20px 24px;
overflow-y: auto;
}
.toolbar {
display: flex;
align-items: center;
@@ -477,16 +776,30 @@ onMounted(() => {
}
.filters { margin-left: 10px; }
.filters-bar {
display:flex;
align-items:center;
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 0 2px;
padding: 12px 0;
border-bottom: 1px solid #333;
margin-bottom: 16px;
background: #1a1a1a;
/* 覆盖 Element Plus 变量,确保与页面背景一致 */
--el-input-bg-color: #0a0a0a;
--el-fill-color-blank: #0a0a0a;
--el-border-color: #2a2a2a;
--el-text-color-regular: #cbd5e1;
}
.filters-left {
display: flex;
align-items: center;
gap: 12px;
}
.filters-right {
display: flex;
align-items: center;
}
:deep(.filters .el-select .el-input__wrapper),
:deep(.filters .el-date-editor.el-input__wrapper),
:deep(.filters .el-input__wrapper) {