This commit is contained in:
2026-04-27 12:06:02 +08:00
parent ff022bce5d
commit cf64bc4703
2 changed files with 197 additions and 6 deletions

View File

@@ -801,6 +801,58 @@ async def save_config(request: Request):
return RedirectResponse(url=app_home_url(), status_code=303)
def _logs_tail(n: int = 50) -> List[str]:
return list(service.logs)[-n:] if service.logs else []
@app.post("/api/session/init")
async def api_session_init(request: Request):
"""JSON 初始化:便于面板内展示结果,避免仅依赖 303 与整页刷新排错。"""
denied = json_if_console_unauthed(request)
if denied:
return denied
try:
await service.ensure_ready()
return {
"ok": True,
"connected": service.is_connected(),
"message": "Telegram 客户端已就绪。",
"logs_tail": _logs_tail(50),
}
except Exception as e:
msg = str(e)
service._append(f"初始化失败:{msg}")
return {
"ok": False,
"connected": service.is_connected(),
"error": msg,
"logs_tail": _logs_tail(50),
}
@app.post("/api/session/disconnect")
async def api_session_disconnect(request: Request):
denied = json_if_console_unauthed(request)
if denied:
return denied
try:
await service.disconnect()
return {
"ok": True,
"connected": service.is_connected(),
"message": "已断开 Telegram。",
"logs_tail": _logs_tail(50),
}
except Exception as e:
service._append(f"断开失败:{e}")
return {
"ok": False,
"connected": service.is_connected(),
"error": str(e),
"logs_tail": _logs_tail(50),
}
@app.post("/start")
async def start_scraper(request: Request):
redir = redirect_if_console_unauthed(request)

View File

@@ -868,13 +868,18 @@
{% if error %}
<p class="alert-warn" role="alert">客户端:{{ error }}</p>
{% endif %}
<p class="hint" style="margin-bottom:12px;">
初始化可能较慢(网络、扫码登录等)。结果会显示在下方灰色框内,无需只看浏览器网络里的 303
无头登录请开 <code>TELEGRAM_HEADLESS_QR=1</code> 并在<strong>运行日志</strong>中打开二维码链接。
</p>
<div id="conn-action-result" class="list" style="display:none;margin-bottom:14px;max-height:200px;font-size:0.8125rem;" role="status" aria-live="polite"></div>
<div class="btn-row">
<form method="post" action="{{ app_url('/start') }}">
<button class="btn-primary" type="submit">初始化 / 连接 Telegram</button>
</form>
<form method="post" action="{{ app_url('/stop') }}">
<button class="btn-danger" type="submit">断开 Telegram</button>
</form>
<div>
<button class="btn-primary" type="button" id="btn-session-init">初始化 / 连接 Telegram</button>
</div>
<div>
<button class="btn-danger" type="button" id="btn-session-disconnect">断开 Telegram</button>
</div>
<form method="post" action="{{ app_url('/jobs/continuous/start') }}">
<button class="btn-primary" type="submit">启动持续抓取(含心跳)</button>
</form>
@@ -1401,6 +1406,140 @@
setInterval(refreshStatus, 3000);
(function () {
var initBtn = document.getElementById("btn-session-init");
var discBtn = document.getElementById("btn-session-disconnect");
var out = document.getElementById("conn-action-result");
if (!initBtn || !out) return;
function showConnResult(html, isErr) {
out.style.display = "block";
out.innerHTML = html;
out.style.borderColor = isErr ? "rgba(239,68,68,0.45)" : "rgba(34,197,94,0.35)";
}
function renderInitPayload(data, httpStatus) {
var ok = data && data.ok === true;
var lines = [];
if (ok) {
lines.push(
"<p class=\"line\" style=\"margin:0 0 8px;color:#86efac;font-weight:600;\">成功:" +
escapeHtml(data.message || "已就绪") +
"</p>"
);
lines.push(
"<p class=\"line\" style=\"margin:0 0 4px;color:#94a3b8;\">连接状态:" +
(data.connected ? "已连接" : "未连接(请查看日志)") +
"</p>"
);
} else {
var errText =
(data && data.error) ||
(httpStatus && httpStatus !== 200 ? "HTTP " + httpStatus : "") ||
"未知错误";
lines.push(
"<p class=\"line\" style=\"margin:0 0 8px;color:#fca5a5;font-weight:600;\">失败:" +
escapeHtml(String(errText)) +
"</p>"
);
lines.push(
"<p class=\"line\" style=\"margin:0 0 4px;color:#94a3b8;\">连接状态:" +
(data && data.connected ? "已连接" : "未连接") +
"</p>"
);
}
if (data && data.logs_tail && data.logs_tail.length) {
lines.push(
"<pre style=\"margin:8px 0 0;font-size:0.75rem;color:#bae6fd;white-space:pre-wrap;word-break:break-word;\">" +
escapeHtml(data.logs_tail.join("\n")) +
"</pre>"
);
}
return { html: lines.join(""), isErr: !ok };
}
initBtn.addEventListener("click", async function () {
initBtn.disabled = true;
if (discBtn) discBtn.disabled = true;
showConnResult("<p class=\"line\" style=\"margin:0;color:#94a3b8;\">正在连接,请稍候(扫码场景可能需数分钟)…</p>", false);
try {
var res = await fetch(appPath("/api/session/init"), {
method: "POST",
credentials: "same-origin",
headers: { Accept: "application/json" },
});
var data = await res.json().catch(function () {
return {};
});
var r = renderInitPayload(data, res.status);
showConnResult(r.html, r.isErr);
await refreshStatus();
} catch (e) {
showConnResult(
"<p class=\"line\" style=\"margin:0;color:#fca5a5;\">请求失败:" +
escapeHtml(e && e.message ? e.message : String(e)) +
"</p>",
true
);
} finally {
initBtn.disabled = false;
if (discBtn) discBtn.disabled = false;
}
});
if (discBtn) {
discBtn.addEventListener("click", async function () {
initBtn.disabled = true;
discBtn.disabled = true;
showConnResult("<p class=\"line\" style=\"margin:0;color:#94a3b8;\">正在断开…</p>", false);
try {
var res = await fetch(appPath("/api/session/disconnect"), {
method: "POST",
credentials: "same-origin",
headers: { Accept: "application/json" },
});
var data = await res.json().catch(function () {
return {};
});
var ok = data && data.ok === true;
var lines = [];
if (ok) {
lines.push(
"<p class=\"line\" style=\"margin:0 0 8px;color:#86efac;font-weight:600;\">" +
escapeHtml(data.message || "已断开") +
"</p>"
);
} else {
lines.push(
"<p class=\"line\" style=\"margin:0;color:#fca5a5;font-weight:600;\">失败:" +
escapeHtml((data && data.error) || "未知错误") +
"</p>"
);
}
if (data && data.logs_tail && data.logs_tail.length) {
lines.push(
"<pre style=\"margin:8px 0 0;font-size:0.75rem;color:#bae6fd;white-space:pre-wrap;word-break:break-word;\">" +
escapeHtml(data.logs_tail.join("\n")) +
"</pre>"
);
}
showConnResult(lines.join(""), !ok);
await refreshStatus();
} catch (e) {
showConnResult(
"<p class=\"line\" style=\"margin:0;color:#fca5a5;\">请求失败:" +
escapeHtml(e && e.message ? e.message : String(e)) +
"</p>",
true
);
} finally {
initBtn.disabled = false;
discBtn.disabled = false;
}
});
}
})();
(function () {
var form = document.querySelector(".account-pick-form");
if (!form) return;