13. 小程序支付与电商功能
小程序支付与电商功能是微信小程序中非常重要的一部分,通过支付功能可以实现用户购买商品、支付订单等功能。下面将介绍小程序支付的接入和配置以及实现电商功能和订单管理的方法。
13.1 小程序支付的接入和配置
13.1.1 获取微信支付商户号和密钥
在使用小程序支付功能之前,需要先在微信支付平台注册商户号,并获取商户号和密钥。商户号是用于标识商户的唯一编号,密钥用于加密和签名支付请求。
13.1.2 配置小程序支付
在小程序开发者工具中,找到项目目录下的project.config.json
文件,添加以下配置项:
{"appid": "Your AppID","projectname": "Your Project Name","setting": {"urlCheck": true,"es6": false,"postcss": false,"minified": true,"newFeature": true},"payment": {"merchantId": "Your Merchant ID","key": "Your Merchant Key"}
}
其中,appid
为小程序的AppID,merchantId
为商户号,key
为密钥。
13.1.2 创建支付订单
在小程序中实现支付功能,需要先创建一个支付订单,并将订单信息发送给微信支付平台。下面是一个创建支付订单的示例代码:
// 获取当前时间戳
function getTimestamp() {return parseInt(Date.now() / 1000).toString();
}// 生成随机字符串
function getRandomString(len) {len = len || 32;var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';var maxPos = chars.length;var randomString = '';for (var i = 0; i < len; i++) {randomString += chars.charAt(Math.floor(Math.random() * maxPos));}return randomString;
}// 创建支付订单
function createPaymentOrder(totalPrice) {// 生成随机订单号var orderNo = getRandomString(16);// 获取当前时间戳var timestamp = getTimestamp();// 构造支付参数var params = {appid: 'Your AppID',mch_id: 'Your Merchant ID',nonce_str: getRandomString(),body: '订单支付',out_trade_no: orderNo,total_fee: totalPrice * 100, // 将价格转换为分spbill_create_ip: '127.0.0.1',notify_url: 'https://yourdomain.com/pay/notify',trade_type: 'JSAPI',openid: 'Your User OpenID'};// 对支付参数进行签名params.sign = createSign(params);// 发送请求到后端生成预支付订单wx.request({url: 'https://yourdomain.com/pay/create',method: 'POST',data: params,success: function(res) {// 获取预支付订单号var prepayId = res.data.prepay_id;// 调用微信支付接口wx.requestPayment({timeStamp: timestamp,nonceStr: params.nonce_str,package: 'prepay_id=' + prepayId,signType: 'MD5',paySign: createSign({timeStamp: timestamp,nonceStr: params.nonce_str,package: 'prepay_id=' + prepayId,signType: 'MD5',appId: 'Your AppID',key: 'Your Merchant Key'}),success: function(res) {// 支付成功回调console.log('支付成功');},fail: function(res) {// 支付失败回调console.log('支付失败');}});},fail: function(res) {console.log('生成预支付订单失败');}});
}
以上代码中的createSign
函数用于对支付参数进行签名,createSign
函数的具体实现可以参考微信支付官方文档。
在调用wx.requestPayment
接口进行支付时,需要传入时间戳、随机字符串、预支付订单号等参数,并对这些参数进行签名。
13.1.3 配置支付通知回调
在支付流程中,支付完成后,微信支付平台会向开发者服务器发送一个支付通知,通知开发者订单的支付状态。因此,需要配置支付通知回调的接口。
下面是一个简单的支付通知回调接口的示例代码:
// 引入相关库和模块
const express = require('express');
const bodyParser = require('body-parser');
const xml2js = require('xml2js');const app = express();
app.use(bodyParser.raw({ type: 'text/xml' }));// 支付通知回调接口
app.post('/pay/notify', (req, res) => {var parser = new xml2js.Parser({ explicitArray: false });parser.parseString(req.body.toString('utf-8'), (err, result) => {if (err) {console.log('解析支付通知报文失败');res.send('FAIL');} else {var responseData = {return_code: 'SUCCESS',return_msg: 'OK'};var xmlBuilder = new xml2js.Builder({ cdata: true, rootName: 'xml' });var xmlData = xmlBuilder.buildObject(responseData);res.send(xmlData);// 处理订单的支付状态var orderNo = result.xml.out_trade_no;var totalFee = parseFloat(result.xml.total_fee) / 100;var transactionId = result.xml.transaction_id;// 更新订单的支付状态updateOrderStatus(orderNo, totalFee, transactionId);}});
});// 启动服务器
app.listen(80, () => {console.log('Server started on port 80');
});
以上代码中,示例代码使用的是Node.js的Express框架来搭建一个简单的服务器,并使用了body-parser
和xml2js
库来解析支付通知的报文。
在支付通知回调的接口中,首先使用xml2js
库将报文解析为JSON格式的数据。然后,根据解析后的数据进行相应的处理,比如更新订单的支付状态。
最后,需要将处理结果返回给微信支付平台,以确保支付通知的正确处理。示例代码中使用xml2js
库将回复数据转换为XML格式,并通过res.send
方法返回给微信支付平台。
13.2 实现电商功能和订单管理
在实现电商功能和订单管理方面,需要考虑以下几个关键点:
- 商品列表展示:展示商品的名称、价格、图片等信息,并提供购买按钮。
- 购物车功能:用户可以将商品添加到购物车,并进行数量的调整和删除等操作。
- 订单生成和管理:用户可以将购物车中的商品生成订单,并管理订单的支付状态和物流信息等。
下面是一个简单的示例代码,实现了电商功能和订单管理的示例:
// pages/index/index.jsPage({data: {productList: [{id: 1,name: "商品1",price: 10,image: "http://example.com/product1.jpg"},{id: 2,name: "商品2",price: 20,image: "http://example.com/product2.jpg"},// 其他商品...],cartList: [],orderList: []},// 添加商品到购物车addToCart(e) {const productId = e.currentTarget.dataset.id;const product = this.data.productList.find(item => item.id === productId);// 将商品添加到购物车const cartItem = this.data.cartList.find(item => item.id === productId);if (cartItem) {cartItem.quantity += 1;} else {this.data.cartList.push({id: product.id,name: product.name,price: product.price,quantity: 1});}// 更新购物车数据this.setData({cartList: this.data.cartList});},// 从购物车移除商品removeFromCart(e) {const productId = e.currentTarget.dataset.id;// 从购物车中移除指定商品const cartIndex = this.data.cartList.findIndex(item => item.id === productId);if (cartIndex >= 0) {this.data.cartList.splice(cartIndex,1);// 更新购物车数据this.setData({cartList: this.data.cartList});}},// 生成订单createOrder() {// 生成订单号const orderNo = Date.now().toString();// 将购物车中的商品生成订单const orderItems = this.data.cartList.map(item => ({id: item.id,name: item.name,price: item.price,quantity: item.quantity}));// 创建订单对象const order = {orderNo: orderNo,items: orderItems,totalAmount: this.calculateTotalAmount(),status: '待支付'};// 将订单添加到订单列表中this.data.orderList.push(order);// 清空购物车this.setData({cartList: []});// 更新订单列表数据this.setData({orderList: this.data.orderList});},// 计算购物车中商品总金额calculateTotalAmount() {let total = 0;this.data.cartList.forEach(item => {total += item.price * item.quantity;});return total;},// 支付订单payOrder(e) {const orderNo = e.currentTarget.dataset.orderno;const orderIndex = this.data.orderList.findIndex(item => item.orderNo === orderNo);if (orderIndex >= 0) {const order = this.data.orderList[orderIndex];// 调用支付接口wx.requestPayment({timeStamp: '',nonceStr: '',package: '',signType: '',paySign: '',success: res => {// 支付成功,更新订单状态为已支付order.status = '已支付';// 更新订单列表数据this.setData({orderList: this.data.orderList});// 弹窗提示支付成功wx.showToast({title: '支付成功',icon: 'success'});},fail: res => {// 支付失败,更新订单状态为支付失败order.status = '支付失败';// 更新订单列表数据this.setData({orderList: this.data.orderList});// 弹窗提示支付失败wx.showToast({title: '支付失败',icon: 'none'});}});},// 取消订单cancelOrder(e) {const orderNo = e.currentTarget.dataset.orderno;const orderIndex = this.data.orderList.findIndex(item => item.orderNo === orderNo);if (orderIndex >= 0) {// 从订单列表中移除订单this.data.orderList.splice(orderIndex, 1);// 更新订单列表数据this.setData({orderList: this.data.orderList});// 弹窗提示取消成功wx.showToast({title: '取消成功',icon: 'success'});}}
})
在上述代码中,我们定义了一些与电商功能相关的函数。
-
createOrder
函数用于生成订单。首先生成订单号,然后将购物车中的商品转换为订单项,并计算订单的总金额。接下来,将订单添加到订单列表中,并清空购物车。最后,更新订单列表的数据。 -
calculateTotalAmount
函数用于计算购物车中商品的总金额。 -
payOrder
函数用于支付订单。首先获取需要支付的订单号和订单索引,然后调用wx.requestPayment
接口进行支付。支付成功后,更新订单状态为已支付,并更新订单列表数据。支付失败时,更新订单状态为支付失败。 -
cancelOrder
函数用于取消订单。首先获取需要取消的订单号和订单索引,然后从订单列表中移除该订单。最后,更新订单列表数据并弹出提示框显示取消成功。
以上是一个简单的电商功能示例,包括生成订单、支付订单和取消订单。你可以根据自己的需求进行修改和扩展。
接下来,需要在小程序的页面中添加相应的布局和交互,以及页面跳转和数据传递的逻辑。详细的页面设计和布局步骤可以参考前面的第3章和第4章的内容。