This commit is contained in:
2026-04-27 01:42:47 +08:00
parent e30292e330
commit 384d7e4838
2 changed files with 281 additions and 35 deletions

View File

@@ -722,6 +722,9 @@
</style>
</head>
<body>
{% if need_auth_banner %}
<div class="shell"><p class="banner-warn" role="alert">该操作需要控制台密码:请点击右上角任意按钮,在弹出框中输入密码后再试。</p></div>
{% endif %}
{% if error %}
<div class="shell"><p class="banner-warn" role="alert">列表加载提示:{{ error }}</p></div>
{% endif %}
@@ -760,6 +763,11 @@
<button type="button" class="btn-ghost" data-open="channels">频道管理</button>
<button type="button" class="btn-ghost" data-open="config">环境配置</button>
<button type="button" class="btn-ghost" data-open="logs">运行日志</button>
{% if console_authed %}
<form method="post" action="/auth/console/logout" style="margin:0;">
<button type="submit" class="btn-ghost">退出验证</button>
</form>
{% endif %}
</div>
</header>
@@ -821,6 +829,26 @@
</div>
</div>
<dialog class="modal" id="dlg-console-auth" aria-labelledby="dlg-console-auth-title">
<div class="modal-head">
<h2 id="dlg-console-auth-title">控制台密码验证</h2>
<button type="button" class="modal-close" data-close>关闭</button>
</div>
<div class="modal-body">
<p class="hint">须验证通过后才能打开「连接 / 常规操作 / 频道管理 / 环境配置 / 运行日志」等面板。请在服务器环境变量中设置 <code>WEB_CONSOLE_PASSWORD</code>(未设置时使用程序内置默认值)。务必设置随机长字符串 <code>WEB_CONSOLE_SESSION_SECRET</code> 用于会话签名,勿泄露。</p>
<form id="form-console-auth" class="config-form">
<div class="field-row">
<label for="console-auth-password">密码</label>
<input type="password" id="console-auth-password" name="password" autocomplete="current-password" />
</div>
<div class="config-actions">
<button type="submit" class="btn-primary">验证并继续</button>
</div>
</form>
<p id="console-auth-err" class="banner-warn" style="display:none;margin-top:12px;" role="alert"></p>
</div>
</dialog>
<dialog class="modal" id="dlg-conn" aria-labelledby="dlg-conn-title">
<div class="modal-head">
<h2 id="dlg-conn-title">连接与持续抓取</h2>
@@ -945,7 +973,7 @@
</form>
{% else %}
<div class="list" role="list">
<div class="line" role="listitem">请先连接 Telegram 后刷新本页加载列表</div>
<div class="line" role="listitem">{% if not console_authed %}请先通过右上角验证(输入密码)后刷新本页以加载账号频道列表。{% else %}请先连接 Telegram 后刷新本页加载列表{% endif %}</div>
</div>
{% endif %}
</div>
@@ -1003,7 +1031,7 @@
<button type="button" class="modal-close" data-close>关闭</button>
</div>
<div class="modal-body">
<pre id="logs-box" tabindex="0" aria-label="运行日志">{{ logs }}</pre>
<pre id="logs-box" tabindex="0" aria-label="运行日志">{% if logs %}{{ logs }}{% else %}(验证通过前不展示日志内容;验证后刷新或等待自动刷新。){% endif %}</pre>
</div>
</dialog>
@@ -1014,14 +1042,93 @@
return Number(n).toLocaleString("zh-CN");
}
function openDialogById(id) {
var el = document.getElementById(id);
if (el && typeof el.showModal === "function") el.showModal();
}
async function consoleAuthStatus() {
try {
var r = await fetch("/auth/console/status", { credentials: "same-origin" });
if (!r.ok) return false;
var j = await r.json();
return j.ok === true;
} catch (_e) {
return false;
}
}
var pendingOpenDlgId = null;
document.querySelectorAll("[data-open]").forEach(function (btn) {
btn.addEventListener("click", function () {
var id = "dlg-" + btn.getAttribute("data-open");
var el = document.getElementById(id);
if (el && typeof el.showModal === "function") el.showModal();
btn.addEventListener("click", async function () {
var key = btn.getAttribute("data-open");
var dlgId = "dlg-" + key;
if (!await consoleAuthStatus()) {
pendingOpenDlgId = dlgId;
openDialogById("dlg-console-auth");
return;
}
openDialogById(dlgId);
});
});
(function () {
var authForm = document.getElementById("form-console-auth");
var authErr = document.getElementById("console-auth-err");
var authPwd = document.getElementById("console-auth-password");
if (!authForm) return;
authForm.addEventListener("submit", async function (ev) {
ev.preventDefault();
if (authErr) {
authErr.style.display = "none";
authErr.textContent = "";
}
var pw = authPwd ? authPwd.value : "";
try {
var res = await fetch("/auth/console/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "same-origin",
body: JSON.stringify({ password: pw }),
});
var data = await res.json().catch(function () { return ({}); });
if (res.ok && data.ok) {
var authDlg = document.getElementById("dlg-console-auth");
if (authDlg) authDlg.close();
var tail = "";
if (pendingOpenDlgId) {
tail = "?opendlg=" + encodeURIComponent(pendingOpenDlgId.replace(/^dlg-/, ""));
pendingOpenDlgId = null;
}
if (authPwd) authPwd.value = "";
window.location.href = "/" + tail;
} else {
if (authErr) {
authErr.textContent = (data && data.error) ? data.error : "验证失败";
authErr.style.display = "block";
}
}
} catch (_e) {
if (authErr) {
authErr.textContent = "网络错误";
authErr.style.display = "block";
}
}
});
})();
(function () {
var p = new URLSearchParams(window.location.search);
var o = p.get("opendlg");
if (!o) return;
var el = document.getElementById("dlg-" + o);
if (el && typeof el.showModal === "function") el.showModal();
p.delete("opendlg");
var clean = window.location.pathname + (p.toString() ? "?" + p.toString() : "");
history.replaceState(null, "", clean);
})();
document.querySelectorAll("[data-close]").forEach(function (btn) {
btn.addEventListener("click", function () {
var d = btn.closest("dialog");
@@ -1200,7 +1307,7 @@
async function refreshStatus() {
try {
var statusResp = await fetch("/api/jobs/status");
var statusResp = await fetch("/api/jobs/status", { credentials: "same-origin" });
if (statusResp.ok) {
var status = await statusResp.json();
var runningEl = document.getElementById("job-running");
@@ -1248,7 +1355,7 @@
}
}
var channelsResp = await fetch("/api/channels/monitored");
var channelsResp = await fetch("/api/channels/monitored", { credentials: "same-origin" });
if (channelsResp.ok) {
var payload = await channelsResp.json();
var wrap = document.getElementById("monitored-list");