From 914e8c70f2a63ed278a6c04b6ea845e3ff46f2f6 Mon Sep 17 00:00:00 2001 From: XingQue Date: Thu, 9 Jul 2026 21:57:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=8B=E6=9C=BA=E5=8F=B7?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E5=AE=8C=E6=88=90=E5=90=8E=E4=BB=8D=E5=8F=8D?= =?UTF-8?q?=E5=A4=8D=E5=BC=B9=E7=AA=97=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 认证提交接口在仅上传头像时错误返回成功,检查接口也未兼容已有手机号的老数据。 Co-authored-by: Cursor --- config/views/miniapp_config.py | 20 +++++++++++-- users/views/user_info.py | 54 ++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/config/views/miniapp_config.py b/config/views/miniapp_config.py index 9a02a6b..e31a194 100644 --- a/config/views/miniapp_config.py +++ b/config/views/miniapp_config.py @@ -252,10 +252,24 @@ class CheckPhoneAuthView(APIView): permission_classes = [IsAuthenticated] - def post(self, request): - user = request.user + @staticmethod + def _phone_auth_completed(user): + """是否已完成手机号认证(兼容 PhoneVerified 未写入的老数据)。""" + if bool(getattr(user, 'PhoneVerified', False)): + return True + phone = (getattr(user, 'Phone', None) or '').strip() + return len(phone) >= 11 - if getattr(user, 'PhoneVerified', False): + def post(self, request): + uid = getattr(request.user, 'UserUID', None) + user = request.user + if uid: + try: + user = User.query.get(UserUID=uid) + except User.DoesNotExist: + user = request.user + + if self._phone_auth_completed(user): return Response({'code': 0, 'need_auth': False}) if self._dashou_meets_threshold(user): diff --git a/users/views/user_info.py b/users/views/user_info.py index 98563ac..6ebfa35 100644 --- a/users/views/user_info.py +++ b/users/views/user_info.py @@ -164,6 +164,7 @@ def huoquKehuduanIP(request): class UserInfoUpdateView(APIView): permission_classes = [permissions.IsAuthenticated] + parser_classes = [MultiPartParser, FormParser, JSONParser] # 进程内缓存,防止同一code被重复调用微信(单进程安全,多进程小概率重复,但用户极少可忽略) _phone_cache = {} @@ -173,6 +174,7 @@ class UserInfoUpdateView(APIView): user = request.user boss = self._get_or_create_boss(user) result = {} + nick = request.data.get('nicheng') # 诊断日志:记录入参和实例状态 logger.warning( @@ -201,7 +203,6 @@ class UserInfoUpdateView(APIView): return Response({'code': 2, 'msg': '头像上传失败', 'data': None}, status=500) # 昵称 - nick = request.data.get('nicheng') if nick: nick = str(nick).strip() if len(nick) > 20: @@ -209,9 +210,28 @@ class UserInfoUpdateView(APIView): boss.nickname = nick result['nicheng'] = nick - # 手机号 —— 失败不阻塞其他字段(头像/昵称)的保存 - code = request.data.get('shoujihao_code') + # 手机号 —— multipart 表单字段兼容 request.data / request.POST + code = ( + request.data.get('shoujihao_code') + or request.POST.get('shoujihao_code') + or '' + ) + if isinstance(code, str): + code = code.strip() + else: + code = str(code or '').strip() + + # 认证页仅上传头像+手机号,不带昵称 + is_phone_auth_flow = bool(av) and not nick phone_error = None + + if is_phone_auth_flow and not code: + return Response({ + 'code': 6, + 'msg': '未收到手机号授权,请重新点击获取手机号', + 'data': None, + }, status=200) + if code: phone = self._get_phone_safe(code, request) if phone is None: @@ -220,6 +240,7 @@ class UserInfoUpdateView(APIView): user.Phone = phone user.PhoneVerified = True result['phone'] = phone + result['phone_verified'] = True if not result and not phone_error: logger.warning("[USERINFO_XIUGAI] 无更新,result 为空") @@ -237,15 +258,36 @@ class UserInfoUpdateView(APIView): phone_error, ) - # 有字段更新时先保存(即使手机号失败,头像/昵称也应入库) + # 认证流:必须拿到手机号才算成功,避免只存头像却返回 code=0 导致反复弹窗 + if is_phone_auth_flow and 'phone' not in result: + msg = phone_error or '手机号获取失败,请重新授权' + if result: + with transaction.atomic(): + user_update_fields = [] + if 'touxiang' in result: + user_update_fields.append('Avatar') + if user_update_fields: + user.save(update_fields=user_update_fields) + if 'nicheng' in result: + boss.save() + return Response({'code': 6, 'msg': msg, 'data': result or None}, status=200) + + # 有字段更新时先保存(资料编辑:手机号失败不阻塞头像/昵称) if result: + user_update_fields = [] + if 'touxiang' in result: + user_update_fields.append('Avatar') + if 'phone' in result: + user_update_fields.extend(['Phone', 'PhoneVerified']) with transaction.atomic(): - user.save() + if user_update_fields: + user.save(update_fields=user_update_fields) + elif result: + user.save() boss.save() logger.warning("[USERINFO_XIUGAI] 保存成功 result_keys=%s", list(result.keys())) if phone_error: - # 其他字段已保存,但手机号失败 —— 返回已保存的字段供前端更新缓存 return Response({'code': 6, 'msg': phone_error, 'data': result}, status=200) return Response({'code': 0, 'msg': '更新成功', 'data': result})