359 lines
9.6 KiB
Vue
359 lines
9.6 KiB
Vue
<template>
|
||
<div class="dashboard-wrapper">
|
||
<div v-if="isAdmin" class="admin-layout" :class="{ 'sidebar-open': isMobileSidebarOpen }">
|
||
<div class="mobile-header">
|
||
<button @click="isMobileSidebarOpen = !isMobileSidebarOpen" class="hamburger-button">
|
||
<span class="hamburger-icon"></span>
|
||
</button>
|
||
<span class="mobile-header-title">后台管理</span>
|
||
</div>
|
||
<div class="admin-sidebar">
|
||
<div class="sidebar-header">
|
||
<h3>后台管理</h3>
|
||
</div>
|
||
<ul class="sidebar-nav">
|
||
<li @click="selectAdminView('event-management')" :class="{ active: currentAdminView === 'event-management' }"><a>赛事管理</a></li>
|
||
<li @click="selectAdminView('player-management')" :class="{ active: currentAdminView === 'player-management' }"><a>赛事玩家管理</a></li>
|
||
<li @click="selectAdminView('service-hall')" :class="{ active: currentAdminView === 'service-hall' }"><a>办事大厅</a></li>
|
||
</ul>
|
||
<div class="sidebar-footer">
|
||
<button @click="selectAdminView('code-generator')" :class="['sidebar-button', 'code-generator-button', { 'active': currentAdminView === 'code-generator' }]">
|
||
代码生成器
|
||
</button>
|
||
<button @click="goToHomePage" class="home-button sidebar-button">
|
||
返回主界面
|
||
</button>
|
||
<button @click="handleLogout" class="logout-button sidebar-button">
|
||
退出登录
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="admin-main-content">
|
||
<div v-if="currentAdminView === 'event-management'">
|
||
<TournamentList />
|
||
</div>
|
||
<div v-else-if="currentAdminView === 'player-management'">
|
||
<PlayerList />
|
||
</div>
|
||
<div v-else-if="currentAdminView === 'service-hall'">
|
||
<ServiceHallView />
|
||
</div>
|
||
<div v-else-if="currentAdminView === 'code-generator'">
|
||
<CodeGenerator />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, computed } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import TournamentList from '../../components/backend/TournamentList.vue'
|
||
import PlayerList from '../../components/backend/PlayerList.vue'
|
||
import ServiceHallView from '../../components/backend/ServiceHallView.vue'
|
||
import CodeGenerator from '../../components/backend/CodeGenerator.vue'
|
||
|
||
const router = useRouter()
|
||
const hasToken = ref(false)
|
||
const userId = ref(localStorage.getItem('user_id'))
|
||
const currentAdminView = ref('event-management')
|
||
const isMobileSidebarOpen = ref(false)
|
||
|
||
const isAdmin = computed(() => {
|
||
return userId.value === '1846172115' || userId.value === '1400429906' || userId.value === '3422054939'
|
||
})
|
||
|
||
onMounted(() => {
|
||
// 检查是否有token
|
||
const token = localStorage.getItem('access_token')
|
||
hasToken.value = !!token
|
||
if (!token) {
|
||
router.push('/')
|
||
return;
|
||
}
|
||
|
||
// userId 应该已经从 localStorage 初始化了
|
||
// 可以在这里再次检查或记录,以防 localStorage 在组件加载后发生变化
|
||
const currentStoredUserId = localStorage.getItem('user_id');
|
||
if (currentStoredUserId) {
|
||
// 如果 ref 中的值与当前 localStorage 中的值不同(例如,初始为 null,现在有值了)
|
||
if (userId.value !== currentStoredUserId) {
|
||
userId.value = currentStoredUserId;
|
||
console.log('Dashboard.vue - 用户ID已在 onMounted 中更新:', userId.value);
|
||
} else {
|
||
console.log('Dashboard.vue - 当前用户ID (onMounted, 与初始值一致):', userId.value);
|
||
}
|
||
} else {
|
||
// 如果 userId.value 为 null(初始即为 null 且 onMounted 时 localStorage 仍为 null)
|
||
// 并且我们删除了非管理员视图,管理员内容将不会显示
|
||
console.log('Dashboard.vue - 未在 localStorage 中检测到用户ID (onMounted)');
|
||
}
|
||
})
|
||
|
||
const handleLogout = () => {
|
||
// 清除本地存储的 token
|
||
localStorage.removeItem('access_token')
|
||
// 可选:清除用户ID
|
||
localStorage.removeItem('user_id')
|
||
// 清除当前视图状态 (如果需要)
|
||
currentAdminView.value = 'event-management'
|
||
isMobileSidebarOpen.value = false; // 退出时关闭侧边栏
|
||
// 跳转到登录页面
|
||
router.push('/')
|
||
}
|
||
|
||
const goToHomePage = () => {
|
||
router.push('/') // 假设主页路由是 '/'
|
||
isMobileSidebarOpen.value = false; // 返回主页时关闭侧边栏
|
||
}
|
||
|
||
// 新增:选择管理员视图的方法
|
||
const selectAdminView = (viewName) => {
|
||
currentAdminView.value = viewName
|
||
if (window.innerWidth <= 768) {
|
||
isMobileSidebarOpen.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* Global reset and base styles (optional, but good for consistency) */
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.dashboard-wrapper, .admin-layout {
|
||
height: 100%;
|
||
width: 100%;
|
||
overflow-x: hidden; /* Prevent horizontal scroll on body/wrapper */
|
||
}
|
||
|
||
.dashboard-wrapper {
|
||
font-family: 'Arial', sans-serif;
|
||
background-color: #f0f2f5; /* Default background for non-admin or loading states */
|
||
}
|
||
|
||
/* Admin Layout Styles */
|
||
.admin-layout {
|
||
display: flex;
|
||
position: relative; /* For mobile sidebar positioning */
|
||
}
|
||
|
||
.admin-sidebar {
|
||
width: 240px; /* Sidebar width */
|
||
background-color: #e0f2fe; /* 淡蓝色 - light sky blue, adjust as needed */
|
||
color: #075985; /* Darker blue for text for contrast */
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%; /* Full height */
|
||
position: fixed; /* Fixed position */
|
||
left: 0;
|
||
top: 0px; /* Stick to the top of the webpage */
|
||
z-index: 1000;
|
||
transition: transform 0.3s ease;
|
||
box-shadow: 2px 0 8px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.sidebar-header {
|
||
padding: 20px;
|
||
text-align: center;
|
||
border-bottom: 1px solid #bae6fd; /* Lighter blue for border */
|
||
}
|
||
|
||
.sidebar-header h3 {
|
||
color: #0c4a6e; /* Even darker blue for header */
|
||
margin: 0;
|
||
font-size: 1.6rem;
|
||
}
|
||
|
||
.sidebar-nav {
|
||
list-style: none;
|
||
flex-grow: 1;
|
||
overflow-y: auto; /* Allow scrolling for many nav items */
|
||
}
|
||
|
||
.sidebar-nav li a {
|
||
display: block;
|
||
padding: 15px 20px;
|
||
color: #075985;
|
||
text-decoration: none;
|
||
transition: background-color 0.2s, color 0.2s;
|
||
cursor: pointer;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.sidebar-nav li a:hover {
|
||
background-color: #7dd3fc; /* Lighter blue for hover */
|
||
color: #0c4a6e;
|
||
}
|
||
|
||
.sidebar-nav li.active a {
|
||
background-color: #38bdf8; /* Medium blue for active */
|
||
color: #ffffff;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.sidebar-footer {
|
||
padding: 20px;
|
||
border-top: 1px solid #bae6fd;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.sidebar-button {
|
||
width: 100%;
|
||
padding: 12px 15px;
|
||
border-radius: 6px;
|
||
text-align: center;
|
||
font-weight: 500;
|
||
transition: background-color 0.2s, opacity 0.2s;
|
||
border: none;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.sidebar-button.home-button {
|
||
background-color: #0ea5e9; /* Sky blue */
|
||
}
|
||
.sidebar-button.home-button:hover {
|
||
background-color: #0284c7; /* Darker sky blue */
|
||
}
|
||
|
||
.sidebar-button.code-generator-button {
|
||
background-color: #10b981; /* Emerald green */
|
||
}
|
||
.sidebar-button.code-generator-button:hover {
|
||
background-color: #059669; /* Darker emerald green */
|
||
}
|
||
.sidebar-button.code-generator-button.active {
|
||
background-color: #047857;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.sidebar-button.logout-button {
|
||
background-color: #ef4444; /* Red */
|
||
}
|
||
.sidebar-button.logout-button:hover {
|
||
background-color: #dc2626; /* Darker Red */
|
||
}
|
||
|
||
.admin-main-content {
|
||
flex-grow: 1;
|
||
background-color: #ffffff; /* White background for content */
|
||
padding: 20px;
|
||
margin-left: 240px; /* Same as sidebar width */
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
transition: margin-left 0.3s ease;
|
||
}
|
||
|
||
/* Mobile Header Styles */
|
||
.mobile-header {
|
||
display: none; /* Hidden by default, shown on mobile */
|
||
background-color: #e0f2fe; /* Same as sidebar */
|
||
color: #0c4a6e;
|
||
padding: 10px 15px;
|
||
align-items: center;
|
||
position: fixed;
|
||
top: 0px; /* Stick to the top of the webpage */
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 1001; /* Above sidebar when closed */
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.hamburger-button {
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
padding: 10px;
|
||
display: flex; /* For centering span inside */
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.hamburger-icon {
|
||
display: block;
|
||
width: 24px;
|
||
height: 2px;
|
||
background-color: #0c4a6e;
|
||
position: relative;
|
||
}
|
||
|
||
.hamburger-icon::before,
|
||
.hamburger-icon::after {
|
||
content: '';
|
||
position: absolute;
|
||
width: 24px;
|
||
height: 2px;
|
||
background-color: #0c4a6e;
|
||
left: 0;
|
||
}
|
||
|
||
.hamburger-icon::before {
|
||
top: -7px;
|
||
}
|
||
|
||
.hamburger-icon::after {
|
||
bottom: -7px;
|
||
}
|
||
|
||
.mobile-header-title {
|
||
margin-left: 15px;
|
||
font-size: 1.2rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* Mobile Responsiveness */
|
||
@media (max-width: 768px) {
|
||
.admin-sidebar {
|
||
transform: translateX(-100%); /* Hide sidebar off-screen */
|
||
box-shadow: none; /* Hide shadow when off-screen or covered */
|
||
}
|
||
|
||
.admin-layout.sidebar-open .admin-sidebar {
|
||
transform: translateX(0); /* Show sidebar */
|
||
box-shadow: 2px 0 8px rgba(0,0,0,0.15); /* Shadow for open sidebar on mobile */
|
||
}
|
||
|
||
.admin-main-content {
|
||
margin-left: 0; /* Content takes full width */
|
||
padding-top: 55px; /* Space for fixed mobile header (now at top:0), adjusted from 70px */
|
||
}
|
||
|
||
.mobile-header {
|
||
display: flex;
|
||
}
|
||
|
||
.sidebar-header h3 {
|
||
font-size: 1.3rem; /* Slightly smaller header for mobile sidebar */
|
||
}
|
||
|
||
.sidebar-nav li a {
|
||
padding: 12px 20px; /* Adjust padding if needed */
|
||
}
|
||
|
||
/* Overlay for when mobile sidebar is open */
|
||
.admin-layout.sidebar-open::after {
|
||
content: '';
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0,0,0,0.3);
|
||
z-index: 999; /* Below sidebar, above content */
|
||
}
|
||
}
|
||
|
||
/* Styles for the placeholder non-admin page if it's not the main content area */
|
||
/*
|
||
.dashboard-container {
|
||
|
||
}
|
||
*/
|
||
</style> |