diff --git a/app_web.py b/app_web.py index 1398a01..61260d0 100644 --- a/app_web.py +++ b/app_web.py @@ -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) diff --git a/templates/index.html b/templates/index.html index e6595b4..129d133 100644 --- a/templates/index.html +++ b/templates/index.html @@ -868,13 +868,18 @@ {% if error %} {% endif %} +

+ 初始化可能较慢(网络、扫码登录等)。结果会显示在下方灰色框内,无需只看浏览器网络里的 303; + 无头登录请开 TELEGRAM_HEADLESS_QR=1 并在运行日志中打开二维码链接。 +

+
-
- -
-
- -
+
+ +
+
+ +
@@ -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( + "

成功:" + + escapeHtml(data.message || "已就绪") + + "

" + ); + lines.push( + "

连接状态:" + + (data.connected ? "已连接" : "未连接(请查看日志)") + + "

" + ); + } else { + var errText = + (data && data.error) || + (httpStatus && httpStatus !== 200 ? "HTTP " + httpStatus : "") || + "未知错误"; + lines.push( + "

失败:" + + escapeHtml(String(errText)) + + "

" + ); + lines.push( + "

连接状态:" + + (data && data.connected ? "已连接" : "未连接") + + "

" + ); + } + if (data && data.logs_tail && data.logs_tail.length) { + lines.push( + "
" +
+                            escapeHtml(data.logs_tail.join("\n")) +
+                            "
" + ); + } + return { html: lines.join(""), isErr: !ok }; + } + + initBtn.addEventListener("click", async function () { + initBtn.disabled = true; + if (discBtn) discBtn.disabled = true; + showConnResult("

正在连接,请稍候(扫码场景可能需数分钟)…

", 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( + "

请求失败:" + + escapeHtml(e && e.message ? e.message : String(e)) + + "

", + true + ); + } finally { + initBtn.disabled = false; + if (discBtn) discBtn.disabled = false; + } + }); + + if (discBtn) { + discBtn.addEventListener("click", async function () { + initBtn.disabled = true; + discBtn.disabled = true; + showConnResult("

正在断开…

", 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( + "

" + + escapeHtml(data.message || "已断开") + + "

" + ); + } else { + lines.push( + "

失败:" + + escapeHtml((data && data.error) || "未知错误") + + "

" + ); + } + if (data && data.logs_tail && data.logs_tail.length) { + lines.push( + "
" +
+                                    escapeHtml(data.logs_tail.join("\n")) +
+                                    "
" + ); + } + showConnResult(lines.join(""), !ok); + await refreshStatus(); + } catch (e) { + showConnResult( + "

请求失败:" + + escapeHtml(e && e.message ? e.message : String(e)) + + "

", + true + ); + } finally { + initBtn.disabled = false; + discBtn.disabled = false; + } + }); + } + })(); + (function () { var form = document.querySelector(".account-pick-form"); if (!form) return;