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.

316 lines
9.4 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. import NotPermission from '@/components/error/403.tsx'
  2. import NotFound from '@/components/error/404.tsx'
  3. import ErrorPage from '@/components/error/error.tsx'
  4. import Loading from '@/components/loading'
  5. import FetchLoading from '@/components/loading/FetchLoading.tsx'
  6. import PageLoading from '@/components/page-loading'
  7. import { PageStoreProvider } from '@/store'
  8. import { AuthenticatedRoute as AuthenticatedImport } from './_authenticatedRoute.tsx'
  9. import EmptyLayout from '@/layout/EmptyLayout.tsx'
  10. // import ListPageLayout from '@/layout/ListPageLayout.tsx'
  11. // import { Route as DashboardImport } from '@/pages/dashboard'
  12. import { Route as LoginRouteImport } from '@/pages/login'
  13. import { generateUUID } from '@/utils/uuid.ts'
  14. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  15. import {
  16. AnyRoute,
  17. createRootRouteWithContext,
  18. createRoute,
  19. createRouter, lazyRouteComponent,
  20. Outlet,
  21. redirect,
  22. RouterProvider,
  23. } from '@tanstack/react-router'
  24. // import { TanStackRouterDevtools } from '@tanstack/router-devtools'
  25. import { memo, useEffect, useRef } from 'react'
  26. import RootLayout from './layout/RootLayout'
  27. import { IRootContext, MenuItem } from './global'
  28. import { DevTools } from 'jotai-devtools'
  29. import { useAtomValue } from 'jotai'
  30. import { userMenuDataAtom } from '@/store/system/user.ts'
  31. const PageRootLayout = () => {
  32. return <PageStoreProvider>
  33. <RootLayout/>
  34. </PageStoreProvider>
  35. }
  36. export const queryClient = new QueryClient({
  37. defaultOptions: {
  38. queries: {
  39. retry: false,
  40. }
  41. }
  42. })
  43. const rootRoute = createRootRouteWithContext<IRootContext>()({
  44. component: () => (
  45. <>
  46. <FetchLoading/>
  47. <Outlet/>
  48. <DevTools/>
  49. {/*<TanStackRouterDevtools position={'bottom-right'}/>*/}
  50. </>
  51. ),
  52. beforeLoad: ({ location }) => {
  53. if (location.pathname === '/') {
  54. return redirect({ to: '/dashboard' })
  55. }
  56. },
  57. loader: () => {
  58. },
  59. notFoundComponent: NotFound,
  60. pendingComponent: PageLoading,
  61. errorComponent: ({ error }) => <ErrorPage error={error}/>,
  62. })
  63. const emptyRoute = createRoute({
  64. getParentRoute: () => rootRoute,
  65. id: '/_empty',
  66. component: EmptyLayout,
  67. })
  68. const authRoute = AuthenticatedImport.update({
  69. getParentRoute: () => rootRoute,
  70. id: '/_authenticated',
  71. } as any)
  72. const layoutNormalRoute = createRoute({
  73. getParentRoute: () => rootRoute,
  74. id: '/_normal_layout',
  75. component: PageRootLayout,
  76. })
  77. const layoutAuthRoute = createRoute({
  78. getParentRoute: () => authRoute,
  79. id: '/_auth_layout',
  80. component: PageRootLayout,
  81. })
  82. const notAuthRoute = createRoute({
  83. getParentRoute: () => layoutNormalRoute,
  84. path: '/not-auth',
  85. component: NotPermission
  86. })
  87. // const dashboardRoute = DashboardImport.update({
  88. // path: '/dashboard',
  89. // getParentRoute: () => layoutAuthRoute,
  90. // } as any)
  91. const loginRoute = LoginRouteImport.update({
  92. path: '/login',
  93. getParentRoute: () => emptyRoute,
  94. } as any)
  95. //
  96. // const menusRoute = createRoute({
  97. // getParentRoute: () => layoutAuthRoute,
  98. // path: '/system/menus',
  99. // }).lazy(async () => await import('@/pages/system/menus').then(d => d.Route))
  100. //
  101. // const departmentsRoute = createRoute({
  102. // getParentRoute: () => layoutAuthRoute,
  103. // path: '/system/departments',
  104. // }).lazy(async () => await import('@/pages/system/departments').then(d => d.Route))
  105. //
  106. // const usersRoute = createRoute({
  107. // getParentRoute: () => layoutAuthRoute,
  108. // path: '/system/users',
  109. // }).lazy(async () => await import('@/pages/system/users').then(d => d.Route))
  110. //
  111. // const rolesRoute = createRoute({
  112. // getParentRoute: () => layoutAuthRoute,
  113. // path: '/system/roles',
  114. // }).lazy(async () => await import('@/pages/system/roles').then(d => d.Route))
  115. declare module '@tanstack/react-router' {
  116. interface FileRoutesByPath {
  117. '/_authenticated': {
  118. preLoaderRoute: typeof AuthenticatedImport
  119. parentRoute: typeof rootRoute
  120. },
  121. '/_normal_layout': {
  122. preLoaderRoute: typeof layoutNormalRoute
  123. parentRoute: typeof rootRoute
  124. },
  125. '/_layout': {
  126. preLoaderRoute: typeof layoutAuthRoute
  127. parentRoute: typeof rootRoute
  128. },
  129. // '/': {
  130. // preLoaderRoute: typeof DashboardImport
  131. // parentRoute: typeof layoutAuthRoute
  132. // },
  133. // '/dashboard': {
  134. // preLoaderRoute: typeof DashboardImport
  135. // parentRoute: typeof layoutAuthRoute
  136. // },
  137. '/login': {
  138. preLoaderRoute: typeof LoginRouteImport
  139. parentRoute: typeof rootRoute
  140. },
  141. // '/system/menus': {
  142. // preLoaderRoute: typeof menusRoute
  143. // parentRoute: typeof layoutAuthRoute
  144. // },
  145. // '/system/departments': {
  146. // preLoaderRoute: typeof departmentsRoute
  147. // parentRoute: typeof layoutAuthRoute
  148. // },
  149. // '/system/users': {
  150. // preLoaderRoute: typeof usersRoute
  151. // parentRoute: typeof layoutAuthRoute
  152. // },
  153. // '/system/roles': {
  154. // preLoaderRoute: typeof rolesRoute
  155. // parentRoute: typeof layoutAuthRoute
  156. // },
  157. '/welcome': {
  158. preLoaderRoute: typeof rootRoute
  159. parentRoute: typeof layoutAuthRoute
  160. },
  161. }
  162. }
  163. const generateDynamicRoutes = (menuData: MenuItem[], parentRoute: AnyRoute) => {
  164. // 递归生成路由,如果有routes则递归生成子路由
  165. const generateRoutes = (menu: MenuItem, parentRoute: AnyRoute) => {
  166. const path = menu.path?.replace(parentRoute.options?.path, '')
  167. const isLayout = menu.children && menu.children.length > 0 && menu.type === 'menu'
  168. if (isLayout && (!menu.path || !menu.component)) {
  169. //没有component的layout,直接返回
  170. return createRoute({
  171. getParentRoute: () => layoutAuthRoute,
  172. id: `/layout-no-path-${generateUUID()}`,
  173. component: EmptyLayout,
  174. })
  175. }
  176. // @ts-ignore 添加menu属性,方便后面获取
  177. const options = {
  178. getParentRoute: () => parentRoute,
  179. menu,
  180. } as any
  181. if (isLayout) {
  182. options.id = path ?? `/layout-${generateUUID()}`
  183. } else {
  184. if (!path) {
  185. console.log(`${menu.name}没有设置视图`)
  186. } else {
  187. options.path = path
  188. }
  189. }
  190. let component = menu.component
  191. // menu.type
  192. // 1,组件(页面),2,IFrame,3,外链接,4,按钮
  193. if (menu.type === 'iframe') {
  194. component = '@/components/Iframe'
  195. }
  196. //处理component路径
  197. component = component.replace(/^\/pages/, '')
  198. component = component.replace(/^\//, '')
  199. return createRoute({
  200. ...options,
  201. component: lazyRouteComponent(() => import(`./pages/${component}`)),
  202. notFoundComponent: NotFound,
  203. })
  204. }
  205. // 对menuData递归生成路由,只处理type =1 的菜单
  206. const did = (menus: MenuItem[], parentRoute: AnyRoute) => {
  207. return menus.filter((item) => item.type === 'menu').map((item, index) => {
  208. // 如果有children则递归生成子路由,同样只处理type =1 的菜单
  209. const route = generateRoutes(item, parentRoute)
  210. // console.log(route)
  211. if (item.children && item.children.length > 0) {
  212. const children = did(item.children, route)
  213. if (children.length > 0) {
  214. route.addChildren(children)
  215. }
  216. }
  217. route.init({ originalIndex: index })
  218. return route
  219. })
  220. }
  221. const routes = did(menuData, parentRoute)
  222. parentRoute.addChildren(routes)
  223. }
  224. const routeTree = rootRoute.addChildren(
  225. [
  226. //非Layout
  227. loginRoute,
  228. emptyRoute,
  229. //不带权限Layout
  230. layoutNormalRoute.addChildren([
  231. notAuthRoute,
  232. ]),
  233. //带权限Layout
  234. // dashboardRoute,
  235. authRoute.addChildren(
  236. [
  237. layoutAuthRoute
  238. /*.addChildren(
  239. [
  240. menusRoute,
  241. departmentsRoute,
  242. usersRoute,
  243. rolesRoute,
  244. ]
  245. ),*/
  246. ]),
  247. ]
  248. )
  249. export const RootProvider = memo((props: { context: Partial<IRootContext> }) => {
  250. const { data: menuData, isLoading, refetch } = useAtomValue(userMenuDataAtom)
  251. const isFetchRef = useRef(false)
  252. useEffect(() => {
  253. if (isFetchRef.current) {
  254. return
  255. }
  256. isFetchRef.current = true
  257. refetch()
  258. }, [])
  259. if (isLoading) {
  260. return <PageLoading/>
  261. }
  262. generateDynamicRoutes(menuData ?? [], layoutAuthRoute)
  263. const router = createRouter({
  264. routeTree,
  265. context: { queryClient, menuData: [] },
  266. defaultPreload: 'intent',
  267. defaultPendingComponent: () => <Loading loading={true} delay={300}/>
  268. })
  269. return (
  270. <QueryClientProvider client={queryClient}>
  271. <RouterProvider router={router} context={{ ...props.context, menuData, queryClient }}/>
  272. </QueryClientProvider>
  273. )
  274. })