useWechatMiniPay.js 5.14 KB
import { computed, ref } from 'vue'
import Taro from '@tarojs/taro'
import { getWechatPayParamsAPI } from '@/api'
import { clearSessionId } from '@/utils/request'
import { hasAuth, silentAuth } from '@/utils/authRedirect'

/**
 * @description 微信小程序支付能力封装
 * - 可复用于测试页、WebView 容器页、后续其他按钮点击场景
 * - 统一处理:授权、获取支付参数、拉起 requestPayment、状态回传
 */
export const useWechatMiniPay = () => {
  const auth_loading = ref(false)
  const pay_loading = ref(false)
  const sessionid = ref('')
  const last_result_text = ref('等待开始测试')

  const is_authed = computed(() => !!sessionid.value)
  const sessionid_preview = computed(() => {
    if (!sessionid.value) return '暂无'
    if (sessionid.value.length <= 18) return sessionid.value
    return `${sessionid.value.slice(0, 8)}...${sessionid.value.slice(-8)}`
  })

  const update_result_text = (text, options = {}) => {
    last_result_text.value = text
    if (typeof options.on_status === 'function') {
      options.on_status(text)
    }
  }

  const sync_auth_state = () => {
    const current_sessionid = Taro.getStorageSync('sessionid') || ''
    sessionid.value = current_sessionid
    return current_sessionid
  }

  const refresh_auth = async (options = {}) => {
    auth_loading.value = true

    try {
      if (options.force_refresh) {
        clearSessionId()
      }

      await silentAuth(null, null, {
        show_loading: options.show_loading !== false,
      })
      sync_auth_state()
      update_result_text('静默授权成功,可以继续测试支付。', options)
      return { code: 1, msg: '静默授权成功' }
    } catch (error) {
      sync_auth_state()
      const message = error?.message || '静默授权失败'
      update_result_text(message, options)
      return { code: 0, msg: message, data: error || null }
    } finally {
      auth_loading.value = false
    }
  }

  const pay_by_order_id = async (raw_order_id, options = {}) => {
    const normalized_order_id = String(raw_order_id || '').trim()

    if (!normalized_order_id) {
      const message = '请先输入订单 ID'
      Taro.showToast({
        title: message,
        icon: 'none',
      })
      update_result_text(message, options)
      return { code: 0, status: 'invalid', msg: message, data: null }
    }

    if (!hasAuth()) {
      if (options.auto_auth !== false) {
        const auth_res = await refresh_auth({
          ...options,
          force_refresh: false,
          show_loading: true,
        })
        if (!auth_res?.code) {
          return {
            code: 0,
            status: 'auth_fail',
            msg: auth_res?.msg || '授权失败',
            data: auth_res?.data || null,
          }
        }
      } else {
        const message = '当前未授权,请先重新授权'
        Taro.showToast({
          title: message,
          icon: 'none',
        })
        update_result_text(message, options)
        return { code: 0, status: 'auth_required', msg: message, data: null }
      }
    } else {
      sync_auth_state()
    }

    pay_loading.value = true
    update_result_text('正在请求支付参数...', options)

    try {
      const pay_res = await getWechatPayParamsAPI({ order_id: normalized_order_id })
      if (!pay_res?.code || !pay_res?.data) {
        const message = pay_res?.msg || '获取支付参数失败'
        update_result_text(message, options)
        return { code: 0, status: 'params_fail', msg: message, data: pay_res?.data || null }
      }

      const pay_data = pay_res.data
      update_result_text('已获取支付参数,准备拉起微信支付弹框...', options)

      const pay_result = await new Promise((resolve) => {
        Taro.requestPayment({
          timeStamp: pay_data.timeStamp,
          nonceStr: pay_data.nonceStr,
          package: pay_data.package,
          signType: pay_data.signType,
          paySign: pay_data.paySign,
          success: (res) => resolve({ ok: true, res }),
          fail: (err) => resolve({ ok: false, err }),
        })
      })

      if (pay_result?.ok) {
        const message = '支付流程已提交成功,微信支付返回 success。'
        update_result_text(message, options)
        return { code: 1, status: 'success', msg: message, data: pay_result.res || null }
      }

      const err_msg = pay_result?.err?.errMsg || '支付未完成'
      const message = `微信支付已拉起,结果:${err_msg}`
      update_result_text(message, options)
      const is_cancelled = String(err_msg).toLowerCase().includes('cancel')
      return {
        code: 0,
        status: is_cancelled ? 'cancel' : 'fail',
        msg: message,
        data: pay_result?.err || null,
      }
    } catch (error) {
      const message = error?.message || '拉起支付失败'
      update_result_text(message, options)
      return { code: 0, status: 'exception', msg: message, data: error || null }
    } finally {
      pay_loading.value = false
    }
  }

  sync_auth_state()

  return {
    auth_loading,
    pay_loading,
    sessionid,
    is_authed,
    sessionid_preview,
    last_result_text,
    sync_auth_state,
    refresh_auth,
    pay_by_order_id,
  }
}