<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="UTF-8" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<title>登录 - Board</title>
|
<link rel="stylesheet" href="<%= basePath %>/static/style.css" />
|
</head>
|
<body class="page-login">
|
<main class="card">
|
<h1>Board 门户</h1>
|
<p class="muted">请使用域账号登录</p>
|
<form id="loginForm" class="form" autocomplete="on">
|
<label>
|
<span>用户名</span>
|
<input type="text" name="username" required autofocus />
|
</label>
|
<label>
|
<span>密码</span>
|
<input type="password" name="password" required />
|
</label>
|
<p id="loginError" class="error" hidden></p>
|
<button type="submit" class="btn primary">登录</button>
|
</form>
|
</main>
|
<script>
|
(function () {
|
const params = new URLSearchParams(location.search);
|
const next = params.get("next") || "<%= basePath %>/";
|
const form = document.getElementById("loginForm");
|
const err = document.getElementById("loginError");
|
form.addEventListener("submit", async (e) => {
|
e.preventDefault();
|
err.hidden = true;
|
const fd = new FormData(form);
|
const body = {
|
username: fd.get("username"),
|
password: fd.get("password"),
|
next: next.startsWith("<%= basePath %>/") ? next : "<%= basePath %>/",
|
};
|
const res = await fetch("<%= basePath %>/api/login", {
|
method: "POST",
|
headers: { "Content-Type": "application/json" },
|
credentials: "include",
|
body: JSON.stringify(body),
|
});
|
const data = await res.json().catch(() => ({}));
|
if (!res.ok || !data.ok) {
|
err.textContent = data.error || "登录失败";
|
err.hidden = false;
|
return;
|
}
|
location.href = data.redirect || "<%= basePath %>/";
|
});
|
})();
|
</script>
|
</body>
|
</html>
|