add:log
This commit is contained in:
@@ -114,9 +114,21 @@ Page({
|
|||||||
|
|
||||||
onGoLogin() {
|
onGoLogin() {
|
||||||
const redirect = `/pages/closet-share-detail/closet-share-detail?uuid=${this.data.uuid}`
|
const redirect = `/pages/closet-share-detail/closet-share-detail?uuid=${this.data.uuid}`
|
||||||
|
const loginUrl = `/pages/login/login?redirect=${encodeURIComponent(redirect)}`
|
||||||
wx.navigateTo({
|
wx.navigateTo({
|
||||||
url: `/pages/login/login?redirect=${encodeURIComponent(redirect)}`,
|
url: loginUrl,
|
||||||
fail: () => wx.switchTab({ url: '/pages/profile/profile' }),
|
fail: (e) => {
|
||||||
|
// 页面栈满(10 层)时 navigateTo 失败:改用 redirectTo 仍跳登录页,
|
||||||
|
// 且保留 redirect 参数(原先跳 profile 会丢失来源,登录后回不到分享页)
|
||||||
|
console.log('[share-detail] navigateTo 登录页失败,改用 redirectTo, err=', e && e.errMsg)
|
||||||
|
wx.redirectTo({
|
||||||
|
url: loginUrl,
|
||||||
|
fail: (e2) => {
|
||||||
|
console.log('[share-detail] redirectTo 登录页也失败, err=', e2 && e2.errMsg)
|
||||||
|
wx.switchTab({ url: '/pages/profile/profile' })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad(query: Record<string, string>) {
|
onLoad(query: Record<string, string>) {
|
||||||
|
console.log('[login] onLoad, query=', JSON.stringify(query), 'isLoggedIn=', auth.isLoggedIn())
|
||||||
if (query.redirect) this.setData({ redirect: query.redirect })
|
if (query.redirect) this.setData({ redirect: query.redirect })
|
||||||
if (auth.isLoggedIn()) {
|
if (auth.isLoggedIn()) {
|
||||||
this.goAfterLogin()
|
this.goAfterLogin()
|
||||||
@@ -29,27 +30,50 @@ Page({
|
|||||||
// 登录完成后的落地页:带 redirect 时回跳来源页(分享详情等),否则进衣橱
|
// 登录完成后的落地页:带 redirect 时回跳来源页(分享详情等),否则进衣橱
|
||||||
goAfterLogin(fallback = false) {
|
goAfterLogin(fallback = false) {
|
||||||
const redirect = this.data.redirect
|
const redirect = this.data.redirect
|
||||||
|
console.log('[login] goAfterLogin, redirect=', redirect, 'fallback=', fallback)
|
||||||
if (redirect && !fallback) {
|
if (redirect && !fallback) {
|
||||||
wx.redirectTo({
|
wx.redirectTo({
|
||||||
url: redirect,
|
url: redirect,
|
||||||
fail: () => this.goAfterLogin(true),
|
fail: (e) => {
|
||||||
|
console.log('[login] redirect 失败,回退衣橱, err=', e && e.errMsg)
|
||||||
|
this.goAfterLogin(true)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wx.switchTab({ url: '/pages/wardrobe/wardrobe' })
|
wx.switchTab({
|
||||||
|
url: '/pages/wardrobe/wardrobe',
|
||||||
|
fail: (e) => console.log('[login] switchTab 衣橱失败, err=', e && e.errMsg),
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onLogin() {
|
onLogin() {
|
||||||
if (this.data.loading) return
|
if (this.data.loading) {
|
||||||
|
console.log('[login] 登录中,忽略重复点击')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('[login] 点击登录, redirect=', this.data.redirect)
|
||||||
this.setData({ loading: true })
|
this.setData({ loading: true })
|
||||||
|
|
||||||
|
// 超时兜底:wx.login / wx.request 异常挂起时复位按钮,避免永久 loading 点不动
|
||||||
|
this.clearLoginTimer()
|
||||||
|
;(this as any).loginTimer = setTimeout(() => {
|
||||||
|
;(this as any).loginTimer = null
|
||||||
|
if (!this.data.loading) return
|
||||||
|
console.log('[login] 登录超时(30s),复位按钮')
|
||||||
|
this.setData({ loading: false })
|
||||||
|
wx.showToast({ title: '登录超时,请重试', icon: 'none' })
|
||||||
|
}, 30000)
|
||||||
|
|
||||||
wx.login({
|
wx.login({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (!res.code) {
|
if (!res.code) {
|
||||||
this.setData({ loading: false })
|
console.log('[login] wx.login 返回空 code')
|
||||||
|
this.finishLogin()
|
||||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
console.log('[login] wx.login 成功, codeLen=', res.code.length)
|
||||||
request<LoginResult>({
|
request<LoginResult>({
|
||||||
url: '/user/wxlogin',
|
url: '/user/wxlogin',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -57,6 +81,12 @@ Page({
|
|||||||
auth: false,
|
auth: false,
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
console.log(
|
||||||
|
'[login] wxlogin 成功, isNew=',
|
||||||
|
data.user_info && data.user_info.is_new_user,
|
||||||
|
'expireTime=',
|
||||||
|
data.expire_time,
|
||||||
|
)
|
||||||
auth.setTokens({
|
auth.setTokens({
|
||||||
accessToken: data.access_token,
|
accessToken: data.access_token,
|
||||||
refreshToken: data.refresh_token,
|
refreshToken: data.refresh_token,
|
||||||
@@ -74,19 +104,40 @@ Page({
|
|||||||
this.goAfterLogin()
|
this.goAfterLogin()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch((e) => {
|
||||||
|
console.log('[login] wxlogin 失败, code=', e && e.code, 'msg=', e && e.message)
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// 无论成功还是失败都复位:分支走向礼包/生日引导时若不复位,登录按钮会永久点不动
|
// 无论成功还是失败都复位:分支走向礼包/生日引导时若不复位,登录按钮会永久点不动
|
||||||
this.setData({ loading: false })
|
this.finishLogin()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fail: () => {
|
fail: (e) => {
|
||||||
this.setData({ loading: false })
|
console.log('[login] wx.login 失败, errMsg=', e && e.errMsg)
|
||||||
|
this.finishLogin()
|
||||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 复位登录态:清超时定时器 + 复位按钮
|
||||||
|
finishLogin() {
|
||||||
|
this.clearLoginTimer()
|
||||||
|
this.setData({ loading: false })
|
||||||
|
},
|
||||||
|
|
||||||
|
clearLoginTimer() {
|
||||||
|
const timer = (this as any).loginTimer
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer)
|
||||||
|
;(this as any).loginTimer = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnload() {
|
||||||
|
this.clearLoginTimer()
|
||||||
|
},
|
||||||
|
|
||||||
showWelcomeGift(userInfo: UserInfo) {
|
showWelcomeGift(userInfo: UserInfo) {
|
||||||
// 额度只用于礼包展示:失败静默降级,绝不能触发登出/清 token
|
// 额度只用于礼包展示:失败静默降级,绝不能触发登出/清 token
|
||||||
request<{ quotas: QuotaItem[] }>({ url: '/quota/info', showError: false, silentAuth: true })
|
request<{ quotas: QuotaItem[] }>({ url: '/quota/info', showError: false, silentAuth: true })
|
||||||
|
|||||||
@@ -34,21 +34,8 @@ export function isLoggedIn(): boolean {
|
|||||||
return !!getAccessToken()
|
return !!getAccessToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
// token 过期提前量(秒):提前 30s 视为过期,避免请求在途时刚好失效
|
// token 过期判定统一由后端 401 驱动,前端不再猜测 expire_time 的单位
|
||||||
const EXPIRE_LEAD_SECONDS = 30
|
// (秒 / 毫秒 / 剩余秒数无法可靠区分,误判会导致不必要的刷新与误踢登录)
|
||||||
|
|
||||||
/**
|
|
||||||
* access token 是否已过期(仅用于请求前预刷新,不参与登录态判定)
|
|
||||||
* expire_time 单位兼容秒与毫秒:数值大于 1e12 视为毫秒时间戳。
|
|
||||||
*/
|
|
||||||
export function isTokenExpired(): boolean {
|
|
||||||
const expireTime = getExpireTime()
|
|
||||||
if (!expireTime) return false // 未记录过期时间时不臆测,交给后端判定
|
|
||||||
|
|
||||||
const isMillisecond = expireTime > 1e12
|
|
||||||
const expireMs = isMillisecond ? expireTime : expireTime * 1000
|
|
||||||
return Date.now() + EXPIRE_LEAD_SECONDS * 1000 >= expireMs
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearUserInfo(): void {
|
export function clearUserInfo(): void {
|
||||||
wx.removeStorageSync(STORAGE_KEYS.USER_INFO)
|
wx.removeStorageSync(STORAGE_KEYS.USER_INFO)
|
||||||
|
|||||||
@@ -44,9 +44,12 @@ function isAuthExpiredCode(code: number, statusCode?: number): boolean {
|
|||||||
// 登录失效后的收尾:非关键请求只 reject,不动登录态
|
// 登录失效后的收尾:非关键请求只 reject,不动登录态
|
||||||
function failAuth(code: number, msg: string, silentAuth: boolean, showError: boolean) {
|
function failAuth(code: number, msg: string, silentAuth: boolean, showError: boolean) {
|
||||||
if (!silentAuth) {
|
if (!silentAuth) {
|
||||||
|
console.log('[auth] failAuth 清理登录态并跳转登录页, code=', code, 'msg=', msg)
|
||||||
auth.clearTokens()
|
auth.clearTokens()
|
||||||
handleAuthExpired()
|
handleAuthExpired()
|
||||||
if (showError) showToast('登录已过期,请重新登录')
|
if (showError) showToast('登录已过期,请重新登录')
|
||||||
|
} else {
|
||||||
|
console.log('[auth] failAuth 静默失败(不动登录态), code=', code)
|
||||||
}
|
}
|
||||||
return new ApiError(code, msg || '登录已过期')
|
return new ApiError(code, msg || '登录已过期')
|
||||||
}
|
}
|
||||||
@@ -66,9 +69,11 @@ function doRefresh(): Promise<boolean> {
|
|||||||
const refreshToken = auth.getRefreshToken()
|
const refreshToken = auth.getRefreshToken()
|
||||||
const accessToken = auth.getAccessToken()
|
const accessToken = auth.getAccessToken()
|
||||||
if (!refreshToken || !accessToken) {
|
if (!refreshToken || !accessToken) {
|
||||||
|
console.log('[auth] doRefresh 无 token,放弃刷新')
|
||||||
resolve(false)
|
resolve(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
console.log('[auth] doRefresh 发起刷新')
|
||||||
wx.request({
|
wx.request({
|
||||||
url: `${BASE_URL}${API_PREFIX}/user/refresh-token`,
|
url: `${BASE_URL}${API_PREFIX}/user/refresh-token`,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -83,12 +88,17 @@ function doRefresh(): Promise<boolean> {
|
|||||||
refreshToken: body.data.refresh_token,
|
refreshToken: body.data.refresh_token,
|
||||||
expireTime: body.data.expire_time,
|
expireTime: body.data.expire_time,
|
||||||
})
|
})
|
||||||
|
console.log('[auth] doRefresh 成功')
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else {
|
} else {
|
||||||
|
console.log('[auth] doRefresh 响应异常, code=', body && body.code)
|
||||||
resolve(false)
|
resolve(false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: () => resolve(false),
|
fail: () => {
|
||||||
|
console.log('[auth] doRefresh 网络失败')
|
||||||
|
resolve(false)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
refreshingPromise = null
|
refreshingPromise = null
|
||||||
@@ -116,11 +126,18 @@ let redirecting = false
|
|||||||
* 2. 当前已在登录页时不重复跳转。
|
* 2. 当前已在登录页时不重复跳转。
|
||||||
*/
|
*/
|
||||||
export function redirectToLogin(): void {
|
export function redirectToLogin(): void {
|
||||||
if (redirecting) return
|
if (redirecting) {
|
||||||
|
console.log('[auth] redirectToLogin 幂等锁生效,丢弃本次跳转')
|
||||||
|
return
|
||||||
|
}
|
||||||
const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : []
|
const pages = typeof getCurrentPages === 'function' ? getCurrentPages() : []
|
||||||
const current = pages[pages.length - 1]
|
const current = pages[pages.length - 1]
|
||||||
if (current && current.route === 'pages/login/login') return
|
if (current && current.route === 'pages/login/login') {
|
||||||
|
console.log('[auth] redirectToLogin 已在登录页,跳过')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[auth] redirectToLogin 跳转登录页, 当前页=', current && current.route, '栈深=', pages.length)
|
||||||
redirecting = true
|
redirecting = true
|
||||||
wx.reLaunch({
|
wx.reLaunch({
|
||||||
url: '/pages/login/login',
|
url: '/pages/login/login',
|
||||||
@@ -234,15 +251,9 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// token 已过期:先静默刷新再发请求,省掉一次必然失败的 401 往返
|
// 直接发请求:由后端 401 判定 token 是否失效,再触发 doRefresh 重试。
|
||||||
// (刷新失败也不直接拒绝:仍发一次,由后端判定,避免网络抖动就把用户踢下线)
|
// 不再做前端「过期预刷新」:expire_time 单位(秒/毫秒/剩余秒数)无法可靠猜测,
|
||||||
if (needAuth && auth.isTokenExpired()) {
|
// 误判会让每次请求都多一次刷新往返,刷新偶发失败时把已登录用户踢回登录页。
|
||||||
doRefresh().then(() => {
|
|
||||||
doCall()
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
doCall()
|
doCall()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user