2026-05-22 11:07:13 +08:00

253 lines
5.5 KiB
Vue

<template>
<div class="index">
<div :class="{ 'has-logo': showLogo }" class="sidebar-container">
<!-- logo -->
<Logo v-if="showLogo" :collapse="isCollapse" />
<!-- 菜单 -->
<happy-scroll color="rgba(0,0,0,0.5)" size="5" class="menu-scroll-container">
<el-menu
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="true"
:active-text-color="variables.menuActiveText"
:collapse-transition="true"
:default-active="activeMenu"
mode="vertical"
class="el-menu-vertical"
>
<sidebar-item
v-for="(route, index) in permissionRoutes"
:key="route.path + index"
:item="route"
:base-path="route.path"
:is-collapse="isCollapse"
/>
</el-menu>
</happy-scroll>
<button
class="sidebar-collapse-btn"
:class="{ collapsed: isCollapse }"
:title="isCollapse ? '展开菜单' : '折叠菜单'"
@click="toggleSideBar"
>
<i :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"></i>
</button>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import SidebarItem from "./SidebarItem.vue";
import variables from "@/styles/variables.scss";
import Logo from "./Logo.vue";
export default {
name: "Sidebar",
components: { SidebarItem, Logo },
computed: {
...mapGetters(["permission_routes", "sidebar", "userType", "orgType"]),
showLogo() {
return true;
},
variables() {
return variables;
},
isCollapse() {
return !this.sidebar.opened;
},
permissionRoutes() {
const routes = this.permission_routes || [];
return routes;
},
activeMenu() {
const route = this.$route;
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
}
},
mounted() {
console.log("Sidebar mounted - 权限路由:", this.permissionRoutes);
},
methods: {
toggleSideBar() {
this.$store.dispatch("app/toggleSideBar");
}
}
};
</script>
<style lang="scss" scoped>
.index {
width: 100%;
height: 100vh;
position: relative;
.sidebar-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
position: relative;
transition: width 0.25s ease;
}
.menu-scroll-container {
flex: 1;
width: 100%;
overflow-x: hidden;
::v-deep .happy-scroll-container {
width: 100% !important;
min-width: unset !important;
.happy-scroll-content {
width: 100%;
min-width: unset !important;
box-sizing: border-box;
}
}
}
.sidebar-collapse-btn {
position: absolute;
right: 16px;
bottom: 18px;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
color: #8a94a6;
font-size: 18px;
cursor: pointer;
background: #ffffff;
border: 1px solid #eef2f7;
border-radius: 50%;
box-shadow: 0 8px 22px rgba(31, 45, 61, 0.12);
transition: all 0.25s ease;
&:hover {
color: #1e6fff;
transform: translateY(-2px);
box-shadow: 0 12px 26px rgba(30, 111, 255, 0.18);
}
&.collapsed {
right: 11px;
}
}
// 更具体的选择器
::v-deep .el-menu-vertical {
border: none;
height: 100%;
width: 100% !important;
min-width: 100% !important;
box-sizing: border-box;
.el-submenu__title,
.el-menu-item {
height: 56px;
line-height: 56px;
margin: 6px 14px;
padding: 0 18px !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-radius: 12px;
transition: all 0.25s ease;
}
.el-submenu__title span,
.el-menu-item span {
transition: opacity 0.2s ease, transform 0.2s ease;
}
.el-submenu__title:hover,
.el-menu-item:not(.is-active):hover {
color: #1e6fff !important;
background: #f4f8ff !important;
}
.el-menu-item.is-active {
color: #ffffff !important;
background: linear-gradient(135deg, #1e6fff, #5d8dff) !important;
}
.el-menu-item.is-active i,
.el-menu-item.is-active span {
color: #ffffff !important;
}
// 子菜单容器
.el-menu--inline {
// 子菜单项
.el-menu-item {
// 激活的子菜单项
&.is-active {
background: linear-gradient(135deg, #1e6fff, #5d8dff) !important;
color: #ffffff !important;
&:before {
display: none;
}
}
// 非激活状态的悬停效果
&:not(.is-active):hover {
background-color: #f4f8ff !important;
}
}
}
}
// 折叠状态
::v-deep .el-menu--collapse {
width: 64px !important;
min-width: 64px !important;
.el-submenu__title,
.el-menu-item {
margin: 6px 8px;
padding: 0 !important;
text-overflow: clip;
justify-content: center;
}
.el-submenu__title span,
.el-menu-item span {
opacity: 0;
transform: translateX(-6px);
}
// 折叠状态下的子菜单激活样式
.el-menu--popup {
.el-menu-item {
&.is-active {
color: #ffffff !important;
background: linear-gradient(135deg, #1e6fff 0%, #244fbd 100%) !important;
}
}
}
}
}
</style>