From c3de6dd0de02e567914bdc4cba1e75ca691a43b6 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Thu, 30 Oct 2025 16:58:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20route/index=20=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/components/RouteContainer.js | 53 ++++++++++++++++++++++ src/routes/components/index.js | 4 ++ src/routes/constants/index.js | 5 ++ src/routes/constants/layoutComponents.js | 26 +++++++++++ src/routes/constants/protectionWrappers.js | 24 ++++++++++ src/routes/utils/renderRoute.js | 50 ++++++++++++++++++++ src/routes/utils/wrapWithProtection.js | 44 ++++++++++++++++++ 7 files changed, 206 insertions(+) create mode 100644 src/routes/components/RouteContainer.js create mode 100644 src/routes/components/index.js create mode 100644 src/routes/constants/index.js create mode 100644 src/routes/constants/layoutComponents.js create mode 100644 src/routes/constants/protectionWrappers.js create mode 100644 src/routes/utils/renderRoute.js create mode 100644 src/routes/utils/wrapWithProtection.js diff --git a/src/routes/components/RouteContainer.js b/src/routes/components/RouteContainer.js new file mode 100644 index 00000000..55a8dd27 --- /dev/null +++ b/src/routes/components/RouteContainer.js @@ -0,0 +1,53 @@ +// src/routes/components/RouteContainer.js +// 路由容器组件 - 提供统一的错误边界、加载状态和主题背景 + +import React, { Suspense } from 'react'; +import { Box, useColorMode } from '@chakra-ui/react'; +import ErrorBoundary from '@components/ErrorBoundary'; +import PageLoader from '@components/Loading/PageLoader'; + +/** + * RouteContainer - 路由容器组件 + * + * 为路由系统提供统一的外层包装,包含: + * 1. 主题感知的背景色(深色/浅色模式) + * 2. Suspense 懒加载边界(显示加载提示) + * 3. ErrorBoundary 错误边界(隔离路由错误) + * + * 这个组件确保: + * - 所有路由页面都有一致的背景色 + * - 懒加载组件有统一的加载提示 + * - 单个路由的错误不会导致整个应用崩溃 + * + * @param {Object} props + * @param {React.ReactNode} props.children - 子组件(通常是 Routes) + * @param {string} [props.loadingMessage='加载页面中...'] - 加载提示文本 + * + * @example + * + * + * } /> + * + * + */ +export function RouteContainer({ + children, + loadingMessage = "加载页面中..." +}) { + const { colorMode } = useColorMode(); + + return ( + + {/* Suspense 统一处理懒加载组件的加载状态 */} + }> + {/* ErrorBoundary 隔离路由错误,防止整个应用崩溃 */} + + {children} + + + + ); +} diff --git a/src/routes/components/index.js b/src/routes/components/index.js new file mode 100644 index 00000000..7a74d66a --- /dev/null +++ b/src/routes/components/index.js @@ -0,0 +1,4 @@ +// src/routes/components/index.js +// 统一导出所有路由组件 + +export { RouteContainer } from './RouteContainer'; diff --git a/src/routes/constants/index.js b/src/routes/constants/index.js new file mode 100644 index 00000000..dc4a5214 --- /dev/null +++ b/src/routes/constants/index.js @@ -0,0 +1,5 @@ +// src/routes/constants/index.js +// 统一导出所有路由常量 + +export { LAYOUT_COMPONENTS } from './layoutComponents'; +export { PROTECTION_WRAPPER_MAP } from './protectionWrappers'; diff --git a/src/routes/constants/layoutComponents.js b/src/routes/constants/layoutComponents.js new file mode 100644 index 00000000..a098af91 --- /dev/null +++ b/src/routes/constants/layoutComponents.js @@ -0,0 +1,26 @@ +// src/routes/constants/layoutComponents.js +// 布局组件映射表 + +import Auth from '@layouts/Auth'; +import HomeLayout from '@layouts/Home'; + +/** + * 特殊布局组件映射表 + * + * 用于将字符串标识符映射到实际的组件。 + * 这些是非懒加载的布局组件,在 routeConfig.js 中通过字符串引用。 + * + * @example + * // 在 routeConfig.js 中: + * { + * path: 'auth/*', + * component: 'Auth', // 字符串标识符 + * ... + * } + * + * // 通过 LAYOUT_COMPONENTS['Auth'] 获取实际组件 + */ +export const LAYOUT_COMPONENTS = { + Auth, + HomeLayout, +}; diff --git a/src/routes/constants/protectionWrappers.js b/src/routes/constants/protectionWrappers.js new file mode 100644 index 00000000..574611cb --- /dev/null +++ b/src/routes/constants/protectionWrappers.js @@ -0,0 +1,24 @@ +// src/routes/constants/protectionWrappers.js +// 路由保护包装器映射表 + +import ProtectedRoute from '@components/ProtectedRoute'; +import ProtectedRouteRedirect from '@components/ProtectedRouteRedirect'; +import { PROTECTION_MODES } from '../routeConfig'; + +/** + * 保护模式包装器映射表 + * + * 根据路由的保护模式选择对应的保护组件。 + * 支持以下保护模式: + * - MODAL: 弹窗登录模式 (ProtectedRoute) + * - REDIRECT: 跳转登录模式 (ProtectedRouteRedirect) + * - PUBLIC: 公开访问,无保护 (无包装器) + * + * @example + * const WrapperComponent = PROTECTION_WRAPPER_MAP[PROTECTION_MODES.MODAL]; + * // 返回 ProtectedRoute 组件 + */ +export const PROTECTION_WRAPPER_MAP = { + [PROTECTION_MODES.MODAL]: ProtectedRoute, + [PROTECTION_MODES.REDIRECT]: ProtectedRouteRedirect, +}; diff --git a/src/routes/utils/renderRoute.js b/src/routes/utils/renderRoute.js new file mode 100644 index 00000000..f030fec1 --- /dev/null +++ b/src/routes/utils/renderRoute.js @@ -0,0 +1,50 @@ +// src/routes/utils/renderRoute.js +// 路由渲染工具函数 + +import React from 'react'; +import { Route } from 'react-router-dom'; +import { LAYOUT_COMPONENTS } from '../constants'; +import { wrapWithProtection } from './wrapWithProtection'; + +/** + * 渲染单个路由 + * + * 根据路由配置项生成 React Router 的 Route 组件。 + * 处理以下逻辑: + * 1. 解析组件(特殊布局组件 vs 懒加载组件) + * 2. 应用路由保护(根据 protection 字段) + * 3. 生成唯一 key + * + * @param {Object} routeItem - 路由配置项(来自 routeConfig.js) + * @param {string} routeItem.path - 路由路径 + * @param {React.ComponentType|string} routeItem.component - 组件或组件标识符 + * @param {string} routeItem.protection - 保护模式 (modal/redirect/public) + * @param {number} index - 路由索引,用于生成唯一 key + * + * @returns {React.ReactElement} Route 组件 + * + * @example + * // 使用示例 + * const routes = [ + * { path: 'community', component: CommunityComponent, protection: 'modal' }, + * { path: 'auth/*', component: 'Auth', protection: 'public' }, + * ]; + * + * routes.map((route, index) => renderRoute(route, index)); + */ +export function renderRoute(routeItem, index) { + const { path, component, protection } = routeItem; + + // 解析组件: + // - 如果是字符串(如 'Auth', 'HomeLayout'),从 LAYOUT_COMPONENTS 映射表查找 + // - 否则直接使用(懒加载组件) + const Component = LAYOUT_COMPONENTS[component] || component; + + return ( + + ); +} diff --git a/src/routes/utils/wrapWithProtection.js b/src/routes/utils/wrapWithProtection.js new file mode 100644 index 00000000..c91bf751 --- /dev/null +++ b/src/routes/utils/wrapWithProtection.js @@ -0,0 +1,44 @@ +// src/routes/utils/wrapWithProtection.js +// 路由保护包装工具函数 + +import React from 'react'; +import { PROTECTION_WRAPPER_MAP } from '../constants'; + +/** + * 根据保护模式包装组件 + * + * 根据路由配置的保护模式,使用对应的保护组件包装目标组件。 + * 如果没有对应的保护组件(如 PUBLIC 模式),则直接返回原组件。 + * + * @param {React.ComponentType} Component - 要包装的组件 + * @param {string} protection - 保护模式 + * - 'modal': 使用 ProtectedRoute (弹窗登录) + * - 'redirect': 使用 ProtectedRouteRedirect (跳转登录) + * - 'public': 无保护,直接渲染 + * + * @returns {React.ReactElement} 包装后的组件元素 + * + * @example + * // PUBLIC 模式 - 无保护 + * wrapWithProtection(HomePage, 'public') + * // 返回: + * + * @example + * // MODAL 模式 - 弹窗登录 + * wrapWithProtection(Community, 'modal') + * // 返回: + */ +export function wrapWithProtection(Component, protection) { + const WrapperComponent = PROTECTION_WRAPPER_MAP[protection]; + + // 如果没有对应的保护组件(PUBLIC 模式),直接返回 + if (!WrapperComponent) { + return ; + } + + return ( + + + + ); +}