wip: 临时提交
This commit is contained in:
@@ -88,15 +88,27 @@ function handleProfileClick() {
|
|||||||
|
|
||||||
// 根据主题和侧边栏配色方案选择样式类
|
// 根据主题和侧边栏配色方案选择样式类
|
||||||
const navbarActionsClass = computed(() => {
|
const navbarActionsClass = computed(() => {
|
||||||
// 暗黑主题
|
const { theme, sidebarColorScheme, layout } = settingStore;
|
||||||
if (settingStore.theme === ThemeMode.DARK) {
|
|
||||||
|
// 暗黑主题下,所有布局都使用白色文字
|
||||||
|
if (theme === ThemeMode.DARK) {
|
||||||
return "navbar-actions--white-text";
|
return "navbar-actions--white-text";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 经典蓝侧边栏
|
// 明亮主题下
|
||||||
if (settingStore.sidebarColorScheme === SidebarColor.CLASSIC_BLUE) {
|
if (theme === ThemeMode.LIGHT) {
|
||||||
|
// 顶部布局和混合布局的顶部区域使用深色背景,需要白色文字
|
||||||
|
if (layout === "top" || layout === "mix") {
|
||||||
return "navbar-actions--white-text";
|
return "navbar-actions--white-text";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 左侧布局下,如果侧边栏是经典蓝色,顶部导航栏仍使用默认颜色
|
||||||
|
if (layout === "left" && sidebarColorScheme === SidebarColor.CLASSIC_BLUE) {
|
||||||
|
return ""; // 使用默认的深色文字
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,19 +142,22 @@ function logout() {
|
|||||||
height: $navbar-height;
|
height: $navbar-height;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
// 默认图标样式(明亮模式 + 左侧布局)
|
||||||
|
:deep([class^="i-svg:"]) {
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
:deep([class^="i-svg:"]) {
|
:deep([class^="i-svg:"]) {
|
||||||
color: var(--el-text-color);
|
color: var(--el-color-primary);
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
background: rgb(0 0 0 / 10%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-profile {
|
.user-profile {
|
||||||
@@ -160,19 +175,41 @@ function logout() {
|
|||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
transition: color 0.3s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-top,
|
// 白色文字样式(用于深色背景:暗黑主题、顶部布局、混合布局)
|
||||||
.layout-mix {
|
.navbar-actions--white-text {
|
||||||
|
.navbar-actions__item {
|
||||||
|
:deep([class^="i-svg:"]) {
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
|
:deep([class^="i-svg:"]) {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.user-profile__name {
|
.user-profile__name {
|
||||||
color: #fff !important;
|
color: rgba(255, 255, 255, 0.85);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-top .navbar-actions--white-text :deep([class^="i-svg:"]),
|
// 确保下拉菜单中的图标不受影响
|
||||||
.layout-mix .navbar-actions--white-text :deep([class^="i-svg:"]) {
|
:deep(.el-dropdown-menu) {
|
||||||
color: #fff !important;
|
[class^="i-svg:"] {
|
||||||
|
color: var(--el-text-color-regular) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--el-color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ const isSidebarOpened = computed(() => appStore.sidebar.opened);
|
|||||||
|
|
||||||
// 切换侧边栏展开/折叠状态
|
// 切换侧边栏展开/折叠状态
|
||||||
function toggleSideBar() {
|
function toggleSideBar() {
|
||||||
|
console.log("🔄 Hamburger clicked! Current state:", isSidebarOpened.value);
|
||||||
|
console.log("🔄 Device type:", appStore.device);
|
||||||
appStore.toggleSidebar();
|
appStore.toggleSidebar();
|
||||||
|
console.log("🔄 New state:", appStore.sidebar.opened);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<!-- 混合布局顶部菜单 -->
|
<!-- 混合布局顶部菜单 -->
|
||||||
<template>
|
<template>
|
||||||
<el-scrollbar>
|
|
||||||
<el-menu
|
<el-menu
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
:default-active="activePath"
|
:default-active="activePath"
|
||||||
@@ -36,7 +35,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -117,3 +115,25 @@ onMounted(() => {
|
|||||||
topMenus.value = permissionStore.routes.filter((item) => !item.meta || !item.meta.hidden);
|
topMenus.value = permissionStore.routes.filter((item) => !item.meta || !item.meta.hidden);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-menu {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&--horizontal {
|
||||||
|
height: $navbar-height !important;
|
||||||
|
|
||||||
|
// 确保菜单项垂直居中
|
||||||
|
:deep(.el-menu-item) {
|
||||||
|
height: 100%;
|
||||||
|
line-height: $navbar-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除默认的底部边框
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -35,10 +35,14 @@ import AppMain from "@/layout/components/AppMain/index.vue";
|
|||||||
import SidebarMenu from "../LayoutMenu.vue";
|
import SidebarMenu from "../LayoutMenu.vue";
|
||||||
|
|
||||||
// 布局相关参数
|
// 布局相关参数
|
||||||
const { isShowTagsView, isShowLogo, isSidebarOpen } = useLayout();
|
const { isShowTagsView, isShowLogo, isSidebarOpen, isMobile } = useLayout();
|
||||||
|
|
||||||
// 菜单相关
|
// 菜单相关
|
||||||
const { routes } = useLayoutMenu();
|
const { routes } = useLayoutMenu();
|
||||||
|
|
||||||
|
// 添加调试日志
|
||||||
|
console.log("🔍 LeftSideLayout - isSidebarOpen:", isSidebarOpen.value);
|
||||||
|
console.log("🔍 LeftSideLayout - isMobile:", isMobile.value);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -78,32 +82,34 @@ const { routes } = useLayoutMenu();
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 移动端样式 */
|
/* 移动端样式 - 注意这里需要正确应用到父元素 */
|
||||||
:deep(.mobile) {
|
.mobile {
|
||||||
.layout__sidebar {
|
.layout__sidebar {
|
||||||
position: fixed;
|
width: $sidebar-width !important;
|
||||||
left: 0;
|
transition:
|
||||||
transition: transform 0.28s;
|
transform 0.28s,
|
||||||
|
width 0s;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hideSidebar {
|
&.hideSidebar {
|
||||||
.layout__sidebar {
|
.layout__sidebar {
|
||||||
width: $sidebar-width !important;
|
|
||||||
transform: translateX(-$sidebar-width);
|
transform: translateX(-$sidebar-width);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.openSidebar {
|
||||||
|
.layout__sidebar {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.layout__main {
|
.layout__main {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.layout__main {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.hasTagsView) {
|
.hasTagsView {
|
||||||
.app-main {
|
:deep(.app-main) {
|
||||||
height: calc(100vh - $navbar-height - $tags-view-height) !important;
|
height: calc(100vh - $navbar-height - $tags-view-height) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,22 @@
|
|||||||
<LayoutBase>
|
<LayoutBase>
|
||||||
<!-- 顶部菜单栏 -->
|
<!-- 顶部菜单栏 -->
|
||||||
<div class="layout__header">
|
<div class="layout__header">
|
||||||
<LayoutSidebar :show-logo="isShowLogo" :is-collapsed="false">
|
<div class="layout__header-content">
|
||||||
|
<!-- Logo区域 -->
|
||||||
|
<div v-if="isShowLogo" class="layout__header-logo">
|
||||||
|
<SidebarLogo :collapse="false" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 顶部菜单区域 -->
|
||||||
|
<div class="layout__header-menu">
|
||||||
<SidebarMixTopMenu />
|
<SidebarMixTopMenu />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧操作区域 -->
|
||||||
|
<div class="layout__header-actions">
|
||||||
<NavbarActions />
|
<NavbarActions />
|
||||||
</LayoutSidebar>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 主内容区容器 -->
|
<!-- 主内容区容器 -->
|
||||||
@@ -13,7 +25,22 @@
|
|||||||
<!-- 左侧菜单栏 -->
|
<!-- 左侧菜单栏 -->
|
||||||
<div class="layout__sidebar--left" :class="{ 'layout__sidebar--collapsed': !isSidebarOpen }">
|
<div class="layout__sidebar--left" :class="{ 'layout__sidebar--collapsed': !isSidebarOpen }">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<SidebarMenu :data="sideMenuRoutes" :base-path="activeTopMenuPath" />
|
<el-menu
|
||||||
|
:default-active="activeMenu"
|
||||||
|
:collapse="!isSidebarOpen"
|
||||||
|
:collapse-transition="false"
|
||||||
|
:unique-opened="false"
|
||||||
|
:background-color="variables['menu-background']"
|
||||||
|
:text-color="variables['menu-text']"
|
||||||
|
:active-text-color="variables['menu-active-text']"
|
||||||
|
>
|
||||||
|
<SidebarMenuItem
|
||||||
|
v-for="route in sideMenuRoutes"
|
||||||
|
:key="route.path"
|
||||||
|
:item="route"
|
||||||
|
:base-path="resolvePath(route.path)"
|
||||||
|
/>
|
||||||
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
<!-- 侧边栏切换按钮 -->
|
<!-- 侧边栏切换按钮 -->
|
||||||
<div class="layout__sidebar-toggle">
|
<div class="layout__sidebar-toggle">
|
||||||
@@ -31,22 +58,52 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
import { useLayout } from "../../composables/useLayout";
|
import { useLayout } from "../../composables/useLayout";
|
||||||
import { useLayoutMenu } from "../../composables/useLayoutMenu";
|
import { useLayoutMenu } from "../../composables/useLayoutMenu";
|
||||||
import LayoutBase from "../LayoutBase.vue";
|
import LayoutBase from "../LayoutBase.vue";
|
||||||
import LayoutSidebar from "../common/LayoutSidebar.vue";
|
import SidebarLogo from "@/layout/components/Sidebar/components/SidebarLogo.vue";
|
||||||
import SidebarMixTopMenu from "@/layout/components/Sidebar/components/SidebarMixTopMenu.vue";
|
import SidebarMixTopMenu from "@/layout/components/Sidebar/components/SidebarMixTopMenu.vue";
|
||||||
import NavbarActions from "@/layout/components/NavBar/components/NavbarActions.vue";
|
import NavbarActions from "@/layout/components/NavBar/components/NavbarActions.vue";
|
||||||
import TagsView from "@/layout/components/TagsView/index.vue";
|
import TagsView from "@/layout/components/TagsView/index.vue";
|
||||||
import AppMain from "@/layout/components/AppMain/index.vue";
|
import AppMain from "@/layout/components/AppMain/index.vue";
|
||||||
import SidebarMenu from "../LayoutMenu.vue";
|
import SidebarMenuItem from "@/layout/components/Sidebar/components/SidebarMenuItem.vue";
|
||||||
import Hamburger from "@/components/Hamburger/index.vue";
|
import Hamburger from "@/components/Hamburger/index.vue";
|
||||||
|
import variables from "@/styles/variables.module.scss";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
// 布局相关参数
|
// 布局相关参数
|
||||||
const { isShowTagsView, isShowLogo, isSidebarOpen, toggleSidebar } = useLayout();
|
const { isShowTagsView, isShowLogo, isSidebarOpen, toggleSidebar } = useLayout();
|
||||||
|
|
||||||
// 菜单相关
|
// 菜单相关
|
||||||
const { sideMenuRoutes, activeTopMenuPath } = useLayoutMenu();
|
const { sideMenuRoutes, activeTopMenuPath } = useLayoutMenu();
|
||||||
|
|
||||||
|
// 当前激活的菜单
|
||||||
|
const activeMenu = computed(() => {
|
||||||
|
const { meta, path } = route;
|
||||||
|
// 如果设置了activeMenu,则使用
|
||||||
|
if (meta?.activeMenu && typeof meta.activeMenu === "string") {
|
||||||
|
return meta.activeMenu;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析路径 - 混合模式下,左侧菜单是从顶级菜单下的子菜单开始的
|
||||||
|
* 所以需要拼接顶级菜单路径
|
||||||
|
*/
|
||||||
|
function resolvePath(routePath: string) {
|
||||||
|
// 如果已经是绝对路径,直接返回
|
||||||
|
if (routePath.startsWith("/")) {
|
||||||
|
return activeTopMenuPath.value + routePath;
|
||||||
|
}
|
||||||
|
// 否则拼接
|
||||||
|
return `${activeTopMenuPath.value}/${routePath}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("🎨 MixMenuLayout rendered");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -57,12 +114,74 @@ const { sideMenuRoutes, activeTopMenuPath } = useLayoutMenu();
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: $navbar-height;
|
height: $navbar-height;
|
||||||
background-color: $menu-background;
|
background-color: var(--menu-background);
|
||||||
|
border-bottom: 1px solid var(--el-border-color-lighter);
|
||||||
|
|
||||||
:deep(.layout-sidebar) {
|
&-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100% !important;
|
align-items: center;
|
||||||
height: $navbar-height;
|
height: 100%;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-logo {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 200px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
:deep(.logo) {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
a {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-menu {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
:deep(.el-menu) {
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-menu--horizontal) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.el-menu-item {
|
||||||
|
height: 100%;
|
||||||
|
line-height: $navbar-height;
|
||||||
|
border-bottom: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.12);
|
||||||
|
border-bottom: 2px solid var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-actions {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +197,7 @@ const { sideMenuRoutes, activeTopMenuPath } = useLayoutMenu();
|
|||||||
background-color: var(--menu-background);
|
background-color: var(--menu-background);
|
||||||
transition: width 0.28s;
|
transition: width 0.28s;
|
||||||
|
|
||||||
&--collapsed {
|
&.layout__sidebar--collapsed {
|
||||||
width: $sidebar-width-collapsed !important;
|
width: $sidebar-width-collapsed !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { computed, watchEffect } from "vue";
|
import { computed } from "vue";
|
||||||
import { useAppStore, useSettingsStore } from "@/store";
|
import { useAppStore, useSettingsStore } from "@/store";
|
||||||
import defaultSettings from "@/settings";
|
import defaultSettings from "@/settings";
|
||||||
|
|
||||||
@@ -24,6 +24,9 @@ export function useLayout() {
|
|||||||
// 是否显示Logo
|
// 是否显示Logo
|
||||||
const isShowLogo = computed(() => settingsStore.sidebarLogo);
|
const isShowLogo = computed(() => settingsStore.sidebarLogo);
|
||||||
|
|
||||||
|
// 是否移动设备
|
||||||
|
const isMobile = computed(() => appStore.device === "mobile");
|
||||||
|
|
||||||
// 布局CSS类
|
// 布局CSS类
|
||||||
const layoutClass = computed(() => ({
|
const layoutClass = computed(() => ({
|
||||||
hideSidebar: !appStore.sidebar.opened,
|
hideSidebar: !appStore.sidebar.opened,
|
||||||
@@ -46,12 +49,13 @@ export function useLayout() {
|
|||||||
appStore.closeSideBar();
|
appStore.closeSideBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 暂时注释掉这个逻辑,避免影响手动操作
|
||||||
// 监听路由变化,在移动端自动关闭侧边栏
|
// 监听路由变化,在移动端自动关闭侧边栏
|
||||||
watchEffect(() => {
|
// watchEffect(() => {
|
||||||
if (appStore.device === "mobile" && appStore.sidebar.opened) {
|
// if (appStore.device === "mobile" && appStore.sidebar.opened) {
|
||||||
appStore.closeSideBar();
|
// appStore.closeSideBar();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentLayout,
|
currentLayout,
|
||||||
@@ -59,6 +63,7 @@ export function useLayout() {
|
|||||||
isShowTagsView,
|
isShowTagsView,
|
||||||
isShowSettings,
|
isShowSettings,
|
||||||
isShowLogo,
|
isShowLogo,
|
||||||
|
isMobile,
|
||||||
layoutClass,
|
layoutClass,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
closeSidebar,
|
closeSidebar,
|
||||||
|
|||||||
Reference in New Issue
Block a user