From 7c933f4a82efa2e98447b324eb46fb739734a88d Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 12 Jan 2026 15:21:52 +0800 Subject: [PATCH] ts --- app/web.py | 49 ++++++++++-- static/app.js | 72 +++++++++-------- templates/login_test.html | 157 ++++++++++++++++++++++++++++++++++++++ vnc_setup.sh | 44 +++++++++++ 4 files changed, 286 insertions(+), 36 deletions(-) create mode 100644 templates/login_test.html create mode 100644 vnc_setup.sh diff --git a/app/web.py b/app/web.py index 39fda8a..a2da283 100644 --- a/app/web.py +++ b/app/web.py @@ -74,6 +74,8 @@ async def index(request: Request): return templates.TemplateResponse("index.html", {"request": request}) + + @app.get("/api/status", response_model=StatusResponse) async def get_status(): """获取当前状态""" @@ -395,6 +397,7 @@ async def export_users_to_txt(): class LoginStatusResponse(BaseModel): logged_in: bool login_time: Optional[str] = None + expire_time: Optional[str] = None @app.get("/api/login/status", response_model=LoginStatusResponse) @@ -409,9 +412,20 @@ async def get_login_status(): with open(auth_file, 'r', encoding='utf-8') as f: auth_data = json.load(f) + # 检查是否过期 + login_time = auth_data.get("login_time") + expire_time = auth_data.get("expire_time") + current_time = datetime.now().isoformat() + + if expire_time and current_time > expire_time: + # 登录已过期,清除状态 + os.remove(auth_file) + return LoginStatusResponse(logged_in=False) + return LoginStatusResponse( logged_in=auth_data.get("logged_in", False), - login_time=auth_data.get("login_time") + login_time=login_time, + expire_time=expire_time ) except Exception: return LoginStatusResponse(logged_in=False) @@ -419,12 +433,35 @@ async def get_login_status(): @app.post("/api/login/qrcode") async def generate_qrcode(): - """生成登录二维码""" - # 这里应该调用实际的小红书登录API - # 暂时返回模拟数据 + """模拟登录成功""" + import uuid + from datetime import datetime, timedelta + + # 生成登录状态(模拟登录成功) + login_id = str(uuid.uuid4()) + current_time = datetime.now() + expire_time = current_time + timedelta(hours=24) # 24小时后过期 + + # 保存登录状态到文件 + auth_file = os.path.join(config.DATA_DIR, "auth_state.json") + auth_data = { + "logged_in": True, + "login_time": current_time.isoformat(), + "expire_time": expire_time.isoformat(), + "login_id": login_id, + "platform": "xiaohongshu" + } + + with open(auth_file, 'w', encoding='utf-8') as f: + json.dump(auth_data, f, ensure_ascii=False, indent=2) + + # 返回登录信息 return { - "qr_url": "https://example.com/login/qrcode", - "qr_id": "123456" + "login_id": login_id, + "login_time": current_time.isoformat(), + "expire_time": expire_time.isoformat(), + "message": "登录成功(模拟)", + "expire_in_hours": 24 } diff --git a/static/app.js b/static/app.js index b6812cf..de75a67 100644 --- a/static/app.js +++ b/static/app.js @@ -144,6 +144,9 @@ function init() { // 加载主题 loadTheme(); + // 加载登录状态 + loadAccountStatus(); + // 加载初始数据 loadInitialData(); @@ -692,42 +695,36 @@ function closeAccountModal() { // 打开登录二维码模态框 async function openLoginQrModal() { elements.loginQrModal.classList.add('show'); - elements.qrLoginStatus.textContent = '正在生成二维码...'; + elements.qrLoginStatus.textContent = '正在模拟登录...'; try { const response = await fetch('/api/login/qrcode'); const data = await response.json(); if (response.ok) { - // 显示二维码 - if (data.qr_url) { - // 使用简单的二维码显示(实际项目中可以使用QRCode.js等库) - elements.qrcodeContainer.innerHTML = ` -
- 登录二维码 -
- `; - elements.qrLoginStatus.textContent = '请扫码登录'; + // 显示登录成功信息 + elements.qrcodeContainer.innerHTML = ` +
+
✅
+

${data.message}

+

登录状态已保存到本地

+ ${data.expire_in_hours ? `

有效期:${data.expire_in_hours}小时

` : ''} +
+ `; + elements.qrLoginStatus.textContent = '登录成功!'; - // 开始检查登录状态 - checkLoginStatus(); + // 开始检查登录状态 + checkLoginStatus(); - // 设置二维码过期倒计时 - let countdown = 120; - const countdownInterval = setInterval(() => { - countdown--; - elements.qrExpireTime.textContent = `${countdown}秒`; - - if (countdown <= 0) { - clearInterval(countdownInterval); - elements.qrLoginStatus.textContent = '二维码已过期,请重新生成'; - elements.qrcodeContainer.innerHTML = '

二维码已过期

'; - } - }, 1000); - } + // 3秒后自动关闭 + setTimeout(() => { + closeLoginQrModal(); + closeAccountModal(); + showToast('登录成功', 'success'); + }, 3000); } else { - elements.qrcodeContainer.innerHTML = '

生成二维码失败

'; - elements.qrLoginStatus.textContent = '生成失败'; + elements.qrcodeContainer.innerHTML = '

登录失败

'; + elements.qrLoginStatus.textContent = '登录失败'; } } catch (error) { elements.qrcodeContainer.innerHTML = '

网络错误

'; @@ -751,7 +748,7 @@ async function checkLoginStatus() { setTimeout(() => { closeLoginQrModal(); closeAccountModal(); - updateLoginStatus(true, data.login_time); + updateLoginStatus(true, data.login_time, data.expire_time); showToast('登录成功', 'success'); }, 1000); } else { @@ -783,7 +780,7 @@ async function logout() { } // 更新登录状态显示 -function updateLoginStatus(isLoggedIn, loginTime = null) { +function updateLoginStatus(isLoggedIn, loginTime = null, expireTime = null) { const indicator = elements.loginStatusIndicator; const statusText = elements.loginStatusText; const modalStatus = elements.modalLoginStatus; @@ -797,6 +794,21 @@ function updateLoginStatus(isLoggedIn, loginTime = null) { if (loginTime) { elements.loginTime.textContent = new Date(loginTime).toLocaleString('zh-CN'); } + + // 如果有到期时间,显示剩余时间 + if (expireTime) { + const expireDate = new Date(expireTime); + const now = new Date(); + const timeLeft = expireDate - now; + + if (timeLeft > 0) { + const hours = Math.floor(timeLeft / (1000 * 60 * 60)); + const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60)); + + elements.loginTime.textContent = new Date(loginTime).toLocaleString('zh-CN'); + elements.loginTime.innerHTML += `
(${hours}小时${minutes}分钟后过期)`; + } + } } else { indicator.className = 'status-indicator offline'; statusText.textContent = '未登录'; @@ -811,7 +823,7 @@ async function loadAccountStatus() { try { const response = await fetch('/api/login/status'); const data = await response.json(); - updateLoginStatus(data.logged_in, data.login_time); + updateLoginStatus(data.logged_in, data.login_time, data.expire_time); } catch (error) { updateLoginStatus(false); } diff --git a/templates/login_test.html b/templates/login_test.html new file mode 100644 index 0000000..9ad7357 --- /dev/null +++ b/templates/login_test.html @@ -0,0 +1,157 @@ + + + + + + 登录测试 + + + +
+

小红书登录测试

+ + + + + + + +
+ + + + \ No newline at end of file diff --git a/vnc_setup.sh b/vnc_setup.sh new file mode 100644 index 0000000..2bf1a7d --- /dev/null +++ b/vnc_setup.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# VNC 设置脚本 + +# 安装 VNC 服务器和相关工具 +apt-get update +apt-get install -y \ + x11vnc \ + xvfb \ + firefox \ + python3-tk \ + python3-pip + +# 安装 Python 依赖 +pip3 install pyvirtualdisplay selenium webdriver-manager + +# 创建 VNC 密码 +echo "vncpassword" | x11vnc -storepasswd /etc/vncpasswd + +# 创建启动脚本 +cat > /start_vnc.sh << 'EOF' +#!/bin/bash +# 设置显示环境 +export DISPLAY=:1 + +# 启动虚拟显示器 +Xvfb :1 -screen 0 1920x1080x16 & +XVFB_PID=$! + +# 启动 VNC 服务器 +x11vnc -display :1 -passwd /etc/vncpasswd -forever -shared -rfbport 5900 & +VNC_PID=$! + +# 等待 VNC 启动 +sleep 3 + +echo "VNC 服务器已启动" +echo "VNC 地址: localhost:5900" +echo "VNC 密码: vncpassword" + +# 保持脚本运行 +wait $XVFB_PID $VNC_PID +EOF + +chmod +x /start_vnc.sh \ No newline at end of file