| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- <template>
- <el-container>
- <el-header class="header">
- <div class="header-left" @click="router.push('/')">
- <img src="/logo.svg" alt="logo" class="logo">
- <h2 class="title">{{ metaStore.title }}</h2>
- </div>
- <h1 class="admin-title">后台管理</h1>
- <div class="header-right">
- <template v-if="login">
- <el-dropdown placement="bottom">
- <el-button>
- <el-icon><UserFilled /></el-icon>
- {{ loginUserStore.loginUser?.user?.name }}
- </el-button>
- <template #dropdown>
- <el-dropdown-menu>
- <el-dropdown-item @click="router.push('/profile')">个人信息</el-dropdown-item>
- <el-dropdown-item @click="router.push('/booking')">返回前台</el-dropdown-item>
- <el-dropdown-item divided @click="logoutHandler">退出</el-dropdown-item>
- </el-dropdown-menu>
- </template>
- </el-dropdown>
- </template>
- <template v-else>
- <el-button type="primary" size="small" @click="router.push('/login')">登录</el-button>
- </template>
- </div>
- </el-header>
- <el-container class="main-container">
- <el-aside :class="['menu', { collapsed: isCollapse }]">
- <el-radio-group v-model="isCollapse" class="collapse-toggle">
- <el-radio-button :value="false">展开</el-radio-button>
- <el-radio-button :value="true">收起</el-radio-button>
- </el-radio-group>
- <el-menu
- router
- :collapse="isCollapse"
- :default-active="activeIndex"
- >
- <el-menu-item :index="menu.path" v-for="menu in navMenus" :key="menu.path">
- <el-icon><component :is="menu.meta?.icon" /></el-icon>
- <template #title>{{ menu.meta?.title }}</template>
- </el-menu-item>
- </el-menu>
- </el-aside>
- <el-main>
- <router-view />
- </el-main>
- </el-container>
- </el-container>
- </template>
- <script setup lang="ts">
- import { computed, ref } from 'vue'
- import { useRoute } from 'vue-router'
- import { useLoginUserStore, useMetaStore } from '../store'
- import router, { adminRoutes } from '../router'
- import { UserFilled } from '@element-plus/icons-vue'
- import { getAuthController } from '../api/auth-controller'
- const route = useRoute()
- const metaStore = useMetaStore()
- const loginUserStore = useLoginUserStore()
- const login = computed(() => loginUserStore.loginUser.isLogin)
- const isCollapse = ref(false)
- const activeIndex = computed(() => route.path)
- const navMenus = computed(() => {
- return (adminRoutes[0].children || []).filter(m => m.meta?.icon)
- })
- const logoutHandler = async () => {
- try {
- await getAuthController().logout()
- } catch {
- // 忽略服务端登出错误
- }
- loginUserStore.logoutUser()
- router.push('/login')
- }
- </script>
- <style scoped>
- .el-container {
- height: 100vh;
- }
- .header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 20px;
- border-bottom: 1px solid #eee;
- }
- .header-left {
- display: flex;
- align-items: center;
- gap: 10px;
- cursor: pointer;
- }
- .logo {
- width: 40px;
- height: 40px;
- }
- .title {
- margin: 0;
- font-size: 20px;
- }
- .admin-title {
- font-size: 18px;
- color: var(--el-color-primary);
- }
- .header-right {
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .main-container {
- flex: 1;
- }
- .menu {
- width: 200px;
- transition: width 0.3s;
- border-right: 1px solid #eee;
- }
- .menu.collapsed {
- width: 64px;
- }
- .collapse-toggle {
- display: flex;
- justify-content: center;
- margin: 16px 8px;
- }
- </style>
|