|
|
import NotPermission from '@/components/error/403.tsx' import NotFound from '@/components/error/404.tsx' import ErrorPage from '@/components/error/error.tsx' import Loading from '@/components/loading' import FetchLoading from '@/components/loading/FetchLoading.tsx' import PageLoading from '@/components/page-loading' import { PageStoreProvider } from '@/store' import { AuthenticatedRoute as AuthenticatedImport } from './_authenticatedRoute.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, createRootRouteWithContext, createRoute, createRouter, lazyRouteComponent, Outlet, redirect, RouterProvider, // createHashHistory,
} from '@tanstack/react-router' // import { TanStackRouterDevtools } from '@tanstack/router-devtools'
import { memo, useEffect, useRef } from 'react' import RootLayout from './layout/RootLayout' import { IRootContext, MenuItem } from './global' // import { DevTools } from 'jotai-devtools'
import { useAtomValue } from 'jotai' import { userMenuDataAtom } from '@/store/system/user.ts'
const PageRootLayout = () => { return <PageStoreProvider> <RootLayout/> </PageStoreProvider> }
export const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, } } })
const rootRoute = createRootRouteWithContext<IRootContext>()({ component: () => (
<> <FetchLoading/> <Outlet/> {/*<DevTools/>*/} {/*<TanStackRouterDevtools position={'bottom-right'}/>*/} </> ), 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: PageRootLayout, })
const layoutAuthRoute = createRoute({ getParentRoute: () => authRoute, id: '/_auth_layout', component: PageRootLayout, })
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 }, } }
const modules = import.meta.glob('./pages/**/*.{jsx,tsx}')
console.log(modules)
const generateDynamicRoutes = (menuData: MenuItem[], parentRoute: AnyRoute) => { // 递归生成路由,如果有routes则递归生成子路由
const generateRoutes = (menu: MenuItem, parentRoute: AnyRoute) => { 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,直接返回
return createRoute({ getParentRoute: () => layoutAuthRoute, id: `/layout-no-path-${generateUUID()}`, component: EmptyLayout, }) }
// @ts-ignore 添加menu属性,方便后面获取
const options = { getParentRoute: () => parentRoute, menu, } as any
if (isLayout) { options.id = path ?? `/layout-${generateUUID()}` } else { if (!path) { console.log(`${menu.name}没有设置视图`) options.id = menu.meta.name } else { options.path = path } }
let component = menu.component // menu.type
// 1,组件(页面),2,IFrame,3,外链接,4,按钮
if (menu.type === 'iframe') { component = '@/components/Iframe' }
//处理component路径
component = component.replace(/^\/pages/, '') component = component.replace(/^\//, '')
return createRoute({ ...options, // @ts-ignore fix import
component: lazyRouteComponent(() => {
//处理最后可能包含index || index.tsx || index.jsx
if (component.endsWith('.tsx')) { component = component.replace(/\.tsx$/, '') } if (component.endsWith('.jsx')) { component = component.replace(/\.jsx$/, '') } if (component.endsWith('/index')) { component = component.replace(/\/index$/, '') }
let module: () => Promise<any> //优先匹配无index的情况
if (modules[`./pages/${component}.tsx`] || modules[`./pages/${component}.jsx`]) { module = modules[`./pages/${component}.tsx`] || modules[`./pages/${component}.jsx`] } else { module = modules[`./pages/${component}/index.tsx`] || modules[`./pages/${component}/index.jsx`] }
if (!module) { return NotFound }
return module().then((d: any) => { // console.log(d)
if (d.Route) { d.Route.update({ path: menu.path, }) } return d }) }), notFoundComponent: NotFound, }) }
// 对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> }) => {
const { data: menuData, isLoading, refetch } = useAtomValue(userMenuDataAtom)
const isFetchRef = useRef(false)
useEffect(() => {
if (isFetchRef.current) { return } isFetchRef.current = true refetch()
}, [])
if (isLoading) { return <PageLoading/> }
generateDynamicRoutes(menuData ?? [], layoutAuthRoute)
// const hashHistory = createHashHistory()
const router = createRouter({ routeTree, // history: hashHistory,
context: { queryClient, menuData: [] }, defaultPreload: 'intent', defaultPendingComponent: () => <Loading loading={true} delay={100}/> })
return ( <QueryClientProvider client={queryClient}> <RouterProvider router={router} context={{ ...props.context, menuData, queryClient }}/> </QueryClientProvider> ) })
export default RootProvider
|