diff --git a/auth.py b/auth.py index 12a7daf..be7c1f8 100644 --- a/auth.py +++ b/auth.py @@ -107,11 +107,14 @@ async def get_status(scene: str = Query(..., description="create_scene 返回的 # 业务逻辑 # --------------------------------------------------------------------------- -async def handle_scan(scene_str: str, openid: str) -> bool: +async def handle_scan(scene_str: str, openid: str) -> str: """ - 处理扫码事件。 + 处理扫码事件,返回结果(取值与 /auth/status 的 status 一致): + + - "authorized" 场景绑定成功,且用户有可用授权 + - "need_purchase" 场景绑定成功,但用户没有可用授权(需充值) + - "invalid" 场景不存在、已过期,或已被处理过(重复扫码) - 返回 True 表示本次扫码完成授权,False 表示场景无效、已过期或已被处理。 整个流程在事务内完成,并对 scene 行加排他锁,保证同一 scene 只被处理一次。 """ async with db.acquire() as conn: @@ -127,12 +130,12 @@ async def handle_scan(scene_str: str, openid: str) -> bool: if scene_row is None: await conn.rollback() - return False + return "invalid" if scene_row["status"] == "authorized": # 重复扫码:只处理第一次,后续忽略 await conn.rollback() - return False + return "invalid" if not scene_row["not_expired"]: await cur.execute( @@ -141,10 +144,12 @@ async def handle_scan(scene_str: str, openid: str) -> bool: (scene_row["id"],), ) await conn.commit() - return False + return "invalid" user_id = await _find_or_create_user(cur, openid) await _grant_free_authorization(cur, user_id) + # 免费授权发完后仍无可用授权 → 需要充值(阶段 3) + has_auth = await _get_active_authorization(cur, user_id) is not None await cur.execute( "UPDATE auth_scenes SET status = 'authorized', user_id = %s, authorized_at = NOW() " @@ -160,8 +165,9 @@ async def handle_scan(scene_str: str, openid: str) -> bool: ) await conn.commit() - logger.info("扫码授权成功 scene_str=%s openid=%s", scene_str, openid) - return True + result = "authorized" if has_auth else "need_purchase" + logger.info("扫码完成 scene_str=%s openid=%s 结果=%s", scene_str, openid, result) + return result except Exception: await conn.rollback() raise diff --git a/wechat.py b/wechat.py index ce01646..e775762 100644 --- a/wechat.py +++ b/wechat.py @@ -126,10 +126,14 @@ async def _handle_scan_event( # 无场景值的普通关注 return _reply_text(from_user, to_user, "欢迎关注!") - authorized = await auth.handle_scan(scene_str, from_user) - if authorized: - return _reply_text(from_user, to_user, "授权成功,请返回电脑端继续操作。") - return _reply_text(from_user, to_user, "二维码已失效或已被使用,请在电脑端刷新后重新扫码。") + result = await auth.handle_scan(scene_str, from_user) + if result == "authorized": + reply = "授权成功,请返回电脑端继续操作。" + elif result == "need_purchase": + reply = "当前无可用授权,请返回电脑端按提示操作。" + else: + reply = "二维码已失效或已被使用,请在电脑端刷新后重新扫码。" + return _reply_text(from_user, to_user, reply) def _parse_scene_key(event_key: str, is_subscribe: bool) -> str: