import { useEffect, useState } from "react"; import { useActionData, useLoaderData, Form } from "@remix-run/react"; import { type MetaFunction, type LoaderFunctionArgs, type ActionFunctionArgs, redirect } from "@remix-run/node"; import { OAuthClient } from "~/api/login/oauth-client"; import { CLIENT_OAUTH_CONFIG } from "~/config/api-config"; import { getUserSession, getSession, simpleRootLogin } from "~/api/login/auth.server"; import styles from "~/styles/pages/login.css?url"; import { toastService } from "~/components/ui"; export const links = () => [ { rel: "stylesheet", href: styles } ]; export const meta: MetaFunction = () => { return [ { title: "中国烟草AI合同及卷宗审核系统 - 登录" }, { name: "description", content: "中国烟草AI合同及卷宗审核系统登录页面" }, ]; }; // 加载器,获取当前会话状态 export async function loader({ request }: LoaderFunctionArgs) { const { isAuthenticated } = await getUserSession(request); // 如果已登录,重定向到首页 if (isAuthenticated) { return redirect("/"); } // 获取重定向URL并保存到session const url = new URL(request.url); const redirectTo = url.searchParams.get("redirect") || "/"; const session = await getSession(request); // 读取 flash 消息(来自 callback 的错误) const loginError = session.get("loginError"); session.set("redirectTo", redirectTo); // 提交 session 以清除 flash 消息 if (loginError) { const { sessionStorage } = await import("~/api/login/auth.server"); return Response.json({ isAuthenticated: false, redirectTo, flashError: loginError }, { headers: { "Set-Cookie": await sessionStorage.commitSession(session) } }); } return Response.json({ isAuthenticated: false, redirectTo, flashError: null }); } // 处理表单提交的action函数 export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); const intent = formData.get("intent"); const username = formData.get("username")?.toString().trim(); const password = formData.get("password")?.toString().trim(); if (intent === "password_login") { // 获取重定向目标 const session = await getSession(request); const redirectTo = session.get("redirectTo") || "/"; // 调用 simpleRootLogin 方法进行登录 const response = await simpleRootLogin(username || "", password || "", redirectTo); // 检查响应状态 if (response.status === 302) { // 登录成功,直接返回重定向响应 return response; } else { // 登录失败,返回错误信息(不再使用URL参数) const errorData = await response.json(); return Response.json({ success: false, error: errorData.error || "登录失败", retryCount: errorData.retryCount || 0, isLocked: errorData.isLocked || false, remainingAttempts: errorData.remainingAttempts || 5 }, { status: response.status }); } } return null; } export default function Login() { const actionData = useActionData(); const loaderData = useLoaderData(); const [isFlipped, setIsFlipped] = useState(false); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); // 从 actionData 或 loaderData 中获取错误信息 // actionData 的错误优先(来自密码登录) // loaderData.flashError 次之(来自 OAuth 回调) const error = actionData?.error || loaderData?.flashError; const isLocked = actionData?.isLocked || false; const retryCount = actionData?.retryCount || 0; const remainingAttempts = actionData?.remainingAttempts || 5; // 处理OAuth2.0登录 const handleOAuthLogin = () => { try { // 创建OAuth客户端(使用客户端安全配置,不包含 clientSecret) const oauthClient = new OAuthClient(CLIENT_OAUTH_CONFIG); // 生成状态值 const state = oauthClient.generateState(); // 将状态值保存到localStorage(用于后续验证) localStorage.setItem("oauth_state", state); // 获取授权URL const authorizeUrl = oauthClient.getAuthorizeUrl(state); console.log("授权URL:", authorizeUrl); // 重定向到IDaaS登录页面 window.location.href = authorizeUrl; } catch (error) { console.error("启动OAuth2.0登录失败:", error); alert("登录系统初始化失败,请联系系统管理员"); } }; // 处理管理员登录 const handleAdminLogin = () => { setIsFlipped(true); }; // 处理返回OAuth登录 const handleBackToOAuth = () => { setIsFlipped(false); setUsername(""); setPassword(""); }; // 处理账号密码登录表单提交 const handlePasswordLoginSubmit = (e: React.FormEvent) => { // 检查账户是否被锁定 if (isLocked) { e.preventDefault(); toastService.error("账户已被锁定,请联系管理员"); return; } // 客户端验证 if (!username.trim()) { e.preventDefault(); toastService.error("请输入用户名"); return; } if (!password.trim()) { e.preventDefault(); toastService.error("请输入密码"); return; } // 验证通过,让表单正常提交 }; useEffect(() => { // 检查OAuth配置是否完整(客户端不需要检查 clientSecret) if (!CLIENT_OAUTH_CONFIG.serverUrl || !CLIENT_OAUTH_CONFIG.clientId) { console.error("OAuth2.0配置不完整:", CLIENT_OAUTH_CONFIG); } }, []); return (
{/* 正面 - OAuth登录 */}

中国烟草AI合同及卷宗审核系统

统一身份认证登录

{error && (
{isLocked ? ( ) : ( )}
{error} {!isLocked && retryCount > 0 && (
剩余尝试次数:{remainingAttempts} 次
)}
)}

请点击下方按钮进行统一身份认证登录

系统将跳转到统一身份认证平台进行登录

{/* 管理员登录链接 */}

© 2025 中国烟草 版权所有

{/* 背面 - 管理员登录 */}

中国烟草AI合同及卷宗审核系统

管理员登录

{error && (
{isLocked ? ( ) : ( )}
{error} {!isLocked && retryCount > 0 && (
剩余尝试次数:{remainingAttempts} 次
)}
)}
setUsername(e.target.value)} className="form-input" placeholder="请输入用户名" required />
setPassword(e.target.value)} className="form-input" placeholder="请输入密码" required />
{isLocked && (
账户已被锁定,请联系管理员解锁
)}

© 2025 中国烟草 版权所有

); }