修复权限验证问题:普通用户无法访问后台管理页面
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user