diff --git a/app/web.py b/app/web.py index ddcdecb..666a6b7 100644 --- a/app/web.py +++ b/app/web.py @@ -444,38 +444,61 @@ async def get_login_status(): @app.post("/api/login/qrcode") async def generate_qrcode(): - """模拟登录成功""" - import uuid - from datetime import datetime, timedelta + """重定向到小红书官方登录页面""" + # 返回小红书登录页面 URL + login_url = "https://www.xiaohongshu.com/login" - # 生成登录状态(模拟登录成功) - 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 { - "login_id": login_id, - "login_time": current_time.isoformat(), - "expire_time": expire_time.isoformat(), - "message": "登录成功(模拟)", - "expire_in_hours": 24 + "login_url": login_url, + "message": "请在打开的小红书页面完成扫码登录", + "instruction": "登录成功后,返回此页面点击'验证登录'按钮" } +@app.post("/api/login/verify") +async def verify_login(): + """验证登录状态""" + try: + auth_file = os.path.join(config.DATA_DIR, "auth_state.json") + + if not os.path.exists(auth_file): + return { + "success": False, + "message": "未找到登录状态,请先登录" + } + + 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 { + "success": False, + "message": "登录已过期,请重新登录" + } + + return { + "success": True, + "message": "登录成功", + "logged_in": True, + "login_time": login_time, + "expire_time": expire_time, + "expire_in_hours": 24 + } + + except Exception as e: + return { + "success": False, + "message": f"验证失败: {str(e)}" + } + + @app.post("/api/logout") async def logout(): """退出登录""" diff --git a/static/app.js b/static/app.js index 9777f6a..09e2db3 100644 --- a/static/app.js +++ b/static/app.js @@ -119,6 +119,7 @@ function init() { elements.accountModal = document.getElementById('accountModal'); elements.closeAccountModal = document.getElementById('closeAccountModal'); elements.loginBtn = document.getElementById('loginBtn'); + elements.verifyLoginBtn = document.getElementById('verifyLoginBtn'); elements.logoutBtn = document.getElementById('logoutBtn'); elements.loginInfo = document.getElementById('loginInfo'); elements.modalLoginStatus = document.getElementById('modalLoginStatus'); @@ -130,14 +131,9 @@ function init() { elements.addUserIdBtn = document.getElementById('addUserIdBtn'); elements.importFromTxtBtn = document.getElementById('importFromTxtBtn'); elements.exportToTxtBtn = document.getElementById('exportToTxtBtn'); + elements.loginInstructions = document.getElementById('loginInstructions'); - // 登录二维码模态框 - elements.loginQrModal = document.getElementById('loginQrModal'); - elements.closeLoginQrModal = document.getElementById('closeLoginQrModal'); - elements.qrcodeContainer = document.getElementById('qrcodeContainer'); - elements.qrLoginStatus = document.getElementById('qrLoginStatus'); - elements.qrExpireTime = document.getElementById('qrExpireTime'); - + // Toast elements.toast = document.getElementById('toast'); @@ -213,7 +209,8 @@ function bindEvents() { elements.addAccountBtn.addEventListener('click', openAccountModal); elements.refreshAccountsBtn.addEventListener('click', refreshAccounts); elements.closeAccountModal.addEventListener('click', closeAccountModal); - elements.loginBtn.addEventListener('click', openLoginQrModal); + elements.loginBtn.addEventListener('click', openXiaohongshuLogin); + elements.verifyLoginBtn.addEventListener('click', verifyLogin); elements.logoutBtn.addEventListener('click', logout); elements.clearAllUsersBtn.addEventListener('click', clearAllUsers); elements.addUserIdBtn.addEventListener('click', addUserId); @@ -227,17 +224,11 @@ function bindEvents() { } }); - // 登录二维码模态框关闭 - elements.closeLoginQrModal.addEventListener('click', closeLoginQrModal); - // 点击模态框外部关闭 window.addEventListener('click', (e) => { if (e.target === elements.accountModal) { closeAccountModal(); } - if (e.target === elements.loginQrModal) { - closeLoginQrModal(); - } }); } @@ -692,77 +683,55 @@ function closeAccountModal() { elements.accountModal.classList.remove('show'); } -// 打开登录二维码模态框 -async function openLoginQrModal() { - elements.loginQrModal.classList.add('show'); - elements.qrLoginStatus.textContent = '正在模拟登录...'; - +// 打开小红书官方登录页面 +async function openXiaohongshuLogin() { try { const response = await fetch('/api/login/qrcode', { method: 'POST' }); const data = await response.json(); - if (response.ok) { - // 显示登录成功信息 - elements.qrcodeContainer.innerHTML = ` -
登录状态已保存到本地
- ${data.expire_in_hours ? `有效期:${data.expire_in_hours}小时
` : ''} -登录失败
'; - elements.qrLoginStatus.textContent = '登录失败'; + showToast('获取登录页面失败', 'error'); } } catch (error) { - elements.qrcodeContainer.innerHTML = '网络错误
'; - elements.qrLoginStatus.textContent = '网络错误'; + showToast('网络错误', 'error'); } } -// 关闭登录二维码模态框 -function closeLoginQrModal() { - elements.loginQrModal.classList.remove('show'); -} - -// 检查登录状态 -async function checkLoginStatus() { +// 验证登录状态 +async function verifyLogin() { try { - const response = await fetch('/api/login/status'); + const response = await fetch('/api/login/verify', { + method: 'POST' + }); const data = await response.json(); - if (data.logged_in) { - elements.qrLoginStatus.textContent = '登录成功!'; - setTimeout(() => { - closeLoginQrModal(); - closeAccountModal(); - updateLoginStatus(true, data.login_time, data.expire_time); - showToast('登录成功', 'success'); - }, 1000); + if (data.success) { + // 登录成功 + updateLoginStatus(true, data.login_time, data.expire_time); + elements.loginInstructions.style.display = 'none'; + elements.verifyLoginBtn.style.display = 'none'; + closeAccountModal(); + showToast('登录成功!', 'success'); } else { - // 继续检查 - setTimeout(checkLoginStatus, 2000); + showToast(data.message || '验证失败', 'error'); } } catch (error) { - // 网络错误,继续检查 - setTimeout(checkLoginStatus, 2000); + showToast('验证失败', 'error'); } } + // 退出登录 async function logout() { try { diff --git a/templates/index.html b/templates/index.html index b647cc7..1c83e7b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -201,13 +201,20 @@