增加密码

This commit is contained in:
dekun
2026-05-22 11:44:34 +08:00
parent 661305c26a
commit cd129b6a25
8 changed files with 704 additions and 141 deletions
+65 -12
View File
@@ -2,6 +2,34 @@
const toast = document.getElementById("toast");
let settingsCache = null;
let monitorTimer = null;
let authState = { required: false, logged_in: true };
async function apiFetch(url, opts) {
const r = await fetch(url, opts);
if (r.status === 401) {
const next = encodeURIComponent(location.pathname + location.search);
location.href = "/login?next=" + next;
throw new Error("未登录");
}
return r;
}
async function initAuth() {
try {
const r = await fetch("/api/auth/status");
authState = await r.json();
const btn = document.getElementById("btn-logout");
if (btn) btn.style.display = authState.required ? "" : "none";
if (authState.required && !authState.logged_in) {
location.href =
"/login?next=" + encodeURIComponent(location.pathname + location.search);
return false;
}
return true;
} catch (_) {
return true;
}
}
function showToast(msg, isErr) {
toast.textContent = msg;
@@ -63,7 +91,7 @@
}
async function loadSettings() {
const r = await fetch("/api/settings");
const r = await apiFetch("/api/settings");
settingsCache = await r.json();
return settingsCache;
}
@@ -75,11 +103,18 @@
async function loadMonitorBoard() {
const box = document.getElementById("monitor-grid");
try {
const r = await fetch("/api/monitor/board");
const r = await apiFetch("/api/monitor/board");
const data = await r.json();
const rows = data.rows || [];
const online = rows.filter((x) => x.http_ok && (x.agent || {}).ok !== false).length;
const pill = document.getElementById("sys-status");
if (pill) {
pill.textContent = rows.length ? `LINK ${online}/${rows.length}` : "NO DATA";
pill.classList.toggle("warn", rows.length && online < rows.length);
}
document.getElementById("monitor-updated").textContent =
"更新于 " + (data.updated_at || "").replace("T", " ");
const parts = (data.rows || []).map(renderMonitorCard);
"UPD " + (data.updated_at || "").replace("T", " ");
const parts = rows.map(renderMonitorCard);
box.innerHTML = parts.join("") || '<div class="err">无已启用账户</div>';
box.querySelectorAll(".btn-close-ex").forEach((btn) => {
btn.onclick = () => closeOne(btn.dataset.id);
@@ -164,6 +199,9 @@
});
}
}
const online = row.http_ok && agOk;
const cardCls = online ? "card-online" : "card-offline";
const dotCls = online ? "ok" : "bad";
const review = row.review_url
? `<a class="btn-link" href="${esc(row.review_url)}" target="_blank" rel="noopener">复盘</a>`
: "";
@@ -171,10 +209,13 @@
const openFlask = flaskOpen
? `<a class="btn-link" href="${esc(flaskOpen)}" target="_blank" rel="noopener">实例</a>`
: "";
return `<div class="card">
return `<div class="card ${cardCls}">
<div class="card-head">
<div>
<div class="card-title">${esc(row.name)}</div>
<div class="card-title-row">
<span class="status-dot ${dotCls}" title="${online ? "在线" : "离线"}"></span>
<div class="card-title">${esc(row.name)}</div>
</div>
<div class="card-sub">${esc(flaskOpen || "")}</div>
</div>
<div class="card-actions">
@@ -190,7 +231,7 @@
async function closeOne(id) {
if (!confirm("确认对该账户市价全平?")) return;
try {
const r = await fetch("/api/close/" + encodeURIComponent(id), { method: "POST" });
const r = await apiFetch("/api/close/" + encodeURIComponent(id), { method: "POST" });
const j = await r.json();
showToast(JSON.stringify(j, null, 2), !r.ok);
loadMonitorBoard();
@@ -203,7 +244,7 @@
const n = enabledAccounts().length;
if (!confirm(`${n} 个已启用账户执行紧急全平?`)) return;
try {
const r = await fetch("/api/close-all", {
const r = await apiFetch("/api/close-all", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ exclude_ids: [] }),
@@ -218,11 +259,13 @@
async function loadSettingsMetaLine() {
try {
const r = await fetch("/api/settings/meta");
const r = await apiFetch("/api/settings/meta");
const m = await r.json();
const el = document.getElementById("settings-meta-line");
if (!el) return;
const parts = [];
if (m.password_required) parts.push("已启用 HUB_PASSWORD 登录保护");
else parts.push("未设 HUB_PASSWORD(反代公网暴露时建议设置)");
if (m.hub_bridge_token_set) parts.push("中控已配置 HUB_BRIDGE_TOKEN");
else parts.push("中控未设 HUB_BRIDGE_TOKEN(实例需 APP_AUTH_DISABLED 或同令牌)");
if (m.public_origin) parts.push("浏览器外链基址: " + m.public_origin);
@@ -305,7 +348,7 @@
async function saveSettings() {
const body = collectSettingsFromUI();
try {
const r = await fetch("/api/settings", {
const r = await apiFetch("/api/settings", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
@@ -320,6 +363,13 @@
}
}
document.getElementById("btn-logout").onclick = async () => {
try {
await fetch("/api/auth/logout", { method: "POST" });
} catch (_) {}
location.href = "/login";
};
document.getElementById("btn-monitor-refresh").onclick = loadMonitorBoard;
document.getElementById("auto-monitor").onchange = startMonitorPoll;
document.getElementById("btn-close-all").onclick = closeAll;
@@ -342,6 +392,9 @@
loadSettingsUI();
};
setActiveNav();
window.addEventListener("popstate", setActiveNav);
initAuth().then((ok) => {
if (!ok) return;
setActiveNav();
window.addEventListener("popstate", setActiveNav);
});
})();