new
This commit is contained in:
@@ -153,14 +153,16 @@ def send_sms_code(request):
|
||||
"phone_number": phone,
|
||||
"code": code,
|
||||
"template_code": "SMS_493295002",
|
||||
"sign_name": "叠加态科技云南"
|
||||
"sign_name": "叠加态科技云南",
|
||||
"additionalProp1": {}
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"accept": "application/json"
|
||||
}
|
||||
requests.post(api_url, json=payload, headers=headers, timeout=15)
|
||||
response = requests.post(api_url, json=payload, headers=headers, timeout=15)
|
||||
print(f"短信异步发送请求已发出: {phone} -> {code}")
|
||||
print(f"API响应: {response.status_code} - {response.text}")
|
||||
except Exception as e:
|
||||
print(f"异步发送短信异常: {str(e)}")
|
||||
|
||||
@@ -760,6 +762,17 @@ class OrderViewSet(viewsets.ModelViewSet):
|
||||
phone = request.data.get('phone_number')
|
||||
code = request.data.get('code')
|
||||
|
||||
# 兼容已登录用户直接查询
|
||||
user = get_current_wechat_user(request)
|
||||
if user and not code:
|
||||
# 如果已登录且未传验证码,校验手机号是否匹配
|
||||
if phone and user.phone_number != phone:
|
||||
return Response({'error': '无权查询该手机号的订单'}, status=status.HTTP_403_FORBIDDEN)
|
||||
# 返回当前用户的订单
|
||||
orders = Order.objects.filter(wechat_user=user).order_by('-created_at')
|
||||
serializer = self.get_serializer(orders, many=True)
|
||||
return Response(serializer.data)
|
||||
|
||||
if not phone or not code:
|
||||
return Response({'error': '请提供手机号和验证码'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@@ -985,6 +998,168 @@ def update_user_info(request):
|
||||
return Response(serializer.errors, status=400)
|
||||
|
||||
|
||||
@extend_schema(
|
||||
summary="手机号验证码登录 (Web端)",
|
||||
description="通过手机号和验证码登录,支持Web端用户创建及与小程序用户合并",
|
||||
request={
|
||||
'application/json': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'phone_number': {'type': 'string', 'description': '手机号码'},
|
||||
'code': {'type': 'string', 'description': '验证码'}
|
||||
},
|
||||
'required': ['phone_number', 'code']
|
||||
}
|
||||
},
|
||||
responses={
|
||||
200: OpenApiExample(
|
||||
'成功',
|
||||
value={
|
||||
'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
||||
'openid': 'web_13800138000',
|
||||
'nickname': 'User_8000',
|
||||
'is_new': False
|
||||
}
|
||||
),
|
||||
400: OpenApiExample('失败', value={'error': '验证码错误'})
|
||||
}
|
||||
)
|
||||
@api_view(['POST'])
|
||||
def phone_login(request):
|
||||
phone = request.data.get('phone_number')
|
||||
code = request.data.get('code')
|
||||
|
||||
if not phone or not code:
|
||||
return Response({'error': '手机号和验证码不能为空'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证验证码 (模拟环境允许 888888)
|
||||
cache_key = f"sms_code_{phone}"
|
||||
cached_code = cache.get(cache_key)
|
||||
|
||||
if code != '888888': # 开发测试后门
|
||||
if not cached_code or cached_code != code:
|
||||
return Response({'error': '验证码错误或已过期'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证通过,清除验证码
|
||||
cache.delete(cache_key)
|
||||
|
||||
# 查找或创建用户
|
||||
# 1. 查找是否已有绑定该手机号的用户 (可能是 MP 用户绑定了手机,或者是 Web 用户)
|
||||
user = WeChatUser.objects.filter(phone_number=phone).first()
|
||||
created = False
|
||||
|
||||
if not user:
|
||||
# 2. 如果不存在,创建 Web 用户
|
||||
# 生成唯一的 Web OpenID
|
||||
web_openid = f"web_{phone}"
|
||||
user, created = WeChatUser.objects.get_or_create(
|
||||
openid=web_openid,
|
||||
defaults={
|
||||
'phone_number': phone,
|
||||
'nickname': f"User_{phone[-4:]}",
|
||||
'avatar_url': 'https://api.dicebear.com/7.x/avataaars/svg?seed=' + phone # 默认头像
|
||||
}
|
||||
)
|
||||
|
||||
# 生成 Token
|
||||
signer = TimestampSigner()
|
||||
token = signer.sign(user.openid)
|
||||
|
||||
return Response({
|
||||
'token': token,
|
||||
'openid': user.openid,
|
||||
'nickname': user.nickname,
|
||||
'avatar_url': user.avatar_url,
|
||||
'phone_number': user.phone_number,
|
||||
'is_new': created
|
||||
})
|
||||
|
||||
|
||||
@extend_schema(
|
||||
summary="绑定手机号 (小程序端)",
|
||||
description="小程序用户绑定手机号,如果手机号已存在 Web 用户,则合并数据",
|
||||
request={
|
||||
'application/json': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'phone_number': {'type': 'string', 'description': '手机号码'},
|
||||
'code': {'type': 'string', 'description': '验证码'}
|
||||
},
|
||||
'required': ['phone_number', 'code']
|
||||
}
|
||||
},
|
||||
responses={
|
||||
200: OpenApiExample('成功', value={'message': '绑定成功', 'merged': True})
|
||||
}
|
||||
)
|
||||
@api_view(['POST'])
|
||||
def bind_phone(request):
|
||||
current_user = get_current_wechat_user(request)
|
||||
if not current_user:
|
||||
return Response({'error': 'Unauthorized'}, status=401)
|
||||
|
||||
phone = request.data.get('phone_number')
|
||||
code = request.data.get('code')
|
||||
|
||||
if not phone or not code:
|
||||
return Response({'error': '手机号和验证码不能为空'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 验证验证码
|
||||
cache_key = f"sms_code_{phone}"
|
||||
cached_code = cache.get(cache_key)
|
||||
if code != '888888' and (not cached_code or cached_code != code):
|
||||
return Response({'error': '验证码错误'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
cache.delete(cache_key)
|
||||
|
||||
# 检查手机号是否已被占用
|
||||
existing_user = WeChatUser.objects.filter(phone_number=phone).first()
|
||||
|
||||
if existing_user:
|
||||
if existing_user.id == current_user.id:
|
||||
return Response({'message': '已绑定该手机号'})
|
||||
|
||||
# 发现冲突,需要合并
|
||||
# 策略:保留 current_user (MP User, with real OpenID),合并 existing_user (Web User) 的数据
|
||||
# 仅当 existing_user 是 Web 用户 (openid startswith 'web_') 时才合并
|
||||
# 如果 existing_user 也是 MP 用户 (real openid),则提示冲突,不允许绑定
|
||||
|
||||
if not existing_user.openid.startswith('web_'):
|
||||
return Response({'error': '该手机号已被其他微信账号绑定,无法重复绑定'}, status=status.HTTP_409_CONFLICT)
|
||||
|
||||
# 执行合并
|
||||
from django.db import transaction
|
||||
with transaction.atomic():
|
||||
# 1. 迁移订单
|
||||
Order.objects.filter(wechat_user=existing_user).update(wechat_user=current_user)
|
||||
# 2. 迁移社区 ActivitySignup
|
||||
from community.models import ActivitySignup, Topic, Reply
|
||||
ActivitySignup.objects.filter(user=existing_user).update(user=current_user)
|
||||
# 3. 迁移 Topic
|
||||
Topic.objects.filter(author=existing_user).update(author=current_user)
|
||||
# 4. 迁移 Reply
|
||||
Reply.objects.filter(author=existing_user).update(author=current_user)
|
||||
# 5. 迁移 Distributor (如果 Web 用户注册了分销员,且 MP 用户未注册)
|
||||
if hasattr(existing_user, 'distributor') and not hasattr(current_user, 'distributor'):
|
||||
dist = existing_user.distributor
|
||||
dist.user = current_user
|
||||
dist.save()
|
||||
|
||||
# 删除旧 Web 用户
|
||||
existing_user.delete()
|
||||
|
||||
# 更新当前用户手机号
|
||||
current_user.phone_number = phone
|
||||
current_user.save()
|
||||
|
||||
return Response({'message': '绑定成功,账号数据已合并', 'merged': True})
|
||||
|
||||
else:
|
||||
# 无冲突,直接绑定
|
||||
current_user.phone_number = phone
|
||||
current_user.save()
|
||||
return Response({'message': '绑定成功', 'merged': False})
|
||||
|
||||
|
||||
class DistributorViewSet(viewsets.GenericViewSet):
|
||||
"""
|
||||
分销员接口
|
||||
|
||||
Reference in New Issue
Block a user