This commit is contained in:
@@ -45,7 +45,7 @@ def get_current_wechat_user(request):
|
||||
except (BadSignature, SignatureExpired):
|
||||
return None
|
||||
|
||||
def get_access_token(config=None):
|
||||
def get_access_token(config=None, force_refresh=False):
|
||||
"""
|
||||
获取微信接口调用凭证 (client_credential)
|
||||
"""
|
||||
@@ -54,9 +54,10 @@ def get_access_token(config=None):
|
||||
if config:
|
||||
cache_key = f'wechat_access_token_{config.app_id}'
|
||||
|
||||
token = cache.get(cache_key)
|
||||
if token:
|
||||
return token
|
||||
if not force_refresh:
|
||||
token = cache.get(cache_key)
|
||||
if token:
|
||||
return token
|
||||
|
||||
if not config:
|
||||
# 优先查找指定 AppID
|
||||
|
||||
@@ -1016,6 +1016,15 @@ def wechat_login(request):
|
||||
phone_res = requests.post(phone_url, json={'code': phone_code}, timeout=5)
|
||||
phone_data = phone_res.json()
|
||||
|
||||
# Retry if access token is invalid or expired
|
||||
if phone_data.get('errcode') in [40001, 40014, 42001]:
|
||||
print(f"Access token invalid/expired ({phone_data.get('errcode')}), refreshing...")
|
||||
access_token = get_access_token(config, force_refresh=True)
|
||||
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()
|
||||
|
||||
if phone_data.get('errcode') == 0:
|
||||
phone_info = phone_data.get('phone_info')
|
||||
phone_number = phone_info.get('purePhoneNumber')
|
||||
@@ -1066,14 +1075,21 @@ def wechat_login(request):
|
||||
dist.user = mp_user
|
||||
dist.save()
|
||||
|
||||
# 4. 迁移用户信息(如果小程序用户没有昵称/头像,继承Web用户的)
|
||||
if not mp_user.nickname and phone_user.nickname:
|
||||
# 4. 迁移用户信息(优先使用Web用户的信息,覆盖小程序的信息,保持体验一致)
|
||||
if phone_user.nickname:
|
||||
mp_user.nickname = phone_user.nickname
|
||||
if not mp_user.avatar_url and phone_user.avatar_url:
|
||||
if phone_user.avatar_url:
|
||||
mp_user.avatar_url = phone_user.avatar_url
|
||||
if mp_user.gender == 0 and phone_user.gender != 0:
|
||||
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徽章
|
||||
mp_user.has_web_badge = True
|
||||
mp_user.save()
|
||||
@@ -1096,6 +1112,8 @@ def wechat_login(request):
|
||||
# 只有当它是 Web 虚拟用户时,才覆盖 OpenID
|
||||
if user.openid.startswith('web_') or not user.openid:
|
||||
user.openid = openid
|
||||
# 确保标记为拥有 Web 徽章 (虽然它本来就是 Web 用户转过来的)
|
||||
user.has_web_badge = True
|
||||
user.save()
|
||||
elif user.openid != openid:
|
||||
# 冲突: 手机号已被另一个真实 OpenID 绑定,但当前登录的是新的 OpenID
|
||||
@@ -1134,8 +1152,20 @@ def wechat_login(request):
|
||||
# 更新用户基本信息 (如果有传入)
|
||||
if nickname:
|
||||
user.nickname = nickname
|
||||
elif not user.nickname:
|
||||
# 默认昵称逻辑 (与 Web 端保持一致)
|
||||
if user.phone_number:
|
||||
user.nickname = f"User_{user.phone_number[-4:]}"
|
||||
else:
|
||||
user.nickname = f"WeChat_User_{user.openid[-4:]}"
|
||||
|
||||
if avatar_url:
|
||||
user.avatar_url = avatar_url
|
||||
elif not user.avatar_url:
|
||||
# 默认头像逻辑
|
||||
seed = user.phone_number or user.openid
|
||||
user.avatar_url = f"https://api.dicebear.com/7.x/avataaars/svg?seed={seed}"
|
||||
|
||||
if gender is not None:
|
||||
user.gender = gender
|
||||
if country:
|
||||
@@ -1338,6 +1368,23 @@ def bind_phone(request):
|
||||
dist.user = current_user
|
||||
dist.save()
|
||||
|
||||
# 6. 迁移用户信息 (优先使用 Web 用户信息)
|
||||
if existing_user.nickname:
|
||||
current_user.nickname = existing_user.nickname
|
||||
if existing_user.avatar_url:
|
||||
current_user.avatar_url = existing_user.avatar_url
|
||||
if existing_user.gender != 0:
|
||||
current_user.gender = existing_user.gender
|
||||
|
||||
# 7. 迁移系统用户关联
|
||||
if existing_user.user and not current_user.user:
|
||||
current_user.user = existing_user.user
|
||||
existing_user.user = None
|
||||
existing_user.save()
|
||||
|
||||
# 8. 标记 Web 徽章
|
||||
current_user.has_web_badge = True
|
||||
|
||||
# 删除旧 Web 用户
|
||||
existing_user.delete()
|
||||
|
||||
|
||||
@@ -318,14 +318,6 @@ export default function UserIndex() {
|
||||
|
||||
{userInfo && (
|
||||
<View className='badges-row'>
|
||||
{/* 明星技术用户 */}
|
||||
{userInfo.is_star && (
|
||||
<View className='badge star'>
|
||||
<Text className='badge-icon'>🌟</Text>
|
||||
<Text className='badge-text'>技术专家</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 管理员 */}
|
||||
{userInfo.is_admin && (
|
||||
<View className='badge admin'>
|
||||
@@ -333,9 +325,17 @@ export default function UserIndex() {
|
||||
<Text className='badge-text'>管理员</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 明星技术用户/专家 */}
|
||||
{userInfo.is_star && (
|
||||
<View className='badge star'>
|
||||
<Text className='badge-icon'>🌟</Text>
|
||||
<Text className='badge-text'>{userInfo.title || '技术专家'}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 网页用户徽章 - 仅在 has_web_badge 为 true 时显示 */}
|
||||
{userInfo.has_web_badge && (
|
||||
{/* 网页用户徽章 */}
|
||||
{(userInfo.has_web_badge || userInfo.has_web_account) && (
|
||||
<View className='badge web active'>
|
||||
<Text className='badge-icon'>🌐</Text>
|
||||
<Text className='badge-text'>网页用户</Text>
|
||||
|
||||
Reference in New Issue
Block a user