uniapp+tp6实现微信公众号内H5支付
说明
前端使用uniapp,后端使用php,简单实现公众号内微信支付
后端还使用了easywechat
这个微信开发库的4.x版本
微信支付流程
1.先去微信支付官方下单
2.然后我们拿着返回的参数再去前端发起支付
3.支付结果
步骤
uniapp部分
uniapp部分需要做到的就是拉起支付
需要安装一个库
npm install jweixin-module --save
import jweixin from 'jweixin-module';
import {pay_xd} from '@/server/index.js';
/**
* 支付订单
* @param {string} title 商品类型或者商品标题
* @param {int} total_fee 商品价格,1等于1分,100等于1元
*/
export function pay(title,total_fee) {
console.log('点击支付');
const parmas = {
uid:getStorage('uid'),
openid: getStorage('openid'),
title: title,
total_fee: total_fee
};
pay_xd(parmas).then(res => {
console.log(res.data);
const data = res.data.msg;
jweixin.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.appId, // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.paySign, // 必填,签名
jsApiList: ['chooseWXPay'],
});
jweixin.chooseWXPay({
appId: data.appId,
timestamp: data
.timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: data.nonceStr, // 支付签名随机串,不长于 32
package: data.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: data.paySign, // 支付签名
success: function(res) {
console.log('付款成功!', res);
uni.showToast({
title: "付款成功!",
duration: 1000
})
},
cancel: function(res) {
console.log('付款取消!', res);
uni.showToast({
title: "付款取消!",
duration: 1000
})
},
fail: function(res) {
console.log('付款失败!', res);
uni.showToast({
title: "付款失败!",
duration: 1000
})
}
});
})
}
后端tp部分
需要安装一下easywechat4.0
composer require overtrue/wechat:~4.0 -vvv
protected $payConfig = [
// 必要配置
'app_id' => '你的appid',
'mch_id' => '你的微信支付商户id',
'key' => '微信支付的v2密钥', // API v2 密钥 (注意: 是v2密钥 是v2密钥 是v2密钥)
// 如需使用敏感接口(如退款、发送红包等)需要配置 API 证书路径(登录商户平台下载 API 证书)
'cert_path' => 'path/to/your/cert.pem', // XXX: 绝对路径!!!!
'key_path' => 'path/to/your/key', // XXX: 绝对路径!!!!
'notify_url' => 'http://xxxx.cn/api/Pay/notification', //你也可以在下单时单独设置来想覆盖它
];
/**
* 这是让前端调用的下单的接口
* 1.首先判断一下该订单是否已经去微信支付那边下过单了,并且是未支付的
* 2.如果是已下单未支付则使用已下单的订单号,否则生成新的订单号,然后去微信支付那里下单
* 3.接着通过easywechat的方法计算一下前端调起支付需要的参数,返回给前端
*/
public function pay_xd()
{
$params = input();
if ($params) {
$data = [
'uid' => $params['uid'],
'type' => $params['title'],
'fee' => $params['total_fee'],
'state' => 1
];
//下单之前先判断该订单是否已经去微信下过单
$res = Db::name('order')->where('uid', $params['uid'])->where('type', $params['title'])->where('state', 1)->find();
if (!empty($res)) {
//使用之前创建号的订单号发起支付
$this->pay($params['openid'], $res['orderid'], $params['title'], $params['total_fee']);
} else {
//创建新订单号,发起支付
$data['orderid'] = $this->msectime();
$records = Db::name('order')->save($data);
if (!empty($records)) {
//去微信支付下单
$this->pay($params['openid'], $data['orderid'], $params['title'], $params['total_fee']);
} else {
$this->returnCode(1, '下单失败');
}
}
}
}
/**
* 微信支付下单
* $openid 微信下单者的openid
* $orderid 商户自己设置的订单号
* $title 商品标题
* $total_fee 商品金额,单位是分
*/
public function pay($openid, $orderid, $title, $total_fee)
{
$app = Factory::payment($this->payConfig);
$result = $app->order->unify([
'body' => $title,
'out_trade_no' => $orderid, //商户自己设置的订单号
'total_fee' => $total_fee, //订单金额(单位是分)
'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
'openid' => $openid,
]);
// $this->returnCode('成功',$result);
//成功就返回prepay_id
if ($result['result_code'] == 'SUCCESS') {
$this->returnCode('成功', (new \EasyWeChat\Payment\Jssdk\Client($app))->sdkConfig($result['prepay_id']), 1);
} else {
$this->returnCode('失败', $result['err_code_des'], 0);
}
}
// 微信支付通知地址
public function notification()
{
$app = Factory::payment($this->payConfig);
$response = $app->handlePaidNotify(function ($message, $fail) {
// 你的逻辑.
///////////// <- 建议在这里调用微信的【订单查询】接口查一下该笔订单的情况,确认是已经支付 /////////////
//test这些都是我开发时候记录到本地文本里面调试用的,可以删掉不会影响代码
$this->test('out_trade_no:' . $message['out_trade_no']);
$this->test('return_code:' . $message['return_code']);
$this->test('time_end:' . $message['time_end']);
$this->test('transaction_id:' . $message['transaction_id']);
if ($message['return_code'] == 'SUCCESS') {
// 查询订单接口,去查询一下订单是否真的交易成功
$status = $this->search_order($message['out_trade_no']);
$payTime = date('Y-m-d H:i:s', strtotime($message['time_end']));
$this->test('$status:' . $status);
if ($status) {
$res = Db::name('order')->where('orderid', $message['out_trade_no'])->update([
'payorder' => $message['transaction_id'],
'state' => 2,
'paytime' => $payTime
]);
$this->test('$res:' . $res);
if (!empty($res)) {
$this->test($message['out_trade_no'] . '状态修改成功');
} else {
$this->test($message['out_trade_no'] . '状态修改失败');
}
$this->test($message['out_trade_no'] . '通知成功前');
$aa = $this->search_order($message['out_trade_no']);
// $this->test(var_export($aa,true));
$this->test($message['out_trade_no'] . '通知成功');
return true;
}
}
$this->test('通讯失败');
return $fail('通信失败,请稍后再通知我');
});
$response->send(); // Laravel 里请使用:return $response;
}
//查询订单
public function search_order($order_id)
{
$app = Factory::payment($this->payConfig);
$order = $app->order->queryByOutTradeNumber($order_id);
if ($order['return_code'] == 'SUCCESS' && $order['result_code'] == 'SUCCESS' && $order['trade_state'] == 'SUCCESS') {
return true;
} else {
return false;
}
}
public function test($site)
{
file_put_contents('./1.txt', $site . "\r\n", FILE_APPEND | LOCK_EX);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了