132 lines
3.1 KiB
Vue
132 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
import { SwitchButton } from '@element-plus/icons-vue'
|
|
import { computed } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { menuSections } from '../config/menu'
|
|
import { useAuthStore } from '../stores/useAuth'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const auth = useAuthStore()
|
|
|
|
function logout() {
|
|
auth.logout()
|
|
router.push({ path: '/login' })
|
|
}
|
|
|
|
const activePath = computed(() => route.path)
|
|
|
|
function onSelect(path: string) {
|
|
router.push(path)
|
|
}
|
|
|
|
const breadcrumbItems = computed(() => {
|
|
for (const section of menuSections) {
|
|
for (const group of section.children) {
|
|
const leaf = group.children.find((item) => item.path === route.path)
|
|
if (leaf) {
|
|
return [section.title, group.title, leaf.title]
|
|
}
|
|
}
|
|
}
|
|
return ['首页']
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<el-container class="app-shell">
|
|
<el-aside width="280px" class="side">
|
|
<div class="brand">贝朗医疗数据分析 Demo</div>
|
|
<el-menu :default-active="activePath" class="menu" @select="onSelect">
|
|
<el-sub-menu v-for="section in menuSections" :key="section.title" :index="section.basePath">
|
|
<template #title>{{ section.title }}</template>
|
|
<el-sub-menu
|
|
v-for="group in section.children"
|
|
:key="`${section.title}-${group.title}`"
|
|
:index="`${section.basePath}-${group.title}`"
|
|
>
|
|
<template #title>{{ group.title }}</template>
|
|
<el-menu-item v-for="leaf in group.children" :key="leaf.path" :index="leaf.path">
|
|
{{ leaf.title }}
|
|
</el-menu-item>
|
|
</el-sub-menu>
|
|
</el-sub-menu>
|
|
</el-menu>
|
|
</el-aside>
|
|
|
|
<el-container>
|
|
<el-header class="header">
|
|
<el-breadcrumb separator="/" class="header-crumb">
|
|
<el-breadcrumb-item v-for="item in breadcrumbItems" :key="item">{{ item }}</el-breadcrumb-item>
|
|
</el-breadcrumb>
|
|
<div class="header-actions">
|
|
<span class="user-label">Demo</span>
|
|
<el-button type="primary" link @click="logout">
|
|
<el-icon class="el-icon--left"><SwitchButton /></el-icon>
|
|
退出登录
|
|
</el-button>
|
|
</div>
|
|
</el-header>
|
|
<el-main class="main">
|
|
<router-view />
|
|
</el-main>
|
|
</el-container>
|
|
</el-container>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.app-shell {
|
|
min-height: 100vh;
|
|
background: var(--bg-color, #f5f7fa);
|
|
}
|
|
|
|
.side {
|
|
background: #001529;
|
|
color: #fff;
|
|
border-right: 1px solid var(--border-color, #e5e7eb);
|
|
}
|
|
|
|
.brand {
|
|
padding: 18px 16px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
|
|
}
|
|
|
|
.menu {
|
|
border-right: none;
|
|
background: transparent;
|
|
}
|
|
|
|
.header {
|
|
background: #fff;
|
|
border-bottom: 1px solid var(--border-color, #eef2f6);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
padding: 0 16px;
|
|
}
|
|
|
|
.header-crumb {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.user-label {
|
|
font-size: 13px;
|
|
color: var(--el-text-color-secondary);
|
|
}
|
|
|
|
.main {
|
|
padding: 16px;
|
|
}
|
|
</style>
|