diff --git a/web/src/App.tsx b/web/src/App.tsx index 032338a3..b3d0708c 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -37,7 +37,7 @@ function App() { const { checkJump } = useUser(); useEffect(() => { const authToken = cookieUtils.get('authToken') - if (!authToken && !window.location.hash.includes('#/login') && !window.location.hash.includes('#/conversation/')) { + if (!authToken && !window.location.hash.includes('#/login') && !window.location.hash.includes('#/conversation/') && !window.location.hash.includes('#/jump')) { window.location.href = `/#/login`; } else { checkJump() diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index 09479f59..13799d2a 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-02 16:33:11 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-02 16:33:11 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-04 18:11:34 */ /** * Route Configuration @@ -23,7 +23,6 @@ import { createHashRouter, createRoutesFromElements, Route } from 'react-router- /** Import route configuration JSON */ import routesConfig from './routes.json'; - /** Recursively collect all element names from routes */ function collectElements(routes: RouteConfig[]): Set { const elements = new Set(); @@ -88,6 +87,7 @@ const componentMap: Record>> = Ontology: lazy(() => import('@/views/Ontology')), OntologyDetail: lazy(() => import('@/views/Ontology/pages/Detail')), Prompt: lazy(() => import('@/views/Prompt')), + Jump: lazy(() => import('@/views/JumpPage')), Login: lazy(() => import('@/views/Login')), InviteRegister: lazy(() => import('@/views/InviteRegister')), NoPermission: lazy(() => import('@/views/NoPermission')), diff --git a/web/src/routes/routes.json b/web/src/routes/routes.json index b02ebddf..476766e0 100644 --- a/web/src/routes/routes.json +++ b/web/src/routes/routes.json @@ -53,7 +53,8 @@ { "element": "NoAuthLayout", "children": [ - { "path": "/conversation/:token", "element": "Conversation" } + { "path": "/conversation/:token", "element": "Conversation" }, + { "path": "/jump", "element": "Jump" } ] }, { diff --git a/web/src/store/user.ts b/web/src/store/user.ts index 505cb768..c9231d9c 100644 --- a/web/src/store/user.ts +++ b/web/src/store/user.ts @@ -1,8 +1,8 @@ /* * @Author: ZhaoYing * @Date: 2026-02-02 16:33:54 - * @Last Modified by: ZhaoYing - * @Last Modified time: 2026-02-02 16:33:54 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-04 18:30:10 */ /** * User Store @@ -59,7 +59,8 @@ export interface UserState { export const whitePage = [ '/conversation', '/login', - '/invite-register' + '/invite-register', + 'jump' ] /** User store */ diff --git a/web/src/views/JumpPage.tsx b/web/src/views/JumpPage.tsx new file mode 100644 index 00000000..d377b13d --- /dev/null +++ b/web/src/views/JumpPage.tsx @@ -0,0 +1,53 @@ +/* + * @Author: ZhaoYing + * @Date: 2026-02-04 18:34:36 + * @Last Modified by: ZhaoYing + * @Last Modified time: 2026-02-04 18:34:36 + */ +import { useEffect, type FC } from 'react' +import { useNavigate, useSearchParams } from 'react-router-dom' + +import { cookieUtils } from '@/utils/request' + +/** + * JumpPage Component + * + * This is an intermediate redirect page used for OAuth authentication flow. + * It handles the callback from external authentication providers by: + * 1. Extracting authentication tokens from URL query parameters + * 2. Storing tokens in cookies for subsequent API requests + * 3. Redirecting users to their intended destination + * + * Expected URL format: + * /jump?access_token=xxx&refresh_token=yyy&target=/dashboard + * + * @returns null - This component doesn't render any UI, it only handles side effects + */ +const JumpPage: FC = () => { + const navigate = useNavigate() + const [searchParams] = useSearchParams() + + useEffect(() => { + // Convert URLSearchParams to a plain object for easier access + const data = Object.fromEntries(searchParams) + const { access_token, refresh_token, target } = data + + // Store authentication tokens in cookies for API authorization + cookieUtils.set('access_token', access_token) + cookieUtils.set('refresh_token', refresh_token) + + // Redirect to the target page if specified + if (target) { + // Use setTimeout to ensure cookie operations complete before navigation + setTimeout(() => { + // Replace current history entry to prevent users from going back to this page + navigate(target, { replace: true }) + }, 0) + } + }, [searchParams, navigate]) + + // No UI rendering needed - this is a pure redirect handler + return null +} + +export default JumpPage \ No newline at end of file