From f0c62eb57ce36cba12e1cedcdc7ce3baf1062770 Mon Sep 17 00:00:00 2001 From: jeremygan2021 Date: Mon, 2 Mar 2026 16:47:40 +0800 Subject: [PATCH] =?UTF-8?q?wx=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/shop/views.py | 136 ++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 78 deletions(-) diff --git a/backend/shop/views.py b/backend/shop/views.py index 9131719..a032072 100644 --- a/backend/shop/views.py +++ b/backend/shop/views.py @@ -1049,82 +1049,65 @@ def wechat_login(request): if mp_user and phone_user: if mp_user != phone_user: # 【合并场景】: 小程序用户 和 手机号用户 都存在且不同 + # 规则: 只要手机号一致,强制合并。以当前 OpenID (mp_user) 为准,吸纳旧用户 (phone_user) 的数据。 - # 检查 phone_user 是否已经是真实的 MP 用户 (防止覆盖已绑定的其他微信账号) - # 规则: 如果 phone_user.openid 不是以 'web_' 开头,说明它已经是一个微信用户 - # 此时我们不能简单的合并,因为这意味着两个不同的微信账号绑定了同一个手机号(可能是异常或用户更换了微信号) - # 策略: 优先保留当前的 mp_user,提示用户手机号已被占用,或者这里简单处理为不合并手机号,只登录 mp_user + # 1. 迁移订单 + Order.objects.filter(wechat_user=phone_user).update(wechat_user=mp_user) - if not phone_user.openid.startswith('web_'): - print(f"冲突: 手机号 {phone_number} 已被用户 {phone_user.id} (OpenID: {phone_user.openid}) 绑定,无法合并到当前用户 {mp_user.id}") - # 这种情况下,我们让当前用户登录,但不更新手机号 (或者可以返回错误提示需人工解绑) - user = mp_user - # 也可以选择强制更新手机号到当前用户,并解绑旧用户(取决于业务规则,这里选择保守策略:不合并,仅登录) - else: - # 是 Web 虚拟用户,可以安全合并 - # 1. 迁移订单 - Order.objects.filter(wechat_user=phone_user).update(wechat_user=mp_user) - # 2. 迁移社区数据 (延迟导入避免循环引用) - from community.models import ActivitySignup, Topic, Reply - ActivitySignup.objects.filter(user=phone_user).update(user=mp_user) - Topic.objects.filter(author=phone_user).update(author=mp_user) - Reply.objects.filter(author=phone_user).update(author=mp_user) - # 3. 迁移分销员 - if hasattr(phone_user, 'distributor') and not hasattr(mp_user, 'distributor'): - dist = phone_user.distributor - dist.user = mp_user - dist.save() - - # 4. 迁移用户信息(优先使用Web用户的信息,覆盖小程序的信息,保持体验一致) - if phone_user.nickname: - mp_user.nickname = phone_user.nickname - if phone_user.avatar_url: - mp_user.avatar_url = phone_user.avatar_url - if phone_user.gender != 0: - mp_user.gender = phone_user.gender - - # 迁移关联的系统用户 (用于管理员权限等) - if phone_user.user and not mp_user.user: - mp_user.user = phone_user.user - # 清除旧对象的关联,防止唯一约束冲突(虽然即将删除,但为了安全) - phone_user.user = None - phone_user.save() - - # 标记拥有Web徽章 + # 2. 迁移社区数据 (延迟导入避免循环引用) + from community.models import ActivitySignup, Topic, Reply + ActivitySignup.objects.filter(user=phone_user).update(user=mp_user) + Topic.objects.filter(author=phone_user).update(author=mp_user) + Reply.objects.filter(author=phone_user).update(author=mp_user) + + # 3. 迁移分销员 + if hasattr(phone_user, 'distributor') and not hasattr(mp_user, 'distributor'): + dist = phone_user.distributor + dist.user = mp_user + dist.save() + + # 4. 迁移用户信息 + # 如果 mp_user 尚未设置昵称头像(新用户),则沿用 phone_user 的 + if not mp_user.nickname and phone_user.nickname: + mp_user.nickname = phone_user.nickname + if not mp_user.avatar_url and phone_user.avatar_url: + mp_user.avatar_url = phone_user.avatar_url + if mp_user.gender == 0 and phone_user.gender != 0: + mp_user.gender = phone_user.gender + + # 迁移关联的系统用户 (用于管理员权限等) + if phone_user.user and not mp_user.user: + mp_user.user = phone_user.user + phone_user.user = None + phone_user.save() + + # 标记拥有Web徽章 (如果旧用户是 Web 用户) + if phone_user.openid.startswith('web_') or phone_user.has_web_badge: mp_user.has_web_badge = True - mp_user.save() - - # 删除旧用户 - phone_user.delete() - user = mp_user - - # 更新手机号 - user.phone_number = phone_number - user.save() + + # 更新手机号 + mp_user.phone_number = phone_number + mp_user.save() + + # 删除旧用户 + phone_user.delete() + user = mp_user else: # 同一个用户 user = mp_user elif phone_user: - # 【绑定场景】: 只有手机号用户存在 (通常是 Web 用户) -> 升级为小程序用户 + # 【绑定场景】: 只有手机号用户存在 + # 无论是否 Web 用户,只要 OpenID 不同,都更新为最新的 OpenID user = phone_user - # 只有当它是 Web 虚拟用户时,才覆盖 OpenID - if user.openid.startswith('web_') or not user.openid: - user.openid = openid - # 确保标记为拥有 Web 徽章 (虽然它本来就是 Web 用户转过来的) + if user.openid.startswith('web_'): user.has_web_badge = True + + if user.openid != openid: + print(f"用户更换 OpenID: {user.openid} -> {openid}, Phone: {phone_number}") + user.openid = openid user.save() - elif user.openid != openid: - # 冲突: 手机号已被另一个真实 OpenID 绑定,但当前登录的是新的 OpenID - # 策略: 创建新用户,不合并 (避免安全风险) - # 检查 openid 是否已被其他用户占用 (理论上 mp_user 为 None 说明没有,但双重检查) - existing_openid_user = WeChatUser.objects.filter(openid=openid).first() - if existing_openid_user: - user = existing_openid_user - else: - user = WeChatUser.objects.create(openid=openid) - # 此时不绑定手机号,因为手机号被 phone_user 占用了 elif mp_user: # 【更新场景】: 只有小程序用户存在 -> 更新手机号 @@ -1345,12 +1328,8 @@ def bind_phone(request): 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) + # 策略:保留 current_user (MP User, with real OpenID),合并 existing_user (Phone User) 的数据 + # 无论 existing_user 是否是 Web 用户,都允许合并,以 current_user 为主(覆盖旧 OpenID) # 执行合并 from django.db import transaction @@ -1364,18 +1343,18 @@ def bind_phone(request): 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 用户未注册) + # 5. 迁移 Distributor (如果旧用户注册了分销员,且新用户未注册) if hasattr(existing_user, 'distributor') and not hasattr(current_user, 'distributor'): dist = existing_user.distributor dist.user = current_user dist.save() - # 6. 迁移用户信息 (优先使用 Web 用户信息) - if existing_user.nickname: + # 6. 迁移用户信息 (如果新用户尚未设置,则使用旧用户的信息) + if not current_user.nickname and existing_user.nickname: current_user.nickname = existing_user.nickname - if existing_user.avatar_url: + if not current_user.avatar_url and existing_user.avatar_url: current_user.avatar_url = existing_user.avatar_url - if existing_user.gender != 0: + if current_user.gender == 0 and existing_user.gender != 0: current_user.gender = existing_user.gender # 7. 迁移系统用户关联 @@ -1384,10 +1363,11 @@ def bind_phone(request): existing_user.user = None existing_user.save() - # 8. 标记 Web 徽章 - current_user.has_web_badge = True + # 8. 标记 Web 徽章 (如果旧用户是 Web 用户或已有徽章) + if existing_user.openid.startswith('web_') or existing_user.has_web_badge: + current_user.has_web_badge = True - # 删除旧 Web 用户 + # 删除旧用户 existing_user.delete() # 更新当前用户手机号