diff --git a/frontend-web/src/pages/LoginPage.tsx b/frontend-web/src/pages/LoginPage.tsx index 8aa6a45b..0662c5bd 100644 --- a/frontend-web/src/pages/LoginPage.tsx +++ b/frontend-web/src/pages/LoginPage.tsx @@ -82,6 +82,17 @@ export default function LoginPage() { // 任务深链:外部系统带 ?taskId=&goPath= 时,登录后拉任务详情并直送对应问答/会商页 const taskId = searchParams.get('taskId')?.trim() ?? ''; const goPath = searchParams.get('goPath')?.trim() ?? ''; + // 通用「登录后跳指定页」:?redirect=page/strategy/dashboard-agent(值可不带前导斜杠, + // 也可自带 query,如 page/strategy/dashboard-agent?taskId=1580——记得整体 URL 编码)。 + // 优先级最高:显式指定即按它跳,先于 taskId/goPath 深链与默认首页。出于安全只接受**站内 + // 相对路径**:拒绝带协议的绝对 URL(http(s):、javascript: 等)、协议相对 URL(//host)与反斜杠, + // 避免开放式跳转;缺前导斜杠时自动补全。 + const redirectTo = useMemo(() => { + const raw = searchParams.get('redirect')?.trim() ?? ''; + if (!raw) return ''; + if (/^[a-z][a-z0-9+.-]*:/i.test(raw) || raw.startsWith('//') || raw.includes('\\')) return ''; + return raw.startsWith('/') ? raw : `/${raw}`; + }, [searchParams]); const externalParams = useMemo( () => ({ theme: searchParams.get('theme') ?? '', @@ -186,6 +197,13 @@ export default function LoginPage() { if (!isEmbed) persistSidebarEnabled(sidebarEnabled); setStatus('success'); + // 通用跳转:显式 ?redirect= 指定站内页面时,登录后直接跳过去(优先级最高, + // 先于 taskId/goPath 深链与默认首页)。value 自带的 query 会被原样保留。 + if (redirectTo) { + navigate(redirectTo, { replace: true }); + return; + } + // 任务深链:带 taskId + goPath 时拉任务详情并直送对应问答/会商页; // 任一环节失败(无地址/拉取失败/未配置智能体/goPath 无法识别)都回退默认首页。 if (taskId && goPath) { @@ -238,6 +256,7 @@ export default function LoginPage() { gatePassword, taskId, goPath, + redirectTo, isEmbed, ]);