优化真机测试环境下的用户授权流程

问题分析:
1. 微信已废弃自动弹出授权框功能
2. 用户不清楚如何选择头像和昵称
3. 授权流程引导不清晰

解决方案:
1. 优化授权页面布局
   - 分步骤引导:第一步选择头像,第二步输入昵称
   - 添加清晰的步骤标签和提示文字
   - 头像选择后显示"已选择"状态
   - 昵称输入框添加提示文字

2. 增强交互体验
   - 选择头像成功后显示Toast提示
   - 按钮状态根据是否填写完整显示不同样式
   - 未填写完整时按钮半透明不可点击
   - 授权成功后延长Toast显示时间

3. 完善错误处理
   - 添加详细的错误提示信息
   - 区分头像和昵称为空的提示
   - 授权失败时显示具体原因

4. 优化提示说明
   - 更新授权说明内容
   - 说明如何获取微信昵称
   - 说明可以手动输入自定义昵称

测试要点:
- 首次使用自动跳转到授权页面
- 点击头像按钮可选择微信头像或相册图片
- 点击昵称输入框可自动填充微信昵称
- 授权成功后"我的"页面显示头像和昵称
This commit is contained in:
H1d3rOne committed 2026-03-09 16:31:37 +08:00
1 parent 75d4901476
commit 28848d541d
1 file changed
+93 -35
+93 -35
View File
@@ -9,35 +9,44 @@
</view>
<view class="auth-card">
<button class="auth-avatar-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image class="avatar-img" :src="avatarUrl || defaultAvatar" mode="aspectFit" />
<text class="auth-tip">点击选择头像</text>
</button>
<view class="auth-section">
<text class="section-label">第一步:选择头像</text>
<button class="auth-avatar-btn" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
<image class="avatar-img" :src="avatarUrl || defaultAvatar" mode="aspectFill" />
<text class="auth-tip">{{ avatarUrl ? '已选择' : '点击选择头像' }}</text>
</button>
</view>
<view class="auth-nickname">
<input
class="nickname-input"
type="nickname"
v-model="nickname"
placeholder="点击获取昵称"
@blur="onNicknameInput"
/>
<view class="auth-section">
<text class="section-label">第二步:输入昵称</text>
<view class="auth-nickname">
<input
class="nickname-input"
type="nickname"
v-model="nickname"
placeholder="点击输入或获取微信昵称"
@blur="onNicknameInput"
@confirm="onNicknameInput"
/>
<text class="nickname-hint">点击输入框可获取微信昵称</text>
</view>
</view>
</view>
<view class="tips-card">
<text class="tips-title">授权说明</text>
<text class="tips-content">• 获取您的微信头像和昵称用于显示用户信息
• 我们不会收集与功能无关的个人信息
• 您的信息将被安全保存在服务器上</text>
<text class="tips-title">💡 授权说明</text>
<text class="tips-content">• 点击头像按钮选择微信头像或从相册选择
• 点击昵称输入框可自动获取微信昵称
• 您也可以手动输入自定义昵称
• 信息仅用于显示用户资料</text>
</view>
<button class="auth-btn" :loading="loading" @click="doAuth">
<text class="auth-btn-text">{{ loading ? '授权中...' : '授权登录' }}</text>
<button class="auth-btn" :class="{ 'auth-btn-disabled': !canSubmit }" :loading="loading" @click="doAuth">
<text class="auth-btn-text">{{ loading ? '授权中...' : '确认授权' }}</text>
</button>
<view class="skip-auth" @click="skipAuth">
<text class="skip-text">暂不授权</text>
<text class="skip-text">暂不授权,稍后再说</text>
</view>
</view>
</template>
@@ -54,6 +63,11 @@ export default {
defaultAvatar: '/static/default-avatar.png'
}
},
computed: {
canSubmit() {
return this.avatarUrl && this.nickname
}
},
methods: {
onChooseAvatar(e) {
console.log('选择头像:', e)
@@ -61,6 +75,11 @@ export default {
if (avatarUrl) {
this.avatarUrl = avatarUrl
console.log('头像URL:', avatarUrl)
uni.showToast({
title: '头像已选择',
icon: 'success',
duration: 1500
})
}
},
@@ -75,7 +94,12 @@ export default {
async doAuth() {
if (!this.avatarUrl) {
uni.showToast({ title: '请选择头像', icon: 'none' })
uni.showToast({ title: '请先选择头像', icon: 'none' })
return
}
if (!this.nickname) {
uni.showToast({ title: '请输入昵称', icon: 'none' })
return
}
@@ -97,12 +121,13 @@ export default {
const res = await api.userApi.loginOrRegister({
code: loginRes.code,
nickname: this.nickname || '微信用户',
nickname: this.nickname,
avatarUrl: this.avatarUrl
})
if (res.success) {
console.log('登录成功:', res.data)
uni.setStorageSync('userId', res.data.userId)
uni.setStorageSync('userInfo', JSON.stringify(res.data))
uni.setStorageSync('userCoins', res.data.coins || 10)
@@ -110,19 +135,24 @@ export default {
uni.setStorageSync('username', res.data.username || res.data.nickname)
uni.setStorageSync('userAvatar', res.data.avatarUrl)
uni.showToast({ title: '登录成功', icon: 'success' })
uni.showToast({
title: '授权成功',
icon: 'success',
duration: 2000
})
setTimeout(() => {
uni.switchTab({ url: '/pages/index/index' })
}, 1500)
}, 2000)
} else {
throw new Error(res.error || '登录失败')
}
} catch (err) {
console.error('登录失败:', err)
uni.showToast({
title: err.message || '网络错误',
icon: 'none'
title: err.message || '授权失败,请重试',
icon: 'none',
duration: 3000
})
} finally {
this.loading = false
@@ -211,11 +241,26 @@ page {
width: 100%;
}
.auth-section {
margin-bottom: 32rpx;
}
.auth-section:last-child {
margin-bottom: 0;
}
.section-label {
font-size: 28rpx;
font-weight: 600;
color: #065F46;
display: block;
margin-bottom: 16rpx;
}
.auth-avatar-btn {
width: 160rpx;
height: 160rpx;
margin: 0 auto 24rpx;
position: relative;
height: 200rpx;
margin: 0 auto;
background: transparent;
border: none;
padding: 0;
@@ -232,30 +277,38 @@ page {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
border: 4rpx solid #10B981;
}
.auth-tip {
font-size: 22rpx;
color: #10B981;
background: rgba(255, 255, 255, 0.9);
padding: 4rpx 16rpx;
background: rgba(16, 185, 129, 0.1);
padding: 8rpx 24rpx;
border-radius: 16rpx;
margin-top: 10rpx;
margin-top: 16rpx;
}
.auth-nickname {
display: flex;
align-items: center;
gap: 16rpx;
flex-direction: column;
gap: 12rpx;
}
.nickname-input {
flex: 1;
padding: 20rpx 24rpx;
width: 100%;
padding: 24rpx;
background: #ECFDF5;
border-radius: 16rpx;
font-size: 28rpx;
color: #065F46;
border: 2rpx solid rgba(16, 185, 129, 0.2);
}
.nickname-hint {
font-size: 22rpx;
color: #6B7280;
padding-left: 8rpx;
}
.tips-card {
@@ -297,6 +350,10 @@ page {
opacity: 0.7;
}
.auth-btn-disabled {
opacity: 0.5;
}
.auth-btn-text {
font-size: 32rpx;
color: #ffffff;
@@ -305,6 +362,7 @@ page {
.skip-auth {
text-align: center;
padding: 16rpx;
}
.skip-text {