snowy/snowy-admin-web/src/store/menu.js

157 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* Copyright [2022] [https://www.xiaonuo.vip]
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改Snowy源码头部的版权声明。
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
* 5.不可二次分发开源参与同类竞品如有想法可联系团队xiaonuobase@qq.com商议合作。
* 6.若您的项目无法满足以上几点需要更多功能代码获取Snowy商业授权许可请在官网购买授权地址为 https://www.xiaonuo.vip
*/
import { defineStore } from 'pinia'
import tool from '@/utils/tool'
import { cloneDeep } from 'lodash-es'
import userRoutes from '@/config/route'
import { searchStore } from '@/store/search'
import router from '@/router'
import userCenterApi from '@/api/sys/userCenterApi'
import whiteList from '@/router/whiteList'
import routesData from '@/router/systemRouter'
// findPwd和login路由组件已静态加载此处不在进行异步加载
const modules = import.meta.glob([
'/src/views/**/**.vue',
'!/src/views/auth/findPwd/**.vue',
'!/src/views/auth/login/**.vue'
])
export const useMenuStore = defineStore('menuStore', () => {
const menuData = ref([])
const refreshFlag = ref(false)
// 改变刷新标志
const changeRefreshFlag = (flag) => {
refreshFlag.value = flag
}
// 加载菜单
const loadMenu = () => {
// 获取用户菜单
const apiMenu = tool.data.get('MENU') || []
if (apiMenu.length === 0) {
// 创建默认模块,显示默认菜单
apiMenu[0] = cloneDeep(userRoutes.module[0])
}
const childrenApiMenu = apiMenu[0].children
apiMenu[0].children = [...(childrenApiMenu ? childrenApiMenu : []), ...userRoutes.menu]
let menuRouter = filterAsyncRouter(apiMenu)
menuRouter = flatAsyncRoutes(menuRouter)
menuData.value = menuRouter
// 初始化搜索
const search_store = searchStore()
search_store.init(menuRouter)
}
// 过滤异步路由
const filterAsyncRouter = (routerMap) => {
const accessedRouters = []
routerMap.forEach((item) => {
item.meta = item.meta ? item.meta : {}
// 处理外部链接特殊路由
if (item.meta.type === 'iframe') {
item.meta.url = item.path
item.path = `/${item.name}`
}
// MAP转路由对象
const route = {
path: item.path,
name: item.name,
meta: item.meta,
redirect: item.redirect,
children: item.children ? filterAsyncRouter(item.children) : null,
component: loadComponent(item.component)
}
accessedRouters.push(route)
})
return accessedRouters
}
// 将异步路由扁平化
const flatAsyncRoutes = (routes, breadcrumb = []) => {
const res = []
routes.forEach((route) => {
const tmp = { ...route }
if (tmp.children) {
const childrenBreadcrumb = [...breadcrumb]
childrenBreadcrumb.push(route)
const tmpRoute = { ...route }
tmpRoute.meta.breadcrumb = childrenBreadcrumb
delete tmpRoute.children
res.push(tmpRoute)
const childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb)
childrenRoutes.map((item) => {
res.push(item)
})
} else {
const tmpBreadcrumb = [...breadcrumb]
tmpBreadcrumb.push(tmp)
tmp.meta.breadcrumb = tmpBreadcrumb
res.push(tmp)
}
})
return res
}
// 动态加载组件
const loadComponent = (component) => {
if (component) {
if (component.includes('/')) {
return modules[`/src/views/${component}.vue`]
}
return modules[`/src/views/${component}/index.vue`]
} else {
return () => import(/* @vite-ignore */ `/src/layout/other/empty.vue`)
}
}
// 从路由中移除菜单
const removeFromRouter = () => {
const routes = router.getRoutes()
// 遍历所有路由
routes.forEach((route) => {
// 过滤白名单
if (
whiteList.filter((e) => e.path === route.path).length > 0 ||
routesData.filter((e) => e.path === route.path).length > 0
) {
return
}
if (route.name && route.name !== 'layout') {
router.removeRoute(route.name)
}
})
}
// 获取用户菜单通过API重新初始化菜单用于界面实时响应
const fetchMenu = async () => {
const menu = await userCenterApi.userLoginMenu()
tool.data.set('MENU', menu)
refreshMenu()
}
// 刷新菜单非API刷新用于路由守卫内使用
const refreshMenu = () => {
loadMenu()
removeFromRouter()
addToRouter()
changeRefreshFlag(true)
}
// 通过API刷新菜单仅在layout的onMounted内使用浏览器刷新只刷新一次
const refreshApiMenu = () => {
userCenterApi.userLoginMenu().then((data) => {
tool.data.set('MENU', data)
nextTick(() => {
refreshMenu()
})
})
}
// 将菜单添加到路由
const addToRouter = () => {
menuData.value.forEach((item) => {
router.addRoute('layout', item)
})
}
return { menuData, loadMenu, addToRouter, refreshMenu, changeRefreshFlag, refreshFlag, fetchMenu, refreshApiMenu }
})