import type { Menu, Route } from '#/global'
import type { RouteRecordRaw } from 'vue-router'
import api from '@/api'
import menu from '@/menu'
import { resolveRoutePath } from '@/utils'
import { cloneDeep } from 'lodash-es'
import useRouteStore from './route'
import useSettingsStore from './settings'
import useUserStore from './user'
const useMenuStore = defineStore(
// 唯一ID
'menu',
() => {
const settingsStore = useSettingsStore()
const userStore = useUserStore()
const routeStore = useRouteStore()
const filesystemMenusRaw = ref
([])
const actived = ref(0)
// 将原始路由转换成导航菜单
function convertRouteToMenu(routes: Route.recordMainRaw[]): Menu.recordMainRaw[] {
const returnMenus: Menu.recordMainRaw[] = []
routes.forEach((item) => {
if (item.children.length > 0) {
if (settingsStore.settings.menu.mode === 'single') {
returnMenus.length === 0 && returnMenus.push({
meta: {},
children: [],
})
returnMenus[0].children.push(...convertRouteToMenuRecursive(item.children))
}
else {
const menuItem: Menu.recordMainRaw = {
meta: {
title: item?.meta?.title,
icon: item?.meta?.icon,
auth: item?.meta?.auth,
},
children: [],
}
menuItem.children = convertRouteToMenuRecursive(item.children)
returnMenus.push(menuItem)
}
}
})
return returnMenus
}
function convertRouteToMenuRecursive(routes: RouteRecordRaw[], basePath = ''): Menu.recordRaw[] {
const returnMenus: Menu.recordRaw[] = []
routes.forEach((item) => {
const menuItem: Menu.recordRaw = {
path: resolveRoutePath(basePath, item.path),
meta: {
title: item?.meta?.title,
icon: item?.meta?.icon,
defaultOpened: item?.meta?.defaultOpened,
auth: item?.meta?.auth,
menu: item?.meta?.menu,
link: item?.meta?.link,
},
}
if (item.children) {
menuItem.children = convertRouteToMenuRecursive(item.children, menuItem.path)
}
returnMenus.push(menuItem)
})
return returnMenus
}
// 完整导航数据
const allMenus = computed(() => {
let returnMenus: Menu.recordMainRaw[] = []
if (settingsStore.settings.app.routeBaseOn !== 'filesystem') {
returnMenus = convertRouteToMenu(routeStore.routesRaw)
}
else {
returnMenus = filesystemMenusRaw.value
}
// 如果权限功能开启,则需要对导航数据进行筛选过滤
if (settingsStore.settings.app.enablePermission) {
returnMenus = filterAsyncMenus(returnMenus, userStore.permissions)
}
return returnMenus
})
// 次导航数据
const sidebarMenus = computed(() => {
return allMenus.value.length > 0
? allMenus.value.length > 1
? allMenus.value[actived.value].children
: allMenus.value[0].children
: []
})
// 次导航第一层最深路径
const sidebarMenusFirstDeepestPath = computed(() => {
return sidebarMenus.value.length > 0
? getDeepestPath(sidebarMenus.value[0])
: settingsStore.settings.home.fullPath
})
function getDeepestPath(menu: Menu.recordRaw, rootPath = '') {
let retnPath = ''
if (menu.children) {
const item = menu.children.find(item => item.meta?.menu !== false)
if (item) {
retnPath = getDeepestPath(item, resolveRoutePath(rootPath, menu.path))
}
else {
retnPath = getDeepestPath(menu.children[0], resolveRoutePath(rootPath, menu.path))
}
}
else {
retnPath = resolveRoutePath(rootPath, menu.path)
}
return retnPath
}
// 默认展开的导航路径
const defaultOpenedPaths = computed(() => {
const defaultOpenedPaths: string[] = []
if (settingsStore.settings.app.routeBaseOn !== 'filesystem') {
allMenus.value.forEach((item) => {
defaultOpenedPaths.push(...getDefaultOpenedPaths(item.children))
})
}
return defaultOpenedPaths
})
function getDefaultOpenedPaths(menus: Menu.recordRaw[], rootPath = '') {
const defaultOpenedPaths: string[] = []
menus.forEach((item) => {
if (item.meta?.defaultOpened && item.children) {
defaultOpenedPaths.push(resolveRoutePath(rootPath, item.path))
const childrenDefaultOpenedPaths = getDefaultOpenedPaths(item.children, resolveRoutePath(rootPath, item.path))
if (childrenDefaultOpenedPaths.length > 0) {
defaultOpenedPaths.push(...childrenDefaultOpenedPaths)
}
}
})
return defaultOpenedPaths
}
// 判断是否有权限
function hasPermission(permissions: string[], menu: Menu.recordMainRaw | Menu.recordRaw) {
let isAuth = false
if (menu.meta?.auth) {
isAuth = permissions?.some((auth) => {
if (typeof menu.meta?.auth === 'string') {
return menu.meta.auth !== '' ? menu.meta.auth === auth : true
}
else if (typeof menu.meta?.auth === 'object') {
return menu.meta.auth.length > 0 ? menu.meta.auth.includes(auth) : true
}
else {
return false
}
})
}
else {
isAuth = true
}
return isAuth
}
// 根据权限过滤导航
function filterAsyncMenus(menus: T, permissions: string[]): T {
const res: any = []
menus.forEach((menu) => {
if (hasPermission(permissions, menu)) {
const tmpMenu = cloneDeep(menu)
if (tmpMenu.children && tmpMenu.children.length > 0) {
tmpMenu.children = filterAsyncMenus(tmpMenu.children, permissions) as Menu.recordRaw[]
tmpMenu.children.length > 0 && res.push(tmpMenu)
}
else {
delete tmpMenu.children
res.push(tmpMenu)
}
}
})
return res
}
// 生成导航(前端生成)
async function generateMenusAtFront() {
filesystemMenusRaw.value = menu.filter(item => item.children.length !== 0)
}
// 生成导航(后端生成)
async function generateMenusAtBack() {
await api.appApi.menuList().then(async (res) => {
filesystemMenusRaw.value = (res.data as Menu.recordMainRaw[]).filter(item => item.children.length !== 0)
}).catch(() => {})
}
// 设置主导航
function isPathInMenus(menus: Menu.recordRaw[], path: string) {
let flag = false
flag = menus.some((item) => {
if (item.children) {
return isPathInMenus(item.children, path)
}
return path.indexOf(`${item.path}/`) === 0 || path === item.path
})
return flag
}
function setActived(data: number | string) {
if (typeof data === 'number') {
// 如果是 number 类型,则认为是主导航的索引
actived.value = data
}
else {
// 如果是 string 类型,则认为是路由,需要查找对应的主导航索引
const findIndex = allMenus.value.findIndex(item => isPathInMenus(item.children, data))
if (findIndex >= 0) {
actived.value = findIndex
}
}
}
return {
actived,
allMenus,
sidebarMenus,
sidebarMenusFirstDeepestPath,
defaultOpenedPaths,
generateMenusAtFront,
generateMenusAtBack,
setActived,
}
},
)
export default useMenuStore