准备工作:
申请小程序AppID、APPSECRET、MCHID(商户ID)、KEY(商户密钥)
制作签名,签名需要五个参数分别是:appId(小程序AppID)、timeStamp(当前时间戳)、nonceStr(随机字符串)、package(统一下单返回数据包,注意参数值的格式一定要是:prepay_id=数据包)、signType(加密类型,默认MD5就行了)。
wx.requestPayment中的随机字符串与当前时间戳一定要与签名中的保持一致,不然会报“支付验证签名错误”,拿签名中的参数值拉起支付。
小程序端:
wxml
<button type='primary' class='submit' bindtap='payment'>确认充值</button>
<view wx:if='{{show}}'>
<view class='marks'>
<view class='myLoginContent'>
<view class='myLoginTitle'>
<text>请先登录</text>
</view>
<button open-type="getUserInfo" bindgetuserinfo='bindGetUserInfo' class='myLogin'>
<image src='/pages/images/wx.png'> </image> 微信用户快捷登录
</button>
</view>
</view>
</view>
js
// 登录授权
bindGetUserInfo: function (res) {
let that = this;
wx.login({
success: function (rea) {
wx.getUserInfo({
success: function (info) {
let obj = {
userinfo: info.rawData,
code: rea.code
}
utils.postRequest('Index/getModeOpenid', obj, '登录中', (res) => {
wx.setStorageSync('modeInfo', res.data.data);
console.log(res)
that.setData({
modeInfo: wx.getStorageSync('modeInfo'),
openid: res.data.data.openid,
show: false
})
})
}
})
}
})
},
/**
* 充值支付
* store_id 门店id
* total_fee 充值金额
*/
payment: function() {
let that = this;
let payInfo = {
store_id: that.data.store_id,
sms_money: that.data.total_fee,
openid: that.data.openid
}
utils.postRequest('Manager/WxPay', payInfo, '加载中', (res) => {
let payResult = res.data.data;
that.payCallBack(payResult);
})
},
/**
* 微信唤醒支付的回调操作
*/
payCallBack: function(payResult) {
wx.requestPayment({
'timeStamp': payResult.timeStamp.toString(),
'nonceStr': payResult.nonceStr,
'package': payResult.package,
'signType': payResult.signType,
'paySign': payResult.paySign,
'success': function (res) {
if (res.errMsg == "requestPayment:ok") {
wx.showModal({
title: '支付',
content: '恭喜您支付成功',
showCancel: false,
success: function (res) {
that.onShow()
},
})
} else if (res.errMsg == 'requestPayment:cancel') {
wx.showModal({
title: '支付',
content: '很遗憾!您支付失败啦',
showCancel: false,
success: function (res) { },
})
}
},
'fail': function (err) {
// 取消支付
console.log(err)
},
'complete': function (comp) {
}
})
},
服务端:
public function WxPay(){
$id = input('get.product_id/d') <= 0 ? $this->ReturnStatus(false,'充值ID异常') : input('get.product_id/d');
$uid = empty(input('get.uid')) ? $this->ReturnStatus(false,'UID异常') : input('get.uid/d');
$money = db('goods')
->field('price,describe,type_id')
->where('id',$id)
->find();
//导入微信支付类库
import('SmallWxPay.WxPayApi');
//调用统一下单接口
$input = new \WxPayUnifiedOrder();
$input->SetBody($money['describe']);//商品描述
$input->SetAttach($money['describe']);//商品附加描述
$out_trade_no = \WxPayConfig::MCHID.date("YmdHis");
$input->SetOut_trade_no($out_trade_no);//唯一订单号
$input->SetTotal_fee(intval($money['price']));//金额
$input->SetTime_start(date("YmdHis"));//开始时间
$input->SetTime_expire(date("YmdHis", time() + 600));//结束时间
$input->SetNotify_url("https://www.***.com/home/Wxnotify/notify");//异步回调地址
$input->SetTrade_type("JSAPI");//交易类型:小程序填JSAPI
$openId = db('member')
->where('id',$uid)
->value('small_open_id');
$input->SetOpenid($openId);//用户Openid
$result = \WxPayApi::unifiedOrder($input);//调用微信API提交数据并取得返回
$type = $money['type_id'] == 2 || $money['type_id'] == 3 ? 2 : 1;//充值类型
$res = array();
//判断预支付是否成功
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
//生成签名
$nonceStr = $this->createNoncestr();//随机字符串
//生成签名所需参数
$sign_arr = array(
'appId' => $result['appid'],//小程序Appid
'timeStamp' => strval(time()),//当前时间戳
'nonceStr' => $nonceStr,//随机字符串32位
'package' => 'prepay_id='.$result['prepay_id'],//统计下单返回
'signType' => 'MD5',//加密类型
);
ksort($sign_arr);//根据键,以升序对关联数组进行排序
$sign = "";
//拼接签名
foreach ($sign_arr as $k => $v)
{
if($k != "sign"){
$sign .= $k . "=" . $v . "&";
}
}
$sign = trim($sign, "&");
$sign = $sign.'&key='.\WxPayConfig::KEY;//KEY拼接到最后
$sign_md = md5($sign);//md5加密
$sign_res = strtoupper($sign_md);//转为大写
$res = array(
'sign' => $sign_res,//签名
'time' => $sign_arr['timeStamp'],//当前时间戳
'nonceStr' => $sign_arr['nonceStr'],//随机字符串32位
'prepay_id' => 'prepay_id='.$result['prepay_id'],//统一下单返回数据包
);
}else{
$this->ReturnStatus(false,'充值异常');
}
return $result['return_code'] == 'SUCCESS' ? $this->ReturnStatus(true,'成功',$res) : $this->ReturnStatus(false,'失败',$result);
}
/*
* 生成随机字符串
* @author DongQiang
*/
private function createNoncestr($length = 32) {
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}