Files
shanxia2.0/miniprogram/utils/wechatBindingFlow.js
T

70 lines
2.6 KiB
JavaScript

export const initialBindingState = () => ({
ready: false, enabled: false, bound: false, subscribed: false, busy: false,
sessionId: '', sessionStatus: '', sessionSubscribed: false, verificationCode: '', error: ''
})
export function createWechatBindingFlow({ state, api, getSessionKey, isActive, openAuthorization }) {
let owner = '', revision = 0
const cancel = () => { revision++; state.busy = false }
const clearSession = () => {
state.sessionId = ''; state.sessionStatus = ''; state.sessionSubscribed = false; state.verificationCode = ''
}
const run = async (operation) => {
const key = getSessionKey()
if (owner !== key) {
cancel()
Object.assign(state, initialBindingState())
owner = key
}
if (!key || !isActive() || state.busy) return
const version = ++revision
const current = () => version === revision && isActive() && getSessionKey() === key
state.busy = true
state.error = ''
try { await operation(current) } catch (error) {
if (current()) state.error = error?.message || '绑定操作失败,请重试'
} finally {
if (current()) state.busy = false
}
}
const refresh = () => run(async (current) => {
state.ready = false
const status = await api.status()
if (!current()) return
Object.assign(state, status, { ready: true })
if (!status.enabled || status.bound) { clearSession(); return }
if (!state.sessionId) return
const session = await api.session(state.sessionId)
if (!current()) return
if (session.status === 'expired') {
clearSession()
state.error = '授权会话已过期,请重新绑定'
return
}
state.sessionStatus = session.status
state.sessionSubscribed = session.subscribed
state.verificationCode = session.verificationCode || ''
if (session.status !== 'scanned') return
if (!session.subscribed) {
state.error = '请先关注服务号,再重新授权绑定'
return
}
// 仅确认本页面由当前登录用户主动发起的会话;回调网页不持有登录令牌。
const result = await api.confirm(state.sessionId)
if (!current()) return
if (!result.bound || !result.subscribed) throw new Error('绑定未完成,请刷新状态后重试')
Object.assign(state, result)
clearSession()
})
const start = () => run(async (current) => {
if (!state.ready || !state.enabled || state.bound) return
clearSession()
const session = await api.start()
if (!current()) return
state.sessionId = session.sessionId
state.sessionStatus = 'waiting'
await openAuthorization(session.authorizeUrl)
})
return { refresh, start, cancel }
}