Skip to content

前端-小程序微信支付接入

1. 调用后端创建支付订单

javascript
// api/pay.js
import request from '@/utils/request.js'

export function pay(orderId) {
  return request({
    url: `/api/wx-pay/user/createWxPay/${orderId}`,
    method: 'post'
  })
}

2. 支付流程

用户点击支付 -> 调用后端API -> 获取支付参数 -> 调起微信支付 -> 支付结果回调

3. 完整支付实现

javascript
// 支付参数缓存配置
const PAYMENT_CACHE_KEY = 'payment_params'
const PAYMENT_CACHE_EXPIRY = 14 * 60 * 1000 // 14分钟

// 缓存支付参数
const cachePaymentParams = (payData) => {
  try {
    const cacheData = {
      data: payData,
      expiry: Date.now() + PAYMENT_CACHE_EXPIRY
    }
    uni.setStorageSync(PAYMENT_CACHE_KEY, JSON.stringify(cacheData))
  } catch (e) {
    console.error('缓存支付参数失败:', e)
  }
}

// 获取缓存的支付参数
const getCachedPaymentParams = () => {
  try {
    const jsonStr = uni.getStorageSync(PAYMENT_CACHE_KEY)
    if (!jsonStr) return null

    const cacheData = JSON.parse(jsonStr)
    if (Date.now() > cacheData.expiry) {
      uni.removeStorageSync(PAYMENT_CACHE_KEY)
      return null
    }
    return cacheData.data
  } catch (e) {
    return null
  }
}

// 清除支付参数缓存
const clearPaymentCache = () => {
  uni.removeStorageSync(PAYMENT_CACHE_KEY)
}

// 调用后端创建支付订单
const createPayment = async (orderId) => {
  try {
    const res = await pay(orderId)
    if (res.code === 200) {
      // 缓存支付参数
      cachePaymentParams(res.data)
      return res.data
    }
    throw new Error(res.msg || '创建支付订单失败')
  } catch (e) {
    throw e
  }
}

// 执行微信支付
const executeWechatPayment = (payData) => {
  return new Promise((resolve, reject) => {
    uni.getProvider({
      service: 'payment',
      success: (providerRes) => {
        if (providerRes.provider && providerRes.provider.includes('wxpay')) {
          uni.requestPayment({
            provider: 'wxpay',
            signType: payData.signType,
            package: payData.packageValue,
            nonceStr: payData.nonceStr,
            timeStamp: payData.timeStamp,
            paySign: payData.paySign,
            success: (res) => {
              clearPaymentCache()
              uni.showToast({ title: '支付成功', icon: 'success' })
              resolve(res)
            },
            fail: (err) => {
              uni.showToast({ title: '支付失败', icon: 'none' })
              reject(err)
            }
          })
        } else {
          reject(new Error('不支持微信支付'))
        }
      },
      fail: (err) => {
        reject(err)
      }
    })
  })
}

// 完整的支付流程
const handlePayment = async (orderId) => {
  try {
    // 1. 调用后端创建支付订单
    const payData = await createPayment(orderId)

    // 2. 调起微信支付
    await executeWechatPayment(payData)

    // 3. 支付成功后刷新订单状态
    await getOrderDetail()

  } catch (e) {
    console.error('支付失败:', e)
  }
}

4. 订单页面集成示例

vue
<template>
  <view class="order-page">
    <view v-if="orderDetail">
      <!-- 订单信息 -->
      <view class="order-info">
        <text>订单金额: ¥{{ orderDetail.deposit }}</text>
      </view>

      <!-- 立即支付按钮 -->
      <up-button
        v-if="orderDetail.orderStatus === '0' && orderDetail.depositStatus === '11'"
        type="primary"
        @click="handlePayment"
        :loading="loading"
      >
        立即支付
      </up-button>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { pay } from '@/api/pay'
import { getOrderDetail } from '@/api/order'

const orderDetail = ref(null)
const loading = ref(false)

const handlePayment = async () => {
  if (loading.value) return
  loading.value = true

  try {
    // 调用后端创建支付订单
    const res = await pay(orderDetail.value.id)
    const payData = res.data

    // 调起微信支付
    await new Promise((resolve, reject) => {
      uni.getProvider({
        service: 'payment',
        success: (providerRes) => {
          if (providerRes.provider.includes('wxpay')) {
            uni.requestPayment({
              provider: 'wxpay',
              signType: payData.signType,
              package: payData.packageValue,
              nonceStr: payData.nonceStr,
              timeStamp: payData.timeStamp,
              paySign: payData.paySign,
              success: resolve,
              fail: reject
            })
          } else {
            reject(new Error('不支持微信支付'))
          }
        },
        fail: reject
      })
    })

    uni.showToast({ title: '支付成功', icon: 'success' })
    // 刷新订单数据
    await getOrderDetailData()
  } catch (e) {
    console.error('支付失败:', e)
  } finally {
    loading.value = false
  }
}

onMounted(() => {
  getOrderDetailData()
})
</script>

5. 后端返回的支付参数

json
{
  "code": 200,
  "data": {
    "outTradeNo": "654573755628130304",
    "timeStamp": "1765521745",
    "nonceStr": "2Zf7IcDLIRSRekd1jokTMabUrbkM8U0G",
    "packageValue": "prepay_id=wx12144220348995c58017ac64913b050000",
    "signType": "RSA",
    "paySign": "h2dav6D83onQjQH+JGIjPvzB0fUXQTIzbgSfxUxOpFL..."
  }
}

6. 支付结果回调

结果说明
success支付成功,刷新订单状态
fail支付失败,提示用户重试

7. 注意事项

场景解决方案
用户取消支付保留缓存,允许重试
支付参数过期提示用户返回重新操作
非微信环境提示不支持微信支付
网络异常缓存支付参数,支持重试

8. 缓存策略

  • 支付参数缓存 14 分钟
  • 支付成功后立即清除缓存
  • 支付失败时保留缓存供重试