添加 vue-router 依赖并配置路由,重构登录组件,完善 HTTP 请求拦截器以支持 token 刷新机制
This commit is contained in:
138
src/layouts/AdminLayout.vue
Normal file
138
src/layouts/AdminLayout.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="admin-layout">
|
||||
<aside class="sider">
|
||||
<div class="brand">
|
||||
<img class="logo" src="https://vuejs.org/images/logo.png" alt="logo" />
|
||||
<span class="name">管理后台</span>
|
||||
</div>
|
||||
<el-menu
|
||||
class="menu"
|
||||
router
|
||||
:default-active="$route.name"
|
||||
:collapse="collapsed"
|
||||
background-color="#001529"
|
||||
text-color="#bfcbd9"
|
||||
active-text-color="#fff"
|
||||
>
|
||||
<el-menu-item index="Dashboard" :route="{ name: 'Dashboard' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/></svg></i>
|
||||
<span>仪表盘</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="canAccessUsers" index="Users" :route="{ name: 'Users' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 12c2.7 0 5-2.3 5-5s-2.3-5-5-5s-5 2.3-5 5s2.3 5 5 5m0 2c-3.3 0-10 1.7-10 5v3h20v-3c0-3.3-6.7-5-10-5Z"/></svg></i>
|
||||
<span>用户管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="canAccessGames" index="Games" :route="{ name: 'Games' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M6 8h12v8H6z"/></svg></i>
|
||||
<span>游戏管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="canAccessOrders" index="Orders" :route="{ name: 'Orders' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg></i>
|
||||
<span>订单管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="canAccessReports" index="Reports" :route="{ name: 'Reports' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M3 3h2v18H3V3m4 8h2v10H7V11m4-6h2v16h-2V5m4 10h2v6h-2v-6m4-3h2v9h-2v-9Z"/></svg></i>
|
||||
<span>报表分析</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item v-if="canAccessSettings" index="Settings" :route="{ name: 'Settings' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="m12 8l-2 4h4l-2 4"/></svg></i>
|
||||
<span>系统设置</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="ErrorTest" :route="{ name: 'ErrorTest' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg></i>
|
||||
<span>错误测试</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="PermissionTest" :route="{ name: 'PermissionTest' }">
|
||||
<i class="el-icon"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg></i>
|
||||
<span>权限测试</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</aside>
|
||||
<section class="main">
|
||||
<header class="header">
|
||||
<el-button text @click="collapsed = !collapsed" class="collapse-btn">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24"><path fill="currentColor" d="M3 6h18v2H3V6m0 5h12v2H3v-2m0 5h18v2H3v-2Z"/></svg>
|
||||
</el-button>
|
||||
<div class="spacer" />
|
||||
<el-dropdown>
|
||||
<span class="el-dropdown-link">
|
||||
管理员<i class="el-icon el-icon--right"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentColor" d="M7 10l5 5 5-5z"/></svg></i>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="onProfile">个人中心</el-dropdown-item>
|
||||
<el-dropdown-item divided @click="onLogout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</header>
|
||||
<main class="content">
|
||||
<router-view />
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { clearTokens } from '@/utils/auth'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { canAccessRoute } from '@/utils/permission'
|
||||
|
||||
const collapsed = ref(false)
|
||||
const router = useRouter()
|
||||
|
||||
// 权限检查
|
||||
const canAccessUsers = computed(() => canAccessRoute('Users'))
|
||||
const canAccessGames = computed(() => canAccessRoute('Games'))
|
||||
const canAccessOrders = computed(() => canAccessRoute('Orders'))
|
||||
const canAccessReports = computed(() => canAccessRoute('Reports'))
|
||||
const canAccessSettings = computed(() => canAccessRoute('Settings'))
|
||||
|
||||
function onProfile() {
|
||||
// 可跳转到个人中心占位页
|
||||
}
|
||||
|
||||
function onLogout() {
|
||||
clearTokens()
|
||||
router.replace({ name: 'Login' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.admin-layout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
.sider {
|
||||
width: 220px;
|
||||
background: #001529;
|
||||
color: #bfcbd9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.brand {
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 0 16px;
|
||||
color: #fff;
|
||||
}
|
||||
.logo { width: 24px; height: 24px; }
|
||||
.menu { border-right: none; flex: 1; }
|
||||
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
||||
.header {
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.collapse-btn { margin-right: 8px; }
|
||||
.spacer { flex: 1; }
|
||||
.content { padding: 16px; overflow: auto; background: #f5f7fa; height: calc(100vh - 56px); }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user