You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
8.3 KiB
315 lines
8.3 KiB
import NotPermission from '@/components/error/403.tsx'
|
|
import NotFound from '@/components/error/404.tsx'
|
|
import ErrorPage from '@/components/error/error.tsx'
|
|
import FetchLoading from '@/components/loading/FetchLoading.tsx'
|
|
import PageLoading from '@/components/page-loading'
|
|
import { Route as AuthenticatedImport } from '@/layout/_authenticated.tsx'
|
|
import EmptyLayout from '@/layout/EmptyLayout.tsx'
|
|
import ListPageLayout from '@/layout/ListPageLayout.tsx'
|
|
import { Route as DashboardImport } from '@/pages/dashboard'
|
|
import { Route as LoginRouteImport } from '@/pages/login'
|
|
import { generateUUID } from '@/utils/uuid.ts'
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
import {
|
|
AnyRoute,
|
|
createLazyRoute,
|
|
createRootRouteWithContext,
|
|
createRoute,
|
|
createRouter,
|
|
Outlet,
|
|
redirect,
|
|
RouterProvider,
|
|
} from '@tanstack/react-router'
|
|
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
|
|
import { memo } from 'react'
|
|
import RootLayout from './layout/RootLayout'
|
|
import { IRootContext, MenuItem } from './types'
|
|
import { DevTools } from 'jotai-devtools'
|
|
|
|
|
|
export const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
}
|
|
}
|
|
})
|
|
|
|
|
|
const rootRoute = createRootRouteWithContext<IRootContext>()({
|
|
component: () => (
|
|
|
|
<div>
|
|
<FetchLoading/>
|
|
<Outlet/>
|
|
<DevTools />
|
|
<TanStackRouterDevtools position={'bottom-right'}/>
|
|
</div>
|
|
),
|
|
beforeLoad: ({ location }) => {
|
|
if (location.pathname === '/') {
|
|
return redirect({ to: '/dashboard' })
|
|
}
|
|
},
|
|
loader: () => {
|
|
|
|
},
|
|
notFoundComponent: NotFound,
|
|
pendingComponent: PageLoading,
|
|
errorComponent: ({ error }) => <ErrorPage error={error}/>,
|
|
})
|
|
|
|
const emptyRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
id: '/_empty',
|
|
component: EmptyLayout,
|
|
})
|
|
|
|
const authRoute = AuthenticatedImport.update({
|
|
getParentRoute: () => rootRoute,
|
|
id: '/_authenticated',
|
|
} as any)
|
|
|
|
const layoutNormalRoute = createRoute({
|
|
getParentRoute: () => rootRoute,
|
|
id: '/_normal_layout',
|
|
component: RootLayout,
|
|
})
|
|
|
|
const layoutAuthRoute = createRoute({
|
|
getParentRoute: () => authRoute,
|
|
id: '/_auth_layout',
|
|
component: RootLayout,
|
|
})
|
|
|
|
const notAuthRoute = createRoute({
|
|
getParentRoute: () => layoutNormalRoute,
|
|
path: '/not-auth',
|
|
component: NotPermission
|
|
})
|
|
|
|
// const dashboardRoute = DashboardImport.update({
|
|
// path: '/dashboard',
|
|
// getParentRoute: () => layoutAuthRoute,
|
|
// } as any)
|
|
|
|
const loginRoute = LoginRouteImport.update({
|
|
path: '/login',
|
|
getParentRoute: () => emptyRoute,
|
|
} as any)
|
|
|
|
const menusRoute = createRoute({
|
|
getParentRoute: () => layoutAuthRoute,
|
|
path: '/system/menus',
|
|
}).lazy(async () => await import('@/pages/system/menus').then(d => d.Route))
|
|
|
|
const departmentsRoute = createRoute({
|
|
getParentRoute: () => layoutAuthRoute,
|
|
path: '/system/departments',
|
|
}).lazy(async () => await import('@/pages/system/departments').then(d => d.Route))
|
|
|
|
const usersRoute = createRoute({
|
|
getParentRoute: () => layoutAuthRoute,
|
|
path: '/system/users',
|
|
}).lazy(async () => await import('@/pages/system/users').then(d => d.Route))
|
|
|
|
const rolesRoute = createRoute({
|
|
getParentRoute: () => layoutAuthRoute,
|
|
path: '/system/roles',
|
|
}).lazy(async () => await import('@/pages/system/roles').then(d => d.Route))
|
|
|
|
|
|
declare module '@tanstack/react-router' {
|
|
interface FileRoutesByPath {
|
|
'/_authenticated': {
|
|
preLoaderRoute: typeof AuthenticatedImport
|
|
parentRoute: typeof rootRoute
|
|
},
|
|
'/_normal_layout': {
|
|
preLoaderRoute: typeof layoutNormalRoute
|
|
parentRoute: typeof rootRoute
|
|
},
|
|
'/_layout': {
|
|
preLoaderRoute: typeof layoutAuthRoute
|
|
parentRoute: typeof rootRoute
|
|
},
|
|
'/': {
|
|
preLoaderRoute: typeof DashboardImport
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
'/dashboard': {
|
|
preLoaderRoute: typeof DashboardImport
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
'/login': {
|
|
preLoaderRoute: typeof LoginRouteImport
|
|
parentRoute: typeof rootRoute
|
|
},
|
|
'/system/menus': {
|
|
preLoaderRoute: typeof menusRoute
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
'/system/departments': {
|
|
preLoaderRoute: typeof departmentsRoute
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
'/system/users': {
|
|
preLoaderRoute: typeof usersRoute
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
'/system/roles': {
|
|
preLoaderRoute: typeof rolesRoute
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
'/welcome': {
|
|
preLoaderRoute: typeof rootRoute
|
|
parentRoute: typeof layoutAuthRoute
|
|
},
|
|
}
|
|
}
|
|
|
|
export const generateDynamicRoutes = (menuData: MenuItem[], parentRoute: AnyRoute) => {
|
|
// 递归生成路由,如果有routes则递归生成子路由
|
|
|
|
const generateRoutes = (menu: MenuItem, parentRoute: AnyRoute) => {
|
|
console.log('gen route', menu)
|
|
const path = menu.path?.replace(parentRoute.options?.path, '')
|
|
const isLayout = menu.children && menu.children.length > 0 && menu.type === 'menu'
|
|
|
|
if (isLayout && (!menu.path || !menu.component)) {
|
|
//没有component的layout,直接返回
|
|
console.log('no-page')
|
|
return createRoute({
|
|
getParentRoute: () => layoutAuthRoute,
|
|
id: `/layout-no-path-${generateUUID()}`,
|
|
component: RootLayout,
|
|
})
|
|
}
|
|
|
|
// @ts-ignore 添加menu属性,方便后面获取
|
|
const options = {
|
|
getParentRoute: () => parentRoute,
|
|
menu,
|
|
} as any
|
|
|
|
if (isLayout) {
|
|
options.id = path ?? `/layout-${generateUUID()}`
|
|
} else {
|
|
if (!path) {
|
|
console.log(`${menu.name}没有设置视图`)
|
|
} else {
|
|
options.path = path
|
|
}
|
|
}
|
|
|
|
console.log('gen route', options)
|
|
|
|
//删除掉parentRoute的path,避免重复
|
|
const route = createRoute(options).lazy(async () => {
|
|
|
|
// @ts-ignore 获取route中的menu属性
|
|
const menu = route.options.menu as MenuItem
|
|
let component = menu.component
|
|
|
|
// menu.type
|
|
// 1,组件(页面),2,IFrame,3,外链接,4,按钮
|
|
if (menu.type === 'iframe') {
|
|
component = '@/components/Iframe'
|
|
}
|
|
|
|
if (!component) {
|
|
return createLazyRoute(options.path)({
|
|
component: () => <div>404 Not Found</div>
|
|
})
|
|
}
|
|
|
|
//处理component路径
|
|
component = component.replace(/^\/pages/, '')
|
|
component = component.replace(/^\//, '')
|
|
|
|
console.log('load', `/pages/${component}`)
|
|
/* @vite-ignore */
|
|
const d = await import(`/pages/${component}`)
|
|
if (d.Route) {
|
|
console.log(d.Route)
|
|
return d.Route
|
|
}
|
|
if (d.GenRoute) {
|
|
return d.GenRoute(options.path)
|
|
}
|
|
return createLazyRoute(options.path)({
|
|
component: d.default || d
|
|
})
|
|
})
|
|
|
|
return route
|
|
}
|
|
|
|
// 对menuData递归生成路由,只处理type =1 的菜单
|
|
const did = (menus: MenuItem[], parentRoute: AnyRoute) => {
|
|
return menus.filter((item) => item.type === 'menu').map((item, index) => {
|
|
// 如果有children则递归生成子路由,同样只处理type =1 的菜单
|
|
const route = generateRoutes(item, parentRoute)
|
|
|
|
// console.log(route)
|
|
if (item.children && item.children.length > 0) {
|
|
const children = did(item.children, route)
|
|
if (children.length > 0) {
|
|
route.addChildren(children)
|
|
}
|
|
}
|
|
route.init({ originalIndex: index })
|
|
return route
|
|
})
|
|
}
|
|
|
|
const routes = did(menuData, parentRoute)
|
|
|
|
parentRoute.addChildren(routes)
|
|
|
|
}
|
|
const routeTree = rootRoute.addChildren(
|
|
[
|
|
//非Layout
|
|
loginRoute,
|
|
emptyRoute,
|
|
|
|
//不带权限Layout
|
|
layoutNormalRoute.addChildren([
|
|
notAuthRoute,
|
|
]),
|
|
|
|
//带权限Layout
|
|
// dashboardRoute,
|
|
authRoute.addChildren(
|
|
[
|
|
layoutAuthRoute
|
|
/*.addChildren(
|
|
[
|
|
menusRoute,
|
|
departmentsRoute,
|
|
usersRoute,
|
|
rolesRoute,
|
|
]
|
|
),*/
|
|
]),
|
|
]
|
|
)
|
|
|
|
|
|
export const RootProvider = memo((props: { context: Partial<IRootContext> }) => {
|
|
|
|
generateDynamicRoutes(props.context.menuData ?? [], layoutAuthRoute)
|
|
|
|
const router = createRouter({
|
|
routeTree,
|
|
context: { queryClient, menuData: [] },
|
|
defaultPreload: 'intent'
|
|
})
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<RouterProvider router={router} context={{ ...props.context, queryClient }}/>
|
|
</QueryClientProvider>
|
|
)
|
|
})
|