import { shallowRef, defineAsyncComponent, Component } from 'vue' import { useRoute, useRouter } from 'vue-router' import { useMenuStore } from '@/stores' import { AuthType } from '@/constants/menu' export function useMenu(authCode?: string) { const { userMenus } = useMenuStore() const route = useRoute() const router = useRouter() const componentMap = new Map() const componentId = shallowRef() // 当前选中的组件 // 过滤菜单 const filterMenu = (data: Ermcp.UserMenu[], parentPath = '') => { const result: Ermcp.UserMenu[] = [] data.forEach((e) => { if (!e.hidden && e.authType === AuthType.Menu) { const routePath = (parentPath ? parentPath + '/' : '') + e.url result.push({ ...e, url: routePath, children: e.children ? filterMenu(e.children, routePath) : [], }) } }) return result } /** * 根据 code 查找对应的子菜单 * @returns */ const findChildren = (data: Ermcp.UserMenu[], code?: string): Ermcp.UserMenu[] => { const routeName = code ?? route.name?.toString() for (const item of data) { const { code, children } = item if (code === routeName) return children ?? [] if (children) { const res = findChildren(children, routeName) if (res.length) return res } } return [] } /** * 获取路由菜单(无限级) * @param level * @returns */ const getMenus = (level = 0) => { // 过滤层级 const filterLevel = (data: Ermcp.UserMenu[], n: number): Ermcp.UserMenu[] => { if (level) { return data.map((e) => ({ ...e, children: n <= 1 ? [] : filterLevel(e.children ?? [], n - 1) })) } return data } return filterMenu(filterLevel(userMenus.value, level)) } /** * 获取路由子菜单 * @param code * @returns */ const getChildrenMenus = (code?: string) => { const children = findChildren(userMenus.value, code) return filterMenu(children) } /** * 获取操作权限 * @returns */ const getAuth = (authType: AuthType) => { const children = findChildren(userMenus.value, authCode) return children.reduce((res, cur) => { if (!cur.hidden && cur.authType === authType) { if (!componentMap.get(cur.code) && cur.component) { const componentString = cur.component.replace(/^\/+/, '') // 过滤字符串前面所有 '/' 字符 const componentPath = componentString.replace(/\.\w+$/, '') // 过滤后缀名,为了让 import 加入 .vue ,不然会有警告提示... const asyncComponent = defineAsyncComponent({ loader: () => import('/' + process.env.VUE_APP_ROOT + componentPath + '.vue'), }) componentMap.set(cur.code, asyncComponent) } res.push(JSON.parse(JSON.stringify(cur))) } return res }, [] as Ermcp.UserMenu[]) } /** * 过滤操作权限 * @param filtered 过滤的数据项 * @param reverse 是否反向过滤 * @returns */ const authFilter = (authType: AuthType, filtered: string[], reverse: boolean) => { const auth = getAuth(authType); if (filtered.length) { if (reverse) { // 返回除指定的权限代码 return auth.filter((e) => !filtered.includes(e.code)) } else { // 返回指定的权限代码 return auth.filter((e) => filtered.includes(e.code)) } } return auth } /** * 获取权限按钮 * @param filtered * @param reverse * @returns */ const getAuthButtons = (filtered: string[] = [], reverse = false) => authFilter(AuthType.Button, filtered, reverse) /** * 获取权限组件 * @param filtered * @param reverse * @returns */ const getAuthComponents = (filtered: string[] = [], reverse = false) => authFilter(AuthType.Component, filtered, reverse) return { route, router, userMenus, componentMap, componentId, getMenus, getChildrenMenus, getAuthButtons, getAuthComponents, } }