wechatBindingFlow.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. export const initialBindingState = () => ({
  2. ready: false, enabled: false, bound: false, subscribed: false, busy: false,
  3. sessionId: '', sessionStatus: '', sessionSubscribed: false, verificationCode: '', error: ''
  4. })
  5. export function createWechatBindingFlow({ state, api, getSessionKey, isActive, openAuthorization }) {
  6. let owner = '', revision = 0
  7. const cancel = () => { revision++; state.busy = false }
  8. const clearSession = () => {
  9. state.sessionId = ''; state.sessionStatus = ''; state.sessionSubscribed = false; state.verificationCode = ''
  10. }
  11. const run = async (operation) => {
  12. const key = getSessionKey()
  13. if (owner !== key) {
  14. cancel()
  15. Object.assign(state, initialBindingState())
  16. owner = key
  17. }
  18. if (!key || !isActive() || state.busy) return
  19. const version = ++revision
  20. const current = () => version === revision && isActive() && getSessionKey() === key
  21. state.busy = true
  22. state.error = ''
  23. try { await operation(current) } catch (error) {
  24. if (current()) state.error = error?.message || '绑定操作失败,请重试'
  25. } finally {
  26. if (current()) state.busy = false
  27. }
  28. }
  29. const refresh = () => run(async (current) => {
  30. state.ready = false
  31. const status = await api.status()
  32. if (!current()) return
  33. Object.assign(state, status, { ready: true })
  34. if (!status.enabled || status.bound) { clearSession(); return }
  35. if (!state.sessionId) return
  36. const session = await api.session(state.sessionId)
  37. if (!current()) return
  38. if (session.status === 'expired') {
  39. clearSession()
  40. state.error = '授权会话已过期,请重新绑定'
  41. return
  42. }
  43. state.sessionStatus = session.status
  44. state.sessionSubscribed = session.subscribed
  45. state.verificationCode = session.verificationCode || ''
  46. if (session.status !== 'scanned') return
  47. if (!session.subscribed) {
  48. state.error = '请先关注服务号,再重新授权绑定'
  49. return
  50. }
  51. // 仅确认本页面由当前登录用户主动发起的会话;回调网页不持有登录令牌。
  52. const result = await api.confirm(state.sessionId)
  53. if (!current()) return
  54. if (!result.bound || !result.subscribed) throw new Error('绑定未完成,请刷新状态后重试')
  55. Object.assign(state, result)
  56. clearSession()
  57. })
  58. const start = () => run(async (current) => {
  59. if (!state.ready || !state.enabled || state.bound) return
  60. clearSession()
  61. const session = await api.start()
  62. if (!current()) return
  63. state.sessionId = session.sessionId
  64. state.sessionStatus = 'waiting'
  65. await openAuthorization(session.authorizeUrl)
  66. })
  67. return { refresh, start, cancel }
  68. }