'use client'; import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { clearTokens, consumeHandoffCode, getMe, setTokens } from '@/lib/api'; import { useChatStore } from '@/lib/store'; const HANDOFF_STATE_KEY = 'nanobot_handoff_state'; type HandoffState = { code?: string; accessToken?: string; refreshToken?: string; nextPath?: string; }; function parseHandoffStateFromLocation(): HandoffState { if (typeof window === 'undefined') { return {}; } const query = new URLSearchParams(window.location.search); const code = query.get('code') || ''; const nextFromQuery = query.get('next') || ''; if (code) { return { code, nextPath: nextFromQuery || '/', }; } const rawHash = window.location.hash.startsWith('#') ? window.location.hash.slice(1) : window.location.hash; const hash = new URLSearchParams(rawHash); const accessToken = hash.get('access_token') || ''; if (accessToken) { return { accessToken, refreshToken: hash.get('refresh_token') || '', nextPath: hash.get('next') || '/', }; } return {}; } function loadHandoffState(): HandoffState { if (typeof window === 'undefined') { return {}; } const fromLocation = parseHandoffStateFromLocation(); if (fromLocation.code || fromLocation.accessToken) { sessionStorage.setItem(HANDOFF_STATE_KEY, JSON.stringify(fromLocation)); return fromLocation; } const cached = sessionStorage.getItem(HANDOFF_STATE_KEY) || ''; if (!cached) { return {}; } try { const parsed = JSON.parse(cached) as HandoffState; return parsed && typeof parsed === 'object' ? parsed : {}; } catch { return {}; } } function clearHandoffState(): void { if (typeof window === 'undefined') { return; } sessionStorage.removeItem(HANDOFF_STATE_KEY); } export default function HandoffPage() { const router = useRouter(); const setUser = useChatStore((s) => s.setUser); const [error, setError] = useState(''); useEffect(() => { let cancelled = false; const run = async () => { const handoff = loadHandoffState(); const nextPath = handoff.nextPath || '/'; if (!handoff.code && !handoff.accessToken) { clearHandoffState(); setError('缺少登录凭证,无法进入目标前端。'); return; } window.history.replaceState(null, '', '/handoff'); try { const tokenPayload = handoff.accessToken ? { access_token: handoff.accessToken, refresh_token: handoff.refreshToken || '', } : await consumeHandoffCode(handoff.code || ''); setTokens(tokenPayload.access_token, tokenPayload.refresh_token || ''); const me = await getMe(); if (cancelled) return; clearHandoffState(); setUser(me); router.replace(nextPath.startsWith('/') ? nextPath : '/'); } catch (err) { clearHandoffState(); clearTokens(); if (cancelled) return; setError(err instanceof Error ? err.message : '目标前端登录失败'); } }; void run(); return () => { cancelled = true; }; }, [router, setUser]); return (

正在进入目标前端...

{error ?

{error}

:

正在同步登录态,请稍候。

}
); }