uni-app 支付功能

章节概览

在移动应用开发中,支付功能是非常重要的一部分,它可以帮助我们实现商品购买、服务付费等功能,为用户提供便捷的支付体验。本章节将详细介绍 uni-app 中的支付功能,包括支付 API 的使用、多端支付集成、支付流程等,帮助开发者实现商品购买支付流程。

核心知识点

1. 支付 API

uni-app 提供了统一的支付 API,用于发起支付请求,主要包括:

  • **uni.requestPayment()**:发起支付请求,支持多种支付方式

2. 多端支付集成

uni-app 支持在多个平台上集成支付功能,主要包括:

  • 微信支付:在微信小程序、App、H5 等平台上集成微信支付
  • 支付宝:在 App、H5 等平台上集成支付宝
  • 银联支付:在 App 等平台上集成银联支付
  • 苹果支付:在 iOS App 上集成苹果支付

3. 支付流程

一个完整的支付流程通常包括以下步骤:

  • 创建订单:用户选择商品后,后端创建订单
  • 获取支付参数:后端根据订单信息生成支付参数
  • 发起支付:前端使用支付参数发起支付请求
  • 处理支付结果:支付完成后,处理支付结果
  • 订单状态更新:后端更新订单状态

实用案例:实现商品购买支付流程

案例描述

我们将创建一个商品购买支付流程,实现用户选择商品,创建订单,选择支付方式,发起支付,处理支付结果等功能。

案例实现

1. 创建商品详情页

首先,我们创建一个商品详情页,用于展示商品信息和购买按钮:

<template>
  <view class="goods-detail">
    <!-- 商品图片 -->
    <view class="goods-image">
      <image :src="goods.image" mode="aspectFill"></image>
    </view>
    
    <!-- 商品信息 -->
    <view class="goods-info">
      <text class="goods-title">{{ goods.title }}</text>
      <text class="goods-price">¥{{ goods.price }}</text>
      <text class="goods-sales">销量: {{ goods.sales }}</text>
    </view>
    
    <!-- 商品详情 -->
    <view class="goods-details">
      <text class="section-title">商品详情</text>
      <view class="goods-desc">
        <text>{{ goods.description }}</text>
      </view>
    </view>
    
    <!-- 底部操作栏 -->
    <view class="bottom-bar">
      <view class="action-btn">
        <text>客服</text>
      </view>
      <view class="action-btn">
        <text>收藏</text>
      </view>
      <view class="buy-btn">
        <text>加入购物车</text>
      </view>
      <view class="buy-btn primary" @click="buyNow">
        <text>立即购买</text>
      </view>
    </view>
  </view>
</template>

<script>
import { goodsApi } from '@/api/index';

export default {
  data() {
    return {
      goods: {
        id: '',
        title: '',
        price: 0,
        sales: 0,
        image: '',
description: ''
      }
    };
  },
  
  onLoad(options) {
    // 获取商品 ID
    const id = options.id;
    if (id) {
      // 获取商品详情
      this.getGoodsDetail(id);
    }
  },
  
  methods: {
    // 获取商品详情
    async getGoodsDetail(id) {
      try {
        uni.showLoading({
          title: '加载中...',
          mask: true
        });
        
        const res = await goodsApi.getGoodsDetail(id);
        this.goods = res;
      } catch (error) {
        console.error('获取商品详情失败:', error);
        uni.showToast({
          title: '加载失败,请重试',
          icon: 'none'
        });
      } finally {
        uni.hideLoading();
      }
    },
    
    // 立即购买
    buyNow() {
      // 跳转到确认订单页面
      uni.navigateTo({
        url: `/pages/order-confirm/order-confirm?goodsId=${this.goods.id}&goodsPrice=${this.goods.price}&goodsTitle=${this.goods.title}&goodsImage=${this.goods.image}`
      });
    }
  }
};
</script>

<style scoped>
.goods-detail {
  min-height: 100vh;
  background-color: #f5f5f5;
}

.goods-image {
  width: 100%;
  height: 50vh;
  background-color: #fff;
}

.goods-image image {
  width: 100%;
  height: 100%;
}

.goods-info {
  padding: 20rpx;
  background-color: #fff;
  margin-bottom: 10rpx;
}

.goods-title {
  font-size: 32rpx;
  font-weight: bold;
  color: #333;
  margin-bottom: 10rpx;
}

.goods-price {
  font-size: 36rpx;
  color: #ff4d4f;
  margin-bottom: 10rpx;
}

.goods-sales {
  font-size: 24rpx;
  color: #999;
}

.goods-details {
  padding: 20rpx;
  background-color: #fff;
  margin-bottom: 100rpx;
}

.section-title {
  font-size: 28rpx;
  font-weight: bold;
  color: #333;
  margin-bottom: 20rpx;
}

.goods-desc {
  font-size: 24rpx;
  color: #666;
  line-height: 1.5;
}

.bottom-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100rpx;
  background-color: #fff;
  display: flex;
  align-items: center;
  border-top: 1rpx solid #e8e8e8;
  /* 适配 iPhone X 等机型的底部安全区域 */
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

.action-btn {
  flex: 1;
  height: 100rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24rpx;
  color: #666;
}

.buy-btn {
  flex: 2;
  height: 70rpx;
  margin: 0 10rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28rpx;
  color: #fff;
  background-color: #ffb000;
  border-radius: 35rpx;
}

.buy-btn.primary {
  background-color: #ff4d4f;
}
</style>

2. 创建确认订单页

接下来,我们创建一个确认订单页,用于确认订单信息和选择支付方式:

<template>
  <view class="order-confirm">
    <!-- 收货地址 -->
    <view class="address-section">
      <view class="section-header">
        <text class="title">收货地址</text>
      </view>
      <view class="address-content" @click="chooseAddress">
        <view class="address-info" v-if="address">
          <view class="address-top">
            <text class="name">{{ address.name }}</text>
            <text class="phone">{{ address.phone }}</text>
          </view>
          <text class="address-detail">{{ address.province }}{{ address.city }}{{ address.district }}{{ address.detail }}</text>
        </view>
        <view class="address-placeholder" v-else>
          <text class="icon">+</text>
          <text class="text">添加收货地址</text>
        </view>
      </view>
    </view>
    
    <!-- 商品信息 -->
    <view class="goods-section">
      <view class="section-header">
        <text class="title">商品信息</text>
      </view>
      <view class="goods-content">
        <image :src="orderInfo.goodsImage" mode="aspectFill"></image>
        <view class="goods-info">
          <text class="goods-title">{{ orderInfo.goodsTitle }}</text>
          <text class="goods-price">¥{{ orderInfo.goodsPrice }}</text>
        </view>
      </view>
    </view>
    
    <!-- 支付方式 -->
    <view class="payment-section">
      <view class="section-header">
        <text class="title">支付方式</text>
      </view>
      <view class="payment-content">
        <view 
          v-for="(item, index) in paymentMethods" 
          :key="index"
          class="payment-item"
          :class="{ 'selected': selectedPayment === item.value }"
          @click="selectedPayment = item.value"
        >
          <view class="payment-icon">
            <image :src="item.icon" mode="aspectFit"></image>
          </view>
          <text class="payment-name">{{ item.name }}</text>
          <view class="payment-check" v-if="selectedPayment === item.value">
            <text class="icon">✓</text>
          </view>
        </view>
      </view>
    </view>
    
    <!-- 订单金额 -->
    <view class="amount-section">
      <view class="amount-item">
        <text class="label">商品金额</text>
        <text class="value">¥{{ orderInfo.goodsPrice }}</text>
      </view>
      <view class="amount-item">
        <text class="label">运费</text>
        <text class="value">¥{{ orderInfo.freight }}</text>
      </view>
      <view class="amount-item total">
        <text class="label">合计</text>
        <text class="value">¥{{ totalAmount }}</text>
      </view>
    </view>
    
    <!-- 底部操作栏 -->
    <view class="bottom-bar">
      <view class="total-amount">
        <text class="label">合计:</text>
        <text class="value">¥{{ totalAmount }}</text>
      </view>
      <view class="submit-btn" @click="submitOrder">
        <text>提交订单</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      // 收货地址
      address: null,
      // 订单信息
      orderInfo: {
        goodsId: '',
        goodsTitle: '',
        goodsPrice: 0,
        goodsImage: '',
        freight: 0
      },
      // 支付方式
      paymentMethods: [
        {
          name: '微信支付',
          value: 'wechat',
          icon: '/static/wechat-pay.png'
        },
        {
          name: '支付宝',
          value: 'alipay',
          icon: '/static/alipay.png'
        },
        {
          name: '银联支付',
          value: 'unionpay',
          icon: '/static/unionpay.png'
        }
      ],
      // 选中的支付方式
      selectedPayment: 'wechat',
      // 是否正在提交订单
      isSubmitting: false
    };
  },
  
  computed: {
    // 总金额
    totalAmount() {
      return (parseFloat(this.orderInfo.goodsPrice) + parseFloat(this.orderInfo.freight)).toFixed(2);
    }
  },
  
  onLoad(options) {
    // 获取商品信息
    this.orderInfo = {
      goodsId: options.goodsId,
      goodsTitle: options.goodsTitle,
      goodsPrice: options.goodsPrice,
      goodsImage: options.goodsImage,
      freight: 0
    };
    
    // 获取默认地址
    this.getDefaultAddress();
  },
  
  methods: {
    // 获取默认地址
    getDefaultAddress() {
      // 模拟获取默认地址
      this.address = {
        id: 1,
        name: '张三',
        phone: '13800138000',
        province: '北京市',
        city: '北京市',
        district: '朝阳区',
        detail: '建国路88号'
      };
    },
    
    // 选择地址
    chooseAddress() {
      uni.navigateTo({
        url: '/pages/address-select/address-select'
      });
    },
    
    // 提交订单
    async submitOrder() {
      if (!this.address) {
        uni.showToast({
          title: '请添加收货地址',
          icon: 'none'
        });
        return;
      }
      
      if (this.isSubmitting) return;
      
      uni.showLoading({
        title: '提交中...',
        mask: true
      });
      
      this.isSubmitting = true;
      
      try {
        // 创建订单
        const order = await this.createOrder();
        
        // 获取支付参数
        const payParams = await this.getPayParams(order.orderId, this.selectedPayment);
        
        // 发起支付
        const payResult = await this.requestPayment(payParams);
        
        // 处理支付结果
        await this.handlePayResult(order.orderId, payResult);
        
        // 跳转到支付成功页面
        uni.navigateTo({
          url: `/pages/pay-success/pay-success?orderId=${order.orderId}&amount=${this.totalAmount}`
        });
      } catch (error) {
        console.error('支付失败:', error);
        uni.showToast({
          title: error.message || '支付失败,请重试',
          icon: 'none'
        });
      } finally {
        uni.hideLoading();
        this.isSubmitting = false;
      }
    },
    
    // 创建订单
    createOrder() {
      return new Promise((resolve, reject) => {
        // 模拟创建订单
        setTimeout(() => {
          resolve({
            orderId: 'ORD' + Date.now(),
            orderNo: 'NO' + Date.now(),
            amount: this.totalAmount,
            createTime: new Date().getTime()
          });
        }, 1000);
      });
    },
    
    // 获取支付参数
    getPayParams(orderId, paymentMethod) {
      return new Promise((resolve, reject) => {
        // 模拟获取支付参数
        setTimeout(() => {
          // 根据支付方式返回不同的支付参数
          if (paymentMethod === 'wechat') {
            resolve({
              provider: 'wxpay',
              timeStamp: Date.now().toString(),
              nonceStr: 'nonce' + Date.now(),
              package: 'prepay_id=wx201410272009395522657a690389285100',
              signType: 'MD5',
              paySign: 'C380BEC2BFD727A4B6845133519F3AD6'
            });
          } else if (paymentMethod === 'alipay') {
            resolve({
              provider: 'alipay',
              orderInfo: 'partner="2088511833207846"&seller_id="xxx@alipay.com"&out_trade_no="ORD' + Date.now() + '"&subject="商品购买"&body="商品购买"&total_fee="' + this.totalAmount + '"&notify_url="http://www.example.com/notify"'
            });
          } else if (paymentMethod === 'unionpay') {
            resolve({
              provider: 'unionpay',
              orderInfo: 'orderId=ORD' + Date.now() + '&amount=' + this.totalAmount + '&currency=156'
            });
          }
        }, 1000);
      });
    },
    
    // 发起支付
    requestPayment(payParams) {
      return new Promise((resolve, reject) => {
        uni.requestPayment({
          ...payParams,
          success: (res) => {
            console.log('支付成功:', res);
            resolve(res);
          },
          fail: (err) => {
            console.error('支付失败:', err);
            reject(new Error(err.errMsg || '支付失败'));
          }
        });
      });
    },
    
    // 处理支付结果
    handlePayResult(orderId, payResult) {
      return new Promise((resolve, reject) => {
        // 模拟处理支付结果
        setTimeout(() => {
          console.log('处理支付结果:', orderId, payResult);
          resolve();
        }, 1000);
      });
    }
  }
};
</script>

<style scoped>
.order-confirm {
  min-height: 100vh;
  background-color: #f5f5f5;
}

.address-section,
.goods-section,
.payment-section,
.amount-section {
  margin-bottom: 20rpx;
  background-color: #fff;
}

.section-header {
  height: 80rpx;
  padding: 0 30rpx;
  display: flex;
  align-items: center;
  border-bottom: 1rpx solid #e8e8e8;
}

.section-header .title {
  font-size: 28rpx;
  font-weight: bold;
  color: #333;
}

.address-content {
  padding: 30rpx;
  min-height: 150rpx;
}

.address-info {
  width: 100%;
}

.address-top {
  display: flex;
  margin-bottom: 15rpx;
}

.address-top .name {
  font-size: 28rpx;
  font-weight: bold;
  color: #333;
  margin-right: 30rpx;
}

.address-top .phone {
  font-size: 28rpx;
  color: #333;
}

.address-detail {
  font-size: 24rpx;
  color: #666;
  line-height: 1.4;
}

.address-placeholder {
  width: 100%;
  min-height: 150rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 2rpx dashed #d9d9d9;
  border-radius: 8rpx;
  color: #999;
}

.address-placeholder .icon {
  font-size: 48rpx;
  line-height: 1;
  margin-bottom: 10rpx;
}

.address-placeholder .text {
  font-size: 24rpx;
}

.goods-content {
  padding: 30rpx;
  display: flex;
}

.goods-content image {
  width: 150rpx;
  height: 150rpx;
  border-radius: 8rpx;
}

.goods-content .goods-info {
  flex: 1;
  margin-left: 20rpx;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.goods-content .goods-title {
  font-size: 28rpx;
  color: #333;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.goods-content .goods-price {
  font-size: 32rpx;
  color: #ff4d4f;
  font-weight: bold;
  margin-top: 10rpx;
}

.payment-content {
  padding: 0 30rpx;
}

.payment-item {
  height: 100rpx;
  display: flex;
  align-items: center;
  border-bottom: 1rpx solid #e8e8e8;
}

.payment-item:last-child {
  border-bottom: none;
}

.payment-item .payment-icon {
  width: 50rpx;
  height: 50rpx;
  margin-right: 20rpx;
}

.payment-item .payment-icon image {
  width: 100%;
  height: 100%;
}

.payment-item .payment-name {
  flex: 1;
  font-size: 28rpx;
  color: #333;
}

.payment-item .payment-check {
  width: 30rpx;
  height: 30rpx;
  border-radius: 50%;
  background-color: #ff4d4f;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 20rpx;
}

.payment-item.selected {
  color: #ff4d4f;
}

.amount-section {
  padding: 30rpx;
}

.amount-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20rpx;
}

.amount-item .label {
  font-size: 28rpx;
  color: #666;
}

.amount-item .value {
  font-size: 28rpx;
  color: #333;
}

.amount-item.total {
  margin-top: 20rpx;
  padding-top: 20rpx;
  border-top: 1rpx solid #e8e8e8;
}

.amount-item.total .label {
  font-size: 32rpx;
  font-weight: bold;
  color: #333;
}

.amount-item.total .value {
  font-size: 32rpx;
  font-weight: bold;
  color: #ff4d4f;
}

.bottom-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100rpx;
  background-color: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 30rpx;
  border-top: 1rpx solid #e8e8e8;
  /* 适配 iPhone X 等机型的底部安全区域 */
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

.total-amount {
  display: flex;
  align-items: center;
}

.total-amount .label {
  font-size: 28rpx;
  color: #333;
}

.total-amount .value {
  font-size: 32rpx;
  font-weight: bold;
  color: #ff4d4f;
}

.submit-btn {
  width: 200rpx;
  height: 70rpx;
  background-color: #ff4d4f;
  color: #fff;
  font-size: 28rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 35rpx;
}
</style>

3. 创建支付成功页

现在,我们创建一个支付成功页,用于显示支付结果:

<template>
  <view class="pay-success">
    <view class="success-icon">
      <text class="icon">✓</text>
    </view>
    <text class="success-title">支付成功</text>
    <text class="success-desc">您的订单已支付成功,我们将尽快为您发货</text>
    <view class="order-info">
      <text class="label">订单编号:</text>
      <text class="value">{{ orderId }}</text>
    </view>
    <view class="amount-info">
      <text class="label">支付金额:</text>
      <text class="value">¥{{ amount }}</text>
    </view>
    <view class="btn-group">
      <view class="btn normal" @click="goToHome">
        <text>返回首页</text>
      </view>
      <view class="btn primary" @click="goToOrderDetail">
        <text>查看订单</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      orderId: '',
      amount: ''
    };
  },
  
  onLoad(options) {
    // 获取订单编号和支付金额
    this.orderId = options.orderId || '';
    this.amount = options.amount || '';
  },
  
  methods: {
    // 返回首页
    goToHome() {
      uni.switchTab({
        url: '/pages/index/index'
      });
    },
    
    // 查看订单详情
    goToOrderDetail() {
      uni.navigateTo({
        url: `/pages/order-detail/order-detail?orderId=${this.orderId}`
      });
    }
  }
};
</script>

<style scoped>
.pay-success {
  min-height: 100vh;
  background-color: #f5f5f5;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 100rpx 30rpx;
}

.success-icon {
  width: 150rpx;
  height: 150rpx;
  border-radius: 50%;
  background-color: #52c41a;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 50rpx;
}

.success-icon .icon {
  font-size: 96rpx;
  color: #fff;
  font-weight: bold;
}

.success-title {
  font-size: 36rpx;
  font-weight: bold;
  color: #333;
  margin-bottom: 30rpx;
}

.success-desc {
  font-size: 28rpx;
  color: #666;
  text-align: center;
  line-height: 1.5;
  margin-bottom: 50rpx;
}

.order-info,
.amount-info {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20rpx;
  background-color: #fff;
  border-radius: 8rpx;
  margin-bottom: 20rpx;
}

.order-info .label,
.amount-info .label {
  font-size: 28rpx;
  color: #666;
}

.order-info .value,
.amount-info .value {
  font-size: 28rpx;
  color: #333;
}

.amount-info .value {
  font-size: 32rpx;
  font-weight: bold;
  color: #ff4d4f;
}

.btn-group {
  width: 100%;
  display: flex;
  justify-content: space-between;
  margin-top: 50rpx;
}

.btn {
  flex: 1;
  height: 80rpx;
  border-radius: 8rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28rpx;
}

.btn.normal {
  background-color: #fff;
  color: #333;
  border: 1rpx solid #e8e8e8;
  margin-right: 20rpx;
}

.btn.primary {
  background-color: #ff4d4f;
  color: #fff;
}
</style>

4. 创建支付服务

为了方便管理支付相关的功能,我们可以创建一个支付服务:

// services/paymentService.js

/**
 * 创建订单
 * @param {Object} orderInfo - 订单信息
 * @returns {Promise} - 返回订单信息
 */
export const createOrder = (orderInfo) => {
  return new Promise((resolve, reject) => {
    // 模拟创建订单
    setTimeout(() => {
      resolve({
        orderId: 'ORD' + Date.now(),
        orderNo: 'NO' + Date.now(),
        amount: orderInfo.amount,
        createTime: new Date().getTime()
      });
    }, 1000);
  });
};

/**
 * 获取支付参数
 * @param {string} orderId - 订单编号
 * @param {string} paymentMethod - 支付方式
 * @param {number} amount - 支付金额
 * @returns {Promise} - 返回支付参数
 */
export const getPaymentParams = (orderId, paymentMethod, amount) => {
  return new Promise((resolve, reject) => {
    // 模拟获取支付参数
    setTimeout(() => {
      // 根据支付方式返回不同的支付参数
      if (paymentMethod === 'wechat') {
        resolve({
          provider: 'wxpay',
          timeStamp: Date.now().toString(),
          nonceStr: 'nonce' + Date.now(),
          package: 'prepay_id=wx201410272009395522657a690389285100',
          signType: 'MD5',
          paySign: 'C380BEC2BFD727A4B6845133519F3AD6'
        });
      } else if (paymentMethod === 'alipay') {
        resolve({
          provider: 'alipay',
          orderInfo: 'partner="2088511833207846"&seller_id="xxx@alipay.com"&out_trade_no="' + orderId + '"&subject="商品购买"&body="商品购买"&total_fee="' + amount + '"&notify_url="http://www.example.com/notify"'
        });
      } else if (paymentMethod === 'unionpay') {
        resolve({
          provider: 'unionpay',
          orderInfo: 'orderId=' + orderId + '&amount=' + amount + '&currency=156'
        });
      } else {
        reject(new Error('不支持的支付方式'));
      }
    }, 1000);
  });
};

/**
 * 发起支付
 * @param {Object} payParams - 支付参数
 * @returns {Promise} - 返回支付结果
 */
export const requestPayment = (payParams) => {
  return new Promise((resolve, reject) => {
    uni.requestPayment({
      ...payParams,
      success: (res) => {
        console.log('支付成功:', res);
        resolve(res);
      },
      fail: (err) => {
        console.error('支付失败:', err);
        reject(new Error(err.errMsg || '支付失败'));
      }
    });
  });
};

/**
 * 处理支付结果
 * @param {string} orderId - 订单编号
 * @param {Object} payResult - 支付结果
 * @returns {Promise} - 返回处理结果
 */
export const handlePaymentResult = (orderId, payResult) => {
  return new Promise((resolve, reject) => {
    // 模拟处理支付结果
    setTimeout(() => {
      console.log('处理支付结果:', orderId, payResult);
      resolve({ success: true });
    }, 1000);
  });
};

/**
 * 查询订单支付状态
 * @param {string} orderId - 订单编号
 * @returns {Promise} - 返回订单支付状态
 */
export const queryOrderStatus = (orderId) => {
  return new Promise((resolve, reject) => {
    // 模拟查询订单支付状态
    setTimeout(() => {
      resolve({
        orderId: orderId,
        status: 'paid', // paid: 已支付, unpaid: 未支付, cancelled: 已取消
        payTime: new Date().getTime()
      });
    }, 1000);
  });
};

案例解析

  1. 商品详情页:我们创建了一个商品详情页,用于展示商品信息和购买按钮,点击"立即购买"按钮跳转到确认订单页面。
  2. 确认订单页:我们创建了一个确认订单页,用于确认订单信息和选择支付方式,包括收货地址、商品信息、支付方式、订单金额等。
  3. 支付成功页:我们创建了一个支付成功页,用于显示支付结果,包括订单编号、支付金额等,并提供返回首页和查看订单的按钮。
  4. 支付服务:我们创建了 services/paymentService.js 文件,封装了支付相关的功能,包括创建订单、获取支付参数、发起支付、处理支付结果等。

代码优化建议

  1. 添加支付结果轮询:在支付完成后,添加订单状态轮询,确保订单状态正确更新。
  2. 优化错误处理:对支付过程中可能出现的错误进行更详细的处理,提供更友好的错误提示。
  3. 添加支付超时处理:处理支付超时的情况,避免订单状态不一致。
  4. 优化用户体验:在支付过程中添加加载动画,提高用户体验。
  5. 添加支付方式图标:为支付方式添加图标,提高视觉效果。

常见问题与解决方案

  1. 支付失败

    • 问题:支付失败,可能是支付参数错误或用户取消支付
    • 解决方案
      • 检查支付参数是否正确
      • 处理用户取消支付的情况
      • 提供重试机制
  2. 支付结果回调失败

    • 问题:支付完成后,回调失败,导致订单状态未更新
    • 解决方案
      • 添加订单状态轮询
      • 提供手动查询订单状态的功能
      • 后端添加定时任务,处理未支付的订单
  3. 跨平台支付差异

    • 问题:不同平台的支付 API 实现存在差异
    • 解决方案
      • 使用 uni-app 提供的统一支付 API
      • 针对不同平台进行适配
      • 测试不同平台的支付流程
  4. 支付安全

    • 问题:支付过程中可能存在安全风险
    • 解决方案
      • 使用 HTTPS 协议
      • 对支付参数进行加密
      • 后端验证支付结果的真实性
  5. 支付限额

    • 问题:不同支付方式可能存在支付限额
    • 解决方案
      • 提示用户支付限额
      • 提供多种支付方式
      • 处理支付限额的情况

学习总结

通过本章节的学习,我们掌握了以下知识:

  1. 支付 API:了解了 uni-app 提供的支付 API,包括 uni.requestPayment() 等。
  2. 多端支付集成:了解了如何在不同平台上集成支付功能,包括微信支付、支付宝、银联支付等。
  3. 支付流程:了解了一个完整的支付流程,包括创建订单、获取支付参数、发起支付、处理支付结果等。
  4. 实际应用:通过实际案例,掌握了如何实现商品购买支付流程,包括商品详情页、确认订单页、支付成功页等。

在实际开发中,我们需要根据具体需求,选择合适的支付方式,并结合项目特点进行适当的封装和优化,以提高应用的性能和用户体验。同时,我们也需要注意支付安全和不同平台的兼容性问题,确保应用在各种设备上都能正常运行。

« 上一篇 uni-app 地图与定位 下一篇 » uni-app 推送功能