This commit is contained in:
jeremygan2021
2026-02-12 17:13:30 +08:00
parent ee3e932aa5
commit 5a7b2032c4
14 changed files with 122 additions and 19 deletions

View File

@@ -10,6 +10,7 @@ from django.http import HttpResponse
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter, OpenApiExample
from .models import ESP32Config, Order, WeChatPayConfig, Service, VCCourse, ServiceOrder, Salesperson, CommissionLog, WeChatUser, Distributor, Withdrawal, CourseEnrollment
from .serializers import ESP32ConfigSerializer, OrderSerializer, ServiceSerializer, VCCourseSerializer, ServiceOrderSerializer, WeChatUserSerializer, DistributorSerializer, WithdrawalSerializer, CommissionLogSerializer, CourseEnrollmentSerializer
from .utils import get_access_token
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.contrib.auth.models import User
from wechatpayv3 import WeChatPay, WeChatPayType
@@ -953,9 +954,13 @@ def get_current_wechat_user(request):
@extend_schema(
summary="微信小程序登录",
description="支持通过 code 登录,以及可选的 phone_code 用于直接获取手机号并合并 Web 用户账号",
request={
'application/json': {
'properties': {'code': {'type': 'string', 'description': 'wx.login获取的code'}},
'properties': {
'code': {'type': 'string', 'description': 'wx.login获取的code'},
'phone_code': {'type': 'string', 'description': 'getPhoneNumber获取的code (可选)'}
},
'required': ['code']
}
},
@@ -964,14 +969,21 @@ def get_current_wechat_user(request):
@api_view(['POST'])
def wechat_login(request):
code = request.data.get('code')
phone_code = request.data.get('phone_code')
if not code:
return Response({'error': 'Code is required'}, status=400)
config = WeChatPayConfig.objects.filter(is_active=True).first()
# 1. 获取配置 (优先使用指定 AppID)
target_app_id = 'wxdf2ca73e6c0929f0'
config = WeChatPayConfig.objects.filter(app_id=target_app_id).first()
if not config:
config = WeChatPayConfig.objects.filter(is_active=True).first()
if not config or not config.app_id or not config.app_secret:
return Response({'error': 'WeChat config missing'}, status=500)
# 换取 OpenID
# 2. 换取 OpenID
url = f"https://api.weixin.qq.com/sns/jscode2session?appid={config.app_id}&secret={config.app_secret}&js_code={code}&grant_type=authorization_code"
try:
res = requests.get(url, timeout=10)
@@ -985,26 +997,70 @@ def wechat_login(request):
openid = data.get('openid')
session_key = data.get('session_key')
unionid = data.get('unionid')
# 3. 处理手机号 (尝试获取并合并 Web 用户)
user = None
phone_number = None
if phone_code:
access_token = get_access_token(config)
if access_token:
try:
phone_url = f"https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={access_token}"
phone_res = requests.post(phone_url, json={'code': phone_code}, timeout=5)
phone_data = phone_res.json()
if phone_data.get('errcode') == 0:
phone_info = phone_data.get('phone_info')
phone_number = phone_info.get('purePhoneNumber')
if phone_number:
# 查找已存在的用户 (Web 用户或已绑定手机的 MP 用户)
existing_user = WeChatUser.objects.filter(phone_number=phone_number).first()
if existing_user:
user = existing_user
# 如果是 Web 虚拟账号 (openid 以 web_ 开头),更新为真实 OpenID
if user.openid.startswith('web_') or not user.openid:
user.openid = openid
user.session_key = session_key
user.unionid = unionid
user.save()
# 如果已是真实账号但 OpenID 不匹配,可能是不同 AppID暂不处理避免覆盖
except Exception as e:
print(f"获取手机号失败: {e}")
# 创建或更新用户
user, created = WeChatUser.objects.update_or_create(
openid=openid,
defaults={
# 4. 创建或更新用户 (如果未通过手机号找到)
if not user:
defaults = {
'session_key': session_key,
'unionid': unionid
}
)
if phone_number:
defaults['phone_number'] = phone_number
user, created = WeChatUser.objects.update_or_create(
openid=openid,
defaults=defaults
)
else:
# 如果找到了用户,且 OpenID 匹配(或刚被更新),更新 session_key
if user.openid == openid:
user.session_key = session_key
user.unionid = unionid
user.save()
created = False
# 生成 Token
signer = TimestampSigner()
token = signer.sign(openid)
token = signer.sign(user.openid)
return Response({
'token': token,
'id': user.id,
'openid': openid,
'openid': user.openid,
'is_new': created,
'nickname': user.nickname
'nickname': user.nickname,
'phone_number': user.phone_number
})
@extend_schema(