diff --git a/backend/shop/__pycache__/views.cpython-312.pyc b/backend/shop/__pycache__/views.cpython-312.pyc index c2c010c..60cb3fa 100644 Binary files a/backend/shop/__pycache__/views.cpython-312.pyc and b/backend/shop/__pycache__/views.cpython-312.pyc differ diff --git a/backend/shop/views.py b/backend/shop/views.py index 6c998f4..6ffe8a3 100644 --- a/backend/shop/views.py +++ b/backend/shop/views.py @@ -1004,9 +1004,9 @@ def wechat_login(request): phone_number = None if phone_code: - access_token = get_access_token(config) - if access_token: - try: + try: + access_token = get_access_token(config) + if access_token: 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() @@ -1014,8 +1014,13 @@ def wechat_login(request): if phone_data.get('errcode') == 0: phone_info = phone_data.get('phone_info') phone_number = phone_info.get('purePhoneNumber') - except Exception as e: - print(f"获取手机号失败: {e}") + else: + print(f"获取手机号API返回错误: {phone_data}") + else: + print("获取 AccessToken 失败,无法解密手机号") + except Exception as e: + print(f"获取手机号异常: {str(e)}") + try: with transaction.atomic(): @@ -1029,29 +1034,41 @@ def wechat_login(request): if mp_user and phone_user: if mp_user != phone_user: - # 【合并场景】: 小程序用户 和 手机号用户 都存在且不同 -> 将手机号用户(Web)合并到小程序用户 - # 注意: 如果 phone_user 也是真实的 MP 用户(有 openid 且不是 web_), 则可能冲突,这里默认保留当前登录的 mp_user + # 【合并场景】: 小程序用户 和 手机号用户 都存在且不同 - # 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() + # 检查 phone_user 是否已经是真实的 MP 用户 (防止覆盖已绑定的其他微信账号) + # 规则: 如果 phone_user.openid 不是以 'web_' 开头,说明它已经是一个微信用户 + # 此时我们不能简单的合并,因为这意味着两个不同的微信账号绑定了同一个手机号(可能是异常或用户更换了微信号) + # 策略: 优先保留当前的 mp_user,提示用户手机号已被占用,或者这里简单处理为不合并手机号,只登录 mp_user - # 删除旧用户 - phone_user.delete() - user = mp_user - - # 更新手机号 - if not user.phone_number: - user.phone_number = phone_number + 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() + + # 删除旧用户 + phone_user.delete() + user = mp_user + + # 更新手机号 + if not user.phone_number: + user.phone_number = phone_number + user.save() else: # 同一个用户 user = mp_user @@ -1059,31 +1076,46 @@ def wechat_login(request): elif phone_user: # 【绑定场景】: 只有手机号用户存在 (通常是 Web 用户) -> 升级为小程序用户 user = phone_user + # 只有当它是 Web 虚拟用户时,才覆盖 OpenID - # 或者如果它就是目标用户,直接更新 if user.openid.startswith('web_') or not user.openid: user.openid = openid + user.save() elif user.openid != openid: # 冲突: 手机号已被另一个真实 OpenID 绑定,但当前登录的是新的 OpenID # 策略: 创建新用户,不合并 (避免安全风险) - user = WeChatUser.objects.create(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: # 【更新场景】: 只有小程序用户存在 -> 更新手机号 user = mp_user if phone_number: + # 检查手机号是否冲突 (理论上 phone_user 为 None 说明没有冲突) user.phone_number = phone_number + user.save() else: # 【新建场景】: 都不存在 -> 创建新用户 user = WeChatUser.objects.create(openid=openid) if phone_number: user.phone_number = phone_number + user.save() - # 统一更新会话信息 - user.session_key = session_key - user.unionid = unionid - user.save() + # 统一更新会话信息 (确保 user 对象是最新的) + # 重新获取对象以防状态不一致 (可选,但推荐) + # user.refresh_from_db() + + if user.openid == openid: + user.session_key = session_key + user.unionid = unionid + user.save() + created = False # 简化处理 except Exception as e: diff --git a/miniprogram/src/pages/user/index.tsx b/miniprogram/src/pages/user/index.tsx index ee9d18c..03fec4d 100644 --- a/miniprogram/src/pages/user/index.tsx +++ b/miniprogram/src/pages/user/index.tsx @@ -61,6 +61,8 @@ export default function UserIndex() { const { code: loginCode } = await Taro.login() // 2. 调用后端登录 (Code + PhoneCode) + console.log('loginCode:', loginCode) + console.log('phoneCode:', phoneCode) const res = await Taro.request({ url: 'https://market.quant-speed.com/api/wechat/login/', method: 'POST',