2025-11-24 22:37:11 +08:00

145 lines
6.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<image class="logo" src="/static/logo.png" mode="widthFix"></image>
<view class="title">微信登录</view>
<!-- #ifdef MP-WEIXIN -->
<button class="btn" open-type="getPhoneNumber" :disabled="loading" @getphonenumber="onGetPhoneNumber">授权手机号快速登录</button>
<!-- #endif -->
<view class="agreements">
<text>注册或登录即表示您已阅读并同意</text>
<text class="link" @tap="toUserAgreement">用户协议</text>
<text></text>
<text class="link" @tap="toPurchaseAgreement">购买协议</text>
</view>
<view v-if="needBindPhone" class="tip">登录成功请绑定手机号以完成登录</view>
<view v-if="error" class="error">{{ error }}</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { wechatLogin, bindPhone, getUserStats, getPointsBalance } from '../../api/appUser'
const loading = ref(false)
const error = ref('')
const needBindPhone = ref(false)
const loggedIn = computed(() => !!uni.getStorageSync('token'))
function onLogin() {}
function toUserAgreement() { uni.navigateTo({ url: '/pages/agreement/user' }) }
function toPurchaseAgreement() { uni.navigateTo({ url: '/pages/agreement/purchase' }) }
function onGetPhoneNumber(e) {
const phoneCode = e.detail.code
console.log('login_flow start getPhoneNumber, codeExists:', !!phoneCode)
if (!phoneCode) {
uni.showToast({ title: '未授权手机号', icon: 'none' })
console.error('login_flow error: missing phoneCode')
return
}
loading.value = true
error.value = ''
uni.login({
provider: 'weixin',
success: async (res) => {
try {
const loginCode = res.code
console.log('login_flow uni.login success, loginCode exists:', !!loginCode)
const data = await wechatLogin(loginCode)
console.log('login_flow wechatLogin response user_id:', data && data.user_id)
const token = data && data.token
const user_id = data && data.user_id
const avatar = data && data.avatar
const nickname = data && data.nickname
const invite_code = data && data.invite_code
uni.setStorageSync('user_info', data || {})
if (token) {
uni.setStorageSync('token', token)
console.log('login_flow token stored')
}
if (user_id) {
uni.setStorageSync('user_id', user_id)
console.log('login_flow user_id stored:', user_id)
}
if (avatar) {
uni.setStorageSync('avatar', avatar)
}
if (nickname) {
uni.setStorageSync('nickname', nickname)
}
if (invite_code) {
uni.setStorageSync('invite_code', invite_code)
}
console.log('login_flow bindPhone start')
try {
// 首次绑定前短暂延迟,确保服务端 token 生效
await new Promise(r => setTimeout(r, 600))
const bindRes = await bindPhone(user_id, phoneCode, { 'X-Suppress-Auth-Modal': true })
const phoneNumber = (bindRes && (bindRes.phone || bindRes.phone_number || bindRes.mobile)) || ''
if (phoneNumber) uni.setStorageSync('phone_number', phoneNumber)
} catch (bindErr) {
if (bindErr && bindErr.statusCode === 401) {
console.warn('login_flow bindPhone 401, try re-login and retry')
// 重新获取登录 code
const relogin = await new Promise((resolve, reject) => {
uni.login({ provider: 'weixin', success: resolve, fail: reject })
})
const data2 = await wechatLogin(relogin.code)
const token2 = data2 && data2.token
const user2 = data2 && data2.user_id
if (token2) uni.setStorageSync('token', token2)
if (user2) uni.setStorageSync('user_id', user2)
// 再次延迟后重试绑定
await new Promise(r => setTimeout(r, 600))
const bindRes2 = await bindPhone(user2 || user_id, phoneCode, { 'X-Suppress-Auth-Modal': true })
const phoneNumber2 = (bindRes2 && (bindRes2.phone || bindRes2.phone_number || bindRes2.mobile)) || ''
if (phoneNumber2) uni.setStorageSync('phone_number', phoneNumber2)
} else {
throw bindErr
}
}
uni.setStorageSync('phone_bound', true)
console.log('login_flow bindPhone success, phone_bound stored')
try {
const stats = await getUserStats(user_id)
console.log('login_flow getUserStats success')
const balance = await getPointsBalance(user_id)
console.log('login_flow getPointsBalance success')
uni.setStorageSync('user_stats', stats)
const b = balance && balance.balance !== undefined ? balance.balance : balance
uni.setStorageSync('points_balance', b)
} catch (e) {
console.error('login_flow fetch stats/points error:', e && (e.message || e.errMsg))
}
uni.showToast({ title: '登录并绑定成功', icon: 'success' })
console.log('login_flow navigate to index')
uni.reLaunch({ url: '/pages/index/index' })
} catch (err) {
console.error('login_flow error:', err && (err.message || err.errMsg), 'status:', err && err.statusCode)
error.value = err.message || '登录或绑定失败'
} finally {
loading.value = false
}
},
fail: (e) => {
console.error('login_flow uni.login fail:', e && e.errMsg)
error.value = '微信登录失败'
loading.value = false
}
})
}
</script>
<style scoped>
.container { padding: 40rpx; display: flex; flex-direction: column; align-items: center }
.logo { width: 200rpx; margin-top: 100rpx; margin-bottom: 40rpx }
.title { font-size: 36rpx; margin-bottom: 20rpx }
.btn { width: 80%; margin-top: 20rpx }
.agreements { margin-top: 16rpx; font-size: 24rpx; color: #666; display: flex; flex-wrap: wrap; justify-content: center }
.link { color: #007AFF; margin: 0 6rpx }
.tip { color: #666; margin-top: 12rpx }
.error { color: #e43; margin-top: 20rpx }
</style>