uniapp+tp6实现微信公众号内H5支付

发布时间 2023-06-24 02:17:07作者: 天宁哦

说明

前端使用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);
}