优化细节

This commit is contained in:
2026-02-05 17:11:41 +08:00
parent 821205b18a
commit 151f5a5e1a
10 changed files with 634 additions and 194 deletions

View File

@@ -1,17 +1,17 @@
<template>
<view class="layout-root">
<!-- 移动端遮罩层 -->
<!-- 统一遮罩层 (复刻 CRMEB: 用于所有 Overlay 状态) -->
<view
v-if="isMobile && isMobileMenuOpen"
class="mobile-mask"
@click="isMobileMenuOpen = false"
:class="{ 'mask-show': isOverlayVisible || (isMobile && isMobileMenuOpen) }"
@click="closeAllMenu"
></view>
<!-- 主侧边栏 (CRMEB风格) -->
<!-- 主侧边栏 (CRMEB风格: 70px) -->
<AdminAside
class="admin-sidebar"
:class="{ 'mobile-aside-open': isMobileMenuOpen }"
:collapsed="isMainAsideCollapsed"
:collapsed="false"
:topMenus="topMenus"
:activeTopMenuId="activeTopMenuId"
@toggle="toggleMainAsideCollapse"
@@ -19,14 +19,15 @@
:asideWidth="ASIDE_W"
/>
<!-- 二级侧边栏 (CRMEB风格 - 内容区左侧) -->
<!-- 二级侧边栏 (1:1 复刻 CRMEB 抽屉/Dock 平滑切换) -->
<AdminSubSider
v-if="showSubSider && !isMobile"
:visible="isSubSiderVisible"
:class="{ 'sub-sider-overlay': isSubSiderOverlay || layoutMode === 'mobile' }"
:topMenuTitle="activeTopMenuTitle"
:groups="activeGroups"
:routes="activeRoutes"
:activeRouteId="activeRouteId"
:asideWidth="ASIDE_W"
:asideWidth="layoutMode === 'mobile' ? 0 : ASIDE_W"
:siderWidth="SUB_W"
@route-click="onRouteClick"
/>
@@ -41,7 +42,6 @@
:breadcrumb="breadcrumb"
:hasNotification="hasNotification"
:isMobile="isMobile"
@toggle-mobile-menu="isMobileMenuOpen = !isMobileMenuOpen"
@search="onSearch"
@refresh="onRefresh"
@notify="onNotify"
@@ -93,30 +93,73 @@ import {
isMainAsideCollapsed,
showSubSider,
windowWidth,
layoutMode,
isMobile,
isMobileMenuOpen,
isOverlayVisible,
openRoute,
closeTab,
closeOtherTabs,
closeAllTabs,
toggleMainAsideCollapse as storeToggleCollapse,
toggleSubSider as storeToggleSubSider,
initNavState
} from '@/layouts/admin/store/adminNavStore.uts'
import type { TabItem } from '@/layouts/admin/store/adminNavStore.uts'
import { getComponent } from '@/layouts/admin/router/adminComponentMap.uts'
// 侧边栏宽度配置
const ASIDE_W = 96 // 主侧边栏宽度
const SUB_W = 180 // 二级侧边栏宽度
// 侧边栏宽度配置 (CRMEB 1:1)
const ASIDE_W = 70
const SUB_W = 200
const hasNotification = ref<boolean>(false)
// 计算主内容区左边距
/**
* 核心逻辑:计算二级菜单是否应该以 Overlay (抽屉) 模式展示
* CRMEB 规则Tablet 屏 (768~1199) 为 Overlay
*/
const isSubSiderOverlay = computed<boolean>(() => {
return layoutMode.value === 'tablet'
})
/**
* 核心逻辑:二级菜单是否可见
* 1. 如果有子菜单内容 (activeGroups > 0)
* 2. 如果是 Desktop 且 showSubSider 为真 (Dock模式)
* 3. 如果是 Tablet/Mobile 且 isOverlayVisible 为真 (Overlay模式)
*/
const isSubSiderVisible = computed<boolean>(() => {
if (activeGroups.value.length === 0) return false
if (layoutMode.value === 'desktop') {
return showSubSider.value
}
// Tablet 和 Mobile 模式下,作为 Overlay 受 isOverlayVisible 控制
return isOverlayVisible.value
})
/**
* 核心逻辑:计算主内容区左偏移量 (mainLeft)
* 严格按照断点策略计算,防止遮挡
* 1. Desktop: ASIDE_W + (SUB_W if dock)
* 2. Tablet: ASIDE_W (sub-sider 是 overlay不占位)
* 3. Mobile: 0
*/
const mainLeft = computed<string>(() => {
const asideWidth = isMainAsideCollapsed.value ? 0 : ASIDE_W
const subWidth = showSubSider.value ? SUB_W : 0
return (asideWidth + subWidth) + 'px'
if (layoutMode.value === 'mobile') {
return '0px'
}
let left = ASIDE_W // 只要不是 Mobile主侧栏 70px 始终 Dock
// 只有在 Desktop 模式且二级菜单处于 Dock 模式显示时,才累加宽度
if (layoutMode.value === 'desktop' && showSubSider.value && activeGroups.value.length > 0) {
left += SUB_W
}
return left + 'px'
})
// 获取一级菜单列表
@@ -162,13 +205,28 @@ const currentComponent = computed<any>(() => {
function onTopMenuClick(menu: TopMenu): void {
activeTopMenuId.value = menu.id
if (menu.groups.length === 0) {
// 1:1 复刻 CRMEB 交互:
// 1. 如果有子菜单Desktop 下 dockTablet/Mobile 下唤起 Overlay
if (menu.groups.length > 0) {
if (layoutMode.value === 'desktop') {
showSubSider.value = true
} else {
isOverlayVisible.value = true
}
} else {
// 2. 如果没有子菜单:直接跳转并关闭所有 Overlay
openRoute(menu.id + '_index')
closeAllMenu()
}
}
function onRouteClick(routeId: string): void {
openRoute(routeId)
// 1:1 复刻 CRMEB在移动端或平板叠加模式下点击具体子路由后自动收起
if (layoutMode.value !== 'desktop') {
closeAllMenu()
}
}
function onTabClick(tab: TabItem): void {
@@ -191,6 +249,12 @@ function toggleMainAsideCollapse(): void {
storeToggleCollapse()
}
function closeAllMenu(): void {
isMobileMenuOpen.value = false
isOverlayVisible.value = false
// 注意:在 Desktop 模式下closeAllMenu 通常不隐藏 showSubSider除非用户手动点汉堡按钮
}
function onSearch(): void {
uni.showToast({ title: '搜索', icon: 'none' })
}
@@ -207,19 +271,37 @@ function onNotify(): void {
// 生命周期
// ============================================
let resizeTid: any = null
onMounted(() => {
initNavState()
// 初始化窗口宽度
windowWidth.value = uni.getWindowInfo().windowWidth
// 监听窗口变化
// 监听窗口变化 (增加节流保护与跨断点状态重置)
uni.onWindowResize((res) => {
windowWidth.value = res.size.windowWidth
// 窗口变大时自动关闭移动端菜单
if (windowWidth.value >= 768) {
isMobileMenuOpen.value = false
if (resizeTid != null) {
cancelAnimationFrame(resizeTid)
}
resizeTid = requestAnimationFrame(() => {
const oldMode = layoutMode.value
windowWidth.value = res.size.windowWidth
const newMode = layoutMode.value
// 跨断点自动关闭所有 Overlay防止状态残留遮挡内容
if (oldMode != newMode) {
isOverlayVisible.value = false
isMobileMenuOpen.value = false
// 如果切到桌面端,默认展开二级侧栏以符合 CRMEB 习惯
if (newMode === 'desktop') {
showSubSider.value = true
}
}
resizeTid = null
})
})
})
</script>
@@ -237,7 +319,7 @@ onMounted(() => {
/* 移动端侧边栏样式 */
.mobile-aside {
position: absolute;
left: -100px; /* 隐藏在左侧 */
left: -70px; /* 隐藏在左侧,匹配 ASIDE_W: 70 */
top: 0;
bottom: 0;
z-index: 1001;
@@ -246,17 +328,26 @@ onMounted(() => {
}
.mobile-aside-open {
transform: translateX(100px); /* 移入视图 */
transform: translateX(70px); /* 移入视图 */
}
.mobile-mask {
position: absolute;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 300ms ease, visibility 0s linear 300ms;
}
.mask-show {
opacity: 1;
visibility: visible;
transition: opacity 300ms ease, visibility 0s linear 0s;
}
.main {
@@ -264,7 +355,7 @@ onMounted(() => {
display: flex;
flex-direction: column;
min-height: 100vh;
transition: margin-left 0.3s ease;
transition: margin-left 300ms ease;
background: #f0f2f5;
width: 100%;
}
@@ -278,7 +369,7 @@ onMounted(() => {
/* 强行改变侧边栏布局模式 */
.admin-sidebar {
position: absolute !important;
left: -100px !important; /* 隐藏在左侧,假设 ASIDE_W 是 96 */
left: -70px !important; /* 隐藏在左侧 */
top: 0;
bottom: 0;
z-index: 1001;
@@ -287,7 +378,7 @@ onMounted(() => {
/* 展开时的状态 */
.mobile-aside-open {
transform: translateX(100px) !important;
transform: translateX(70px) !important;
}
}