增加密码
This commit is contained in:
@@ -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);
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user