import asyncio import os import threading from flask import Blueprint, request, jsonify, render_template from server.database import get_db from server.services.auth_service import get_auth_path, has_auth, login_with_password bp = Blueprint('accounts', __name__, url_prefix='/accounts') @bp.route('/') def list_accounts(): db = get_db() accounts = db.execute('SELECT * FROM accounts ORDER BY id DESC').fetchall() db.close() return render_template('accounts.html', accounts=accounts) @bp.route('/add', methods=['POST']) def add_account(): name = request.form.get('name', '').strip() phone = request.form.get('phone', '').strip() password = request.form.get('password', '').strip() if not name or not phone or not password: return jsonify(success=False, msg='请填写完整信息'), 400 db = get_db() cursor = db.execute( 'INSERT INTO accounts (name, phone, password, auth_file, login_msg) VALUES (?, ?, ?, ?, ?)', (name, phone, password, '', '登录中...') ) account_id = cursor.lastrowid auth_file = get_auth_path(account_id) db.execute('UPDATE accounts SET auth_file = ? WHERE id = ?', (auth_file, account_id)) db.commit() db.close() # 后台异步登录 _start_bg_login(account_id, phone, password) return jsonify(success=True, id=account_id) @bp.route('/delete/', methods=['POST']) def delete_account(account_id): db = get_db() db.execute('DELETE FROM tasks WHERE account_id = ?', (account_id,)) db.execute('DELETE FROM accounts WHERE id = ?', (account_id,)) db.commit() db.close() path = get_auth_path(account_id) if os.path.exists(path): os.remove(path) return jsonify(success=True) @bp.route('/login/', methods=['POST']) def do_login(account_id): """用 Playwright 模拟浏览器自动登录微店""" db = get_db() account = db.execute('SELECT * FROM accounts WHERE id = ?', (account_id,)).fetchone() db.close() if not account: return jsonify(success=False, msg='账号不存在'), 404 phone = account['phone'] password = account['password'] if not phone or not password: return jsonify(success=False, msg='该账号未设置手机号或密码'), 400 # 标记为登录中 db = get_db() db.execute( "UPDATE accounts SET is_logged_in = 0, login_msg = '登录中...', updated_at = datetime('now','localtime') WHERE id = ?", (account_id,) ) db.commit() db.close() # 后台异步登录 _start_bg_login(account_id, phone, password) return jsonify(success=True, msg='登录中...') @bp.route('/status/') def get_status(account_id): """轮询账号登录状态""" db = get_db() account = db.execute( 'SELECT is_logged_in, login_msg FROM accounts WHERE id = ?', (account_id,) ).fetchone() db.close() if not account: return jsonify(is_logged_in=False, login_msg='账号不存在', done=True) msg = account['login_msg'] or '' is_logged_in = bool(account['is_logged_in']) # 登录中... 表示还在进行 done = msg != '登录中...' return jsonify(is_logged_in=is_logged_in, login_msg=msg, done=done) def _start_bg_login(account_id, phone, password): """在后台线程中执行登录""" def _run(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: ok, msg = loop.run_until_complete( login_with_password(account_id, phone, password) ) except Exception as e: ok, msg = False, str(e) finally: loop.close() db = get_db() if ok: db.execute( "UPDATE accounts SET is_logged_in = 1, login_msg = '登录成功', " "updated_at = datetime('now','localtime') WHERE id = ?", (account_id,) ) else: db.execute( "UPDATE accounts SET is_logged_in = 0, login_msg = ?, " "updated_at = datetime('now','localtime') WHERE id = ?", (msg, account_id) ) db.commit() db.close() t = threading.Thread(target=_run, daemon=True) t.start()