Browse Source

充值退款调试

zhangxiaobin 1 year ago
parent
commit
53f696be79

+ 71 - 0
addons/epay/library/Service.php

@@ -18,6 +18,77 @@ class Service
 {
 
     /**
+     * 提交退款订单
+     * @param array|float $amount    订单金额
+     * @param array|float $refund_money    退款金额
+     * @param string      $orderid   订单号
+     * @param string      $refund_sn   退款订单号
+     * @param string      $type      支付类型,可选alipay或wechat
+     * @param string      $remark     退款原因
+     * @param string      $notifyurl 通知回调URL
+     * @param string      $returnurl 跳转返回URL
+     * @param string      $method    支付方式
+     * @return Response|RedirectResponse|Collection
+     * @throws Exception
+     */
+    public static function submitRefund($amount=null,$refund_money,$orderid,$refund_sn,$type,$remark = null,$notifyurl = null,$returnurl = null,$method = 'app'){
+        if (!is_array($amount)) {
+            $params = [
+                'amount'    => $amount,
+                'type'      => $type,
+                'notifyurl' => $notifyurl,
+                'returnurl' => $returnurl,
+                'method'    => $method,
+            ];
+        } else {
+            $params = $amount;
+        }
+        $type = isset($params['type']) && in_array($params['type'], ['alipay', 'wechat']) ? $params['type'] : 'wechat';
+        $request = request();
+        $notifyurl = isset($params['notifyurl']) ? $params['notifyurl'] : $request->root(true) . '/addons/epay/index/' . $type . 'notify';
+        // $returnurl = isset($params['returnurl']) ? $params['returnurl'] : $request->root(true) . '/addons/epay/index/' . $type . 'return/out_trade_no/' . $orderid;
+        $config = Service::getConfig($type);
+        $config['notify_url'] = $notifyurl;
+        $config['return_url'] = $returnurl;
+        $result = null;
+        //退款参数
+        $order_data = [
+            'out_trade_no' => $orderid//原订单号
+        ];
+        if ($type == 'wechat') {
+            //创建支付对象
+            $pay = Pay::wechat($config);
+            $total_fee = $amount * 100;
+            $refund_fee = $refund_money * 100;
+            $order_data = array_merge($order_data, [
+                'out_refund_no' => $refund_sn,//退款订单号
+                'total_fee' => $total_fee,//支付金额
+                'refund_fee' => $refund_fee,//退款金额
+                'refund_desc' => $remark,//退款原因
+                //'type' => $method  //支付方式
+            ]);
+        } else {
+            $pay = Pay::alipay($config);
+            $order_data = array_merge($order_data, [
+                'out_request_no' => $refund_sn,//退款订单号
+                'refund_amount' => $refund_money,
+            ]);
+        }
+
+        $result = $pay->refund($order_data);
+
+        //使用重写的Response类、RedirectResponse、Collection类
+        if ($result instanceof \Symfony\Component\HttpFoundation\RedirectResponse) {
+            $result = RedirectResponse::create($result->getTargetUrl());
+        } elseif ($result instanceof \Symfony\Component\HttpFoundation\Response) {
+            $result = Response::create($result->getContent());
+        } elseif ($result instanceof \Yansongda\Supports\Collection) {
+            $result = Collection::make($result->all());
+        }
+        return $result;
+    }
+
+    /**
      * 提交订单
      * @param array|float $amount    订单金额
      * @param string      $orderid   订单号

+ 147 - 0
application/admin/controller/RecharOrder.php

@@ -0,0 +1,147 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\common\controller\Backend;
+use think\Db;
+use think\Exception;
+
+/**
+ * 充值订单管理
+ *
+ * @icon fa fa-circle-o
+ */
+class RecharOrder extends Backend
+{
+    
+    /**
+     * RecharOrder模型对象
+     * @var \app\admin\model\RecharOrder
+     */
+    protected $model = null;
+
+    public function _initialize()
+    {
+        parent::_initialize();
+        $this->model = new \app\admin\model\RecharOrder;
+        $this->view->assign("statusList", $this->model->getStatusList());
+        $this->view->assign("payTypeList", $this->model->getPayTypeList());
+        $this->view->assign("platformList", $this->model->getPlatformList());
+    }
+
+    public function import()
+    {
+        parent::import();
+    }
+
+    /**
+     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
+     * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
+     * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
+     */
+    
+
+    /**
+     * 查看
+     */
+    public function index()
+    {
+        //当前是否为关联查询
+        $this->relationSearch = true;
+        //设置过滤方法
+        $this->request->filter(['strip_tags', 'trim']);
+        if ($this->request->isAjax()) {
+            //如果发送的来源是Selectpage,则转发到Selectpage
+            if ($this->request->request('keyField')) {
+                return $this->selectpage();
+            }
+            list($where, $sort, $order, $offset, $limit) = $this->buildparams();
+
+            $list = $this->model
+                    ->with(['user'])
+                    ->where($where)
+                    ->order($sort, $order)
+                    ->paginate($limit);
+
+            foreach ($list as $row) {
+                
+                $row->getRelation('user')->visible(['nickname']);
+            }
+
+            $result = array("total" => $list->total(), "rows" => $list->items());
+
+            return json($result);
+        }
+        return $this->view->fetch();
+    }
+
+    /**
+     * 退款
+     */
+    public function refund($ids = null)
+    {
+        Db::startTrans();
+        try {
+            $row = $this->model->get($ids);
+            if (!$row) {
+                throw new Exception(__('No Results were found'));
+            }
+            $adminIds = $this->getDataLimitAdminIds();
+            if (is_array($adminIds)) {
+                if (!in_array($row[$this->dataLimitField], $adminIds)) {
+                    throw new Exception(__('You have no permission'));
+                }
+            }
+            if ($row['status'] != 1) {
+                throw new Exception('支付成功才能退款');
+            }
+            if ($row['refund_money'] != 0) {
+                throw new Exception('已退款');
+            }
+            //验证用户钻石是否足够
+            $userWhere['id'] = $row['user_id'];
+            $user = model('User')->where($userWhere)->lock(true)->find();
+            $userJewel = isset($user['jewel']) ? $user['jewel'] : 0;
+            if ($userJewel < $row['jewel']) {
+                throw new Exception('钻石不足,无法退款');
+            }
+            //更新退款金额
+            $data = [
+                'refund_money' => $row['money'],//退款金额
+            ];
+            $where['id'] = $ids;
+            $res = $this->model->update($data,$where);
+            if (!$res) {
+                throw new Exception('更新退款金额失败');
+            }
+            //记录退款日志
+            $res = model('Wallet')->lockChangeAccountRemain($row['user_id'],$row['jewel'],'-',$user['jewel'],'充值退款',18,'jewel');
+            if (!$res['status']) {
+                throw new Exception($res['msg']);
+            }
+            //实际退款
+            $refundParams = [
+                'order' => [
+                    'pay_out_trade_no' => $row['order_no'],
+                    'pay_fee' => $row['money'],
+                    'pay_type' => $row['pay_type'],
+                ],
+                'table' => 'rechar_order',
+                'table_id' => $ids,
+                'refund_price' => $row['money'],
+                'remark' => '充值退款',
+            ];
+            $refundParams['order']['pay_fee'] = 0.01;
+            $refundParams['refund_price'] = 0.01;
+            $refundRes = $this->model->old_refund($refundParams);
+            if ($refundRes['status'] == 0) {
+                throw new Exception($refundRes['msg']);
+            }
+            Db::commit();
+            $this->success('操作成功');
+        } catch (Exception $e) {
+            Db::rollback();
+            $this->error($e->getMessage());
+        }
+    }
+}

+ 30 - 0
application/admin/lang/zh-cn/rechar_order.php

@@ -0,0 +1,30 @@
+<?php
+
+return [
+    'Id'             => '主键ID',
+    'User_id'        => '用户ID',
+    'Order_no'       => '订单编号',
+    'Money'          => '充值金额',
+    'Jewel'          => '获得钻石',
+    'Refund_money'   => '退款金额',
+    'Service_fee'    => '手续费',
+    'Transaction_id' => '支付订单号',
+    'Status'         => '订单状态',
+    'Status -1'      => '支付超时',
+    'Status 0'       => '支付中',
+    'Status 1'       => '支付成功',
+    'Status 2'       => '退款',
+    'Business_no'    => '商户号',
+    'Pay_type'       => '支付渠道',
+    'Pay_type 1'     => '微信',
+    'Pay_type 2'     => '支付宝',
+    'Pay_type 3'     => '衫德',
+    'Platform'       => '充值平台',
+    'Platform 1'     => '安卓',
+    'Platform 2'     => 'ios',
+    'Platform 3'     => '公众号',
+    'Createtime'     => '创建时间',
+    'Paytime'        => '支付时间',
+    'Updatetime'     => '更新时间',
+    'User.nickname'  => '昵称'
+];

+ 215 - 0
application/admin/model/RecharOrder.php

@@ -0,0 +1,215 @@
+<?php
+
+namespace app\admin\model;
+
+use addons\epay\library\Service;
+use think\Db;
+use think\Model;
+
+
+class RecharOrder extends Model
+{
+
+    
+
+    
+
+    // 表名
+    protected $name = 'rechar_order';
+    
+    // 自动写入时间戳字段
+    protected $autoWriteTimestamp = 'int';
+
+    // 定义时间戳字段名
+    protected $createTime = 'createtime';
+    protected $updateTime = 'updatetime';
+    protected $deleteTime = false;
+
+    // 追加属性
+    protected $append = [
+        'status_text',
+        'pay_type_text',
+        'platform_text',
+        'paytime_text'
+    ];
+
+    public function old_refund($params = [])
+    {
+        $result = [
+            'status' => 1,
+            'msg' => '',
+            'data' => [],
+        ];
+        try {
+            $order = isset($params['order']) ? $params['order'] : [];
+            $table = isset($params['table']) ? $params['table'] : '';
+            $tableId = isset($params['table_id']) ? $params['table_id'] : 0;
+            $refund_price = isset($params['refund_price']) ? $params['refund_price'] : 0.00;
+            $remark = isset($params['remark']) ? $params['remark'] : '';
+            // 生成退款单
+            $refund_data = [
+                'out_refund_no'=> createUniqueNo('R',$tableId),
+                'pay_fee'  => $order['pay_fee'],
+                'refund_price' => $refund_price,
+                'pay_type' => $order['pay_type'],
+                'status' => 0,
+                'createtime' => time(),
+                'updatetime' => time(),
+                'table' => $table,
+                'table_id' => $tableId,
+            ];
+            $refund_log_id = Db::name('order_refund_log')->insertGetId($refund_data);
+            if (in_array($order['pay_type'],[1,2])) {
+                // 微信|支付宝退款
+
+                // 退款数据
+                $order_data = [
+                    'out_trade_no' => $order['pay_out_trade_no']
+                ];
+
+                if ($order['pay_type'] == 1) {//微信
+                    $total_fee = $order['pay_fee'] * 100;
+                    $refund_fee = $refund_price * 100;
+
+                    $order_data = array_merge($order_data, [
+                        'out_refund_no' => $refund_data['out_refund_no'],
+                        'total_fee' => $total_fee,
+                        'refund_fee' => $refund_fee,
+                        'refund_desc' => $remark,
+                    ]);
+                } elseif ($order['pay_type'] == 2) {//支付宝
+                    $order_data = array_merge($order_data, [
+                        'out_request_no' => $refund_data['out_refund_no'],
+                        'refund_amount' => $refund_price,
+                    ]);
+                }
+
+                //
+                if ($order['pay_type'] == 1) {
+                    $wxpay = new \app\common\library\Wxpay;
+                    $result = $wxpay->WxPayRefund($order_data);
+                    // 微信通知回调 pay->notifyr
+                    if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
+                        Db::name('order_refund_log')->where('id',$refund_log_id)->update(['status'=>1]);
+                    } else {
+                        throw new Exception($result['return_msg']);
+                    }
+                } elseif ($order['pay_type'] == 2) {
+                    $result = Service::submitRefund($order['pay_fee'],$refund_price,$order['pay_out_trade_no'],$refund_data['out_refund_no'],$order['pay_type'],$remark,'');
+                    if($result['code'] == '10000'){
+                        Db::name('order_refund_log')->where('id',$refund_log_id)->update(['status'=>1]);
+                    }else{
+                        throw new Exception($result['msg']);
+                    }
+
+                    /* return 'alipay wrong way';
+                     $alipay = new \app\common\library\AliPay;
+                     $result = $alipay->AliPayRefund($order_data);
+                     // 支付宝通知回调 pay->notifyx
+                     return $result;*/
+
+                    /*if ($result['code'] == "10000") {
+                        return true;
+                    } else {
+                        throw new \Exception($result['msg']);
+                    }*/
+                }
+
+                // {        // 微信返回结果
+                //     "return_code":"SUCCESS",
+                //     "return_msg":"OK",
+                //     "appid":"wx39cd0799d4567dd0",
+                //     "mch_id":"1481069012",
+                //     "nonce_str":"huW9eIAb5BDPn0Ma",
+                //     "sign":"250316740B263FE53F5DFF50AF5A8FA1",
+                //     "result_code":"SUCCESS",
+                //     "transaction_id":"4200000497202004072822298902",
+                //     "out_trade_no":"202010300857029180027000",
+                //     "out_refund_no":"1586241595",
+                //     "refund_id":"50300603862020040700031444448",
+                //     "refund_channel":[],
+                //     "refund_fee":"1",
+                //     "coupon_refund_fee":"0",
+                //     "total_fee":"1",
+                //     "cash_fee":"1",
+                //     "coupon_refund_count":"0",
+                //     "cash_refund_fee":"1
+                // }
+
+                // {        // 支付宝返回结果
+                //     "code": "10000",
+                //     "msg": "Success",
+                //     "buyer_logon_id": "157***@163.com",
+                //     "buyer_user_id": "2088902485164146",
+                //     "fund_change": "Y",
+                //     "gmt_refund_pay": "2020-08-15 16:11:45",
+                //     "out_trade_no": "202002460317545607015300",
+                //     "refund_fee": "0.01",
+                //     "send_back_fee": "0.00",
+                //     "trade_no": "2020081522001464141438570535"
+                // }
+            }
+        } catch (Exception $e) {
+            $result['status'] = 0;
+            $result['msg'] = '';
+        }
+        return $result;
+    }
+    
+    public function getStatusList()
+    {
+        return ['-1' => __('Status -1'), '0' => __('Status 0'), '1' => __('Status 1'), '2' => __('Status 2')];
+    }
+
+    public function getPayTypeList()
+    {
+        return ['1' => __('Pay_type 1'), '2' => __('Pay_type 2'), '3' => __('Pay_type 3')];
+    }
+
+    public function getPlatformList()
+    {
+        return ['1' => __('Platform 1'), '2' => __('Platform 2'), '3' => __('Platform 3')];
+    }
+
+
+    public function getStatusTextAttr($value, $data)
+    {
+        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
+        $list = $this->getStatusList();
+        return isset($list[$value]) ? $list[$value] : '';
+    }
+
+
+    public function getPayTypeTextAttr($value, $data)
+    {
+        $value = $value ? $value : (isset($data['pay_type']) ? $data['pay_type'] : '');
+        $list = $this->getPayTypeList();
+        return isset($list[$value]) ? $list[$value] : '';
+    }
+
+
+    public function getPlatformTextAttr($value, $data)
+    {
+        $value = $value ? $value : (isset($data['platform']) ? $data['platform'] : '');
+        $list = $this->getPlatformList();
+        return isset($list[$value]) ? $list[$value] : '';
+    }
+
+
+    public function getPaytimeTextAttr($value, $data)
+    {
+        $value = $value ? $value : (isset($data['paytime']) ? $data['paytime'] : '');
+        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
+    }
+
+    protected function setPaytimeAttr($value)
+    {
+        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
+    }
+
+
+    public function user()
+    {
+        return $this->belongsTo('User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
+    }
+}

+ 27 - 0
application/admin/validate/RecharOrder.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace app\admin\validate;
+
+use think\Validate;
+
+class RecharOrder extends Validate
+{
+    /**
+     * 验证规则
+     */
+    protected $rule = [
+    ];
+    /**
+     * 提示消息
+     */
+    protected $message = [
+    ];
+    /**
+     * 验证场景
+     */
+    protected $scene = [
+        'add'  => [],
+        'edit' => [],
+    ];
+    
+}

+ 100 - 0
application/admin/view/rechar_order/add.html

@@ -0,0 +1,100 @@
+<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="nickname" class="form-control selectpage" name="row[user_id]" type="text" value="">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Order_no')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-order_no" data-rule="required" class="form-control" name="row[order_no]" type="text">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Money')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-money" class="form-control" step="0.01" name="row[money]" type="number" value="0.00">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Jewel')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-jewel" class="form-control" name="row[jewel]" type="number" value="0">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Refund_money')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-refund_money" class="form-control" step="0.01" name="row[refund_money]" type="number">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Service_fee')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-service_fee" class="form-control" step="0.01" name="row[service_fee]" type="number" value="0.00">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Transaction_id')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-transaction_id" data-rule="required" data-source="transaction/index" class="form-control selectpage" name="row[transaction_id]" type="text" value="">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            
+            <div class="radio">
+            {foreach name="statusList" item="vo"}
+            <label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="-1"}checked{/in} /> {$vo}</label> 
+            {/foreach}
+            </div>
+
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Business_no')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-business_no" data-rule="required" class="form-control" name="row[business_no]" type="text" value="">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Pay_type')}:</label>
+        <div class="col-xs-12 col-sm-8">
+                        
+            <select  id="c-pay_type" data-rule="required" class="form-control selectpicker" name="row[pay_type]">
+                {foreach name="payTypeList" item="vo"}
+                    <option value="{$key}" {in name="key" value="0"}selected{/in}>{$vo}</option>
+                {/foreach}
+            </select>
+
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Platform')}:</label>
+        <div class="col-xs-12 col-sm-8">
+                        
+            <select  id="c-platform" class="form-control selectpicker" name="row[platform]">
+                {foreach name="platformList" item="vo"}
+                    <option value="{$key}" {in name="key" value="1"}selected{/in}>{$vo}</option>
+                {/foreach}
+            </select>
+
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Paytime')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-paytime" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[paytime]" type="text" value="{:date('Y-m-d H:i:s')}">
+        </div>
+    </div>
+    <div class="form-group layer-footer">
+        <label class="control-label col-xs-12 col-sm-2"></label>
+        <div class="col-xs-12 col-sm-8">
+            <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
+            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
+        </div>
+    </div>
+</form>

+ 100 - 0
application/admin/view/rechar_order/edit.html

@@ -0,0 +1,100 @@
+<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="nickname" class="form-control selectpage" name="row[user_id]" type="text" value="{$row.user_id|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Order_no')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-order_no" data-rule="required" class="form-control" name="row[order_no]" type="text" value="{$row.order_no|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Money')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-money" class="form-control" step="0.01" name="row[money]" type="number" value="{$row.money|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Jewel')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-jewel" class="form-control" name="row[jewel]" type="number" value="{$row.jewel|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Refund_money')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-refund_money" class="form-control" step="0.01" name="row[refund_money]" type="number" value="{$row.refund_money|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Service_fee')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-service_fee" class="form-control" step="0.01" name="row[service_fee]" type="number" value="{$row.service_fee|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Transaction_id')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-transaction_id" data-rule="required" data-source="transaction/index" class="form-control selectpage" name="row[transaction_id]" type="text" value="{$row.transaction_id|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            
+            <div class="radio">
+            {foreach name="statusList" item="vo"}
+            <label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="$row.status"}checked{/in} /> {$vo}</label> 
+            {/foreach}
+            </div>
+
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Business_no')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-business_no" data-rule="required" class="form-control" name="row[business_no]" type="text" value="{$row.business_no|htmlentities}">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Pay_type')}:</label>
+        <div class="col-xs-12 col-sm-8">
+                        
+            <select  id="c-pay_type" data-rule="required" class="form-control selectpicker" name="row[pay_type]">
+                {foreach name="payTypeList" item="vo"}
+                    <option value="{$key}" {in name="key" value="$row.pay_type"}selected{/in}>{$vo}</option>
+                {/foreach}
+            </select>
+
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Platform')}:</label>
+        <div class="col-xs-12 col-sm-8">
+                        
+            <select  id="c-platform" class="form-control selectpicker" name="row[platform]">
+                {foreach name="platformList" item="vo"}
+                    <option value="{$key}" {in name="key" value="$row.platform"}selected{/in}>{$vo}</option>
+                {/foreach}
+            </select>
+
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Paytime')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-paytime" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[paytime]" type="text" value="{:$row.paytime?datetime($row.paytime):''}">
+        </div>
+    </div>
+    <div class="form-group layer-footer">
+        <label class="control-label col-xs-12 col-sm-2"></label>
+        <div class="col-xs-12 col-sm-8">
+            <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
+            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
+        </div>
+    </div>
+</form>

+ 45 - 0
application/admin/view/rechar_order/index.html

@@ -0,0 +1,45 @@
+<div class="panel panel-default panel-intro">
+    
+    <div class="panel-heading">
+        {:build_heading(null,FALSE)}
+        <ul class="nav nav-tabs" data-field="status">
+            <li class="{:$Think.get.status === null ? 'active' : ''}"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
+            {foreach name="statusList" item="vo"}
+            <li class="{:$Think.get.status === (string)$key ? 'active' : ''}"><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
+            {/foreach}
+        </ul>
+    </div>
+
+
+    <div class="panel-body">
+        <div id="myTabContent" class="tab-content">
+            <div class="tab-pane fade active in" id="one">
+                <div class="widget-body no-padding">
+                    <div id="toolbar" class="toolbar">
+                        <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
+                        <a href="javascript:;" class="btn btn-success btn-add {:$auth->check('rechar_order/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
+                        <a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('rechar_order/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
+                        <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('rechar_order/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
+                        <a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('rechar_order/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>
+
+                        <div class="dropdown btn-group {:$auth->check('rechar_order/multi')?'':'hide'}">
+                            <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
+                            <ul class="dropdown-menu text-left" role="menu">
+                                <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
+                                <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
+                            </ul>
+                        </div>
+
+                        
+                    </div>
+                    <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
+                           data-operate-edit="{:$auth->check('rechar_order/edit')}" 
+                           data-operate-del="{:$auth->check('rechar_order/del')}" 
+                           width="100%">
+                    </table>
+                </div>
+            </div>
+
+        </div>
+    </div>
+</div>

+ 27 - 2
application/api/controller/Money.php

@@ -24,7 +24,8 @@ use app\common\library\Sms as Smslib;
  */
 class Money extends Common
 {
-    protected $noNeedLogin = ['getRecharConfig', 'getRateMoney', 'getExchangeConfig', 'getExchsoundConfig', 'rebateDuty', 'kjRecharge', 'changeWithDrawStatus','moneyConfig'];
+    protected $noNeedLogin = ['getRecharConfig', 'getRateMoney', 'getExchangeConfig', 'getExchsoundConfig', 'rebateDuty',
+        'kjRecharge', 'changeWithDrawStatus','moneyConfig','recharOrderCancel'];
     protected $noNeedRight = '*';
 
     public function _initialize()
@@ -49,7 +50,8 @@ class Money extends Common
         $type = $this->request->request("type", "wechat");// 充值类型:wechat:微信支付,alipay:支付宝支付
         $method = $this->request->request("method", "miniapp");// 支付方式:app:app支付,miniapp:小程序支付
         $openid = $this->request->request("openid", "");// 非小程序支付无需传值
-        $params_from = $this->request->request("params_from",1);// 平台参数充值平台:1=安卓,2=ios
+        $params_from = $this->request->request("params_from",'android');// 平台参数充值平台:1=android,2=ios
+        $params_from = $params_from == 'android' ? 1 : 2;
         $amounts = $this->request->request("amounts",0);// 自定义金额
         $jewelRate = config('site.money_to_jewel');
         if (!$rechar_id && empty($amounts)) {
@@ -1879,4 +1881,27 @@ class Money extends Common
             $this->error($e->getMessage());
         }
     }
+
+    /**
+     * 支付超时关闭
+     * @return void
+     */
+    public function recharOrderCancel()
+    {
+        try {
+            $maxTime = 1;
+            $createTimeEnd = time() - (60 * $maxTime);
+            $where['createtime'] = ['elt',$createTimeEnd];
+            $where['status'] = 0;
+            $recharOrder = model('RecharOrder')->where($where)->count();
+            $recharOrderRes = 0;
+            if (!empty($recharOrder)) {
+                $recharOrderRes = model('RecharOrder')->where($where)->update(['status' => -1]);
+            }
+            $this->success('操作成功',$recharOrderRes);
+        } catch (Exception $e) {
+            $this->error($e->getMessage());
+        }
+    }
+
 }

+ 2 - 1
application/api/controller/Notify.php

@@ -119,8 +119,9 @@ class Notify extends Api
         $rechargelogModel = new \app\common\model\UserRechargeLog();
         $orderInfo = $orderModel->where(["order_no" => $out_trade_no])->find();
         $userInfo = $userModel->where(["id" => $orderInfo["user_id"]])->find();
+        $time = time();
         // 修改订单状态
-        $res1 = $orderModel->update(["status" => 1,'transaction_id' => $trade_no], ["order_no" => $out_trade_no]);
+        $res1 = $orderModel->update(["status" => 1,'transaction_id' => $trade_no,'paytime'=>$time], ["order_no" => $out_trade_no]);
         // 修改用户钻石余额
         $res2 = $userModel->where(["id" => $orderInfo["user_id"]])->setInc("jewel", $orderInfo["jewel"]);
         //判断是否首充

+ 333 - 0
application/common/library/Wxpay.php

@@ -0,0 +1,333 @@
+<?php
+namespace app\common\library;
+
+class WxPay {
+
+    /**
+     * 初始化参数
+     *
+     * @param array $options
+     * @param $options ['app_id']  APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
+     * @param $options ['mch_id'] MCHID:商户号(必须配置,开户邮件中可查看)
+     * @param $options ['key'] KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置)
+     * @param $options ['appsecret'] 公众帐号secert(仅JSAPI支付的时候需要配置),
+     * @param $options ['notify_url'] 支付宝回调地址
+     */
+    public function __construct($options = array()) {
+        $this->config = !empty($options) ? $options : get_addon_config('epay')['wechat'];
+    }
+
+    /**
+     * 微信支付App
+     * @param string $data 业务参数 body out_trade_no total_fee
+     * @param string $data ['out_trade_no'] 订单号  必填
+     * @param string $data ['total_fee'] 订单金额  必填
+     * @param string $data ['body'] 订单详情  必填
+     * @return $response 返回app所需字符串
+     */
+    public function WxPayApp($d) {
+        $wxConfig = $this->config;
+
+        $out_trade_no = $d['out_trade_no'];
+        $total_fee = abs(floatval($d['total_fee'])) * 100;// 微信支付 单位为分
+        $nonce_str = $this->getRandChar(32);
+        $ip = $this->get_client_ip();
+        if ($ip == '::1')
+            $ip = '1.1.1.1';
+        $data ["appid"] = $wxConfig["app_id"];
+        $data ["body"] = $d['body'];
+        $data ["mch_id"] = $wxConfig['mch_id'];
+        $data ["nonce_str"] = $nonce_str;
+        $data ["notify_url"] = $wxConfig["notify_url"];
+        $data ["out_trade_no"] = $out_trade_no;
+        $data ["spbill_create_ip"] = $ip;
+        $data ["total_fee"] = $total_fee;
+        $data ["trade_type"] = "APP";
+        $data['time_expire'] = date('YmdHis', time() + 120);
+        $s = $this->getSign($data);
+        $data ["sign"] = $s;
+        $xml = $this->arrayToXml($data);
+        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
+        $response = $this->postXmlCurl($xml, $url);
+
+        $re = $this->xmlstr_to_array($response);
+        if ($re ['return_code'] == 'FAIL') {
+            return $re['return_msg'];
+        }
+        // 二次签名
+        $reapp = $this->getOrder($re['prepay_id']);
+        return $reapp;
+    }
+
+    /**
+     * 微信App支付退款申请
+     * @param array $d 业务参数 body out_trade_no total_fee
+     * @param string $data ['out_trade_no'] 订单号  必填
+     * @param string $data ['total_fee'] 订单金额  必填
+     * @return $response 返回app所需字符串
+     */
+    public function WxPayRefund($order_data) {
+        $wxConfig = get_addon_config('epay')['wechat'];
+
+        $data['appid'] = $wxConfig['app_id'];
+        $data['mch_id'] = $wxConfig['mch_id'];
+        $data['nonce_str'] = $this->getRandChar(32);;
+        if (isset($wxConfig['refund_notify'])) {
+            $data['notify_url'] = $wxConfig['refund_notify'];
+        }
+        $data['out_trade_no']  = $order_data['out_trade_no'];
+        $data['out_refund_no'] = $order_data['out_refund_no'];
+        $data['total_fee']     = $order_data['total_fee'];
+        $data['refund_fee']    = $order_data['refund_fee'];
+        $data['refund_desc']   = $order_data['refund_desc'];
+        $data['sign'] = $this->getSign($data);
+        $xml = $this->arrayToXml($data);
+        $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
+        $response = $this->postXmlCurl($xml, $url);
+        $re = $this->xmlstr_to_array($response);
+        /*if ($re ['return_code'] == 'FAIL') {
+            return $re['return_msg'];
+        }*/
+        return $re;
+    }
+
+
+    /**
+     * 微信退款通知
+     * @return array 验证正确返回状态及订单数据
+     */
+    public function WxPayRefundNotifyCheck() {
+        $postStr = $GLOBALS['HTTP_RAW_POST_DATA'];
+        if (!$postStr) {
+            $postStr = file_get_contents("php://input");
+        }
+        $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
+        if ($postObj === false) {
+            error_log('parse xml error', 3, './wechat_errorlog.txt');
+        }
+        if ($postObj->return_code != 'SUCCESS') {
+            error_log($postObj->return_msg, 3, './wechat_errorlog.txt');
+        }
+        $arr = (array)$postObj;
+        file_put_contents('wx_refund_error_logs.txt', date('Y-m-d H:i:s').'退款数据1!'.json_encode($arr), FILE_APPEND);
+
+        if($arr['return_code'] == 'SUCCESS') {
+            $wxConfig = $this->config;
+            //解密信息
+            require_once("Plugins/WxPay/OpenSSLAES.php");
+            $aes = new \OpenSSLAES(md5($wxConfig['key']));
+            $decrypted = $aes->decrypt($arr['req_info']);
+            $reqObj = simplexml_load_string($decrypted, 'SimpleXMLElement', LIBXML_NOCDATA);
+            $arr['req_info'] = (array)$reqObj;
+            file_put_contents('wx_refund_error_logs.txt', date('Y-m-d H:i:s').'退款数据2!'.json_encode($arr), FILE_APPEND);
+            return array('status' => true, 'data' => $arr);
+        }
+        return array('status' => false);
+    }
+
+    /**
+     * 微信签名验证
+     * @param string $data 业务参数
+     * @return array
+     */
+    public function WxPayNotifyCheck() {
+        $postStr = $GLOBALS['HTTP_RAW_POST_DATA'];
+        if(!$postStr){
+            $postStr = file_get_contents("php://input");
+        }
+
+        $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
+        if ($postObj === false) {
+            error_log('parse xml error', 3, './wechat_errorlog.txt');
+        }
+        if ($postObj->return_code != 'SUCCESS') {
+            error_log($postObj->return_msg, 3, './wechat_errorlog.txt');
+        }
+
+        $arr = (array)$postObj;
+        unset($arr['sign']);
+        if ($this->getSign($arr) == $postObj->sign) {
+            return array('status' => true, 'data' => $arr);
+        } else
+            return array('status' => false);
+    }
+
+    /**
+     * 以下为微信所需相关方法,请勿修改
+     */
+
+
+    // 执行第二次签名,才能返回给客户端使用
+    public function getOrder($prepayId) {
+        $data ["appid"] = $this->config ["app_id"];
+        $data ["noncestr"] = $this->getRandChar(32);
+        $data ["package"] = "Sign=WXPay";
+        $data ["partnerid"] = $this->config ['mch_id'];
+        $data ["prepayid"] = $prepayId;
+        $data ["timestamp"] = time();
+        $s = $this->getSign($data);
+        $data ["sign"] = $s;
+
+        return $data;
+    }
+
+    //生成签名
+    function getSign($Obj) {
+        foreach ($Obj as $k => $v) {
+            $Parameters [strtolower($k)] = $v;
+        }
+        // 签名步骤一:按字典序排序参数
+        ksort($Parameters);
+        $String = $this->formatBizQueryParaMap($Parameters, false);
+        // echo "【string】 =".$String."</br>";
+        // 签名步骤二:在string后加入KEY
+        $String = $String . "&key=" . $this->config ['key'];
+        // echo "<textarea style='width: 50%; height: 150px;'>$String</textarea> <br />";
+        // 签名步骤三:MD5加密
+        $result_ = strtoupper(md5($String));
+        return $result_;
+    }
+
+    // 获取指定长度的随机字符串
+    function getRandChar($length) {
+        $str = null;
+        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
+        $max = strlen($strPol) - 1;
+
+        for ($i = 0; $i < $length; $i++) {
+            $str .= $strPol [rand(0, $max)]; // rand($min,$max)生成介于min和max两个数之间的一个随机整数
+        }
+
+        return $str;
+    }
+
+    // 数组转xml
+    function arrayToXml($arr) {
+        $xml = "<xml>";
+        foreach ($arr as $key => $val) {
+            if (is_numeric($val)) {
+                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
+            } else
+                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
+        }
+        $xml .= "</xml>";
+        return $xml;
+    }
+
+    // post https请求,CURLOPT_POSTFIELDS xml格式
+    function postXmlCurl($xml, $url, $second = 30) {
+        // 初始化curl
+        $ch = curl_init();
+        // 超时时间
+        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
+        // 这里设置代理,如果有的话
+        // curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
+        // curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+        // 设置header
+        curl_setopt($ch, CURLOPT_HEADER, FALSE);
+        // 要求结果为字符串且输出到屏幕上
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+        // post提交方式
+        curl_setopt($ch, CURLOPT_POST, TRUE);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
+        // 证书
+        curl_setopt($ch, CURLOPT_SSLKEY, APP_PATH . '../addons/epay/certs/apiclient_key.pem');
+        curl_setopt($ch, CURLOPT_SSLCERT, APP_PATH . '../addons/epay/certs/apiclient_cert.pem');
+        // 运行curl
+        $data = curl_exec($ch);
+        // 返回结果
+        if ($data) {
+            curl_close($ch);
+            return $data;
+        } else {
+            $error = curl_errno($ch);
+            echo "curl出错,错误码:$error" . "<br>";
+            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
+            curl_close($ch);
+            return false;
+        }
+    }
+
+    //获取当前服务器的IP
+    function get_client_ip() {
+        if ($_SERVER ['REMOTE_ADDR']) {
+            $cip = $_SERVER ['REMOTE_ADDR'];
+        } elseif (getenv("REMOTE_ADDR")) {
+            $cip = getenv("REMOTE_ADDR");
+        } elseif (getenv("HTTP_CLIENT_IP")) {
+            $cip = getenv("HTTP_CLIENT_IP");
+        } else {
+            $cip = "unknown";
+        }
+        return $cip;
+    }
+
+    // 将数组转成uri字符串
+    function formatBizQueryParaMap($paraMap, $urlencode) {
+        $buff = "";
+        ksort($paraMap);
+        foreach ($paraMap as $k => $v) {
+            if ($urlencode) {
+                $v = urlencode($v);
+            }
+            $buff .= strtolower($k) . "=" . $v . "&";
+        }
+
+        if (strlen($buff) > 0) {
+            $reqPar = substr($buff, 0, strlen($buff) - 1);
+        }
+        return $reqPar;
+    }
+
+    //xml转成数组
+    function xmlstr_to_array($xmlstr) {
+        $doc = new \DOMDocument ();
+        $doc->loadXML($xmlstr);
+        return $this->domnode_to_array($doc->documentElement);
+    }
+
+    //dom转成数组
+    function domnode_to_array($node) {
+        $output = array();
+        switch ($node->nodeType) {
+            case XML_CDATA_SECTION_NODE :
+            case XML_TEXT_NODE :
+                $output = trim($node->textContent);
+                break;
+            case XML_ELEMENT_NODE :
+                for ($i = 0, $m = $node->childNodes->length; $i < $m; $i++) {
+                    $child = $node->childNodes->item($i);
+                    $v = $this->domnode_to_array($child);
+                    if (isset ($child->tagName)) {
+                        $t = $child->tagName;
+                        if (!isset ($output [$t])) {
+                            $output [$t] = array();
+                        }
+                        $output [$t] [] = $v;
+                    } elseif ($v) {
+                        $output = ( string )$v;
+                    }
+                }
+                if (is_array($output)) {
+                    if ($node->attributes->length) {
+                        $a = array();
+                        foreach ($node->attributes as $attrName => $attrNode) {
+                            $a [$attrName] = ( string )$attrNode->value;
+                        }
+                        $output ['@attributes'] = $a;
+                    }
+                    foreach ($output as $t => $v) {
+                        if (is_array($v) && count($v) == 1 && $t != '@attributes') {
+                            $output [$t] = $v [0];
+                        }
+                    }
+                }
+                break;
+        }
+        return $output;
+    }
+
+}

+ 1 - 0
application/extra/wallet.php

@@ -23,6 +23,7 @@ return [
         //15已被占用
         16 => '签到得钻石',//增加
         17 => '平台充值',//增加
+        18 => '充值退款',//减少
 
         //money
         101 => '获赠礼物', //增加

+ 95 - 0
public/assets/js/backend/rechar_order.js

@@ -0,0 +1,95 @@
+define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
+
+    var Controller = {
+        index: function () {
+            // 初始化表格参数配置
+            Table.api.init({
+                extend: {
+                    index_url: 'rechar_order/index' + location.search,
+                    add_url: 'rechar_order/add',
+                    edit_url: 'rechar_order/edit',
+                    del_url: 'rechar_order/del',
+                    multi_url: 'rechar_order/multi',
+                    import_url: 'rechar_order/import',
+                    table: 'rechar_order',
+                }
+            });
+
+            var table = $("#table");
+
+            // 初始化表格
+            table.bootstrapTable({
+                url: $.fn.bootstrapTable.defaults.extend.index_url,
+                pk: 'id',
+                sortName: 'id',
+                columns: [
+                    [
+                        {checkbox: true},
+                        {field: 'id', title: __('Id')},
+                        {field: 'user_id', title: __('User_id')},
+                        {field: 'user.nickname', title: __('User.nickname'), operate: 'LIKE'},
+                        {field: 'order_no', title: __('Order_no'), operate: 'LIKE'},
+                        {field: 'money', title: __('Money'), operate:'BETWEEN'},
+                        {field: 'jewel', title: __('Jewel')},
+                        {field: 'refund_money', title: __('Refund_money'), operate:'BETWEEN'},
+                        {field: 'service_fee', title: __('Service_fee'), operate:'BETWEEN'},
+                        {field: 'transaction_id', title: __('Transaction_id'), operate: 'LIKE'},
+                        {field: 'status', title: __('Status'), searchList: {"-1":__('Status -1'),"0":__('Status 0'),"1":__('Status 1'),"2":__('Status 2')}, formatter: Table.api.formatter.status},
+                        {field: 'business_no', title: __('Business_no'), operate: 'LIKE'},
+                        {field: 'pay_type', title: __('Pay_type'), searchList: {"1":__('Pay_type 1'),"2":__('Pay_type 2'),"3":__('Pay_type 3')}, formatter: Table.api.formatter.normal},
+                        {field: 'platform', title: __('Platform'), searchList: {"1":__('Platform 1'),"2":__('Platform 2'),"3":__('Platform 3')}, formatter: Table.api.formatter.normal},
+                        {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+                        {field: 'paytime', title: __('Paytime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+                        {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+                        {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate,
+                            buttons:[
+                                {
+                                    name: 'refund',
+                                    title: __('退款'),
+                                    classname: 'btn btn-xs btn-warning btn-magic btn-ajax',
+                                    icon: 'fa fa-times-circle',
+                                    confirm: '确认退款?',
+                                    url: 'rechar_order/refund',
+                                    visible: function (row) {
+                                        if (row.status == 1 && row.refund_money == 0) {
+                                            return true;
+                                        } else  {
+                                            return false;
+                                        }
+                                    },
+                                    success: function (data, ret) {
+                                        //Layer.alert(ret.msg);
+                                        //如果需要阻止成功提示,则必须使用return false;
+                                        if (ret.code == 0) {
+                                            return false;
+                                        }
+                                        table.bootstrapTable('refresh');
+                                    },
+                                    error: function (data, ret) {
+                                        Layer.alert(ret.msg);
+                                        return false;
+                                    }
+                                },
+                            ]
+                        }
+                    ]
+                ]
+            });
+
+            // 为表格绑定事件
+            Table.api.bindevent(table);
+        },
+        add: function () {
+            Controller.api.bindevent();
+        },
+        edit: function () {
+            Controller.api.bindevent();
+        },
+        api: {
+            bindevent: function () {
+                Form.api.bindevent($("form[role=form]"));
+            }
+        }
+    };
+    return Controller;
+});