Files
crypto_monitor/manual_trading_hub/static/login.html
T
2026-05-22 11:49:41 +08:00

79 lines
3.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>登录 · 复盘系统中控</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Orbitron:wght@500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/assets/app.css" />
</head>
<body class="login-page">
<div class="login-bg" aria-hidden="true"></div>
<div class="login-panel">
<div class="login-brand">
<span class="brand-mark"></span>
<div>
<div class="login-title">复盘系统中控</div>
<div class="login-sub">CRYPTO MONITOR · COMMAND</div>
</div>
</div>
<form id="login-form" class="login-form" autocomplete="on">
<label class="field">
<span>用户名</span>
<input type="text" name="username" id="login-username" required autocomplete="username" placeholder="HUB_USERNAME" />
</label>
<label class="field">
<span>密码</span>
<input type="password" name="password" id="login-password" required autocomplete="current-password" placeholder="HUB_PASSWORD" />
</label>
<button type="submit" class="primary login-submit">进入系统</button>
<p id="login-err" class="login-err" hidden></p>
</form>
<p class="login-foot">在 hub <code>.env</code> 设置 <code>HUB_USERNAME</code><code>HUB_PASSWORD</code>(未设用户名时默认为 <code>admin</code></p>
</div>
<script>
(function () {
const form = document.getElementById("login-form");
const err = document.getElementById("login-err");
const userInput = document.getElementById("login-username");
const params = new URLSearchParams(location.search);
const next = params.get("next") || "/monitor";
fetch("/api/auth/status")
.then((r) => r.json())
.then((s) => {
if (!s.required || s.logged_in) location.href = next;
if (s.username_hint && !userInput.value) userInput.value = s.username_hint;
})
.catch(() => {});
form.onsubmit = async (e) => {
e.preventDefault();
err.hidden = true;
const username = userInput.value.trim();
const password = document.getElementById("login-password").value;
try {
const r = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, password }),
});
const j = await r.json().catch(() => ({}));
if (r.ok && j.ok) {
location.href = next.startsWith("/") ? next : "/monitor";
return;
}
err.textContent = j.detail || j.msg || "用户名或密码错误";
err.hidden = false;
} catch (ex) {
err.textContent = String(ex);
err.hidden = false;
}
};
})();
</script>
</body>
</html>