Files
schoolNews/schoolNewsWeb/src/layouts/SidebarLayout.vue
2025-10-28 19:04:35 +08:00

239 lines
4.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="sidebar-layout">
<!-- 主内容区域 -->
<div class="layout-content">
<!-- 侧边栏和内容 -->
<div class="content-wrapper" v-if="hasSidebarMenus">
<!-- 侧边栏 -->
<aside class="sidebar">
<!-- Logo区域 -->
<div class="sidebar-header">
<div class="logo-container">
<img src="@/assets/imgs/logo-icon.svg" alt="Logo" class="logo-icon" />
<div class="logo-text">
<div class="logo-title">管理后台</div>
<div class="logo-subtitle">红色思政平台</div>
</div>
</div>
</div>
<!-- 导航菜单 -->
<nav class="sidebar-nav">
<MenuSidebar
:menus="sidebarMenus"
:collapsed="false"
@menu-click="handleMenuClick"
/>
</nav>
</aside>
<!-- 页面内容 -->
<main class="main-content">
<router-view />
</main>
</div>
<!-- 没有侧边栏时直接显示内容 -->
<div class="content-wrapper-full" v-else>
<main class="main-content-full">
<router-view />
</main>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useStore } from 'vuex';
import type { SysMenu } from '@/types';
import { MenuType } from '@/types/enums';
import { MenuSidebar } from '@/components';
const route = useRoute();
const router = useRouter();
const store = useStore();
// 获取所有菜单
const allMenus = computed(() => store.getters['auth/menuTree']);
// 获取所有顶层SIDEBAR菜单作为侧边栏
const sidebarMenus = computed(() => {
// 严格过滤type=SIDEBAR 且 layout='SidebarLayout' 的顶层菜单
return allMenus.value.filter((menu: SysMenu) =>
menu.type === MenuType.SIDEBAR &&
!menu.parentID &&
(menu as any).layout === 'SidebarLayout'
);
});
// 是否有侧边栏菜单
const hasSidebarMenus = computed(() => sidebarMenus.value.length > 0);
// 处理菜单点击
function handleMenuClick(menu: SysMenu) {
if (menu.url && menu.url !== route.path) {
router.push(menu.url);
}
}
</script>
<style lang="scss" scoped>
.sidebar-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
background: #f0f2f5;
}
.layout-content {
flex: 1;
display: flex;
flex-direction: column;
}
.content-wrapper {
flex: 1;
display: flex;
gap: 0;
height: 100vh;
overflow: hidden;
}
.sidebar {
width: 256px;
background: #FFFFFF;
border-right: 1px solid rgba(0, 0, 0, 0.1);
flex-shrink: 0;
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.sidebar-header {
padding: 24px 24px 1px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
height: 97px;
}
.logo-container {
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 40px;
height: 40px;
flex-shrink: 0;
border-radius: 10px;
}
.logo-text {
display: flex;
flex-direction: column;
}
.logo-title {
font-size: 16px;
font-weight: 400;
line-height: 1.5;
color: #C10007;
}
.logo-subtitle {
font-size: 12px;
font-weight: 400;
line-height: 1.33;
color: #6A7282;
}
.sidebar-nav {
flex: 1;
overflow-y: auto;
padding: 16px 16px 0;
// 美化滚动条(深色,适配白色背景)
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
&:hover {
background: #a8a8a8;
}
}
}
.main-content {
flex: 1;
background: #F9FAFB;
overflow-y: auto;
/* min-width: 0; */
padding: 20px;
box-sizing: border-box;
height: 100vh;
// 美化滚动条
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&:hover {
background: #a8a8a8;
}
}
}
.content-wrapper-full {
flex: 1;
}
.main-content-full {
background: #F9FAFB;
height: 100vh;
overflow-y: auto;
padding: 20px;
box-sizing: border-box;
// 美化滚动条
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&:hover {
background: #a8a8a8;
}
}
}
</style>