diff --git a/web/src/app/(auth)/login/page.tsx b/web/src/app/(auth)/login/page.tsx index 4a373e5..851522b 100644 --- a/web/src/app/(auth)/login/page.tsx +++ b/web/src/app/(auth)/login/page.tsx @@ -1,10 +1,14 @@ "use client"; -import { useEffect, useState } from "react"; +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"; @@ -16,6 +20,25 @@ export default function LoginPage() { 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 代劳这层跳转)。 @@ -38,6 +61,10 @@ export default function LoginPage() { async function handleSubmit(e: React.FormEvent) { e.preventDefault(); + if (!agreed) { + setError("请先阅读并同意《使用须知》"); + return; + } setLoading(true); setError(""); try { @@ -96,13 +123,191 @@ export default function LoginPage() { 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 ? "您已浏览全部条款" : "请将条款滚动至底部后再确认"} +

+ + + +
+
+
); }