有段时间没有写实战类的文章了,今天分享一篇,使用yii2+houjs+yii2-wx实现微信送礼物功能。
先来个效果图javascript
简单点说就是点击“送礼物”按钮后出现一个弹出框,里面有不少礼物,点击某个礼物后弹出框刷新并出现一个二维码,微信扫码支付。php
固然这个钱会进入到会员的我的帐号内,而后提现。html
为什么要作这样一个功能那? 说内心话我真心没想过经过这个获得多少,更多算一种激励吧,若是你在咱们学习社群分享了有价值的文章,你很是有可能受到个人礼物。java
好了,仍是说功能吧,功能有几个git
库网址列表github
我勒个去,干货满满呀。开始。json
既然是送礼品,那天然包含礼品表,还有送礼物的日志表,我规划以下。浏览器
礼物表gift服务器
礼物日志表gift_log微信
对于 gift_log 表能够不用lang_id,这里为了统计方便添加了这个字段。
用户送礼物的总体逻辑以下
接下来咱们使用houjs来构建前台功能,关于houjs的使用能够去社群查看 传送门,咱们主要使用其modal弹出框助手和jsmart模板引擎。
首先指定一个按钮
<button class="ui green button" id="giftBtn" data-url="<?= Url::to(['/gift/list','id'=>$lang->id]);?>"> <i class="share icon"></i>送礼物 </button>
data-url表明用于获取礼物列表的路由,为按钮作一个click事件处理
requirejs(['mods/modal','jSmart'],function(modal,jSmart){ $('#giftBtn').click(function(){ var url = $(this).attr('data-url'); $.getJSON(url,{},function(d){ if(d.result === 'ok'){ // d.data }else{ modal.msg(d.message); } }); }); })
发起了一个请求用来获取礼物列表,若是失败则提示错误信息。
接下来咱们新建GiftController.php并定义list动做。
public function actionList($id){ Yii::$app->response->format = 'json'; try { $data = Gift::find()->where(['lang_id'=>$id])->asArray()->all(); return ['result'=>'ok','data'=>$data]; }catch(Exception $e){ return ['result'=>'fail','message'=>$e->getMessage()]; } }
从这里咱们知道如今点击按钮后得到的数据里d.data就是此社群的礼物列表。
当前台获得了礼物列表后,使用jsmart将数据转换成html代码,为此咱们须要先作一个jsmart的模板,在送礼物按钮页面增长此模板。
<script id="giftTpl" type="text/x-jsmart-tmpl"> <div class="gifts-box"> <div class="gifts"> {foreach $data as $key=>$gift} <a href=""> <div class="gift-icon"><img src='{$gift.icon}'/></div> <div class="gift-name">{$gift.name}</div> </a> {/foreach} </div> </div> </script>
这个模板的大致意思就是讲过来的d.data中的数据进行循环,每一个礼物放到标签a中,而后咱们向后台获取礼物列表的js代码进行补充,以下。
requirejs(['mods/modal','jSmart'],function(modal,jSmart){ $('#giftBtn').click(function(){ var url = $(this).attr('data-url'); $.getJSON(url,{},function(d){ if(d.result === 'ok'){ var tplText = $('#giftTpl').html(); var compiledTemplate = new jSmart(tplText); var output = compiledTemplate.fetch(d); modal.alert(output,{ inPage:false, title:'送礼物', size:'tiny' }); }else{ modal.msg(d.message); } }); }); })
进行模板渲染,到了咱们看效果的时候了。
我很喜欢,使用yii2和houjs的modal&jsmart,完成了礼物列表的功能。接下来咱们要作一个重要的事情,和后台交互而且获得支付二维码。
在本章咱们使用yii2-wx扩展实现微信支付功能,其思路点击礼物后获取支付二维码。
在进行以前咱们对上一步的js方法进行优化,将代码放到一个单独的js模块中,在houjs中对于业务上的js代码推荐放到houjs/js/modules中,以下
define(function(require,exports,modules){ var modal = require('mods/modal'); var jSmart = require('jSmart'); exports.list = function(){ $('#giftBtn').click(function(){ var url = $(this).attr('data-url'); $.getJSON(url,{},function(d){ if(d.result === 'ok'){ var tplText = $('#giftTpl').html(); var compiledTemplate = new jSmart(tplText); var output = compiledTemplate.fetch(d); modal.alert(output,{ inPage:false, title:'送礼物给做者', size:'tiny' }); }else{ modal.msg(d.message); } }); }); }; });
所以获取礼物列表的js代码调用就变的简单了,以下
requirejs(['modules/gift'],function(gift){ gift.list(); })
之后关于gift的js代码均可以放到houjs/js/modules/gift.js中。
好,仍是说本部分话题。如何获取支付二维码?
个人思路以下:用户点击每一个礼品后发起一次get请求到服务器,本次请求包含了礼物的ID,后台收到后生成送礼物日志并和微信服务器通信获得支付二维码,返回给浏览器,前台渲染此二维码。
说干就干。
首先补充礼物列表,每一个礼物的a连接,以下
<script id="giftTpl" type="text/x-jsmart-tmpl"> <div class="gifts-box"> <div class="gifts"> {foreach $data as $key=>$gift} <a class="_get_qrcode" href="javascript:;" data-url="<?= Url::to(['/gift/qrcode']);?>?id={$gift.id}"> <div class="gift-icon"><img src='{$gift.icon}'/></div> <div class="gift-name">{$gift.name}</div> </a> {/foreach} </div> </div> </script>
咱们为每一个礼物的a连接设置了3个属性
接下来咱们作一个js方法实现a连接点击的监听,以下
// houjs/js/modules/gift.js define(function(require,exports,modules){ var modal = require('mods/modal'); var jSmart = require('jSmart'); ..... /** * 获取某一个礼物的支付二维码 */ exports.qrcode = function(){ $('._get_qrcode').click(function(){ var url = $(this).attr('data-url'); $.getJSON(url,{},function(d){ if(d.result === 'ok'){ $('#payQrcode') .html("<img width='120' src='"+d.qrcode+"'/>"); }else{ modal.msg(d.message); } }); }); }; });
有一点要说明,所以礼物列表是在页面dom渲染后加入的html代码,所以若是想让礼物列表的a连接被监听,在获取礼物列表成功后须要调用exports.qrcode()函数进行监听,以下
// houjs/js/modules/gift.js define(function(require,exports,modules){ var modal = require('mods/modal'); var jSmart = require('jSmart'); exports.list = function(){ $('#giftBtn').click(function(){ var url = $(this).attr('data-url'); $.getJSON(url,{},function(d){ if(d.result === 'ok'){ .... exports.qrcode(); }else{ modal.msg(d.message); } }); }); }; /** * 获取某一个礼物的支付二维码 */ exports.qrcode = function(){ .... }; });
此刻用户点击了礼物的a连接,gift.qrcode()方法开始运做,请求达到了yii2的gift/qrcode动做,我写了以下代码。
// yii2 GiftController/actionQrcode <?php namespace app\controllers; use app\models\Gift; use app\models\GiftLog; use yii\helpers\Url; use abei2017\wx\Application; use Da\QrCode\QrCode; use Yii; use yii\base\Exception; class GiftController extends NBase { .... public function actionQrcode($id){ Yii::$app->response->format = 'json'; try { $model = Gift::findOne($id); // order $order = new GiftLog(); $order->gift_id = $id; $order->user_id = Yii::$app->user->id; $order->created_at = time(); $order->number = 1; $order->money = $order->number*$model->price; $order->status = 'unpay'; $order->lang_id = $model->lang_id; if($order->save() == false){ throw new Exception(implode(',',$order->getFirstErrors())); } $out_trade_no = "gift-{$order->id}-".rand(1000,9999); $totalFee = $order->money*100; $conf = Yii::$app->params['wx']; $app = new Application(['conf'=>$conf['mp']]); $pay = $app->driver("mp.pay"); $attributes = [ 'body'=>"送礼物", 'detail'=>"{$model->name}", 'out_trade_no'=>$out_trade_no, 'total_fee'=>$totalFee, 'notify_url'=>Yii::$app->urlManager->createAbsoluteUrl(['/gift/notify']), 'product_id'=>'gift-'.$id ]; $native = $pay->native($attributes); $qrCode = (new QrCode($native['code_url']))->setSize(250)->setMargin(20); return ['result'=>'ok','qrcode'=>$qrCode->writeDataUri()]; }catch(Exception $e){ return ['result'=>'fail','message'=>$e->getMessage()]; } } }
首先要说明的是上述代码没有问题,但若是上线仍是要处理细节的。
在actionQrcode方法中咱们作了3件事情
这里使用的是yii2-wx提供的生成二维码方法native,剩下的事情就是如何显示这个二维码。
为了让用户能够在支付前从新选择礼物,本次并无选择弹出二维码,而是使用了礼物页面替换的方法,以下图
在礼物的右侧我增长了一个div来存放二维码,没有选择的时候用一些帮助来填充。这个二维码的存放工做由gift.qrcode()方法实现
$('#payQrcode').html("<img width='120' src='"+d.qrcode+"'/>");
对应的礼物列表模板也增长了支付区域
<script id="giftTpl" type="text/x-jsmart-tmpl"> <div class="gifts-box"> <div class="gifts"> {foreach $data as $key=>$gift} <a class="_get_qrcode" href="javascript:;" data-url="<?= Url::to(['/gift/qrcode']);?>?id={$gift.id}"> <div class="gift-icon"><img src='{$gift.icon}'/></div> <div class="gift-name">{$gift.name}</div> </a> {/foreach} </div> <div id="payQrcode"> <h1>使用小提示</h1> <p> 点击左侧的小礼物后会出现支付二维码,扫码即送。 </p> </div> <div class="clear"></div> </div> </script>
好,看下效果。
当用户获得支付二维码后必然是扫码支付,接下来有两个事情要作
先来处理结果通知,这个使用yii2-wx很是好实现。在GiftController中增长一个notify动做。
// GiftController.php <?php namespace app\controllers; use app\models\Gift; use app\models\GiftLog; use yii\data\ActiveDataProvider; use yii\helpers\Url; use abei2017\wx\Application; use Da\QrCode\QrCode; use Yii; use yii\base\Exception; class GiftController extends NBase { public $enableCsrfValidation = false; ...... public function actionNotify(){ $conf = Yii::$app->params['wx']; $app = new Application(['conf'=>$conf['mp']]); $pay = $app->driver("mp.pay"); $response = $pay->handleNotify(function($notify,$isSuccess){ if($isSuccess){ @list($_,$id,$_) = explode('-',$notify['out_trade_no']); $model = GiftLog::findOne($id); if($model->status == 'pay'){ return true; } $model->status = 'pay'; $model->paid_at = time(); $model->transaction_id = $notify['transaction_id']; $model->update(); return true; } }); return $response; } }
对上面的逻辑有几点要注意,这也是咱们用yii2-wx的时候要注意的。
如今咱们搞定了回调,看下效果。
不错不错
离成功愈来愈近了!接下来咱们要解决一个问题,就是当用户支付后在浏览器上礼物列表的变化,我但愿二维码消失同时出现一个支付成功的页面。
我须要一个轮询,那么开始吧,为此我在gift.js中增长一个轮询功能,这个功能在渲染出二维码后被触发。
//gift.js exports.askIsPay = function(id){ var url = '/gift/is-pay.html'; $.getJSON(url,{id:id},function(d){ if(d.result === 'ok'){ $('#payQrcode').empty() .html("<h1>支付成功</h1><p>感谢您对做者的支持,他会知道您的名字以及打款。</p>"); }else{ setTimeout(function(){ exports.askIsPay(id) },3000); } }); }
每3秒询问一次服务器上gift/is-pay动做是否此送礼物日志已经付款,固然要告诉是哪一个订单,若是已经付款则改变div#payQrcode的内容,不然继续调用exports.askIsPay(id)再一次询问。一点注意的是咱们在生成二维码的时候须要服务器将此日志的id返回(这须要服务器的gift/qrcode动做返回此送礼物日志的ID),当exports.askIsPay触发时export.qrcode将其传入。
... if(d.result === 'ok'){ $('#payQrcode').empty() .html("<img width='120' src='"+d.qrcode+"'/>"); exports.askIsPay(d.oId); }else{ modal.msg(d.message); } ...
固然咱们还要在服务器上新建一个控制器的动做。
// GiftController.php public function actionIsPay($id){ Yii::$app->response->format = 'json'; try { $model = GiftLog::findOne($id); if($model->status == 'unpay'){ throw new Exception('尚未支付'); } return ['result'=>'ok']; }catch(Exception $e){ return ['result'=>'fail','message'=>$e->getMessage()]; } }
大功告成,看看效果。
到此咱们就完成了永不打赏礼物的全过程,算上部吧,下部咱们将实现具体的打款到用户帐号以及使用yii2-wx调用微信企业付款到零钱包接口实现钱到微信功能。
教程中的内容未实现识别哪一个帖子或文章收到的打款,固然个人站点已经实现,你能够试试哈。
更多Yii原创文章