From 6709c8d5ae251cd006c2138a15eb669f60572be4 Mon Sep 17 00:00:00 2001 From: wangxinglong <2371974647@qq.com> Date: Wed, 24 Nov 2021 14:41:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E6=83=A0=E5=88=B8=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/api/Recharge.php | 152 +++++++++++++++++++++++ app/controller/docs/api.php | 35 ------ app/controller/manager/Business.php | 4 +- app/controller/manager/Coupon.php | 99 +++++++++++++++ app/model/Business.php | 5 +- app/model/CouponMain.php | 5 + app/service/Repository.php | 2 +- public/.htaccess | 10 +- public/static/manager/js/coupon/index.js | 100 +++++++++++++++ public/static/manager/js/coupon/info.js | 58 +++++++++ view/manager/coupon/index.html | 118 ++++++++++++++++++ view/manager/coupon/info.html | 134 ++++++++++++++++++++ 12 files changed, 681 insertions(+), 41 deletions(-) create mode 100644 app/controller/api/Recharge.php delete mode 100644 app/controller/docs/api.php create mode 100644 app/controller/manager/Coupon.php create mode 100644 public/static/manager/js/coupon/index.js create mode 100644 public/static/manager/js/coupon/info.js create mode 100644 view/manager/coupon/index.html create mode 100644 view/manager/coupon/info.html diff --git a/app/controller/api/Recharge.php b/app/controller/api/Recharge.php new file mode 100644 index 0000000..469027d --- /dev/null +++ b/app/controller/api/Recharge.php @@ -0,0 +1,152 @@ +json("4001", "参数错误"); + } + $recharge = RechargeRepository::getInstance()->getModel()->where(["order_num" => $orderNum])->lock(true)->find(); + if (empty($recharge)) { + return $this->json("4001", "订单不存在"); + } + if ($recharge['state'] == RechargeModel::state_on) { + return $this->json(); + } + $business = BusinessRepository::getInstance()->getModel()->where(["code" => $recharge['business_code']])->lock(true)->find(); + if (empty($business)) { + return $this->json("4001", "商家不存在"); + } + //查询 交易成功判断条件: return_code、result_code和trade_state都为SUCCESS + $res = WechatPay::getInstance()->order->queryByOutTradeNumber($orderNum); + if ($res['return_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态 + if (isset($res['result_code']) && $res['result_code'] == 'SUCCESS') { + if (isset($res['trade_state']) && $res['trade_state'] == 'SUCCESS') { + Db::startTrans(); + try { + //这里确定支付成功 + $total_fee = $res['total_fee'] / 100; + //加余额 + $business->save(["balance" => ($business["balance"] + $total_fee)]); + //修改支付状态 + $recharge->save([ + "money" => $total_fee, + "state" => RechargeModel::state_on, + "update_time" => date("Y-m-d H:i:s"), + "balance" => $business->balance + ]); + Db::commit(); + return $this->json(); + } catch (RepositoryException $e) { + Db::rollback(); + return $this->json("5001", $e->getMessage()); + } catch (\Exception $e) { + Db::rollback(); + return $this->json("5001", "充值失败"); + } + } + } + } + return $this->json("4001", "未支付成功"); + } + + /** + * 微信的回调 + * + * @throws \EasyWeChat\Kernel\Exceptions\Exception + */ + public function notify(){ + if ($this->request->isPost()) { + $app = WechatPay::getInstance(); + $response = $app->handlePaidNotify(function ($message, $fail) { + // $aa = '{"appid":"wxa02e44170bc722cd","bank_type":"OTHERS","cash_fee":"1","fee_type":"CNY","is_subscribe":"N","mch_id":"1605090111","nonce_str":"60f7d8a1e4ac8","openid":"oKrEm0ehgsy2ZTWzEva4tbLuUgFw","out_trade_no":"16268555858753004863","result_code":"SUCCESS","return_code":"SUCCESS","sign":"DB3F6CDCB7FBB3B9DDF7C0CC8BBD5AAD","time_end":"20210721162000","total_fee":"1","trade_type":"JSAPI","transaction_id":"4200001200202107217942681078"}'; + // $message = json_decode($aa, true); + $m = json_encode($message, JSON_UNESCAPED_UNICODE); + + $recharge = RechargeRepository::getInstance()->getModel()->where(["order_num" => $message['out_trade_no']])->lock(true)->find(); + if (empty($recharge)) { + $this->log(sprintf("[微信支付回调][%s][%s]订单支付成功,但系统查无此订单 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'error'); + return true;//订单不存在 + } + if ($recharge['state'] == RechargeModel::state_on) { + return true;//订单已经支付 + } + $business = BusinessRepository::getInstance()->getModel()->where(["code" => $recharge['business_code']])->lock(true)->find(); + if (empty($business)) { + $this->log(sprintf("[微信支付回调][%s][%s]订单支付成功,但商家不存在 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'error'); + return true; + } + + + if ($message['return_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态 + if (isset($message['result_code']) && $message['result_code'] == 'SUCCESS') { + if (isset($message['trade_state']) && $message['trade_state'] == 'SUCCESS') { + Db::startTrans(); + try { + //这里确定支付成功 + $total_fee = $message['total_fee'] / 100; + //加余额 + $business->save(["balance" => ($business["balance"] + $total_fee)]); + //修改支付状态 + $recharge->save([ + "money" => $total_fee, + "state" => RechargeModel::state_on, + "update_time" => date("Y-m-d H:i:s"), + "balance" => $business->balance + ]); + Db::commit(); + //记录日志 + $this->log(sprintf("[微信支付回调][%s][%s]订单支付成功 info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info'); + return true; + } catch (RepositoryException $e) { + Db::rollback(); + $this->log(sprintf("[微信支付回调][%s][%s]订单支付成功-修改订单状态失败-RepositoryException info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info'); + return $fail('Order status edit failed.'); + } catch (\Exception $e) { + Db::rollback(); + $this->log(sprintf("[微信支付回调][%s][%s]订单支付成功-修改订单状态失败-Exception info:%s", date('Y-m-d H:i:s'), $message['out_trade_no'], $m), 'info'); + return $fail('Order status edit failed.'); + } + } + } + } + return $fail('通信失败,请稍后再通知我'); + }); + + $response->send(); + } + } + /** + * 记录订单日志 + * + * @param string $message + * @param string $type + */ + private function log(string $message, string $type = 'info'): void + { + Log::channel('order')->write($message, $type); + } +} \ No newline at end of file diff --git a/app/controller/docs/api.php b/app/controller/docs/api.php deleted file mode 100644 index ad0d2b2..0000000 --- a/app/controller/docs/api.php +++ /dev/null @@ -1,35 +0,0 @@ -count(); //商家充值总额 - $item->recharge_total_money = Recharge::where(["business_code" => $item->business->code]) - ->where("state", "=", Recharge::state_on) - ->sum("money"); + $item->recharge_total_money = $item->business->total_recharge; }); return $this->json(0, 'success', $list); diff --git a/app/controller/manager/Coupon.php b/app/controller/manager/Coupon.php new file mode 100644 index 0000000..764de30 --- /dev/null +++ b/app/controller/manager/Coupon.php @@ -0,0 +1,99 @@ +request->isPost()) { + $model = new CouponMain(); + $repo = CouponRepository::getInstance($model); + $keyword = $this->request->param('keyword/s', ''); + $on_shelf = $this->request->param('on_shelf'); + $start_time = $this->request->param('start_time',); + $end_time = $this->request->param('end_time'); + $page = $this->request->param('page/d', 1); + $size = $this->request->param('size/d', 30); + + $whereMap = []; + $orders = ['id' => 'desc']; + if (!empty($on_shelf) && in_array($on_shelf, [CouponMain::COMMON_ON, CouponMain::COMMON_OFF])) { + $whereMap[] = ['on_shelf', '=', $on_shelf]; + } + if (!empty($start_time)) { + $whereMap[] = ['start_time', '>=', $start_time]; + } + if (!empty($end_time)) { + $whereMap[] = ['end_time', '<=', $end_time]; + } + if (!empty($keyword)) { + $whereMap[] = ['name', 'like', "%" . $keyword . "%"]; + } + $list = $repo->findList($whereMap, [], $page, $size, function ($q) { + + if (!empty($keyword)) { + return $q::hasWhere('business', function ($q) use ($keyword) { + $q->where('business_name', 'like', "%" . $keyword . "%")->field("code,business_name,business_subtitle,type") + ->with('category'); + }); + } + return $q->with(["business" => function ($query) { + $query->field("code,business_name,business_subtitle,type") + ->with('category'); + }]); + }, $orders); + $time = time(); + $list['list']->each(function ($item) use ($time) { + if (strtotime($item->start_time) > $time) { + $item->state_text = '未开始'; + } else if ((strtotime($item->start_time) < $time) && (strtotime($item->end_time) > $time)) { + $item->state_text = '进行中'; + } else { + $item->state_text = '已过期'; + } + }); + return $this->json(0, 'success', $list); + } + return $this->view(); + } + + public function shelf() + { + $id = input("id/d", 0); + $on_shelf = input("on_shelf/d", 1); + $model = new CouponMain(); + $repo = CouponRepository::getInstance($model); + $coupon = $repo->findById($id); + + if (empty($coupon)) { + return $this->json(4001, "优惠券不存在"); + } + + if (in_array($on_shelf, [CouponMain::COMMON_OFF, CouponMain::COMMON_ON])) { + return $this->json(4001, "状态错误"); + } + $coupon->save(["on_shelf"=>$on_shelf]); + return $this->json(); + } +} \ No newline at end of file diff --git a/app/model/Business.php b/app/model/Business.php index 8e05269..ebaf2f7 100644 --- a/app/model/Business.php +++ b/app/model/Business.php @@ -7,5 +7,8 @@ class Business extends Base const state_reviewing = 0; const state_on = 1; const state_off = 2; - + public function category() + { + return $this->hasOne(Category::class, 'id',"type"); + } } diff --git a/app/model/CouponMain.php b/app/model/CouponMain.php index 5181ec0..ec114f2 100644 --- a/app/model/CouponMain.php +++ b/app/model/CouponMain.php @@ -18,4 +18,9 @@ class CouponMain extends Base const status_off = 1;//停止 const on_shelf_on = 0;//上架状态 const on_shelf_off = 1;//下架状态 + + public function business() + { + return $this->hasOne(Business::class, 'code',"business_code"); + } } \ No newline at end of file diff --git a/app/service/Repository.php b/app/service/Repository.php index a68c2e2..38509f4 100644 --- a/app/service/Repository.php +++ b/app/service/Repository.php @@ -130,7 +130,7 @@ class Repository $line = '['.$name.'] '.$e->getMessage(); Log::error($line); - throw new RepositoryException('Repository异常'.(Env::get('app_debug') ? ': '.$line : ''), 5009); + throw new RepositoryException('Repository异常'.$line.(Env::get('app_debug') ? ': '.$line : ''), 5009); } finally { if ($exception && $failReturn instanceof RepositoryException) { if (Env::get('app_debug')) { diff --git a/public/.htaccess b/public/.htaccess index 0519ecb..8aa9d23 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -1 +1,9 @@ - \ No newline at end of file + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_URI} !^(.*)\.(gif|jpg|jpeg|png|swf|mp4)$ [NC] + RewriteRule ^(.*)$ index.php?s=/$1 [QSA,PT,L] + \ No newline at end of file diff --git a/public/static/manager/js/coupon/index.js b/public/static/manager/js/coupon/index.js new file mode 100644 index 0000000..e0bc76f --- /dev/null +++ b/public/static/manager/js/coupon/index.js @@ -0,0 +1,100 @@ +layui.use(['laytpl', 'table', 'jquery', 'form', 'miniTab', 'xmSelect','laydate'], function () { + let $ = layui.jquery, + form = layui.form, + table = layui.table, + layer = layui.layer, + xmSelect = layui.xmSelect, + laydate = layui.laydate, + miniTab = layui.miniTab; + + /**** index begin ***/ + //index页面 + if ($('.location-index-page').length > 0) { + miniTab.listen(); + + // 渲染表格 + let listUrl = $('#table-container').data('url'); + let insTb = table.render({ + elem: '#table-container', + toolbar: '#toolbar-tpl', + defaultToolbar: [{ //自定义头部工具栏右侧图标。如无需自定义,去除该参数即可 + title: '搜索' + , layEvent: 'search' + , icon: 'layui-icon-search' + }], + url: listUrl, + method: 'post', + even: true, + limits: [10,20,50,100,200,500,1000], + request: { + pageName: 'page', + limitName: 'size', + }, + parseData: function (res) { + return { + "code": res.code, //解析接口状态 + "msg": res.msg, //解析提示文本 + "count": res.data.total, //解析数据长度 + "data": res.data.list //解析数据列表 + }; + }, + page: true, + cols: [[ + // {type: 'checkbox'}, + {field: 'id' , width: 80, title: 'ID'}, + + {field: 'name', title: '名称'}, + {templet:function(d){ + if( d.business != undefined ){ + return d.business.business_name!=null?d.business.business_name:'' + } + return d.business_name; + }, title: '所属商家'}, + {templet:function(d){ + if( d.business != undefined ){ + return d.business.business_subtitle!=null?d.business.business_subtitle:'' + } + return ''; + }, title: '商家简称'}, + {field: 'money', title: '金额'}, + {field: 'deduction_money', title: '扣费'}, + {field: 'start_time', title: '开始时间'}, + {field: 'end_time', title: '结束时间'}, + {templet: '#row-on_shelf', title: '上架状态'}, + {field: 'state_text', title: '状态'}, + {field: 'create_time', title: '创建时间'}, + {templet: '#row-operate', field: 'right', align: 'center', title: '操作', fixed: 'right'} + ]], + done: function () { + Tools.setInsTb(insTb); + } + }); + + // 监听搜索操作 + form.on('submit(data-search-btn)', function (data) { + //执行搜索重载 + table.reload('table-container', { + page: {curr: 1} + , where: data.field + }, 'data'); + + return false; + }); + + //日期时间选择器 + laydate.render({ + elem: '#start_time' + ,type: 'date' + }); + + //日期时间选择器 + laydate.render({ + elem: '#end_time' + ,type: 'date' + }); + + + } + /*** index end ***/ + +}); \ No newline at end of file diff --git a/public/static/manager/js/coupon/info.js b/public/static/manager/js/coupon/info.js new file mode 100644 index 0000000..a06ccd3 --- /dev/null +++ b/public/static/manager/js/coupon/info.js @@ -0,0 +1,58 @@ +layui.use(['laytpl', 'table', 'jquery', 'form', 'miniTab', 'xmSelect'], function () { + let $ = layui.jquery, + form = layui.form, + table = layui.table, + layer = layui.layer, + xmSelect = layui.xmSelect, + miniTab = layui.miniTab; + + /**** index begin ***/ + //index页面 + if ($('.location-index-page').length > 0) { + miniTab.listen(); + + // 渲染表格 + let listUrl = $('#table-container').data('url'); + let insTb = table.render({ + elem: '#table-container', + toolbar: '#toolbar-tpl', + defaultToolbar: null, + url: listUrl, + method: 'post', + even: true, + limits: [10,20,50,100,200,500,1000], + request: { + pageName: 'page', + limitName: 'size', + }, + parseData: function (res) { + return { + "code": res.code, //解析接口状态 + "msg": res.msg, //解析提示文本 + "count": res.data.total, //解析数据长度 + "data": res.data.list //解析数据列表 + }; + }, + page: true, + cols: [[ + // {type: 'checkbox'}, + {field: 'id' , width: 80, title: 'ID'}, + {field: 'name', title: '名称'}, + {field: 'type_name', title: '优惠券类型'}, + {templet: '#row-received_map', title: '领取位置'}, + {field: 'money', title: '金额'}, + {field: 'business_name', title: '商家名称'}, + {field: 'business_name', title: '商家名称'}, + {templet: '#row-sign_map', title: '签到位置'}, + {templet: '#row-state', title: '状态'}, + ]], + done: function () { + Tools.setInsTb(insTb); + } + }); + + + } + /*** index end ***/ + +}); \ No newline at end of file diff --git a/view/manager/coupon/index.html b/view/manager/coupon/index.html new file mode 100644 index 0000000..0e8091f --- /dev/null +++ b/view/manager/coupon/index.html @@ -0,0 +1,118 @@ +{layout name="manager/layout" /} + + +
+
+
+
+
+
+ 搜索信息 +
+
+
+
+ +
+ +
+
+ +
+ +
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/view/manager/coupon/info.html b/view/manager/coupon/info.html new file mode 100644 index 0000000..a3af553 --- /dev/null +++ b/view/manager/coupon/info.html @@ -0,0 +1,134 @@ +{layout name="manager/layout" /} + + +
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+

评论数

+ {$totalComment ?? 0} +
+
+
+
+
+
+

本月评论数

+ {$totalTheMonthComment ?? 0} +
+
+
+
+
+
+

标签

+ {$consumer["tag"]["name"] ?? '无'} +
+
+
+
+
+
+

优惠券领取总数

+ {$couponTotalCount ?? 0} +
+
+
+
+
+
+

优惠券使用总数

+ {$couponUsedTotalCount ?? 0} +
+
+
+
+
+
+

优惠券未使用总数

+ {$couponNotUsedTotalCount ?? 0} +
+
+
+ +
+
+ + + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + \ No newline at end of file