import { asyncRouterHandle } from '@/utils/asyncRouter' import { emitter } from '@/utils/bus.js' import { asyncMenu } from '@/api/menu' import { defineStore } from 'pinia' import { computed, ref, watchEffect } from 'vue' import pathInfo from '@/pathInfo.json' import {useRoute} from "vue-router"; import {config} from "@/core/config.js"; const notLayoutRouterArr = [] const keepAliveRoutersArr = [] const nameMap = {} const formatRouter = (routes, routeMap, parent) => { routes && routes.forEach((item) => { item.parent = parent item.meta.btns = item.btns item.meta.hidden = item.hidden if (item.meta.defaultMenu === true) { if (!parent) { item = { ...item, path: `/${item.path}` } notLayoutRouterArr.push(item) } } routeMap[item.name] = item if (item.children && item.children.length > 0) { formatRouter(item.children, routeMap, item) } }) } const KeepAliveFilter = (routes) => { routes && routes.forEach((item) => { // 子菜单中有 keep-alive 的,父菜单也必须 keep-alive,否则无效。这里将子菜单中有 keep-alive 的父菜单也加入。 if ( (item.children && item.children.some((ch) => ch.meta.keepAlive)) || item.meta.keepAlive ) { const path = item.meta.path keepAliveRoutersArr.push(pathInfo[path]) nameMap[item.name] = pathInfo[path] } if (item.children && item.children.length > 0) { KeepAliveFilter(item.children) } }) } export const useRouterStore = defineStore('router', () => { const keepAliveRouters = ref([]) const asyncRouterFlag = ref(0) const setKeepAliveRouters = (history) => { const keepArrTemp = [] // 1. 首先添加原有的keepAlive配置 keepArrTemp.push(...keepAliveRoutersArr) if (config.keepAliveTabs) { history.forEach((item) => { // 2. 为所有history中的路由强制启用keep-alive // 通过routeMap获取路由信息,然后通过pathInfo获取组件名 const routeInfo = routeMap[item.name] if (routeInfo && routeInfo.meta && routeInfo.meta.path) { const componentName = pathInfo[routeInfo.meta.path] if (componentName) { keepArrTemp.push(componentName) } } // 3. 如果子路由在tabs中打开,父路由也需要keepAlive if (nameMap[item.name]) { keepArrTemp.push(nameMap[item.name]) } }) } keepAliveRouters.value = Array.from(new Set(keepArrTemp)) } // 处理组件缓存 const handleKeepAlive = async (to) => { if (!to.matched.some((item) => item.meta.keepAlive)) return if (to.matched?.length > 2) { for (let i = 1; i < to.matched.length; i++) { const element = to.matched[i - 1] if (element.name === 'layout') { to.matched.splice(i, 1) await handleKeepAlive(to) continue } if (typeof element.components.default === 'function') { await element.components.default() await handleKeepAlive(to) } } } } const route = useRoute() emitter.on('setKeepAlive', setKeepAliveRouters) const asyncRouters = ref([]) const topMenu = ref([]) const leftMenu = ref([]) const menuMap = {} const topActive = ref('') const setLeftMenu = (name) => { sessionStorage.setItem('topActive', name) topActive.value = name leftMenu.value = [] if (menuMap[name]?.children) { leftMenu.value = menuMap[name].children } return menuMap[name]?.children } const findTopActive = (menuMap, routeName) => { for (let topName in menuMap) { const topItem = menuMap[topName]; if (topItem.children?.some(item => item.name === routeName)) { return topName; } const foundName = findTopActive(topItem.children || {}, routeName); if (foundName) { return topName; } } return null; }; watchEffect(() => { let topActive = sessionStorage.getItem('topActive') // 初始化菜单内容,防止重复添加 topMenu.value = []; asyncRouters.value[0]?.children.forEach((item) => { if (item.hidden) return menuMap[item.name] = item topMenu.value.push({ ...item, children: [] }) }) if (!topActive || topActive === 'undefined' || topActive === 'null') { topActive = findTopActive(menuMap, route.name); } setLeftMenu(topActive) }) const routeMap = {} // 从后台获取动态路由 const SetAsyncRouter = async () => { asyncRouterFlag.value++ const baseRouter = [ { path: '/layout', name: 'layout', component: 'view/layout/index.vue', meta: { title: '底层layout' }, children: [] } ] const asyncRouterRes = await asyncMenu() const asyncRouter = asyncRouterRes.data.menus asyncRouter && asyncRouter.push({ path: 'reload', name: 'Reload', hidden: true, meta: { title: '', closeTab: true }, component: 'view/error/reload.vue' }) formatRouter(asyncRouter, routeMap) baseRouter[0].children = asyncRouter if (notLayoutRouterArr.length !== 0) { baseRouter.push(...notLayoutRouterArr) } asyncRouterHandle(baseRouter) KeepAliveFilter(asyncRouter) asyncRouters.value = baseRouter return true } // 根级菜单(一级菜单树):各布局取菜单数据的单一入口,避免 asyncRouters[0].children 散点解构。 const rootMenus = computed(() => asyncRouters.value[0]?.children || []) return { topActive, setLeftMenu, topMenu, leftMenu, rootMenus, asyncRouters, keepAliveRouters, asyncRouterFlag, SetAsyncRouter, routeMap, handleKeepAlive } })