修复登录BUG
This commit is contained in:
parent
46429759b9
commit
6ec1860410
239
me/me.js
239
me/me.js
@ -1,5 +1,18 @@
|
||||
const app = getApp()
|
||||
|
||||
function normalizeAvatarUrl(avatarUrl, baseUrl) {
|
||||
if (!avatarUrl) return ''
|
||||
return avatarUrl.startsWith('http') ? avatarUrl : `${baseUrl}${avatarUrl}`
|
||||
}
|
||||
|
||||
function requestFailHint(errMsg) {
|
||||
const m = String(errMsg || '').toLowerCase()
|
||||
if (m.includes('domain') || m.includes('合法域名')) return '域名未在公众平台配置,或未开启 HTTPS'
|
||||
if (m.includes('ssl') || m.includes('certificate')) return 'HTTPS 证书异常,请检查服务器证书'
|
||||
if (m.includes('timeout') || m.includes('timed out')) return '连接超时,请稍后重试'
|
||||
return '网络异常,请检查网络后重试'
|
||||
}
|
||||
|
||||
const DEFAULT_AVATAR = 'data:image/svg+xml;utf8,' + encodeURIComponent(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="320" viewBox="0 0 320 320">
|
||||
<defs>
|
||||
@ -33,22 +46,52 @@ Page({
|
||||
this.loadProfile()
|
||||
},
|
||||
async loadProfile() {
|
||||
this.setData({ loading: true, error: '' })
|
||||
await app.ensureLogin()
|
||||
if (!app.globalData.openid) {
|
||||
this.setData({ loading: false, error: '登录失败,请稍后重试' })
|
||||
const openid = app.globalData.openid || wx.getStorageSync('openid') || ''
|
||||
if (!openid) {
|
||||
this.setData({
|
||||
loading: false,
|
||||
openid: '',
|
||||
name: '未登录',
|
||||
nickname: '未登录',
|
||||
avatarUrl: '',
|
||||
nicknameDraft: '',
|
||||
badges: 0,
|
||||
days: 0,
|
||||
error: '',
|
||||
})
|
||||
return
|
||||
}
|
||||
this.setData({ loading: true, error: '' })
|
||||
app.globalData.openid = openid
|
||||
const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl
|
||||
let profileErrMsg = ''
|
||||
wx.request({
|
||||
url: `${app.globalData.baseUrl}/api/v1/auth/profile?openid=${encodeURIComponent(app.globalData.openid)}`,
|
||||
url: `${baseUrl}/api/v1/auth/profile?openid=${encodeURIComponent(openid)}`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
const profile = res.data?.data || {}
|
||||
const avatarUrl = profile.avatar_url || wx.getStorageSync(`avatarUrl:${app.globalData.openid}`) || ''
|
||||
const body = res.data || {}
|
||||
const ok = res.statusCode >= 200 && res.statusCode < 300 && body.code === 0 && body.data
|
||||
if (!ok) {
|
||||
profileErrMsg = '个人信息加载失败,请稍后重试'
|
||||
const storedAvatarUrl = wx.getStorageSync(`avatarUrl:${openid}`) || ''
|
||||
const normalizedAvatar = normalizeAvatarUrl(storedAvatarUrl, baseUrl)
|
||||
this.setData({
|
||||
openid,
|
||||
name: '考研战士',
|
||||
nickname: '考研战士',
|
||||
avatarUrl: normalizedAvatar,
|
||||
nicknameDraft: '考研战士',
|
||||
error: profileErrMsg,
|
||||
})
|
||||
return
|
||||
}
|
||||
const profile = body.data
|
||||
const avatarUrl = wx.getStorageSync(`avatarUrl:${openid}`) || profile.avatar_url || ''
|
||||
const nickname = profile.nickname || '考研战士'
|
||||
const normalizedAvatar = avatarUrl.startsWith('http') ? avatarUrl : avatarUrl ? `${app.globalData.baseUrl}${avatarUrl}` : ''
|
||||
const normalizedAvatar = normalizeAvatarUrl(avatarUrl, baseUrl)
|
||||
profileErrMsg = ''
|
||||
this.setData({
|
||||
openid: app.globalData.openid,
|
||||
openid,
|
||||
name: nickname,
|
||||
nickname,
|
||||
avatarUrl: normalizedAvatar,
|
||||
@ -58,19 +101,20 @@ Page({
|
||||
})
|
||||
},
|
||||
fail: () => {
|
||||
const storedAvatarUrl = wx.getStorageSync(`avatarUrl:${app.globalData.openid}`) || ''
|
||||
const normalizedAvatar = storedAvatarUrl.startsWith('http') ? storedAvatarUrl : storedAvatarUrl ? `${app.globalData.baseUrl}${storedAvatarUrl}` : ''
|
||||
profileErrMsg = '个人信息加载失败,请稍后重试'
|
||||
const storedAvatarUrl = wx.getStorageSync(`avatarUrl:${openid}`) || ''
|
||||
const normalizedAvatar = normalizeAvatarUrl(storedAvatarUrl, baseUrl)
|
||||
this.setData({
|
||||
openid: app.globalData.openid,
|
||||
openid,
|
||||
name: '考研战士',
|
||||
nickname: '考研战士',
|
||||
avatarUrl: normalizedAvatar,
|
||||
nicknameDraft: '考研战士',
|
||||
error: '个人信息加载失败,请稍后重试',
|
||||
error: profileErrMsg,
|
||||
})
|
||||
},
|
||||
complete: () => {
|
||||
this.loadAchievements()
|
||||
this.loadAchievements(profileErrMsg)
|
||||
this.setData({ loading: false })
|
||||
},
|
||||
})
|
||||
@ -79,7 +123,7 @@ Page({
|
||||
this.setData({ showNicknameModal: true, nicknameDraft: this.data.nickname || this.data.name || '考研战士' })
|
||||
},
|
||||
onAvatarError() {
|
||||
this.setData({ avatarUrl: '' })
|
||||
this.setData({ avatarUrl: this.data.defaultAvatarUrl })
|
||||
},
|
||||
closeNicknameModal() {
|
||||
this.setData({ showNicknameModal: false, nicknameDraft: this.data.nickname || this.data.name || '考研战士' })
|
||||
@ -95,7 +139,7 @@ Page({
|
||||
return
|
||||
}
|
||||
wx.request({
|
||||
url: `${app.globalData.baseUrl}/api/v1/auth/profile`,
|
||||
url: `${app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl}/api/v1/auth/profile`,
|
||||
method: 'PUT',
|
||||
header: { 'Content-Type': 'application/json' },
|
||||
data: { openid: app.globalData.openid, nickname },
|
||||
@ -108,94 +152,111 @@ Page({
|
||||
fail: () => wx.showToast({ title: '保存失败', icon: 'none' }),
|
||||
})
|
||||
},
|
||||
chooseAvatar() {
|
||||
onChooseAvatar(e) {
|
||||
const tempPath = e.detail?.avatarUrl || ''
|
||||
if (!app.globalData.openid) {
|
||||
wx.showToast({ title: '请先登录', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const localPath = res.tempFilePaths?.[0] || ''
|
||||
if (!localPath) return
|
||||
wx.getImageInfo({
|
||||
src: localPath,
|
||||
success: (info) => {
|
||||
const size = 320
|
||||
const side = Math.min(info.width, info.height)
|
||||
const x = Math.max(0, Math.floor((info.width - side) / 2))
|
||||
const y = Math.max(0, Math.floor((info.height - side) / 2))
|
||||
const ctx = wx.createCanvasContext('avatar-canvas', this)
|
||||
ctx.clearRect(0, 0, size, size)
|
||||
ctx.save()
|
||||
ctx.beginPath()
|
||||
ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI)
|
||||
ctx.clip()
|
||||
ctx.drawImage(localPath, x, y, side, side, 0, 0, size, size)
|
||||
ctx.draw(false, () => {
|
||||
wx.canvasToTempFilePath({
|
||||
canvasId: 'avatar-canvas',
|
||||
width: size,
|
||||
height: size,
|
||||
destWidth: size,
|
||||
destHeight: size,
|
||||
quality: 0.85,
|
||||
success: (canvasRes) => {
|
||||
const uploadPath = canvasRes.tempFilePath || localPath
|
||||
wx.uploadFile({
|
||||
url: `${app.globalData.baseUrl}/api/v1/auth/avatar?openid=${encodeURIComponent(app.globalData.openid)}`,
|
||||
filePath: uploadPath,
|
||||
name: 'file',
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const payload = JSON.parse(uploadRes.data)
|
||||
const avatarUrl = payload?.data?.avatar_url || ''
|
||||
if (!avatarUrl) throw new Error('missing avatar_url')
|
||||
const fullUrl = avatarUrl.startsWith('http') ? avatarUrl : `${app.globalData.baseUrl}${avatarUrl}`
|
||||
wx.setStorageSync(`avatarUrl:${app.globalData.openid}`, fullUrl)
|
||||
this.setData({ avatarUrl: fullUrl })
|
||||
wx.request({
|
||||
url: `${app.globalData.baseUrl}/api/v1/auth/profile?openid=${encodeURIComponent(app.globalData.openid)}`,
|
||||
method: 'GET',
|
||||
success: (profileRes) => {
|
||||
const profile = profileRes.data?.data || {}
|
||||
const nextNickname = profile.nickname || '考研战士'
|
||||
this.setData({ name: nextNickname, nickname: nextNickname, avatarUrl: fullUrl })
|
||||
},
|
||||
})
|
||||
wx.showToast({ title: '头像已更新', icon: 'success' })
|
||||
} catch (err) {
|
||||
wx.showToast({ title: '头像更新失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: () => wx.showToast({ title: '头像上传失败', icon: 'none' }),
|
||||
})
|
||||
},
|
||||
fail: () => wx.showToast({ title: '头像处理失败', icon: 'none' }),
|
||||
}, this)
|
||||
})
|
||||
},
|
||||
fail: () => wx.showToast({ title: '读取图片失败', icon: 'none' }),
|
||||
})
|
||||
if (!tempPath) {
|
||||
wx.showToast({ title: '未选择头像', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl
|
||||
wx.uploadFile({
|
||||
url: `${baseUrl}/api/v1/auth/avatar?openid=${encodeURIComponent(app.globalData.openid)}`,
|
||||
filePath: tempPath,
|
||||
name: 'file',
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const payload = JSON.parse(uploadRes.data || '{}')
|
||||
const ok =
|
||||
uploadRes.statusCode >= 200 &&
|
||||
uploadRes.statusCode < 300 &&
|
||||
payload.code === 0 &&
|
||||
payload.data
|
||||
if (!ok) {
|
||||
wx.showToast({ title: payload.message || '头像上传失败', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const rel = payload.data.avatar_url || ''
|
||||
const full = normalizeAvatarUrl(rel, baseUrl)
|
||||
wx.setStorageSync(`avatarUrl:${app.globalData.openid}`, full)
|
||||
this.setData({ avatarUrl: full })
|
||||
wx.showToast({ title: '头像已更新', icon: 'success' })
|
||||
} catch {
|
||||
wx.showToast({ title: '头像上传结果异常', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: (err) => wx.showToast({ title: requestFailHint(err.errMsg), icon: 'none' }),
|
||||
})
|
||||
},
|
||||
loadAchievements() {
|
||||
loadAchievements(profileErrMsg) {
|
||||
if (!app.globalData.openid) {
|
||||
this.setData({ error: '登录状态已失效,请重新进入页面' })
|
||||
return
|
||||
}
|
||||
const baseUrl = app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl
|
||||
const achFail = '成就数据加载失败,请稍后重试'
|
||||
wx.request({
|
||||
url: `${app.globalData.baseUrl}/api/v1/achievements`,
|
||||
url: `${baseUrl}/api/v1/achievements`,
|
||||
header: { 'X-OpenID': app.globalData.openid },
|
||||
success: (res) => {
|
||||
const list = res.data?.data || []
|
||||
const badges = Array.isArray(list) ? list.filter((i) => i.is_unlocked).length : 0
|
||||
this.setData({ badges })
|
||||
const body = res.data || {}
|
||||
const ok = res.statusCode >= 200 && res.statusCode < 300 && body.code === 0 && Array.isArray(body.data)
|
||||
if (!ok) {
|
||||
this.setData({ error: profileErrMsg ? `${profileErrMsg};${achFail}` : achFail })
|
||||
return
|
||||
}
|
||||
const list = body.data
|
||||
const badges = list.filter((i) => i.is_unlocked).length
|
||||
this.setData({ badges, error: profileErrMsg || '' })
|
||||
},
|
||||
fail: (err) => {
|
||||
const netHint = requestFailHint(err.errMsg)
|
||||
const line = profileErrMsg ? `${profileErrMsg};${achFail}` : achFail
|
||||
this.setData({ error: `${line}(${netHint})` })
|
||||
},
|
||||
})
|
||||
},
|
||||
manualLogin() {
|
||||
wx.login({
|
||||
success: (res) => {
|
||||
const code = res.code || ''
|
||||
console.log('[login] wx.login success', res)
|
||||
console.log('[login] code', code)
|
||||
if (!code) {
|
||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.request({
|
||||
url: `${app.getApiBaseUrl ? app.getApiBaseUrl() : app.globalData.baseUrl}/api/v1/auth/wx-login`,
|
||||
method: 'POST',
|
||||
header: { 'Content-Type': 'application/json' },
|
||||
data: { code },
|
||||
success: (loginRes) => {
|
||||
console.log('[login] wx-login success', loginRes)
|
||||
const payload = loginRes.data?.data || {}
|
||||
if (loginRes.statusCode >= 200 && loginRes.statusCode < 300 && loginRes.data?.code === 0 && payload.openid) {
|
||||
app.globalData.openid = payload.openid
|
||||
wx.setStorageSync('openid', payload.openid)
|
||||
wx.showToast({ title: '登录成功', icon: 'success' })
|
||||
this.loadProfile()
|
||||
return
|
||||
}
|
||||
console.log('[login] wx-login invalid response', loginRes.data)
|
||||
wx.showToast({ title: '登录接口异常,请稍后重试', icon: 'none' })
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('[login] wx-login fail', err)
|
||||
wx.showToast({ title: requestFailHint(err.errMsg), icon: 'none' })
|
||||
},
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('[login] wx.login fail', err)
|
||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
},
|
||||
fail: () => this.setData({ error: '成就数据加载失败,请稍后重试' }),
|
||||
})
|
||||
},
|
||||
goTo(e) {
|
||||
|
||||
14
me/me.wxml
14
me/me.wxml
@ -6,20 +6,26 @@
|
||||
<text class="empty-subtitle">正在获取个人信息</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{!openid}}" class="empty-state">
|
||||
<text class="empty-title">还未登录</text>
|
||||
<text class="empty-subtitle">请点击下方按钮手动登录后继续使用</text>
|
||||
<button class="secondary-btn error-btn" bindtap="manualLogin">手动登录</button>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{error}}" class="error-banner">
|
||||
<text class="error-text">{{error}}</text>
|
||||
<button class="secondary-btn error-btn" bindtap="loadProfile">重试</button>
|
||||
</view>
|
||||
|
||||
<view wx:else class="hero-section">
|
||||
<view class="hero-avatar-wrap" bindtap="chooseAvatar">
|
||||
<button class="hero-avatar-wrap avatar-choose-btn" hover-class="none" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
|
||||
<view class="hero-avatar-border">
|
||||
<image class="hero-avatar" src="{{avatarUrl || defaultAvatarUrl}}" mode="aspectFill" binderror="onAvatarError" />
|
||||
<view class="avatar-mask">
|
||||
<text class="avatar-mask-text">更换头像</text>
|
||||
<text class="avatar-mask-text">选择头像</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</button>
|
||||
<view class="hero-info">
|
||||
<text class="hero-name" bindtap="openNicknameModal">{{name}}</text>
|
||||
<view class="hero-badge">
|
||||
@ -87,7 +93,7 @@
|
||||
<text class="modal-title">修改昵称</text>
|
||||
<text class="modal-close" bindtap="closeNicknameModal">×</text>
|
||||
</view>
|
||||
<input class="modal-input" value="{{nicknameDraft}}" placeholder="请输入昵称" maxlength="100" focus="true" bindinput="onNicknameInput" />
|
||||
<input class="modal-input" type="nickname" value="{{nicknameDraft}}" placeholder="请输入昵称" maxlength="100" focus="true" bindinput="onNicknameInput" />
|
||||
<view class="modal-actions">
|
||||
<button class="modal-btn ghost" bindtap="closeNicknameModal">取消</button>
|
||||
<button class="modal-btn primary" bindtap="saveNickname">保存</button>
|
||||
|
||||
546
me/me.wxss
546
me/me.wxss
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user