"use client"; import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/navigation"; import { AlertTriangle, ShieldCheck } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/lib/api"; import { auth } from "@/lib/auth"; export default function LoginPage() { const router = useRouter(); const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); const [checking, setChecking] = useState(true); const [agreed, setAgreed] = useState(false); const [termsOpen, setTermsOpen] = useState(false); const [readToEnd, setReadToEnd] = useState(false); const termsBodyRef = useRef(null); // 滚动到条款底部(含无需滚动即可完整展示的情况)方可点击「同意」。 function handleTermsScroll() { const el = termsBodyRef.current; if (!el) return; if (el.scrollTop + el.clientHeight >= el.scrollHeight - 8) setReadToEnd(true); } useEffect(() => { if (!termsOpen) return; // 打开时重置,并处理内容本就不足一屏、无法触发滚动的场景。 setReadToEnd(false); const el = termsBodyRef.current; if (el && el.scrollHeight <= el.clientHeight + 8) setReadToEnd(true); }, [termsOpen]); useEffect(() => { // 已登录直接进主界面(静态导出下无 middleware 代劳这层跳转)。 const token = auth.getToken(); if (token) { // localStorage 可能仍有凭据但 cookie 已丢失。先同步,再发起全新请求, // 避免服务端守卫或路由缓存把跳转送回仍处于 checking 状态的登录页。 auth.setToken(token); window.location.replace("/function/tasks"); return; } api .authStatus() .then(({ initialized }) => { if (!initialized) router.replace("/setup"); }) .catch(() => setError("无法连接到后端服务")) .finally(() => setChecking(false)); }, [router]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!agreed) { setError("请先阅读并同意《使用须知》"); return; } setLoading(true); setError(""); try { const { token } = await api.login("ARTEX", password); auth.setToken(token); window.location.replace("/function/tasks"); } catch { setError("用户名或密码错误"); } finally { setLoading(false); } } if (checking) { return (
正在检查登录状态…
); } return (
{/* Left panel */}
{/* eslint-disable-next-line @next/next/no-img-element */} ARTEX
{/* Right panel */}

登录

欢迎回来,请输入密码以继续使用 ARTEX

setPassword(e.target.value)} placeholder="请输入密码" autoFocus autoComplete="current-password" />
setAgreed(v === true)} className="mt-0.5" />
{error &&

{error}

}
ARTEX 使用须知与免责声明

版本 v1.0 · 生效日期 2026-09-18 · 请在登录前完整阅读以下全部条款

本《使用须知与免责声明》(以下简称"本声明")是您与 ARTEX 项目作者及贡献者之间就使用本软件所达成的约定。请您在使用前审慎阅读、充分理解各条款内容,特别是以粗体或色块标注的免责、责任限制及禁止性条款。 {" "} 一旦您下载、安装、访问或以任何方式使用本软件,即视为您已阅读、理解并同意接受本声明的全部约束。

1 第一条 · 定义与开源许可

本软件(ARTEX)是一款基于 GNU Affero General Public License v3.0(AGPL-3.0)发布的开源程序。您可依据该协议自由使用、复制、修改和分发本软件;但任何衍生作品(包括通过网络向第三方提供的在线服务)均须同样以 AGPL-3.0 协议开源并向使用者公开对应的完整源代码。AGPL-3.0 完整条款以随附的 LICENSE 文件为准。

2 第二条 · 授权使用范围

本软件仅供个人学习、代码研究、安全技术原理探讨,以及在您自行搭建的本地隔离环境中进行技术验证之用,适用于学习、学术研究、代码审阅等非攻击性、非破坏性用途。除本条明确许可的情形外,您不得将本软件用于任何其他目的。

3 第三条 · 禁止行为

  • 严禁对任何网站、线上服务、他人或第三方所有的联网系统发起扫描、探测、利用或攻击(无论是否已获得授权、是否为您自有资产);
  • 严禁将本软件用于任何实际的渗透测试、攻防对抗、红蓝演练或生产环境;
  • 严禁将本软件用于非法入侵、数据窃取、勒索、拒绝服务(DoS/DDoS)或任何破坏性、犯罪性活动;
  • 严禁移除、篡改或规避本软件及其输出中的任何版权、许可或安全提示信息;
  • 严禁从事任何违反您所在国家或地区法律、法规及监管规定的行为。

4 第四条 · 知识产权

本软件的著作权及相关知识产权归项目作者及贡献者所有,并在 AGPL-3.0 协议约定的范围内向您授予相应权利。除该协议明确授予的权利外,本声明未以明示或默示方式授予您任何其他权利。

5 第五条 · 数据与隐私

本软件为可自行部署的开源程序,作者不运营任何集中式服务、亦不会收集或上传您的使用数据。您在使用过程中产生、处理或接触的一切数据,均由您自行掌控并负责其合法性与安全性;因数据处理不当引发的任何后果由您自行承担。

6 第六条 · 合规与法律责任

您应自行遵守所在国家或地区关于网络安全、数据安全与个人信息保护、计算机犯罪等方面的全部法律法规(在中国大陆包括但不限于《网络安全法》《数据安全法》《个人信息保护法》及相关司法解释)。 {" "} 因您违反上述法律法规或本声明约定而产生的一切法律责任与后果,均由您本人独立承担,与本软件作者及贡献者无关。

7 第七条 · 免责声明与责任限制

本软件按"现状(AS IS)"与"现有(AS AVAILABLE)"状态提供,不附带任何明示或默示的担保,包括但不限于对适销性、特定用途适用性、准确性及不侵权的担保。在适用法律允许的最大范围内,本软件作者及贡献者不对因使用或无法使用本软件(无论使用方式是否得当)而导致的任何直接、间接、偶然、特殊或后果性损失承担责任,包括但不限于数据丢失、系统损坏、业务中断、利润损失或法律纠纷。

8 第八条 · 条款变更与最终解释

作者有权根据法律法规或项目发展需要不时更新本声明,更新后的版本将随项目发布并自公布之日起生效;您继续使用本软件即视为接受修订后的条款。在法律允许的范围内,本声明的最终解释权归项目作者所有。若本声明任一条款被认定为无效,不影响其余条款的效力。

{readToEnd ? "您已浏览全部条款" : "请将条款滚动至底部后再确认"}

); }