feat: 云闪付入口 token 自动登录及权益状态恢复
- 新增 open-api/hhService/tokenDecode 封装,URL 带 token 时自动解码登录并刷新资格 - 解码失败降级为手机号登录,并用 replaceState 清除地址栏 token 防泄露 - 权益页已登录未认证时自动恢复认证状态,认证取消后停留认证页 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
8d57cf7f92
commit
06e8223c27
@@ -20,12 +20,15 @@ let StoreDetailUrl = 'mp-api/hhrsStore/detail';
|
||||
let WinnerDatesUrl = 'mp-api/hhrsWinner/dates';
|
||||
let WinnerListUrl = 'mp-api/hhrsWinner/list';
|
||||
let AppointUrl = 'zhy-api/cardBag/appoint';
|
||||
let TokenDecodeUrl = 'open-api/hhService/tokenDecode';
|
||||
|
||||
|
||||
// 此处第二个参数vm,就是我们在页面使用的this
|
||||
const install = (Vue, vm) => {
|
||||
let checkerLogin = (params = {}) => vm.$u.post(LoginUrl, params);
|
||||
let sendLoginVerifyCode = (params = {}) => vm.$u.post(SendVerifyCodeUrl, params);
|
||||
// xuchao: 云闪付入口 token 解码
|
||||
let tokenDecode = (params = {}) => vm.$u.post(TokenDecodeUrl, params);
|
||||
|
||||
// 文旅场馆
|
||||
let getVenueList = (params = {}) => vm.$u.get(VenueListUrl, params);
|
||||
@@ -57,6 +60,7 @@ const install = (Vue, vm) => {
|
||||
vm.$u.api = {
|
||||
checkerLogin,
|
||||
sendLoginVerifyCode,
|
||||
tokenDecode,
|
||||
getVenueList,
|
||||
getVenueDetail,
|
||||
getMerchantList,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 同时,我们也可以在此使用getApp().globalData,如果你把token放在getApp().globalData的话,也是可以使用的
|
||||
const install = (Vue, vm) => {
|
||||
Vue.prototype.$u.http.setConfig({
|
||||
baseUrl: 'https://dscp-dev.hn12301.net',
|
||||
baseUrl: 'https://dscp-uat.hn12301.net',
|
||||
// loadingText: '努力加载中~',
|
||||
// loadingTime: 18800,
|
||||
// 如果将此值设置为true,拦截回调中将会返回服务端返回的所有数据response,而不是response.data
|
||||
|
||||
+50
-2
@@ -59,10 +59,56 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
onLoad(options) {
|
||||
if (options.token) {
|
||||
this.handleTokenLogin(options.token)
|
||||
}
|
||||
this.getLocation()
|
||||
},
|
||||
methods: {
|
||||
// xuchao: 云闪付入口 token 自动登录
|
||||
handleTokenLogin(token) {
|
||||
this.$u.api.tokenDecode({ token }).then(res => {
|
||||
if (res.errcode === 0 && res.data && res.data.mobile) {
|
||||
uni.setStorageSync('phone', res.data.mobile)
|
||||
this.$u.api.getEligibility({ phone: res.data.mobile, identityNo: res.data.idNo || '', name: res.data.name || '' }).then(eRes => {
|
||||
if (eRes.errcode === 0) {
|
||||
uni.setStorageSync('isAuth', eRes.data.isAuth)
|
||||
uni.setStorageSync('hasWin', eRes.data.hasWin)
|
||||
uni.setStorageSync('cardNumber', eRes.data.cardNumber)
|
||||
uni.setStorageSync('expiresTime', eRes.data.expiresTime)
|
||||
}
|
||||
})
|
||||
// xuchao: 清除地址栏 token,防止分享泄露
|
||||
this.clearUrlToken()
|
||||
} else {
|
||||
this.degradeToPhoneLogin()
|
||||
}
|
||||
}).catch(() => {
|
||||
this.degradeToPhoneLogin()
|
||||
})
|
||||
},
|
||||
// xuchao: 解码失败兜底,提示并跳手机号登录
|
||||
degradeToPhoneLogin() {
|
||||
uni.showToast({ title: '登录凭证已失效,请使用手机号登录', icon: 'none' })
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({ url: '/pages/index/login' })
|
||||
}, 800)
|
||||
},
|
||||
// xuchao: 从 URL hash 中移除 token 参数
|
||||
clearUrlToken() {
|
||||
try {
|
||||
const hash = window.location.hash || ''
|
||||
const qIndex = hash.indexOf('?')
|
||||
if (qIndex === -1) return
|
||||
const params = new URLSearchParams(hash.substring(qIndex + 1))
|
||||
if (!params.has('token')) return
|
||||
params.delete('token')
|
||||
const rest = params.toString()
|
||||
const base = hash.substring(0, qIndex)
|
||||
window.history.replaceState(null, '', rest ? `${base}?${rest}` : base)
|
||||
} catch (e) {}
|
||||
},
|
||||
getLocation() {
|
||||
import('@/common/location.js').then(module => {
|
||||
module.default.getLocation().then(({ lng, lat }) => {
|
||||
@@ -83,8 +129,10 @@
|
||||
}
|
||||
const isAuth = uni.getStorageSync('isAuth')
|
||||
const hasWin = uni.getStorageSync('hasWin')
|
||||
// xuchao: 最近发起过认证流程(含取消)时忽略旧认证缓存,一律回认证页
|
||||
const authFlowStarted = uni.getStorageSync('authFlowStarted')
|
||||
let status = 'auth'
|
||||
if (isAuth) {
|
||||
if (isAuth && !authFlowStarted) {
|
||||
status = hasWin ? 'info' : 'noWin'
|
||||
}
|
||||
uni.navigateTo({ url: `/pages/rights/rights?status=${status}` })
|
||||
|
||||
@@ -212,11 +212,46 @@
|
||||
this.lat = loc.lat
|
||||
}
|
||||
this.checkAuthResult()
|
||||
// xuchao: 本地无认证缓存时自动查询后端恢复已认证状态
|
||||
this.autoRecoverStatus()
|
||||
if (this.status === 'info') {
|
||||
this.loadRightsList()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// xuchao: 已登录但本地无认证缓存时,仅传手机号查询资格以恢复状态(不带证件号,避免触发被动认证)
|
||||
autoRecoverStatus() {
|
||||
if (this.status !== 'auth') return
|
||||
// xuchao: 用户主动发起过认证流程时,取消后应停留在认证页,不自动恢复
|
||||
if (uni.getStorageSync('authFlowStarted')) return
|
||||
const phone = uni.getStorageSync('phone')
|
||||
if (!phone) return
|
||||
this.$u.api.getEligibility({
|
||||
phone: phone
|
||||
}).then(res => {
|
||||
if (res.errcode !== 0 || !res.data) return
|
||||
uni.setStorageSync('isAuth', res.data.isAuth)
|
||||
uni.setStorageSync('hasWin', res.data.hasWin)
|
||||
uni.setStorageSync('cardNumber', res.data.cardNumber)
|
||||
uni.setStorageSync('expiresTime', res.data.expiresTime)
|
||||
// xuchao: 自动恢复成功,清除流程标记
|
||||
uni.removeStorageSync('authFlowStarted')
|
||||
if (res.data.isAuth) {
|
||||
this.status = res.data.hasWin ? 'info' : 'noWin'
|
||||
if (this.status === 'info') {
|
||||
this.loadRightsList()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// xuchao: 认证取消/未通过:清理旧认证缓存并标记流程已发起,取消后应停留认证页
|
||||
markAuthCanceled() {
|
||||
uni.removeStorageSync('isAuth')
|
||||
uni.removeStorageSync('hasWin')
|
||||
uni.removeStorageSync('cardNumber')
|
||||
uni.removeStorageSync('expiresTime')
|
||||
uni.setStorageSync('authFlowStarted', true)
|
||||
},
|
||||
checkAuthResult() {
|
||||
const url = new URL(window.location.href)
|
||||
let responseStr = url.searchParams.get('response')
|
||||
@@ -261,6 +296,8 @@
|
||||
uni.setStorageSync('hasWin', eRes.data.hasWin)
|
||||
uni.setStorageSync('cardNumber', eRes.data.cardNumber)
|
||||
uni.setStorageSync('expiresTime', eRes.data.expiresTime)
|
||||
// xuchao: 认证成功,清除流程标记
|
||||
uni.removeStorageSync('authFlowStarted')
|
||||
if (eRes.data.isAuth) {
|
||||
this.status = eRes.data.hasWin ? 'info' : 'noWin'
|
||||
if (this.status === 'info') {
|
||||
@@ -270,6 +307,8 @@
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// xuchao: 实名未通过视为取消认证,清理缓存并标记
|
||||
this.markAuthCanceled()
|
||||
uni.showToast({
|
||||
title: '认证未通过',
|
||||
icon: 'none'
|
||||
@@ -288,6 +327,8 @@
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// xuchao: 未返回认证回调视为取消认证,清理缓存并标记
|
||||
this.markAuthCanceled()
|
||||
uni.showToast({
|
||||
title: '认证未通过',
|
||||
icon: 'none'
|
||||
@@ -324,6 +365,8 @@
|
||||
}
|
||||
uni.setStorageSync('authName', this.form.realName)
|
||||
uni.setStorageSync('authIdNo', this.form.idNumber)
|
||||
// xuchao: 标记已发起认证流程,取消后停留在认证页,不自动恢复
|
||||
uni.setStorageSync('authFlowStarted', true)
|
||||
this.loadAliyunSDK().then(() => {
|
||||
const metaInfo = JSON.stringify(window.getMetaInfo())
|
||||
const returnUrl = window.location.origin + window.location.pathname +
|
||||
@@ -467,7 +510,13 @@
|
||||
})
|
||||
},
|
||||
goBack() {
|
||||
// xuchao: 直接通过链接进入(无历史栈)时回到首页
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack()
|
||||
} else {
|
||||
uni.reLaunch({ url: '/pages/index/index' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user