优化驾驶舱页面

This commit is contained in:
guanj
2025-12-20 23:44:46 +08:00
parent 7e4db9d4cd
commit cc0f8bc8b6
10 changed files with 770 additions and 456 deletions

View File

@@ -1,108 +1,169 @@
import { reactive } from 'vue'
import { defineStore } from 'pinia'
import { STORE_TAB_VIEW_CONFIG } from '@/stores/constant/cacheKey'
import type { NavTabs } from '@/stores/interface/index'
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
import { adminBaseRoutePath } from '@/router/static'
export const useNavTabs = defineStore(
'navTabs',
() => {
const state: NavTabs = reactive({
// 激活tab的index
activeIndex: 0,
// 激活的tab
activeRoute: null,
// tab列表
tabsView: [],
// 当前tab是否全屏
tabFullScreen: false,
// 从后台加载到的菜单路由列表
tabsViewRoutes: [],
// 按钮权限节点
authNode: new Map(),
})
function addTab(route: RouteLocationNormalized) {
if (!route.meta.addtab) return
for (const key in state.tabsView) {
if (state.tabsView[key].path === route.path) {
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
return
}
}
state.tabsView.push(route)
}
function closeTab(route: RouteLocationNormalized) {
state.tabsView.map((v, k) => {
if (v.path == route.path) {
state.tabsView.splice(k, 1)
return
}
})
}
/**
* 关闭多个标签
* @param retainMenu 需要保留的标签,否则关闭全部标签
*/
const closeTabs = (retainMenu: RouteLocationNormalized | false = false) => {
if (retainMenu) {
state.tabsView = [retainMenu]
} else {
state.tabsView = []
}
}
const setActiveRoute = (route: RouteLocationNormalized): void => {
const currentRouteIndex: number = state.tabsView.findIndex((item: RouteLocationNormalized) => {
return item.path === route.path
})
if (currentRouteIndex === -1) return
state.activeRoute = route
state.activeIndex = currentRouteIndex
}
const setTabsViewRoutes = (data: RouteRecordRaw[]): void => {
state.tabsViewRoutes = encodeRoutesURI(data)
}
const setAuthNode = (key: string, data: string[]) => {
state.authNode.set(key, data)
}
const fillAuthNode = (data: Map<string, string[]>) => {
state.authNode = data
}
const setFullScreen = (fullScreen: boolean): void => {
state.tabFullScreen = fullScreen
}
return { state, addTab, closeTab, closeTabs, setActiveRoute, setTabsViewRoutes, setAuthNode, fillAuthNode, setFullScreen }
},
{
persist: {
key: STORE_TAB_VIEW_CONFIG,
paths: ['state.tabFullScreen'],
},
}
)
/**
* 对iframe的url进行编码
*/
function encodeRoutesURI(data: RouteRecordRaw[]) {
data.forEach((item) => {
if (item.meta?.menu_type == 'iframe') {
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
}
if (item.children && item.children.length) {
item.children = encodeRoutesURI(item.children)
}
})
return data
}
import { reactive } from 'vue'
import { defineStore } from 'pinia'
import { STORE_TAB_VIEW_CONFIG } from '@/stores/constant/cacheKey'
import type { NavTabs } from '@/stores/interface/index'
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
import { adminBaseRoutePath } from '@/router/static'
import { set } from 'lodash'
export const useNavTabs = defineStore(
'navTabs',
() => {
const state: NavTabs = reactive({
// 激活tab的index
activeIndex: 0,
// 激活的tab
activeRoute: null,
// tab列表
tabsView: [],
// 当前tab是否全屏
tabFullScreen: false,
// 从后台加载到的菜单路由列表
tabsViewRoutes: [],
// 按钮权限节点
authNode: new Map()
})
function addTab(route: RouteLocationNormalized) {
console.log('🚀 ~ addTab ~ route:', route)
if (!route.meta.addtab) return
for (const key in state.tabsView) {
if (state.tabsView[key].path === route.path) {
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
state.tabsView[key].meta = route.query ? route.meta : state.tabsView[key].meta
return
}
}
state.tabsView.push(route)
}
function closeTab(route: RouteLocationNormalized) {
state.tabsView.map((v, k) => {
if (v.path == route.path) {
state.tabsView.splice(k, 1)
return
}
})
}
/**
* 关闭多个标签
* @param retainMenu 需要保留的标签,否则关闭全部标签
*/
const closeTabs = (retainMenu: RouteLocationNormalized | false = false) => {
if (retainMenu) {
state.tabsView = [retainMenu]
} else {
state.tabsView = []
}
}
const setActiveRoute = (route: RouteLocationNormalized): void => {
const currentRouteIndex: number = state.tabsView.findIndex((item: RouteLocationNormalized) => {
return item.path === route.path
})
if (currentRouteIndex === -1) return
state.activeRoute = route
state.activeIndex = currentRouteIndex
}
const setTabsViewRoutes = (data: RouteRecordRaw[]): void => {
state.tabsViewRoutes = encodeRoutesURI(data)
}
const setAuthNode = (key: string, data: string[]) => {
state.authNode.set(key, data)
}
const fillAuthNode = (data: Map<string, string[]>) => {
state.authNode = data
}
const setFullScreen = (fullScreen: boolean): void => {
state.tabFullScreen = fullScreen
}
const refresh = () => {
// setTimeout(() => {
// console.log(123, state.tabsViewRoutes)
let list = matchAndReturnRouteData(state.tabsViewRoutes, state.tabsView)
state.tabsView = []
list.forEach(item => {
addTab(item)
})
// }, 1000)
}
return {
state,
addTab,
closeTab,
closeTabs,
setActiveRoute,
setTabsViewRoutes,
setAuthNode,
fillAuthNode,
setFullScreen,
refresh
}
},
{
persist: {
key: STORE_TAB_VIEW_CONFIG,
paths: ['state.tabFullScreen']
}
}
)
/**
* 核心逻辑:
* 1. 递归遍历树形菜单筛选出与routeList中name匹配的节点
* 2. 将匹配到的节点格式转换为routeList的结构并返回
*/
function matchAndReturnRouteData(tree, routeList) {
// 1. 构建路由name映射name -> 完整路由对象)
const routeMap = new Map()
routeList.forEach(route => {
if (route.name) {
routeMap.set(route.name, route)
}
})
// 2. 递归遍历树形菜单,收集匹配的节点
const matchedNodes = []
function recursion(node) {
// 匹配当前节点
if (routeMap.has(node.name)) {
// 深度克隆路由对象,避免修改原数据
const matchedRoute = JSON.parse(JSON.stringify(routeMap.get(node.name)))
matchedNodes.push(matchedRoute)
}
// 递归处理子节点
if (node.children && node.children.length) {
node.children.forEach(child => recursion(child))
}
}
// 遍历所有顶级节点
tree.forEach(node => recursion(node))
// 3. 返回匹配后的第二个数据格式和routeList结构一致
return matchedNodes
}
/**
* 对iframe的url进行编码
*/
function encodeRoutesURI(data: RouteRecordRaw[]) {
data.forEach(item => {
if (item.meta?.menu_type == 'iframe') {
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
}
if (item.children && item.children.length) {
item.children = encodeRoutesURI(item.children)
}
})
return data
}