From 5d36e1f987ef21e44ded2e8a1d06c28094ec1e76 Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期六, 19 四月 2025 12:39:47 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- zhitan-vue/src/layout/components/Sidebar/index.vue | 562 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 551 insertions(+), 11 deletions(-) diff --git a/zhitan-vue/src/layout/components/Sidebar/index.vue b/zhitan-vue/src/layout/components/Sidebar/index.vue index 2fe645a..658fc19 100644 --- a/zhitan-vue/src/layout/components/Sidebar/index.vue +++ b/zhitan-vue/src/layout/components/Sidebar/index.vue @@ -2,44 +2,124 @@ <div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }" + class="sidebar-container-wrapper" > - <logo v-if="showLogo" :collapse="isCollapse" /> - <el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper"> + <el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper" view-class="scrollbar-view"> + <!-- 濮嬬粓鏄剧ず鑿滃崟椤癸紝涓嶅啀鏍规嵁璺緞鍒ゆ柇 --> <el-menu :default-active="activeMenu" :collapse="isCollapse" - :background-color="sideTheme === 'theme-dark' ? '#232D70' : '#fff'" + :background-color="'transparent'" :text-color="sideTheme === 'theme-dark' ? '#fff' : '#000'" :unique-opened="true" :active-text-color="theme" :collapse-transition="false" mode="vertical" + class="custom-menu" > - <sidebar-item - v-for="(route, index) in sidebarRouters" - :key="route.path + index" - :item="route" - :base-path="route.path" - /> + <!-- 褰撳墠鏄椤电湅鏉垮瓙璺敱鏃讹紝娓叉煋涓撶敤璺敱 --> + <template v-if="isIndexSubRoute"> + <sidebar-item + v-for="(route, index) in indexPageRouters" + :key="route.path + index" + :item="route" + :base-path="route.path" + /> + </template> + <template v-else> + <sidebar-item + v-for="(route, index) in sidebarRouters" + :key="route.path + index" + :item="route" + :base-path="route.path" + /> + </template> </el-menu> </el-scrollbar> + + <!-- 搴曢儴鐢ㄦ埛鍖哄煙 --> + <div class="sidebar-footer" :class="{ 'collapsed': isCollapse, 'theme-light': sideTheme === 'theme-light' }"> + <div class="user-avatar-container"> + <img :src="userStore.avatar" class="user-avatar" /> + </div> + + <!-- 灞曞紑鐘舵�佷笅鏄剧ず瀹屾暣鍐呭 --> + <div class="user-info" v-if="!isCollapse"> + <div class="username">{{ userStore.name || 'admin' }}</div> + + <div class="action-buttons"> + <div class="action-button" :class="{'theme-light': sideTheme === 'theme-light'}" @click="toUserProfile"> + <el-icon><User /></el-icon> + <span>涓汉涓績</span> + </div> + + <div class="action-button" :class="{'theme-light': sideTheme === 'theme-light'}" @click="toggleTheme"> + <el-icon><Brush /></el-icon> + <span>鍒囨崲涓婚</span> + </div> + + <div class="action-button" :class="{'theme-light': sideTheme === 'theme-light'}" @click="handleLogout"> + <el-icon><SwitchButton /></el-icon> + <span>閫�鍑虹櫥褰�</span> + </div> + </div> + </div> + + <!-- 鎶樺彔鐘舵�佷笅鍙樉绀哄浘鏍囨寜閽� --> + <div class="collapsed-actions" v-if="isCollapse"> + <div class="action-icon" :class="{'theme-light': sideTheme === 'theme-light'}" @click="toUserProfile" title="涓汉涓績"> + <el-icon><User /></el-icon> + </div> + + <div class="action-icon" :class="{'theme-light': sideTheme === 'theme-light'}" @click="toggleTheme" title="鍒囨崲涓婚"> + <el-icon><Brush /></el-icon> + </div> + + <div class="action-icon" :class="{'theme-light': sideTheme === 'theme-light'}" @click="handleLogout" title="閫�鍑虹櫥褰�"> + <el-icon><SwitchButton /></el-icon> + </div> + </div> + </div> </div> </template> <script setup> -import Logo from "./Logo" import SidebarItem from "./SidebarItem" import variables from "@/assets/styles/variables.module.scss" import useAppStore from "@/store/modules/app" import useSettingsStore from "@/store/modules/settings" import usePermissionStore from "@/store/modules/permission" +import useUserStore from "@/store/modules/user" +import { User, Brush, SwitchButton } from '@element-plus/icons-vue' +import { ElMessageBox } from 'element-plus' +import { useRouter } from 'vue-router' +const router = useRouter() const route = useRoute() const appStore = useAppStore() const settingsStore = useSettingsStore() const permissionStore = usePermissionStore() +const userStore = useUserStore() const sidebarRouters = computed(() => permissionStore.sidebarRouters) + +// 鍒ゆ柇褰撳墠鏄惁涓洪椤靛瓙璺敱(/index/index) +const isIndexSubRoute = computed(() => { + return route.path === '/index/index' +}) + +// 鍒ゆ柇褰撳墠鏄惁涓轰富棣栭〉璺敱(/index鎴�/) +const isMainIndexRoute = computed(() => { + return route.path === '/index' || route.path === '/' +}) + +// 棣栭〉涓撶敤璺敱锛岄椤电湅鏉跨浉鍏宠彍鍗� +const indexPageRouters = computed(() => { + // 鏌ユ壘name涓篒ndex鐨勮矾鐢� + const indexRoute = sidebarRouters.value.find(route => route.name === 'Index') + return indexRoute ? [indexRoute] : [] +}) + const showLogo = computed(() => settingsStore.sidebarLogo) const sideTheme = computed(() => settingsStore.sideTheme) const theme = computed(() => settingsStore.theme) @@ -53,5 +133,465 @@ } return path }) + +function toUserProfile() { + router.push('/user/profile') +} + +function toggleTheme() { + if (settingsStore.sideTheme == "theme-dark") { + settingsStore.sideTheme = "theme-light" + document.querySelector("body").className = "themeLight" + } else { + settingsStore.sideTheme = "theme-dark" + document.querySelector("body").className = "themeDark" + } +} + +function handleLogout() { + ElMessageBox.confirm("纭畾娉ㄩ攢骞堕��鍑虹郴缁熷悧锛�", "鎻愮ず", { + confirmButtonText: "纭畾", + cancelButtonText: "鍙栨秷", + type: "warning", + }) + .then(() => { + userStore.logOut().then(() => { + location.href = "/index" + }) + }) + .catch(() => {}) +} </script> -<style lang="scss" scoped></style> +<style lang="scss" scoped> +.sidebar-container-wrapper { + position: relative; + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; +} + +:deep(.scrollbar-wrapper) { + height: calc(100% - 220px) !important; + overflow-x: hidden !important; +} + +:deep(.scrollbar-view) { + height: 100%; + padding-bottom: 20px; +} + +:deep(.el-scrollbar__bar.is-vertical) { + right: 0; + width: 6px; +} + +:deep(.el-scrollbar__thumb) { + background-color: rgba(144, 147, 153, 0.3); + &:hover { + background-color: rgba(144, 147, 153, 0.5); + } +} + +.custom-menu { + width: 100%; + padding: 6px 0; + height: auto !important; // 鏀逛负鑷�傚簲楂樺害锛岄伩鍏嶅浐瀹氶珮搴﹀鑷村唴瀹规孩鍑� + transition: all 0.3s ease; + + // Override Element Plus default menu styles + .el-menu-item { + height: 38px !important; + line-height: 38px !important; + border-radius: 4px; + margin: 4px 10px; + width: calc(100% - 20px); + transition: all 0.2s ease; + + &.is-active { + background-color: #3883FA !important; + color: #fff !important; + font-weight: bold; + position: relative; + box-shadow: 0 2px 8px rgba(56, 131, 250, 0.5); + + // 宸︿晶鎸囩ず鏉� + + } + + &:hover { + background-color: rgba(56, 131, 250, 0.1) !important; + } + } + + .el-sub-menu { + .el-sub-menu__title { + height: 38px !important; + line-height: 38px !important; + border-radius: 4px; + margin: 4px 10px; + width: calc(100% - 20px); + transition: all 0.2s ease; + + &:hover { + background-color: rgba(56, 131, 250, 0.1) !important; + } + } + + &.is-active { + > .el-sub-menu__title { + color: #3883FA !important; + font-weight: bold; + } + } + + .el-menu-item { + padding-left: 45px !important; + min-width: auto !important; + + &.is-active { + padding-left: 45px !important; + } + } + + // For nested submenus + .el-menu { + .el-menu-item, + .el-sub-menu__title { + height: 38px !important; + line-height: 38px !important; + } + + // Add styling for deeply nested submenus (level 3+) + .el-sub-menu { + .el-menu-item { + padding-left: 65px !important; + + &.is-active { + padding-left: 65px !important; + } + } + + // Level 4 + .el-menu { + .el-menu-item { + padding-left: 85px !important; + + &.is-active { + padding-left: 85px !important; + } + } + } + } + } + } +} + +// 棣栭〉绌虹櫧鑿滃崟鍖哄煙鏍峰紡 +.home-empty-menu { + height: auto; + min-height: 100px; +} + +// 搴曢儴鐢ㄦ埛鍖哄煙鏍峰紡 +.sidebar-footer { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + border-top: 1px solid rgba(255, 255, 255, 0.1); + padding: 16px; + display: flex; + flex-direction: column; + align-items: center; + + &.collapsed { + padding: 10px; + + .user-avatar-container { + margin-bottom: 10px; + } + } + + &.theme-light { + background-color: rgba(255, 255, 255, 0.6); + border-top: 1px solid rgba(0, 0, 0, 0.1); + + .user-avatar-container { + border-color: rgba(0, 0, 0, 0.1); + } + + .user-info { + .username { + color: #333; + } + } + } + + .user-avatar-container { + margin-bottom: 10px; + border: 2px dashed rgba(255, 255, 255, 0.3); + border-radius: 4px; + width: 54px; + height: 54px; + display: flex; + align-items: center; + justify-content: center; + + .user-avatar { + width: 38px; + height: 38px; + border-radius: 4px; + } + } + + .user-info { + width: 100%; + text-align: center; + + .username { + color: #fff; + font-size: 16px; + font-weight: 500; + margin-bottom: 16px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .action-buttons { + .action-button { + display: flex; + align-items: center; + justify-content: center; + background: rgba(56, 131, 250, 0.11); + border-radius: 9px; + border: 1px solid rgba(255, 255, 255, 0.3); + color: #fff; + padding: 10px; + margin-bottom: 10px; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s; + + &:hover { + background: rgba(56, 131, 250, 0.2); + } + + .el-icon { + margin-right: 8px; + font-size: 16px; + } + + span { + font-size: 14px; + } + + &.theme-light { + background-color: rgba(56, 131, 250, 1); + color: #fff; + border: 1px solid rgba(56, 131, 250, 0.8); + + &:hover { + background-color: rgba(56, 131, 250, 0.9); + } + + .el-icon { + color: #fff; + } + } + } + } + } + + .collapsed-actions { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + + .action-icon { + width: 40px; + height: 40px; + margin-bottom: 8px; + background: rgba(56, 131, 250, 0.11); + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + + &:hover { + background: rgba(56, 131, 250, 0.2); + } + + .el-icon { + font-size: 20px; + color: #fff; + } + + &.theme-light { + background: rgba(56, 131, 250, 1); + border: 1px solid rgba(56, 131, 250, 0.8); + + &:hover { + background: rgba(56, 131, 250, 0.9); + } + + .el-icon { + color: #fff; + } + } + } + } +} + +.theme-light { + :deep(.custom-menu) { + // Override Element Plus menu styles for light theme + .el-menu-item { + &.is-active { + background-color: #3883FA !important; + color: #fff !important; + } + + &:hover { + background-color: rgba(56, 131, 250, 0.1) !important; + } + } + + .el-sub-menu { + .el-sub-menu__title { + &:hover { + background-color: rgba(56, 131, 250, 0.1) !important; + } + } + } + } +} + +// 娣诲姞娣辫壊妯″紡涓撶敤鏍峰紡 +.theme-dark { + :deep(.custom-menu) { + // Override Element Plus menu styles for dark theme + .el-menu-item { + &.is-active { + background-color: #4e77f8 !important; + color: #ffffff !important; + font-weight: bold; + box-shadow: 0 2px 10px rgba(78, 119, 248, 0.6); + position: relative; + + // 宸︿晶鎸囩ず鏉� + + } + + &:hover { + background-color: rgba(78, 119, 248, 0.2) !important; + } + } + + .el-sub-menu { + &.is-active { + > .el-sub-menu__title { + color: #4e77f8 !important; + font-weight: bold; + } + } + + .el-sub-menu__title { + &:hover { + background-color: rgba(78, 119, 248, 0.2) !important; + } + } + + // 宓屽瀛愯彍鍗曟牱寮� + .el-menu { + .el-menu-item { + &.is-active { + background-color: #4e77f8 !important; + color: #ffffff !important; + } + } + + .el-sub-menu { + &.is-active { + > .el-sub-menu__title { + color: #4e77f8 !important; + } + } + } + } + } + } +} + +// Add global style to override Element Plus defaults +:global(.el-menu--vertical .el-menu-item), +:global(.el-menu--vertical .el-sub-menu__title) { + height: 38px !important; + line-height: 38px !important; +} + +// Add styles for collapsed menu items +:deep(.custom-menu.el-menu--collapse) { + width: 54px !important; + + .el-menu-item, .el-sub-menu__title { + width: 36px !important; + min-width: 36px !important; + margin: 4px 9px !important; /* 9px鏄负浜嗙‘淇濆眳涓細(54px瀹� - 36px鑿滃崟椤�) / 2 = 9px */ + padding: 0 !important; + display: flex; + justify-content: center; + align-items: center; + border-radius: 4px; + + &.is-active { + background-color: #3883FA !important; + color: #fff !important; + box-shadow: 0 2px 6px rgba(56, 131, 250, 0.4); + transform: scale(0.95); + transition: all 0.2s ease; + } + + .el-icon, .svg-icon { + margin: 0 !important; + font-size: 18px !important; + + svg { + width: 1.2em; + height: 1.2em; + } + } + + // 纭繚鎶樺彔鏃跺瓙鑿滃崟鐨勬爣棰樹篃灞呬腑瀵归綈 + .el-sub-menu__icon-arrow { + display: none; + } + } + + // 纭繚鎶樺彔鏃跺脊鍑虹殑瀛愯彍鍗曟湁姝g‘鏍峰紡 + .el-tooltip__trigger:focus:not(.focusing) { + outline: none; + } +} + +// 娣辫壊妯″紡涓嬫姌鍙犺彍鍗曠殑鏍峰紡 +.theme-dark { + :deep(.custom-menu.el-menu--collapse) { + .el-menu-item, .el-sub-menu__title { + &.is-active { + background-color: #4e77f8 !important; + color: #ffffff !important; + box-shadow: 0 2px 8px rgba(78, 119, 248, 0.6); + } + + &:hover { + background-color: rgba(78, 119, 248, 0.2) !important; + } + } + } +} +</style> -- Gitblit v1.9.3