mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-04-06 03:57:54 +08:00
208 lines
6.3 KiB
TypeScript
208 lines
6.3 KiB
TypeScript
import type { MenuOption } from 'naive-ui'
|
|
import { RouterLink } from 'vue-router'
|
|
import { h } from 'vue'
|
|
import { clone, construct, min } from 'radash'
|
|
import type { RouteRecordRaw } from 'vue-router'
|
|
import { $t, arrayToTree, local, renderIcon } from '@/utils'
|
|
import { router } from '@/router'
|
|
import { fetchUserRoutes } from '@/service'
|
|
import { staticRoutes } from '@/router/routes.static'
|
|
import { usePermission } from '@/hooks'
|
|
import Layout from '@/layouts/index.vue'
|
|
import { useAuthStore } from '@/store/auth'
|
|
|
|
interface RoutesStatus {
|
|
isInitAuthRoute: boolean
|
|
menus: AppRoute.Route[]
|
|
rowRoutes: AppRoute.RowRoute[]
|
|
activeMenu: string | null
|
|
cacheRoutes: string[]
|
|
}
|
|
export const useRouteStore = defineStore('route-store', {
|
|
state: (): RoutesStatus => {
|
|
return {
|
|
isInitAuthRoute: false,
|
|
menus: [],
|
|
rowRoutes: [],
|
|
activeMenu: null,
|
|
cacheRoutes: [],
|
|
}
|
|
},
|
|
actions: {
|
|
resetRouteStore() {
|
|
this.resetRoutes()
|
|
this.$reset()
|
|
},
|
|
resetRoutes() {
|
|
router.removeRoute('appRoot')
|
|
},
|
|
// set the currently highlighted menu key
|
|
setActiveMenu(key: string) {
|
|
this.activeMenu = key
|
|
},
|
|
/* 生成侧边菜单的数据 */
|
|
createMenus(userRoutes: AppRoute.RowRoute[]) {
|
|
const resultMenus = clone(userRoutes).map(i => construct(i)) as AppRoute.Route[]
|
|
|
|
// filter menus that do not need to be displayed
|
|
const visibleMenus = resultMenus.filter(route => !route.meta.hide)
|
|
|
|
// generate side menu
|
|
this.menus = arrayToTree(this.transformAuthRoutesToMenus(visibleMenus))
|
|
},
|
|
|
|
// render the returned routing table as a sidebar
|
|
transformAuthRoutesToMenus(userRoutes: AppRoute.Route[]): MenuOption[] {
|
|
const { hasPermission } = usePermission()
|
|
// Filter out side menus without permission
|
|
return userRoutes.filter(i => hasPermission(i.meta.roles))
|
|
// Sort the menu according to the order size
|
|
.sort((a, b) => {
|
|
if (a.meta && a.meta.order && b.meta && b.meta.order)
|
|
return a.meta.order - b.meta.order
|
|
else if (a.meta && a.meta.order)
|
|
return -1
|
|
else if (b.meta && b.meta.order)
|
|
return 1
|
|
else return 0
|
|
})
|
|
|
|
// Convert to side menu data structure
|
|
.map((item) => {
|
|
const target: MenuOption = {
|
|
id: item.id,
|
|
pid: item.pid,
|
|
label:
|
|
(!item.meta.menuType || item.meta.menuType === 'page')
|
|
? () =>
|
|
h(
|
|
RouterLink,
|
|
{
|
|
to: {
|
|
path: item.path,
|
|
},
|
|
},
|
|
{ default: () => $t(`route.${String(item.name)}`, item.meta.title) },
|
|
)
|
|
: () => $t(`route.${String(item.name)}`, item.meta.title),
|
|
key: item.path,
|
|
icon: item.meta.icon ? renderIcon(item.meta.icon) : undefined,
|
|
}
|
|
return target
|
|
})
|
|
},
|
|
createRoutes(routes: AppRoute.RowRoute[]) {
|
|
const { hasPermission } = usePermission()
|
|
|
|
// Structure the meta field
|
|
let resultRouter = clone(routes).map(i => construct(i)) as AppRoute.Route[]
|
|
|
|
// Route permission filtering
|
|
resultRouter = resultRouter.filter(i => hasPermission(i.meta.roles))
|
|
|
|
// Generate an array of route names that need to be kept alive
|
|
this.cacheRoutes = resultRouter.filter((i) => {
|
|
return i.meta.keepAlive
|
|
})
|
|
.map(i => i.name)
|
|
|
|
// Generate routes, no need to import files for those with redirect
|
|
const modules = import.meta.glob('@/views/**/*.vue')
|
|
resultRouter = resultRouter.map((item: AppRoute.Route) => {
|
|
if (item.componentPath && !item.redirect)
|
|
item.component = modules[`/src/views${item.componentPath}`]
|
|
return item
|
|
})
|
|
|
|
// Generate route tree
|
|
resultRouter = arrayToTree(resultRouter) as AppRoute.Route[]
|
|
|
|
const appRootRoute: RouteRecordRaw = {
|
|
path: '/appRoot',
|
|
name: 'appRoot',
|
|
redirect: import.meta.env.VITE_HOME_PATH,
|
|
component: Layout,
|
|
meta: {
|
|
title: '',
|
|
icon: 'icon-park-outline:home',
|
|
},
|
|
children: [],
|
|
}
|
|
|
|
// Set the correct redirect path for the route
|
|
this.setRedirect(resultRouter)
|
|
|
|
// Insert the processed route into the root route
|
|
appRootRoute.children = resultRouter as unknown as RouteRecordRaw[]
|
|
router.addRoute(appRootRoute)
|
|
},
|
|
setRedirect(routes: AppRoute.Route[]) {
|
|
routes.forEach((route) => {
|
|
if (route.children) {
|
|
if (!route.redirect) {
|
|
// Filter out a collection of child elements that are not hidden
|
|
const visibleChilds = route.children.filter(child => !child.meta.hide)
|
|
|
|
// Redirect page to the path of the first child element by default
|
|
let target = visibleChilds[0]
|
|
|
|
// Filter out pages with the order attribute
|
|
const orderChilds = visibleChilds.filter(child => child.meta.order)
|
|
|
|
if (orderChilds.length > 0)
|
|
target = min(orderChilds, i => i.meta.order!) as AppRoute.Route
|
|
|
|
route.redirect = target.path
|
|
}
|
|
|
|
this.setRedirect(route.children)
|
|
}
|
|
})
|
|
},
|
|
async initRouteInfo() {
|
|
if (import.meta.env.VITE_AUTH_ROUTE_MODE === 'dynamic') {
|
|
const userInfo = local.get('userInfo')
|
|
|
|
if (!userInfo || !userInfo.id) {
|
|
const authStore = useAuthStore()
|
|
authStore.resetAuthStore()
|
|
return
|
|
}
|
|
|
|
// Get user's route
|
|
const { data } = await fetchUserRoutes({
|
|
id: userInfo.id,
|
|
})
|
|
|
|
if (!data)
|
|
return
|
|
|
|
return data
|
|
}
|
|
else {
|
|
this.rowRoutes = staticRoutes
|
|
return staticRoutes
|
|
}
|
|
},
|
|
async initAuthRoute() {
|
|
this.isInitAuthRoute = false
|
|
|
|
// Initialize route information
|
|
const rowRoutes = await this.initRouteInfo()
|
|
if (!rowRoutes) {
|
|
window.$message.error($t(`app.getRouteError`))
|
|
return
|
|
}
|
|
this.rowRoutes = rowRoutes
|
|
|
|
// Generate actual route and insert
|
|
this.createRoutes(rowRoutes)
|
|
|
|
// Generate side menu
|
|
this.createMenus(rowRoutes)
|
|
|
|
this.isInitAuthRoute = true
|
|
},
|
|
},
|
|
})
|