网页金额控件开发指引

更新时间:2024.11.20

在付款页面展示微信支付金额控件,该控件由金额输入区和键盘组成,用户使用该控件输入金额并轻触付款后完成支付流程。

使用限制

微信客户端版本 8.0.40 开始支持,低版本需要使用自定义金额控件做兼容处理 - 使用自定义的金额控件

开发指引

安装 NPM 包

请在本地开发环境使用NPM安装依赖包

1npm install -S @tenpay/wechatpay-js

控件初始化

在框架入口处引入包后完成初始化,初始化后即可引用 WechatPayment 类和使用扫码支付的wx-payment金额控件。

1import "@tenpay/wechatpay-js";

判断是否支持金额控件

通过 WechatPayment.isSupportScanPosPay 方法判断当前微信客户端是否支持金额控件。

1// 示例代码
2// 使用WechatPayment前先导入
3import {
4  WechatPayment,
5} from '@tenpay/wechatpay-js';
6
7// 判断当前微信客户端版本是否支持金额控件
8const supportScanPosPay = await WechatPayment.isSupportScanPosPay();
9
10// supportScanPosPay为true表示当前微信客户端支持金额控件
11// supportScanPosPay为false表示当前微信客户端不支持金额控件

支持金额控件

使用 wx-payment 标签展示金额控件

1<!-- 展示金额控件 -->
2<wx-payment
3  class="payment-style"
4  v-on:pay-touch="onPayTouch"
5  v-on:pay-success="onPaySuccess"
6  v-on:pay-fail="onPayFail"
7></wx-payment>
8
9<style>
10/* 通过css样式控制金额输入框的位置,大小,边框等属性 */
11.payment-style {
12  display: block;
13  margin: 20px;
14  padding: 10px;
15  border-bottom: 0.5px solid;
16  border-color: rgba(0, 0, 0, 0.1);
17}
18</style>

不支持金额控件

使用默认金额控件

在付款页面中使用微信支付标签 wx-payment 展示金额控件。商户需要实现pay-touchpay-successpay-fail 三个事件的回调处理函数。

客户端支付状态

控件回调事件

行为描述

注意事项

展示金额输入控件

-

【商户前端】使用 wx-payment 标签展示金额控件

 

用户修改支付金额

-

【金额控件】展示用户付款金额并记录 amount 金额参数

 

用户点击 付款

pay-touch

【商户前端】根据事件回调的 amount 金额参数, 调用【商户后端】完成下单。【商户前端】下单完成后,调用orderCompleteCallback函数传入订单信息调起【商业支付收银台】,继续支付流程。
请参考orderCompleteCallback接口说明

如果在pay-touch事件触发后30秒内未完成下单并调用orderCompleteCallback流程自动走到支付失败逻辑,此时触发 pay-fail 事件,回调事件中retcode返回OrderTimeout

用户等待支付

-

【金额控件】等待商户下单过程中屏幕将展示 loading 加载状态,此时用户无法进行其他操作。

 

展示收银台

-

【商业支付收银台】等待用户完成支付鉴权。

 

用户支付成功

pay-success

【用户】在【商业支付收银台】支付成功后,【商户前端】收到支付成功回调事件。

请通过后台查单确定订单状态,如果商户查单接口明确返回支付成功,则给用户展示支付成功页。

用户支付失败
取消支付

pay-fail

【用户】主动取消支付后,【商户前端】收到支付失败事件,回调事件中retcode返回Cancel

 

用户支付失败
下单超时

pay-fail

【用户】点击付款后,若30秒内【商户前端】未调用orderCompleteCallback函数,则触发下单超时,【商户前端】收到支付失败事件,回调事件中retcode返回OrderTimeout

 

用户支付失败
其他异常

pay-fail

如果回调事件中retcode返回PayFail,则表示由于其他未知情况导致的支付失败。

 

控件代码示例

1// 点击付款时回调
2function async onPayTouch(event: Event) {
3  const detail = (event as CustomEvent).detail as WechatPayTouchEventDetail;
4  
5  try {
6    // 从 detail.amount 中获取用户输入的金额,可以根据后端协议转换为相应的单位,转换时注意处理精度问题
7    const amount = Math.round(detail.amount * 100);
8    // 调用商户后台接口进行下单
9    const resp = await createOrder(amount);
10    if (resp.retcode === 0) {
11      // 下单成功后,调用orderCompleteCallback继续支付流程。orderInfo一般由商户后端生成,格式参考如下代码示例
12      const orderInfo = {
13          "appId":"wx2421b1c4370ec43b",
14          "timeStamp":"1395712654",
15          "nonceStr":"e61463f8efa94090b1f366cccfbbb444",
16          "package":"prepay_id=up_wx21201855730335ac86f8c43d1889123400",
17          "signType":"RSA",
18          "paySign":"oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg=="
19      }
20      await detail.orderCompleteCallback(true, orderInfo);
21    } else {
22      // 下单明确失败后,调用orderCompleteCallback取消支付流程
23      await detail.orderCompleteCallback(false, null);
24    }
25  } catch(error) {
26    // 其他异常情况,调用orderCompleteCallback取消支付流程
27    await detail.orderCompleteCallback(false, null);
28  }
29}
30// 支付成功时回调
31function onPaySuccess(event: Event) {
32  const detail = (event as CustomEvent).detail as WechatPaySuccessEventDetail;
33  // 请求商户后台查单确定订单状态、其他处理逻辑...
34}
35// 支付失败时回调
36function onPayFail(event: Event) {
37  const detail = (event as CustomEvent).detail as WechatPayFailEventDetail;
38  // 其他处理逻辑...
39}

使用自定义的金额控件

低版本客户端不支持金额控件,需要进行兼容处理,有两种兼容方案:

方案一

在NPM包example/compatible目录下提供了 custom-payment 组件,该组件封装了和 wx-payment 相同的功能和参数,商户可以参考该组件示例实现兼容逻辑,如有需求可以修改 custom-payment 组件代码。

代码示例:

1// 示例代码
2// 使用WechatPayment前先导入
3import {
4  WechatPayment,
5} from '@tenpay/wechatpay-js';
6// 判断当前微信客户端版本是否支持金额控件
7const supportScanPosPay = await WechatPayment.isSupportScanPosPay();
8// supportScanPosPay为true表示当前微信客户端支持金额控件
9// supportScanPosPay为false表示当前微信客户端不支持金额控件
1<!-- 示例代码 -->
2<!-- 不支持金额控件时使用自定义金额控件 -->
3<custom-payment
4  class="payment-style"
5  v-on:pay-touch="onPayTouch"
6  v-on:pay-success="onPaySuccess"
7  v-on:pay-fail="onPayFail"
8></custom-payment>
9<style>
10/* 通过css样式控制金额输入框的位置,大小,边框等属性 */
11.payment-style {
12  display: block;
13  margin: 20px;
14  padding: 10px;
15  border-bottom: 0.5px solid;
16  border-color: rgba(0, 0, 0, 0.1);
17}
18</style>

方案二

商户在低版本微信客户端使用JSAPI支付实现兼容逻辑。参考JSAPI支付开发指引

代码示例:

1function onBridgeReady() {
2    WeixinJSBridge.invoke('getBrandWCPayRequest', {
3        "AppID": "wx2421b1c4370ec43b",     //公众号ID,由商户传入     
4        "timeStamp": "1395712654",     //时间戳,自1970年以来的秒数     
5        "nonceStr": "e61463f8efa94090b1f366cccfbbb444",      //随机串     
6        "package": "prepay_id=up_wx21201855730335ac86f8c43d1889123400",
7        "signType": "RSA",     //微信签名方式:     
8        "paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==" //微信签名 
9    },
10    function(res) {
11        if (res.err_msg == "get_brand_wcpay_request:ok") {
12            // 使用以上方式判断前端返回,微信团队郑重提示:
13            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
14        }
15    });
16}
17if (typeof WeixinJSBridge == "undefined") {
18    if (document.addEventListener) {
19        document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
20    } else if (document.attachEvent) {
21        document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
22        document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
23    }
24} else {
25    onBridgeReady();
26}

示例程序

为了便于开发者快速接入网页金额控件,降低接入门槛,我们开发了基于 Vue 的示例程序

example/src/components/HelloWorld.vue 可以看到完整的使用例子。

进一步阅读