## 服务器端PHP:
~~~
// 根据业务逻辑组装订单保存订单数据
$order = [
'member_id' => $member->id,
'amount' => $amount,
'status' => 1,
'prepay_id' => 0,
'prepay_result' => ''
];
$order = ChargeOrder::create($order);
// 补充订单序列号
// 根据业务逻辑生成订单序列号
$serial = $this->generateChargeOrderSerial($order->id);
$order->serial = $serial;
$order->save();
// 生成微信预支付订单
$payment = EasyWeChat::payment();
$result = $payment->order->unify([
'body' => '聊播会员充值',
'out_trade_no' => $order->serial,
'total_fee' => $amount * 100, // 金额,单位是分,不是元
'spbill_create_ip' => null, // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
'notify_url' => route('wx.pay.notify'), // 支付结果通知网址,如果不设置则会使用配置里的默认地址
'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
'openid' => $member->wx_open_id,
]);
// 生成微信订单
$payment = EasyWeChat::payment(); // 微信支付
$result = $payment->order->unify([
'body' => '聊播会员充值',
'out_trade_no' => $order->serial,
'total_fee' => $amount * 100,
'spbill_create_ip' => null, // 可选,如不传该参数,SDK 将会自动获取相应 IP 地址
'notify_url' => route('wx.pay.notify'), // 支付结果通知网址,如果不设置则会使用配置里的默认地址
'trade_type' => 'JSAPI', // 请对应换成你的支付方式对应的值类型
'openid' => $member->wx_open_id,
]);
if (strtoupper($result['return_code']) != 'SUCCESS') {
$errorMessage = $result['return_msg'];
Log::error('创建微信预支付订单失败,错误信息:' . $errorMessage);
return $this->responseError(ERROR_UNKNOWN, '创建订单失败');
}
if (strtoupper($result['result_code']) != 'SUCCESS') {
$errorCode = $result['err_code'];
$errorMessage = $result['err_code_des'];
Log::error('创建微信预支付订单失败,错误码:' . $errorCode . ',错误信息:' . $errorMessage);
return $this->responseError(ERROR_UNKNOWN, '创建订单失败');
}
$prepayId = $result['prepay_id'];
$order->prepay_id = $prepayId;
$order->prepay_result = json_encode($result);
$order->save();
~~~
接下来的服务器端程序有以下两种选择:
### 一、如果前端准备使用JSSDK,服务器端接着写下面的PHP代码
~~~
// 配置参数
$officialAccount = EasyWeChat::officialAccount();
$apis = ['chooseWxPay'];
$wxConfig = $officialAccount->jssdk->buildConfig($apis, false, false, false);
// 支付参数
$payConfig = $payment->jssdk->sdkConfig($prepayId); // 返回数组
return $this->responseData(compact('payConfig', 'wxConfig'));
~~~
返回的payConfig和wxConfig的格式如下:
payConfig:
~~~
{
appId:"wx86e4f20564c2f17e",
beta:false,
debug:false,
jsApiList:["chooseWxPay"],
nonceStr:"KPzKlY6QpD",
signature:"767d1164d879a3c4e0a9ac69b16921de19fcdfb5",
timestamp:1556085560, // 此处不是驼峰命名
url:"http://liaobo.com/member/charge"
}
~~~
wxConfig
~~~
{
appId:"wx86e4f20564c2f17e",
beta:false,
debug:false,
jsApiList:["chooseWxPay"],
nonceStr:"KPzKlY6QpD",
signature:"767d1164d879a3c4e0a9ac69b16921de19fcdfb5",
timestamp:1556085560,
url:"http://liaobo.com/member/charge"
}
~~~
### 二、如果前端准备使用WeixinJSBridge,服务器端接着写下面的PHP代码
~~~
$payConfig = $payment->jssdk->sdkConfig($prepayId);
// 因为WeixinJSBridge使用的支付参数中,时间戳字段的键名是驼峰命名的timeStamp,
// 所以这里要重新组装一下数据
$payConfig['timeStamp'] = $payConfig['timestamp'];
unset($payConfig['timestamp']);
return $this->responseData(compact('payConfig'));
~~~
返回的payConfig数据格式如下:
payConfig
~~~
{
appId:"wx86e4f20564c2f17e",
beta:false,
debug:false,
jsApiList:["chooseWxPay"],
nonceStr:"KPzKlY6QpD",
signature:"767d1164d879a3c4e0a9ac69b16921de19fcdfb5",
timeStamp:1556085560, // 此处是驼峰命名
url:"http://liaobo.com/member/charge"
}
~~~
## 前端JS
如上所述,前端JS有两种方法:
### 前端使用JSSDK
~~~
<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script>
$(function () {
// 充值
$('#btn-charge').on('click', function () {
showInputBox('充值', '100', function (amount, index) {
if (amount < 0.01) {
alert('充值金额太小');
return false;
}
var url = '{{route('member.charge.save')}}';
var row = {amount: amount, _token: token};
$.post(url, row, function (data, status, xhr) {
if (data.code != 200) {
var message = data.message;
alert(message);
return false;
}
var payConfig = data.data.payConfig;
payConfig.success = function (res) {
if (res.errMsg == 'chooseWXPay:ok') {
alert('支付成功');
layer.close(index);
window.location.reload();
} else {
alert('支付失败,请重试:' + res.errMsg);
}
};
payConfig.fail = function (res) {
alert('支付失败:' + JSON.stringify(res));
};
payConfig.cancel = function (res) {
alert('用户取消付款');
};
wx.config(data.data.wxConfig);
wx.chooseWXPay(payConfig);
}, 'json');
})
});
});
</script>
~~~
### 前端使用WeixinJSBridge
> 不需要引入JSSDK了
~~~
<script>
$(function () {
// 充值
$('#btn-charge').on('click', function () {
showInputBox('充值', '100', function (amount, index) {
if (amount < 0.01) {
alert('充值金额太小');
return false;
}
var url = '{{route('member.charge.save')}}';
var row = {amount: amount, _token: token};
$.post(url, row, function (data, status, xhr) {
if (data.code != 200) {
var message = data.message;
alert(message);
return false;
}
var payConfig = data.data.payConfig;
payConfig.timeStamp = payConfig.timestamp;
WeixinJSBridge.invoke('getBrandWCPayRequest', payConfig, function(res){
if(res.err_msg == 'get_brand_wcpay_request:ok' ){
alert('支付成功');
layer.close(index);
window.location.reload();
} else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
alert('用户取消支付');
} else {
alert('支付失败');
}
});
}, 'json');
})
});
});
</script>
~~~