完善页面布局
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
buildDefaultTabs,
|
||||
getTopMenus
|
||||
} from '@/layouts/admin/router/adminRoutes.uts'
|
||||
import { addView, activeFullPath, visitedViews } from './tagsViewStore.uts'
|
||||
|
||||
/**
|
||||
* 标签页类型
|
||||
@@ -32,6 +33,12 @@ export const activeTopMenuId = ref<string>('home')
|
||||
/** 当前激活的路由ID */
|
||||
export const activeRouteId = ref<string>('home_index')
|
||||
|
||||
/** 记录每个一级模块上一次访问的二级路由ID (CRMEB 体验增强) */
|
||||
export const lastSubIdByMenu = ref<Record<string, string>>({})
|
||||
|
||||
/** 标记是否由用户手动关闭了 SubSider (移动端) */
|
||||
export const isManualClosed = ref<boolean>(false)
|
||||
|
||||
/** 打开的标签页列表 */
|
||||
export const tabs = ref<TabItem[]>([])
|
||||
|
||||
@@ -82,6 +89,8 @@ export function openRoute(routeId: string, addTab: boolean = true): void {
|
||||
// 更新一级菜单选中态
|
||||
if (route.parentId) {
|
||||
activeTopMenuId.value = route.parentId
|
||||
// 记录该模块最后访问的子路由
|
||||
lastSubIdByMenu.value[route.parentId] = routeId
|
||||
} else {
|
||||
// 首页等顶级路由
|
||||
activeTopMenuId.value = routeId.split('_')[0]
|
||||
@@ -116,6 +125,10 @@ function addTabItem(route: RouteRecord): void {
|
||||
isAffix: route.isAffix || false
|
||||
})
|
||||
}
|
||||
|
||||
// 更新新版 TagsViewStore
|
||||
addView(route, route.path)
|
||||
activeFullPath.value = route.path
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,6 +214,11 @@ export function initNavState(): void {
|
||||
isAffix: r.isAffix || false
|
||||
}))
|
||||
|
||||
// 初始化 TagsViewStore
|
||||
defaultTabs.forEach(r => {
|
||||
addView(r, r.path)
|
||||
})
|
||||
|
||||
// 打开首页
|
||||
openRoute('home_index', false)
|
||||
}
|
||||
|
||||
126
layouts/admin/store/tagsViewStore.uts
Normal file
126
layouts/admin/store/tagsViewStore.uts
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* TagsView 状态管理
|
||||
* 复刻 CRMEB 风格的标签栏逻辑
|
||||
*/
|
||||
|
||||
import { ref } from 'vue'
|
||||
import type { RouteRecord } from '@/layouts/admin/router/adminRoutes.uts'
|
||||
|
||||
/**
|
||||
* 标签页视图类型
|
||||
*/
|
||||
export type TagView = {
|
||||
id: string // 对应路由ID
|
||||
title: string // 标题
|
||||
path: string // 基础路径
|
||||
fullPath: string // 完整路径(包含参数)
|
||||
name: string // 组件Key
|
||||
meta: {
|
||||
affix?: boolean
|
||||
noCache?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
/** 访问过的页面列表 */
|
||||
export const visitedViews = ref<TagView[]>([])
|
||||
|
||||
/** 缓存的页面列表 (用于 keep-alive) */
|
||||
export const cachedViews = ref<string[]>([])
|
||||
|
||||
/** 开启的标签页详情 */
|
||||
export const activeFullPath = ref<string>('')
|
||||
|
||||
// ============================================
|
||||
// Actions
|
||||
// ============================================
|
||||
|
||||
/**
|
||||
* 添加视图
|
||||
*/
|
||||
export function addView(route: RouteRecord, fullPath: string): void {
|
||||
// 1. 添加到访问列表
|
||||
if (visitedViews.value.some(v => v.fullPath === fullPath)) return
|
||||
|
||||
// 如果 ID 相同但 fullPath 不同(参数变化), 则更新或者替换
|
||||
const existingIndex = visitedViews.value.findIndex(v => v.id === route.id)
|
||||
|
||||
const newView: TagView = {
|
||||
id: route.id,
|
||||
title: route.title,
|
||||
path: route.path,
|
||||
fullPath: fullPath,
|
||||
name: route.componentKey,
|
||||
meta: {
|
||||
affix: route.isAffix || false,
|
||||
noCache: false // 默认为缓存,如果有特殊需求可扩展
|
||||
}
|
||||
}
|
||||
|
||||
if (existingIndex > -1) {
|
||||
// 同一路由不同参数, 更新记录
|
||||
visitedViews.value[existingIndex] = newView
|
||||
} else {
|
||||
visitedViews.value.push(newView)
|
||||
}
|
||||
|
||||
// 2. 添加到缓存列表
|
||||
if (!route.componentKey) return
|
||||
if (cachedViews.value.includes(route.componentKey)) return
|
||||
cachedViews.value.push(route.componentKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除视图
|
||||
*/
|
||||
export function delView(view: TagView): void {
|
||||
const index = visitedViews.value.findIndex(v => v.fullPath === view.fullPath)
|
||||
if (index > -1 && !visitedViews.value[index].meta.affix) {
|
||||
visitedViews.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const cacheIndex = cachedViews.value.indexOf(view.name)
|
||||
if (cacheIndex > -1) {
|
||||
cachedViews.value.splice(cacheIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭其他标签
|
||||
*/
|
||||
export function delOthersViews(view: TagView): void {
|
||||
visitedViews.value = visitedViews.value.filter(v => v.meta.affix || v.fullPath === view.fullPath)
|
||||
cachedViews.value = visitedViews.value.map(v => v.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭右侧标签
|
||||
*/
|
||||
export function delRightTags(view: TagView): void {
|
||||
const index = visitedViews.value.findIndex(v => v.fullPath === view.fullPath)
|
||||
if (index === -1) return
|
||||
|
||||
visitedViews.value = visitedViews.value.filter((v, i) => {
|
||||
return i <= index || v.meta.affix
|
||||
})
|
||||
cachedViews.value = visitedViews.value.map(v => v.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭所有
|
||||
*/
|
||||
export function delAllViews(): void {
|
||||
const affixTags = visitedViews.value.filter(v => v.meta.affix)
|
||||
visitedViews.value = affixTags
|
||||
cachedViews.value = affixTags.map(v => v.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新当前视图 (通常结合全局事件通知组件)
|
||||
*/
|
||||
export function refreshView(view: TagView): void {
|
||||
const index = cachedViews.value.indexOf(view.name)
|
||||
if (index > -1) {
|
||||
cachedViews.value.splice(index, 1)
|
||||
}
|
||||
// 通知框架重新加载该组件的逻辑通常在组件内部处理或通过 key 变化
|
||||
}
|
||||
Reference in New Issue
Block a user