106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
"use client";
|
||
|
||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||
import { useEffect, useMemo, useState } from "react";
|
||
|
||
import { useTheme } from "@/contexts/ThemeContext";
|
||
import { loginByUsername } from "@/core/auth/api";
|
||
import { setStoredAuth } from "@/core/auth";
|
||
import {
|
||
persistExternalLoginParams,
|
||
resolveThemeFromQuery,
|
||
} from "@/core/auth/external-login";
|
||
import {
|
||
isSidebarEnabledFromSearch,
|
||
persistSidebarEnabled,
|
||
} from "@/core/page-layout/sidebar-enabled";
|
||
|
||
const DEFAULT_USERNAME = "guest";
|
||
|
||
type LoginStatus = "loading" | "success" | "error";
|
||
|
||
export default function LoginPage() {
|
||
const { username } = useParams<{ username?: string }>();
|
||
const router = useRouter();
|
||
const searchParams = useSearchParams();
|
||
const { setTheme } = useTheme();
|
||
const sidebarEnabled = useMemo(
|
||
() => isSidebarEnabledFromSearch(searchParams.toString()),
|
||
[searchParams],
|
||
);
|
||
const resolvedUsername = useMemo(() => {
|
||
const raw = username?.trim();
|
||
return raw && raw.length > 0 ? raw : DEFAULT_USERNAME;
|
||
}, [username]);
|
||
// 外部跳转参数:theme 直接调 setTheme;ticket/userId/env 持久化到 localStorage
|
||
const externalParams = useMemo(() => ({
|
||
theme: searchParams.get("theme") ?? "",
|
||
ticket: searchParams.get("ticket") ?? "",
|
||
userId: searchParams.get("userId") ?? "",
|
||
env: searchParams.get("env") ?? "",
|
||
}), [searchParams]);
|
||
const [status, setStatus] = useState<LoginStatus>("loading");
|
||
const [errorMessage, setErrorMessage] = useState<string>("");
|
||
|
||
// 主题切换:theme=dark-blue → 深色,其他值或缺省 → 浅色
|
||
useEffect(() => {
|
||
if (!externalParams.theme) return;
|
||
setTheme(resolveThemeFromQuery(externalParams.theme));
|
||
}, [externalParams.theme, setTheme]);
|
||
|
||
// ticket / userId / env 持久化(与 login 请求并行做,互不阻塞)
|
||
useEffect(() => {
|
||
persistExternalLoginParams({
|
||
ticket: externalParams.ticket,
|
||
userId: externalParams.userId,
|
||
env: externalParams.env,
|
||
});
|
||
}, [externalParams.ticket, externalParams.userId, externalParams.env]);
|
||
|
||
useEffect(() => {
|
||
let cancelled = false;
|
||
|
||
async function runLogin() {
|
||
setStatus("loading");
|
||
setErrorMessage("");
|
||
try {
|
||
const auth = await loginByUsername(resolvedUsername);
|
||
if (cancelled) {
|
||
return;
|
||
}
|
||
setStoredAuth(auth);
|
||
persistSidebarEnabled(sidebarEnabled);
|
||
setStatus("success");
|
||
router.replace("/page/workspace/chats/new");
|
||
} catch (error) {
|
||
if (cancelled) {
|
||
return;
|
||
}
|
||
setStatus("error");
|
||
setErrorMessage(
|
||
error instanceof Error ? error.message : "Login request failed.",
|
||
);
|
||
}
|
||
}
|
||
|
||
void runLogin();
|
||
return () => {
|
||
cancelled = true;
|
||
};
|
||
}, [resolvedUsername, router, sidebarEnabled]);
|
||
|
||
return (
|
||
<div className="flex min-h-screen items-center justify-center bg-background px-6">
|
||
<div className="w-full max-w-lg rounded-xl border bg-card p-6 shadow-sm">
|
||
<h1 className="text-xl font-semibold">正在进入智能体模式</h1>
|
||
{status === "error" && (
|
||
<p className="mt-4 text-sm text-red-600">
|
||
登录失败:{errorMessage || "未知错误"}
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|