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

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

@@ -17,7 +17,7 @@
</div>
<div class="nav-item">
<el-icon><Document /></el-icon>
<span>我的作品</span>
<span @click="goToMyWorks">我的作品</span>
</div>
</nav>
@@ -29,16 +29,16 @@
<!-- 工具菜单 -->
<nav class="tools-menu">
<div class="nav-item">
<el-icon><Document /></el-icon>
<span>文生视频</span>
<el-icon><VideoPlay /></el-icon>
<span @click="goToTextToVideo">文生视频</span>
</div>
<div class="nav-item">
<el-icon><Picture /></el-icon>
<span>图生视频</span>
<span @click="goToImageToVideo">图生视频</span>
</div>
<div class="nav-item">
<el-icon><VideoPlay /></el-icon>
<span>分镜视频</span>
<el-icon><Film /></el-icon>
<span @click="goToStoryboardVideo">分镜视频</span>
<el-tag size="small" type="primary" class="sora-tag">Sora2.0</el-tag>
</div>
</nav>
@@ -57,7 +57,7 @@
<el-icon><Bell /></el-icon>
<div class="notification-dot"></div>
</div>
<div class="user-status">
<div class="user-status" @click="showUserMenu = !showUserMenu" ref="userStatusRef">
<div class="status-icon"></div>
</div>
</div>
@@ -74,7 +74,6 @@
<p class="profile-status">还没有设置个人简介,点击填写</p>
<p class="user-id">ID 2994509784706419</p>
</div>
<el-button class="edit-btn">编辑资料</el-button>
</div>
</section>
@@ -98,30 +97,175 @@
</section>
</main>
</div>
<!-- 用户菜单下拉 - 使用Teleport渲染到body -->
<Teleport to="body">
<div v-if="showUserMenu" class="user-menu-teleport" :style="menuStyle">
<!-- 管理员功能 -->
<template v-if="userStore.isAdmin">
<div class="menu-item" @click="goToDashboard">
<el-icon><User /></el-icon>
<span>数据仪表盘</span>
</div>
<div class="menu-item" @click="goToOrders">
<el-icon><Document /></el-icon>
<span>订单管理</span>
</div>
<div class="menu-item" @click="goToMembers">
<el-icon><User /></el-icon>
<span>会员管理</span>
</div>
<div class="menu-item" @click="goToSettings">
<el-icon><Setting /></el-icon>
<span>系统设置</span>
</div>
</template>
<!-- 退出登录 -->
<div class="menu-item" @click="logout">
<el-icon><User /></el-icon>
<span>退出登录</span>
</div>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
import { ref, onMounted, onUnmounted, computed, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import {
User,
Compass,
Document,
Picture,
VideoPlay,
Star,
Bell
Bell,
Setting,
Compass,
VideoPlay,
Picture,
Film
} from '@element-plus/icons-vue'
const router = useRouter()
const userStore = useUserStore()
// 控制用户菜单显示
const showUserMenu = ref(false)
const userStatusRef = ref(null)
// 模拟视频数据
const videos = ref(Array(6).fill({}))
// 计算菜单位置
const menuStyle = computed(() => {
if (!userStatusRef.value || !showUserMenu.value) return {}
const rect = userStatusRef.value.getBoundingClientRect()
return {
position: 'fixed',
top: `${rect.bottom + 8}px`,
right: `${window.innerWidth - rect.right}px`,
zIndex: 99999
}
})
// 跳转到会员订阅页面
const goToSubscription = () => {
router.push('/subscription')
}
const goToMyWorks = () => {
router.push('/works')
}
const goToTextToVideo = () => {
router.push('/text-to-video')
}
const goToImageToVideo = () => {
router.push('/image-to-video')
}
const goToStoryboardVideo = () => {
router.push('/storyboard-video')
}
// 跳转到数据仪表盘
const goToDashboard = () => {
showUserMenu.value = false
// 检查用户权限,只有管理员才能访问数据仪表盘
if (userStore.isAdmin) {
router.push('/admin/dashboard')
} else {
ElMessage.warning('权限不足,只有管理员才能访问数据仪表盘')
}
}
// 跳转到订单管理
const goToOrders = () => {
showUserMenu.value = false
router.push('/orders')
}
// 跳转到会员管理
const goToMembers = () => {
showUserMenu.value = false
// 检查用户权限,只有管理员才能访问会员管理
if (userStore.isAdmin) {
router.push('/member-management')
} else {
ElMessage.warning('权限不足,只有管理员才能访问会员管理')
}
}
// 跳转到系统设置
const goToSettings = () => {
showUserMenu.value = false
// 检查用户权限,只有管理员才能访问系统设置
if (userStore.isAdmin) {
router.push('/system-settings')
} else {
ElMessage.warning('权限不足,只有管理员才能访问系统设置')
}
}
// 退出登录
const logout = async () => {
try {
showUserMenu.value = false
// 清除用户数据
await userStore.logoutUser()
// 清除其他可能的本地存储
localStorage.removeItem('user')
localStorage.removeItem('token')
ElMessage.success('已退出登录')
// 跳转到登录页
router.push('/login')
} catch (error) {
console.error('退出登录失败:', error)
ElMessage.error('退出登录失败')
}
}
// 点击外部关闭菜单
const handleClickOutside = (event) => {
const userStatus = event.target.closest('.user-status')
if (!userStatus) {
showUserMenu.value = false
}
}
onMounted(() => {
document.addEventListener('click', handleClickOutside)
})
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside)
})
</script>
<style scoped>
@@ -135,7 +279,7 @@ const goToSubscription = () => {
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
overflow: visible;
position: relative;
}
@@ -164,32 +308,36 @@ const goToSubscription = () => {
/* 内容层级 */
.profile-page > * {
position: relative;
z-index: 2;
z-index: 1;
}
/* 左侧导航栏 */
.sidebar {
width: 240px;
background: #1a1a1a;
padding: 20px 0;
border-right: 1px solid #333;
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 20px 30px;
font-size: 18px;
padding: 0 24px 32px;
font-size: 20px;
font-weight: 500;
color: white;
}
.nav-menu, .tools-menu {
padding: 0 20px;
padding: 0 24px;
}
.nav-item {
display: flex;
align-items: center;
padding: 12px 16px;
padding: 14px 18px;
margin-bottom: 4px;
border-radius: 8px;
cursor: pointer;
@@ -206,12 +354,12 @@ const goToSubscription = () => {
}
.nav-item .el-icon {
margin-right: 12px;
font-size: 18px;
margin-right: 14px;
font-size: 20px;
}
.nav-item span {
font-size: 14px;
font-size: 15px;
flex: 1;
}
@@ -243,6 +391,8 @@ const goToSubscription = () => {
border-bottom: 1px solid #333;
display: flex;
justify-content: flex-end;
position: relative;
z-index: 99999;
}
.header-right {
@@ -283,6 +433,15 @@ const goToSubscription = () => {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
z-index: 100000;
transition: all 0.3s ease;
}
.user-status:hover {
border-color: #66b1ff;
transform: scale(1.05);
}
.status-icon {
@@ -292,6 +451,54 @@ const goToSubscription = () => {
border-radius: 2px;
}
/* 用户菜单样式 */
.user-menu {
position: absolute;
top: 100%;
right: 0;
margin-top: 8px;
background: #1a1a1a;
border: 1px solid #333;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
min-width: 160px;
z-index: 99999;
overflow: hidden;
}
/* Teleport菜单样式 */
.user-menu-teleport {
background: #1a1a1a;
border: 1px solid #333;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
min-width: 160px;
overflow: hidden;
}
.menu-item {
display: flex;
align-items: center;
padding: 12px 16px;
cursor: pointer;
transition: background-color 0.2s ease;
color: white;
font-size: 14px;
}
.menu-item:hover {
background: #2a2a2a;
}
.menu-item .el-icon {
margin-right: 8px;
font-size: 16px;
}
.menu-item:not(:last-child) {
border-bottom: 1px solid #333;
}
/* 用户资料区域 */
.profile-section {
padding: 30px;
@@ -300,6 +507,7 @@ const goToSubscription = () => {
border-radius: 12px;
border: 1px solid #333;
position: relative;
z-index: 1;
}
.profile-section::before {