dingdanquanliucheng/backend/app/api/h5_bind_service.py
2026-06-26 22:02:04 +08:00

93 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""服务号绑定模块(手机号验证方式)。
用户关注服务号后openid 存入 pending_service_binding 表。
用户在小程序中输入手机号,后端匹配系统用户并完成绑定。
"""
import logging
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.orm import Session
from backend.app.core.config import get_settings
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.db import get_db_session
from backend.app.models.system import PendingServiceBinding, User
logger = logging.getLogger(__name__)
router = APIRouter(tags=["h5-bind-service"])
class VerifyPhoneRequest(BaseModel):
"""手机号验证绑定请求"""
phone: str
@router.get("/api/h5/bind-service-qrcode")
def get_bind_qrcode():
"""返回服务号关注引导信息。"""
settings = get_settings()
if not settings.wechat_sa_app_id:
return {"configured": False, "message": "服务号未配置"}
return {
"configured": True,
"account_name": "特氟龙胶带大表哥",
"message": "请扫码关注服务号「特氟龙胶带大表哥」,或在微信中搜索同名服务号,关注后返回小程序输入手机号完成绑定。",
}
@router.post("/api/h5/verify-phone")
def verify_phone(
payload: VerifyPhoneRequest,
session: Session = Depends(get_db_session),
):
"""手机号验证绑定接口。
接收手机号,匹配系统用户,从 pending_service_binding 取最近的未绑定记录,
完成 service_open_id 的绑定。
"""
phone = payload.phone.strip()
if not phone:
raise AppException(code=ErrorCode.PARAM_ERROR, message="请输入手机号", status_code=400)
# 1. 按手机号匹配系统用户
user = session.execute(
select(User).where(User.mobile == phone, User.status == 1)
).scalar_one_or_none()
if user is None:
raise AppException(code=ErrorCode.NOT_FOUND, message="该手机号未注册系统账号", status_code=404)
# 2. 检查是否已绑定
if user.service_open_id:
return {"success": True, "message": f"{user.real_name},您的账号已绑定服务号通知", "already_bound": True}
# 3. 取最近的未绑定 pending binding
pending = session.execute(
select(PendingServiceBinding)
.where(PendingServiceBinding.bound == False)
.order_by(PendingServiceBinding.id.desc())
.limit(1)
).scalar_one_or_none()
if pending is None:
raise AppException(
code=ErrorCode.NOT_FOUND,
message="未找到待绑定记录。请先关注服务号,然后再试。",
status_code=404,
)
# 4. 完成绑定
user.service_open_id = pending.service_open_id
pending.bound = True
session.add(user)
session.add(pending)
session.commit()
logger.info("用户 %s (id=%s) 通过手机号验证绑定服务号 openid=%s", user.real_name, user.id, pending.service_open_id)
return {"success": True, "message": f"{user.real_name},绑定成功!您将在微信中收到订单提醒"}