70 lines
2.6 KiB
JavaScript
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 }
|
|
}
|