借助小程式云开发实现小程式支付功能
我们在做小程式支付相关的开发时总会遇到这些难题1.小程式呼叫微信支付时必须要有自己的服务器
2.有自己的备案域名
3.有自己的后台开发
这就导致我们做小程式支付时的成本很大
本节就来教大家如何使用小程式云开发实现小程式支付功能的开发,不用搭建自己的服务器,不用有自己的备案域名,只需要简简单单的使用小程式云开发。
老规矩先看效果图:

本节知识点
1.云开发的部署和使用
2.支付相关的云函式开发
3.商品列表
4.订单列表
5.微信支付与支付成功回拨

支付成功给使用者传送推送讯息的功能会在后面讲解
下面就来教大家如何借助云开发使用小程式支付功能
支付所需要用到的配置资讯
1.小程式appid
2.云开发环境id
3.微信商户号
4.商户密匙
一、准备工作
1.已经申请小程式,获取小程式 AppID 和 Secret 在小程式管理后台中——【设定】 →【开发设定】 可以获取微信小程式 AppID 和 Secret。

2.微信支付商户号,获取商户号和商户金钥在微信支付商户管理平台中——【账户中心】→【商户资讯】 可以获取微信支付商户号。

在【账户中心】 ‒> 【API安全】 可以设定商户金钥。

这里特殊说明下——个人小程式是没有办法使用微信支付的,所以如果想使用微信支付功能必须是非个人账号(当然个人可以办个体户工商执照来注册非个人小程式账号
3.微信开发者 IDE
developers.weixin.qq.com/miniprogram…
4.开通小程式云开发功能
edu.csdn.net/course/play…
二、商品列表的实现
效果图如下
由于本节重点是支付的实现所以这里只简单贴出关键程式码

wxml布局如下:
商品: {{[item.name](item.name)}}
价格: {{item.price / 100}} 元
class="button"
type="primary"
bindtap="makeOrder"
data-goodid="{{item._id}}"
>下单
复制程式码
我们所需要做的就是借助云开发获取云数据库里的商品资讯然后展示到商品列表,关于云开发获取商品列表并展示本节不做讲解(感兴趣的同学可以翻看作者历史部落格,有写过的)

三、支付云函式的建立
首先看下我们支付云函式都包含那些内容

简单先讲解下每个的用处
config下的index.js是做支付配置用的,主要配置支付相关的账号资讯
lib是用的第三方的支付库,这里不做讲解
重点讲解的是云函式入口 index.js
下面就来教大家如何去配置
1.配置config下的index.js,
这一步所需要做的就是把小程式appid、云开发环境ID、商户id、商户密匙填进去。

2.配置入口云函式

详细程式码如下
程式码里注释很清楚了这里不再做单独讲解:
const cloud = require(\'wx-server-sdk\')
cloud.init()const app = require(\'tcb-admin-node\');const pay = require(\'./lib/pay\');const {
mpAppId,
KEY
} = require(\'./config/index\');const {
WXPayConstants,
WXPayUtil
} = require(\'wx-js-utils\'); const Res= require(\'./lib/res\'); const ip = require(\'ip\');/**
*
* @param {obj} event
* @param {string} event.type 功能型别
* @param {} userInfo.openId 使用者的openid
*/exports.main = async function(event, context) { const {
type,
data,
userInfo
} = event; onst wxContext = cloud.getWXContext() const openid = userInfo.openId;
app.init(); const db = app.database (); const goodCollection = db.collection(\'goods\'); const orderCollection = db.collection(\'order\');// 订单文件的status 0 未支付 1 已支付 2 已关闭
switch (type) { // [在此处放置 unifiedorder 的相关程式码]
case \'unifiedorder\':
{ // 查询该商品 ID 是否存在于数据库中,并将资料提取出来
const goodId = data.goodId let goods = await goodCollection.doc(goodId).get(); if (!goods.data.length) { return new Res ({ code: 1, message: \'找不到商品\'
});
} // 在云函式中提取资料,包括名称、价格才更合理安全,
// 因为从端里传过来的商品资料都是不可靠的
let good = goods.data[0]; // 拼凑微信支付统一下单的引数
const curTime = Date.now(); const tradeNo =`${goodId}-${curTime}`; const body = [good.name](good.name); const spbill_create_ip = ip.address() || \'[127.0.0.1](127.0.0.1)\'; // 云函式暂不支付 http 触发器,因此这里回拨 notify_url 可以先随便填。
const notify_url = \'[http://www.qq.com](http://www.qq.com)\'; // \'[127.0.0.1](127.0.0.1)\';
const total_fee = good.price; const time_stamp = \'\' + Math.ceil(Date.now() / 1000); const out_trade_no = `${tradeNo}`; const sign_type = WXPayConstants.SIGN_TYPE_MD5; let orderParam = {
body,
spill_create_ip,
notify_url,
out_trade_no,
total_fee,
openid, trade_type: \'JSAPI\', timeStamp: time_stamp,
}; // 呼叫 wx-js-utils 中的统一下单方法
const {
return_code,
...restData
} = await pay.unifiedOrder(orderParam); let order_id = null; if (return_code === \'SUCCESS\' && restData.result_code === \'SUCCESS\') { const {
prepay_id,
nonce_str
} = restData; // 微信小程式支付要单独进地签名,并返回给小程式端
const sign = WXPayUtil.generateSignature ({ appId: mpAppId, nonceStr: nonce_str, package: `prepay_id=${prepay_id}`, signType: \'MD5\', timeStamp: time_stamp
}, KEY); let orderData = {
out_trade_no,
time_stamp,
nonce_str,
sign,
sign_type,
body,
total_fee,
prepay_id,
sign, status: 0, // 订单文件的status 0 未支付 1 已支付 2 已关闭
_openid: openid,
}; let order = await orderCollection.add(orderData);
order_id = [order.id](http://order.id);
} return new Res({ code: return_code === \'SUCCESS\' ? 0 : 1, data: {
out_trade_no,
time_stamp,
order_id,
...restData
}
});
} // [在此处放置 payorder 的相关程式码]
case \'payorder\':
{ // 从端里出来相关的订单相信
const {
out_trade_no,
prepay_id,
body,
total_fee
} = data; // 到微信支付侧查询是否存在该订单,并查询订单状态,看看是否已经支付成功了。
const {
return_code,
...restData
} = await pay.orderQuery({
out_trade_no
}); // 若订单存在并支付成功,则开始处理支付
if (restData.trade_state === \'SUCCESS\') { let result = await orderCollection
.where({
out_trade_no
})
.update({ status: 1, trade_state: restData.trade_state, trade_state_desc: restData.trade_state_desc
}); let curDate = new Date(); let time = `${curDate.getFullYear()}-${curDate.getMonth() + 1}-${curDate.getDate()} ${curDate.getHours()}:${curDate.getMinutes()}:${curDate.getSeconds()}`;
} return new Res({ code: return_code === \'SUCCESS\' ? 0 : 1, data: restData
});
} case \'orderquery\':
{ const {
transaction_id,
out_trade_no
} = data; // 查询订单
const { data: dbData
} = await orderCollection
.where({
out_trade_no
}).get(); const {
return_code,
...restData
} = await pay.orderQuery({
transaction_id,
out_trade_no
}); return new Res({ code: return_code === \'SUCCESS\' ? 0 : 1, data: { ...restData,
...dbData[0]
}
});
} case \'closeorder\':
{ // 关闭订单
const {
out_trade_no
} = data; const {
return_code,
...restData
} = await pay.closeOrder({
out_trade_no
}); if (return_code === \'SUCCESS\' &&
restData.result_code === \'SUCCESS\') { await orderCollection
.where({
out_trade_no
})
.update({ status: 2, trade_state: \'CLOSED\', trade_state_desc: \'订单已关闭\'
});
} return new Res({ code: return_code === \'SUCCESS\' ? 0 : 1, data: restData
});
}
}
}
复制程式码
其实我们支付的关键功能都在上面这些程式码里面了

再来看下支付的相关流程截图

上图就涉及到了我们的订单列表、支付状态、支付成功后的回拨





























