## 服務器端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>
~~~