Przeglądaj źródła

1.有赞云支付独立成组件
2.修正订阅节点不随机问题
3.修正二维码下混淆参数不正确问题
4.更换订阅地址时同时也改变连接密码
5.界面美化

bingo 7 lat temu
rodzic
commit
84a9d2c60d

+ 81 - 0
app/Components/Yzy.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace App\Components;
+
+use App\Http\Models\Config;
+use Cache;
+use Log;
+
+class Yzy
+{
+    protected static $config;
+    protected $accessToken;
+
+    function __construct()
+    {
+        self::$config = $this->systemConfig();
+        $this->accessToken = $this->getAccessToken();
+    }
+
+    // 获取accessToken
+    public function getAccessToken()
+    {
+        if (Cache::has('YZY_TOKEN')) {
+            $token = Cache::get('YZY_TOKEN');
+            if (isset($token['error'])) { // 错误兼容
+                Cache::forget('YZY_TOKEN');
+            } else {
+                return Cache::get('YZY_TOKEN')['access_token'];
+            }
+        }
+
+        $keys['kdt_id'] = self::$config['kdt_id'];
+
+        $token = (new \Youzan\Open\Token(self::$config['youzan_client_id'], self::$config['youzan_client_secret']))->getToken('self', $keys);
+
+        if (isset($token['error'])) {
+            Log::info('获取有赞云支付access_token失败:' . $token['error_description']);
+
+            return '';
+        } else {
+            Cache::put('YZY_TOKEN', $token, 10000);
+
+            return $token['access_token'];
+        }
+    }
+
+    // 生成收款二维码
+    public function createQrCode($goodsName, $price, $orderId)
+    {
+        $client = new \Youzan\Open\Client($this->accessToken);
+
+        $params = [
+            'qr_name'   => $goodsName, // 商品名
+            'qr_price'  => $price, // 单位分
+            'qr_source' => $orderId, // 本地订单号
+            'qr_type'   => 'QR_TYPE_DYNAMIC'
+        ];
+
+        return $client->get('youzan.pay.qrcode.create', '3.0.0', $params);
+    }
+
+    // 通过tid获取交易信息
+    public function getTradeByTid($tid)
+    {
+        $client = new \Youzan\Open\Client($this->accessToken);
+
+        return $client->post('youzan.trade.get', '3.0.0', ['tid' => $tid]);
+    }
+
+    // 系统配置
+    private function systemConfig()
+    {
+        $config = Config::query()->get();
+        $data = [];
+        foreach ($config as $vo) {
+            $data[$vo->name] = $vo->value;
+        }
+
+        return $data;
+    }
+}

+ 11 - 4
app/Http/Controllers/AdminController.php

@@ -55,8 +55,9 @@ class AdminController extends Controller
         $view['onlineUserCount'] = User::query()->where('t', '>=', $online)->count();
         $view['nodeCount'] = SsNode::query()->count();
         $flowCount = SsNodeTrafficDaily::query()->where('created_at', '>=', date('Y-m-d 00:00:00', strtotime("-30 days")))->sum('total');
-        $flowCount = flowAutoShow($flowCount);
-        $view['flowCount'] = $flowCount;
+        $view['flowCount'] = flowAutoShow($flowCount);
+        $totalFlowCount = SsNodeTrafficDaily::query()->sum('total');
+        $view['totalFlowCount'] = flowAutoShow($totalFlowCount);
         $view['totalBalance'] = User::query()->sum('balance') / 100;
         $view['totalWaitRefAmount'] = ReferralLog::query()->whereIn('status', [0, 1])->sum('ref_amount') / 100;
         $view['totalRefAmount'] = ReferralApply::query()->where('status', 2)->sum('amount') / 100;
@@ -419,6 +420,7 @@ class AdminController extends Controller
             $ssNode->country_code = $request->get('country_code', 'un');
             $ssNode->server = $request->get('server', '');
             $ssNode->ip = $request->get('ip');
+            $ssNode->ipv6 = $request->get('ipv6');
             $ssNode->desc = $request->get('desc', '');
             $ssNode->method = $request->get('method');
             $ssNode->protocol = $request->get('protocol');
@@ -486,6 +488,7 @@ class AdminController extends Controller
             $country_code = $request->get('country_code', 'un');
             $server = $request->get('server', '');
             $ip = $request->get('ip');
+            $ipv6 = $request->get('ipv6');
             $desc = $request->get('desc', '');
             $method = $request->get('method');
             $protocol = $request->get('protocol');
@@ -515,6 +518,7 @@ class AdminController extends Controller
                     'country_code'    => $country_code,
                     'server'          => $server,
                     'ip'              => $ip,
+                    'ipv6'            => $ipv6,
                     'desc'            => $desc,
                     'method'          => $method,
                     'protocol'        => $protocol,
@@ -1128,7 +1132,7 @@ class AdminController extends Controller
             $ssr_str .= ($node->server ? $node->server : $node->ip) . ':' . ($node->single ? $node->single_port : $user->port);
             $ssr_str .= ':' . ($node->single ? $node->single_protocol : $user->protocol) . ':' . ($node->single ? $node->single_method : $user->method);
             $ssr_str .= ':' . ($node->single ? $node->single_obfs : $user->obfs) . ':' . ($node->single ? base64url_encode($node->single_passwd) : base64url_encode($user->passwd));
-            $ssr_str .= '/?obfsparam=' . ($node->single ? '' : base64url_encode($obfs_param));
+            $ssr_str .= '/?obfsparam=' . base64url_encode($obfs_param);
             $ssr_str .= '&protoparam=' . ($node->single ? base64url_encode($user->port . ':' . $user->passwd) : base64url_encode($protocol_param));
             $ssr_str .= '&remarks=' . base64url_encode($node->name);
             $ssr_str .= '&group=' . base64url_encode(empty($group) ? '' : $group->name);
@@ -1144,8 +1148,11 @@ class AdminController extends Controller
             $ss_str = base64url_encode($ss_str) . '#' . 'VPN';
             $ss_scheme = 'ss://' . $ss_str;
 
-            // 生成文本配置信息
+            // 生成配置信息
             $txt = "服务器:" . ($node->server ? $node->server : $node->ip) . "\r\n";
+            if ($node->ipv6) {
+                $txt .= "IPv6:" . $node->ipv6 . "\r\n";
+            }
             $txt .= "远程端口:" . ($node->single ? $node->single_port : $user->port) . "\r\n";
             $txt .= "密码:" . ($node->single ? $node->single_passwd : $user->passwd) . "\r\n";
             $txt .= "加密方法:" . ($node->single ? $node->single_method : $user->method) . "\r\n";

+ 3 - 27
app/Http/Controllers/Api/YzyController.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Controllers\Api;
 
+use App\Components\Yzy;
 use App\Http\Controllers\Controller;
 use App\Http\Models\Coupon;
 use App\Http\Models\CouponLog;
@@ -12,9 +13,6 @@ use App\Http\Models\PaymentCallback;
 use App\Http\Models\ReferralLog;
 use App\Http\Models\User;
 use Illuminate\Http\Request;
-use Response;
-use Redirect;
-use Cache;
 use DB;
 use Log;
 
@@ -27,32 +25,10 @@ use Log;
 class YzyController extends Controller
 {
     protected static $config;
-    private $accessToken;
 
     function __construct()
     {
         self::$config = $this->systemConfig();
-        $this->accessToken = $this->getAccessToken();
-    }
-
-    // 获取accessToken
-    private function getAccessToken()
-    {
-        if (Cache::has('YZY_TOKEN')) {
-            return Cache::get('YZY_TOKEN')['access_token'];
-        }
-
-        $clientId = self::$config['youzan_client_id']; // f531e5282e4689712a
-        $clientSecret = self::$config['youzan_client_secret']; // 4020b1743633ef334fd06a32190ee677
-
-        $type = 'self';
-        $keys['kdt_id'] = self::$config['kdt_id']; // 40503761
-
-        $token = (new \Youzan\Open\Token($clientId, $clientSecret))->getToken($type, $keys);
-
-        Cache::put('YZY_TOKEN', $token, 10000);
-
-        return $token['access_token'];
     }
 
     // 接收GET请求
@@ -93,8 +69,8 @@ class YzyController extends Controller
 
         if ($data['type'] == 'TRADE_ORDER_STATE') {
             // 读取订单信息
-            $client = new \Youzan\Open\Client($this->accessToken);
-            $result = $client->post('youzan.trade.get', '3.0.0', ['tid' => $msg['tid']]);
+            $yzy = new Yzy();
+            $result = $yzy->getTradeByTid($msg['tid']);
             if (isset($result['error_response'])) {
                 Log::info('【有赞云】回调订单信息错误:' . $result['error_response']['msg']);
                 exit();

+ 5 - 47
app/Http/Controllers/PaymentController.php

@@ -1,6 +1,7 @@
 <?php
 namespace App\Http\Controllers;
 
+use App\Components\Yzy;
 use App\Http\Models\Coupon;
 use App\Http\Models\Goods;
 use App\Http\Models\Order;
@@ -9,49 +10,16 @@ use App\Http\Models\PaymentCallback;
 use Illuminate\Http\Request;
 use Response;
 use Redirect;
-use Cache;
 use Log;
 use DB;
 
 class PaymentController extends Controller
 {
     protected static $config;
-    private $accessToken;
 
     function __construct()
     {
         self::$config = $this->systemConfig();
-        $this->accessToken = $this->getAccessToken();
-    }
-
-    // 获取accessToken
-    private function getAccessToken()
-    {
-        if (Cache::has('YZY_TOKEN')) {
-            $yzyToken = Cache::get('YZY_TOKEN');
-            if (isset($yzyToken['error'])) { // 错误兼容
-                Cache::forget('YZY_TOKEN');
-            } else {
-                return Cache::get('YZY_TOKEN')['access_token'];
-            }
-        }
-
-        $clientId = self::$config['youzan_client_id'];
-        $clientSecret = self::$config['youzan_client_secret'];
-        $type = 'self';
-        $keys['kdt_id'] = self::$config['kdt_id'];
-
-        $token = (new \Youzan\Open\Token($clientId, $clientSecret))->getToken($type, $keys);
-
-        if (isset($token['error'])) {
-            Log::info('获取有赞云支付access_token失败:' . $token['error_description']);
-
-            return '';
-        } else {
-            Cache::put('YZY_TOKEN', $token, 10000);
-
-            return $token['access_token'];
-        }
     }
 
     // 创建支付单
@@ -59,6 +27,7 @@ class PaymentController extends Controller
     {
         $goods_id = intval($request->get('goods_id'));
         $coupon_sn = $request->get('coupon_sn');
+        $user = $request->session()->get('user');
 
         $goods = Goods::query()->where('id', $goods_id)->where('status', 1)->first();
         if (!$goods) {
@@ -71,7 +40,7 @@ class PaymentController extends Controller
         }
 
         // 判断是否存在同个商品的未支付订单
-        $existsOrder = Order::query()->where('goods_id', $goods_id)->where('status', 0)->first();
+        $existsOrder = Order::query()->where('goods_id', $goods_id)->where('status', 0)->where('user_id', $user['id'])->first();
         if ($existsOrder) {
             return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:尚有未支付的订单,请先去支付']);
         }
@@ -111,19 +80,8 @@ class PaymentController extends Controller
             $order->save();
 
             // 生成支付单
-            $client = new \Youzan\Open\Client($this->accessToken);
-
-            $method = 'youzan.pay.qrcode.create';
-            $apiVersion = '3.0.0';
-
-            $params = [
-                'qr_name'   => $goods->name, // 商品名
-                'qr_price'  => $totalPrice, // 单位分
-                'qr_source' => $orderId, // 本地订单号
-                'qr_type'   => 'QR_TYPE_DYNAMIC'
-            ];
-
-            $result = $client->get($method, $apiVersion, $params);
+            $yzy = new Yzy();
+            $result = $yzy->createQrCode($goods->name, $totalPrice, $orderId);
             if (isset($result['error_response'])) {
                 Log::error('【有赞云】创建二维码失败:' . $result['error_response']['msg']);
 

+ 4 - 1
app/Http/Controllers/SubscribeController.php

@@ -71,6 +71,9 @@ class SubscribeController extends Controller
             exit($this->noneNode());
         }
 
+        // 打乱
+        shuffle($nodeList);
+
         // 控制客户端最多获取节点数
         $scheme = self::$config['subscribe_max'] > 0 ? 'MAX=' . self::$config['subscribe_max'] . "\n" : '';
         foreach ($nodeList as $key => $node) {
@@ -105,6 +108,6 @@ class SubscribeController extends Controller
     // 抛出无可用的节点信息,用于兼容防止客户端订阅失败
     private function noneNode()
     {
-        return base64url_encode('ssr://' . base64url_encode('8.8.8.8:8888:origin:none:plain:' . base64url_encode('0000') . '/?obfsparam=&protoparam=&remarks=' . base64url_encode('无可用节点或账号被封禁') . '&group=' . base64url_encode('VPN') . '&udpport=0&uot=0') . "\n");
+        return base64url_encode('ssr://' . base64url_encode('8.8.8.8:8888:origin:none:plain:' . base64url_encode('0000') . '/?obfsparam=&protoparam=&remarks=' . base64url_encode('无可用节点或账号被封禁或订阅被封禁') . '&group=' . base64url_encode('VPN') . '&udpport=0&uot=0') . "\n");
     }
 }

+ 21 - 4
app/Http/Controllers/UserController.php

@@ -96,7 +96,7 @@ class UserController extends Controller
             $ssr_str .= ($node->server ? $node->server : $node->ip) . ':' . ($node->single ? $node->single_port : $user->port);
             $ssr_str .= ':' . ($node->single ? $node->single_protocol : $user->protocol) . ':' . ($node->single ? $node->single_method : $user->method);
             $ssr_str .= ':' . ($node->single ? $node->single_obfs : $user->obfs) . ':' . ($node->single ? base64url_encode($node->single_passwd) : base64url_encode($user->passwd));
-            $ssr_str .= '/?obfsparam=' . ($node->single ? '' : base64url_encode($obfs_param));
+            $ssr_str .= '/?obfsparam=' . base64url_encode($obfs_param);
             $ssr_str .= '&protoparam=' . ($node->single ? base64url_encode($user->port . ':' . $user->passwd) : base64url_encode($protocol_param));
             $ssr_str .= '&remarks=' . base64url_encode($node->name);
             $ssr_str .= '&group=' . base64url_encode(empty($group) ? '' : $group->name);
@@ -114,6 +114,9 @@ class UserController extends Controller
 
             // 生成文本配置信息
             $txt = "服务器:" . ($node->server ? $node->server : $node->ip) . "\r\n";
+            if ($node->ipv6) {
+                $txt .= "IPv6:" . $node->ipv6 . "\r\n";
+            }
             $txt .= "远程端口:" . ($node->single ? $node->single_port : $user->port) . "\r\n";
             $txt .= "密码:" . ($node->single ? $node->single_passwd : $user->passwd) . "\r\n";
             $txt .= "加密方法:" . ($node->single ? $node->single_method : $user->method) . "\r\n";
@@ -1083,11 +1086,25 @@ class UserController extends Controller
     {
         $user = $request->session()->get('user');
 
-        $code = $this->makeSubscribeCode();
+        DB::beginTransaction();
+        try {
+            // 更换订阅地址
+            $code = $this->makeSubscribeCode();
+            UserSubscribe::query()->where('user_id', $user['id'])->update(['code' => $code]);
+
+            // 更换连接密码
+            User::query()->where('id', $user['id'])->update(['passwd' => makeRandStr()]);
 
-        UserSubscribe::query()->where('user_id', $user['id'])->update(['code' => $code]);
+            DB::commit();
 
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '更换成功']);
+            return Response::json(['status' => 'success', 'data' => '', 'message' => '更换成功']);
+        } catch (\Exception $e) {
+            DB::rollBack();
+
+            Log::info("更换订阅地址异常:" . $e->getMessage());
+
+            return Response::json(['status' => 'fail', 'data' => '', 'message' => '更换失败' . $e->getMessage()]);
+        }
     }
 
     // 转换成管理员的身份

+ 1 - 1
resources/lang/zh-CN/home.php

@@ -5,7 +5,7 @@ return [
     'subscribe_address' => '我的订阅地址',
     'copy_subscribe_address' => '复制地址',
     'exchange_subscribe' => '更换地址',
-    'subscribe_warning' => '警告:该订阅地址仅限个人使用,请勿传播该地址,否则会导致您的账号流量异常;更换订阅地址之后请修改SSR(R)密码即可。',
+    'subscribe_warning' => '警告:该订阅地址仅限个人使用,请勿传播该地址,否则会导致您的账号流量异常。',
 
     // 菜单
     'home' => '首页',

+ 22 - 7
resources/views/admin/addNode.blade.php

@@ -20,7 +20,7 @@
                                 <div class="form-body">
                                     <div class="alert alert-danger alert-dismissable">
                                         <button type="button" class="close" data-dismiss="alert" aria-hidden="true"></button>
-                                        <strong>注意:</strong> 添加节点后自动生成的<code>ID</code>,即为该节点后端部署SSR时<code>usermysql.json</code>的<code>node_id</code>的值
+                                        <strong>注意:</strong> 添加节点后自动生成的<code>ID</code>,即为该节点后端部署SSR(R)时<code>usermysql.json</code>的<code>node_id</code>的值
                                     </div>
                                     <div class="row">
                                         <div class="col-md-6">
@@ -41,13 +41,19 @@
                                                     <div class="form-group">
                                                         <label for="server" class="col-md-3 control-label"> 域名地址 </label>
                                                         <div class="col-md-8">
-                                                            <input type="text" class="form-control" name="server" id="server" placeholder="服务器域名地址,填则优先取域名地址">
+                                                            <input type="text" class="form-control" name="server" id="server" placeholder="服务器域名地址,填则优先取域名地址">
                                                         </div>
                                                     </div>
                                                     <div class="form-group">
-                                                        <label for="ip" class="col-md-3 control-label"> IP地址 </label>
+                                                        <label for="ip" class="col-md-3 control-label"> IPV4地址 </label>
                                                         <div class="col-md-8">
-                                                            <input type="text" class="form-control" name="ip" id="ip" placeholder="服务器IP地址" required>
+                                                            <input type="text" class="form-control" name="ip" id="ip" placeholder="服务器IPV4地址" required>
+                                                        </div>
+                                                    </div>
+                                                    <div class="form-group">
+                                                        <label for="ipv6" class="col-md-3 control-label"> IPV6地址 </label>
+                                                        <div class="col-md-8">
+                                                            <input type="text" class="form-control" name="ipv6" id="ipv6" placeholder="服务器IPV6地址,填写则用户可见,域名无效">
                                                         </div>
                                                     </div>
                                                     <div class="form-group">
@@ -274,8 +280,8 @@
                                                     <div class="form-group">
                                                         <label for="monitor_url" class="col-md-3 control-label">监控地址</label>
                                                         <div class="col-md-8">
-                                                            <input type="text" class="form-control right" name="monitor_url" value="" id="monitor_url" placeholder="">
-                                                            <span class="help-block"> 例如:http://us1.xxx.com/monitor.php </span>
+                                                            <input type="text" class="form-control right" name="monitor_url" value="" id="monitor_url" placeholder="节点实时监控地址">
+                                                            <span class="help-block"> 例如:http://us1.ssrpanel.com/api/monitor </span>
                                                         </div>
                                                     </div>
                                                 </div>
@@ -321,6 +327,7 @@
             var country_code = $("#country_code option:selected").val();
             var server = $('#server').val();
             var ip = $('#ip').val();
+            var ipv6 = $('#ipv6').val();
             var desc = $('#desc').val();
             var method = $('#method').val();
             var traffic_rate = $('#traffic_rate').val();
@@ -342,11 +349,19 @@
             var sort = $('#sort').val();
             var status = $('#status').val();
 
+            // 判断IPV4合法性
+            var reg = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
+            if(reg.test(ip))
+            {
+                if( RegExp.$1<256 && RegExp.$2<256 && RegExp.$3<256 && RegExp.$4<256)
+                    return true;
+            }
+            // 判断IPV6合法性
             $.ajax({
                 type: "POST",
                 url: "{{url('admin/addNode')}}",
                 async: false,
-                data: {_token:'{{csrf_token()}}', name: name, labels:labels, group_id:group_id, country_code:country_code, server:server, ip:ip, desc:desc, method:method, traffic_rate:traffic_rate, protocol:protocol, protocol_param:protocol_param, obfs:obfs, obfs_param:obfs_param, bandwidth:bandwidth, traffic:traffic, monitor_url:monitor_url, compatible:compatible, single:single, single_force:single_force, single_port:single_port, single_passwd:single_passwd, single_method:single_method, single_protocol:single_protocol, single_obfs:single_obfs, sort:sort, status:status},
+                data: {_token:'{{csrf_token()}}', name: name, labels:labels, group_id:group_id, country_code:country_code, server:server, ip:ip, ipv6:ipv6, desc:desc, method:method, traffic_rate:traffic_rate, protocol:protocol, protocol_param:protocol_param, obfs:obfs, obfs_param:obfs_param, bandwidth:bandwidth, traffic:traffic, monitor_url:monitor_url, compatible:compatible, single:single, single_force:single_force, single_port:single_port, single_passwd:single_passwd, single_method:single_method, single_protocol:single_protocol, single_obfs:single_obfs, sort:sort, status:status},
                 dataType: 'json',
                 success: function (ret) {
                     layer.msg(ret.message, {time:1000}, function() {

+ 11 - 4
resources/views/admin/editNode.blade.php

@@ -39,13 +39,19 @@
                                                     <div class="form-group">
                                                         <label for="server" class="col-md-3 control-label"> 域名地址 </label>
                                                         <div class="col-md-8">
-                                                            <input type="text" class="form-control" name="server" value="{{$node->server}}" id="server" placeholder="服务器域名地址,填则优先取域名地址">
+                                                            <input type="text" class="form-control" name="server" value="{{$node->server}}" id="server" placeholder="服务器域名地址,填则优先取域名地址">
                                                         </div>
                                                     </div>
                                                     <div class="form-group">
-                                                        <label for="ip" class="col-md-3 control-label"> IP地址 </label>
+                                                        <label for="ip" class="col-md-3 control-label"> IPV4地址 </label>
                                                         <div class="col-md-8">
-                                                            <input type="text" class="form-control" name="ip" value="{{$node->ip}}" id="ip" placeholder="服务器IP地址" required>
+                                                            <input type="text" class="form-control" name="ip" value="{{$node->ip}}" id="ip" placeholder="服务器IPV4地址" required>
+                                                        </div>
+                                                    </div>
+                                                    <div class="form-group">
+                                                        <label for="ipv6" class="col-md-3 control-label"> IPV6地址 </label>
+                                                        <div class="col-md-8">
+                                                            <input type="text" class="form-control" name="ipv6" value="{{$node->ipv6}}" id="ipv6" placeholder="服务器IPV6地址,填写则用户可见,域名无效">
                                                         </div>
                                                     </div>
                                                     <div class="form-group">
@@ -321,6 +327,7 @@
             var country_code = $("#country_code option:selected").val();
             var server = $('#server').val();
             var ip = $('#ip').val();
+            var ipv6 = $('#ipv6').val();
             var desc = $('#desc').val();
             var method = $('#method').val();
             var traffic_rate = $('#traffic_rate').val();
@@ -346,7 +353,7 @@
                 type: "POST",
                 url: "{{url('admin/editNode')}}",
                 async: false,
-                data: {_token:_token, id:id, name: name, labels:labels, group_id:group_id, country_code:country_code, server:server, ip:ip, desc:desc, method:method, traffic_rate:traffic_rate, protocol:protocol, protocol_param:protocol_param, obfs:obfs, obfs_param:obfs_param, bandwidth:bandwidth, traffic:traffic, monitor_url:monitor_url, compatible:compatible, single:single, single_force:single_force, single_port:single_port, single_passwd:single_passwd, single_method:single_method, single_protocol:single_protocol, single_obfs:single_obfs, sort:sort, status:status},
+                data: {_token:_token, id:id, name: name, labels:labels, group_id:group_id, country_code:country_code, server:server, ip:ip, ipv6:ipv6, desc:desc, method:method, traffic_rate:traffic_rate, protocol:protocol, protocol_param:protocol_param, obfs:obfs, obfs_param:obfs_param, bandwidth:bandwidth, traffic:traffic, monitor_url:monitor_url, compatible:compatible, single:single, single_force:single_force, single_port:single_port, single_passwd:single_passwd, single_method:single_method, single_protocol:single_protocol, single_obfs:single_obfs, sort:sort, status:status},
                 dataType: 'json',
                 success: function (ret) {
                     layer.msg(ret.message, {time:1000}, function() {

+ 2 - 0
resources/views/admin/export.blade.php

@@ -29,6 +29,7 @@
                                                 {{$node->name}}
                                                 @if($node->compatible) <span class="label label-info">兼</span> @endif
                                                 @if($node->single) <span class="label label-danger">单</span> @endif
+                                                @if($node->ipv6) <span class="label label-danger">IPv6</span> @endif
                                             </td>
                                             <td>
                                                 <a class="btn btn-sm green btn-outline" data-toggle="modal" href="#txt_{{$node->id}}"> 文本 </a>
@@ -128,6 +129,7 @@
             var n = function () {
                 @foreach($nodeList as $node)
                     $("#txt_{{$node->id}}").draggable({handle: ".modal-header"});
+                    $("#txt_v6_{{$node->id}}").draggable({handle: ".modal-header"});
                     $("#scheme_{{$node->id}}").draggable({handle: ".modal-header"});
                     $("#qrcode_{{$node->id}}").draggable({handle: ".modal-header"});
                 @endforeach

+ 14 - 1
resources/views/admin/index.blade.php

@@ -28,7 +28,7 @@
                             <h3 class="font-green-sharp">
                                 <span data-counter="counterup" data-value="{{$activeUserCount}}">0</span>
                             </h3>
-                            <small>活跃用户</small>
+                            <small>7日内活跃用户</small>
                         </div>
                         <div class="icon">
                             <i class="icon-user"></i>
@@ -83,6 +83,19 @@
                     </div>
                 </div>
             </div>
+            <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
+                <div class="dashboard-stat2 bordered" onclick="skip('admin/trafficLog');">
+                    <div class="display">
+                        <div class="number">
+                            <h3 class="font-blue-sharp"> {{$totalFlowCount}} </h3>
+                            <small>总消耗流量</small>
+                        </div>
+                        <div class="icon">
+                            <i class="icon-speedometer"></i>
+                        </div>
+                    </div>
+                </div>
+            </div>
             <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
                 <div class="dashboard-stat2 bordered" onclick="skip('admin/trafficLog');">
                     <div class="display">

+ 14 - 14
resources/views/admin/layouts.blade.php

@@ -106,26 +106,26 @@
             <ul class="page-sidebar-menu" data-keep-expanded="false" data-auto-scroll="true" data-slide-speed="200">
                 <li class="nav-item start {{in_array(Request::path(), ['admin']) ? 'active open' : ''}}">
                     <a href="{{url('admin')}}" class="nav-link nav-toggle">
-                        <i class="icon-home"></i>
+                        <i class="fa fa-home"></i>
                         <span class="title">管理中心</span>
                         <span class="selected"></span>
                     </a>
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/inviteList']) ? 'active open' : ''}}">
                     <a href="{{url('admin/inviteList')}}" class="nav-link nav-toggle">
-                        <i class="icon-puzzle"></i>
-                        <span class="title">邀请管理</span>
+                        <i class="fa fa-puzzle-piece"></i>
+                        <span class="title">邀请管理</span>
                     </a>
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/applyList', 'admin/applyDetail']) ? 'active open' : ''}}">
                     <a href="{{url('admin/applyList')}}" class="nav-link nav-toggle">
-                        <i class="icon-credit-card"></i>
+                        <i class="fa fa-credit-card"></i>
                         <span class="title">提现管理</span>
                     </a>
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['shop/goodsList', 'shop/addGoods', 'shop/editGoods']) ? 'active open' : ''}}">
                     <a href="{{url('shop/goodsList')}}" class="nav-link nav-toggle">
-                        <i class="icon-basket"></i>
+                        <i class="fa fa-shopping-cart"></i>
                         <span class="title">商品管理</span>
                     </a>
                 </li>
@@ -137,7 +137,7 @@
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['ticket/ticketList', 'ticket/replyTicket']) ? 'active open' : ''}}">
                     <a href="{{url('ticket/ticketList')}}" class="nav-link nav-toggle">
-                        <i class="icon-question"></i>
+                        <i class="fa fa-question-circle"></i>
                         <span class="title">工单管理</span>
                     </a>
                 </li>
@@ -155,7 +155,7 @@
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/articleList', 'admin/addArticle', 'admin/editArticle', 'admin/articleLogList']) ? 'active open' : ''}}">
                     <a href="javascript:;" class="nav-link nav-toggle">
-                        <i class="icon-docs"></i>
+                        <i class="fa fa-file-word-o"></i>
                         <span class="title">文章管理</span>
                         <span class="arrow"></span>
                     </a>
@@ -170,14 +170,14 @@
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/userList', 'admin/addUser', 'admin/editUser', 'admin/userOrderList', 'admin/userBalanceLogList', 'admin/userBanLogList', 'admin/export', 'admin/userMonitor']) ? 'active open' : ''}}">
                     <a href="javascript:;" class="nav-link nav-toggle">
-                        <i class="icon-users"></i>
+                        <i class="fa fa-users"></i>
                         <span class="title">用户管理</span>
                         <span class="arrow"></span>
                     </a>
                     <ul class="sub-menu">
                         <li class="nav-item {{in_array(Request::path(), ['admin/userList', 'admin/addUser', 'admin/editUser', 'admin/export', 'admin/userMonitor']) ? 'active open' : ''}}">
                             <a href="{{url('admin/userList')}}" class="nav-link ">
-                                <i class="icon-user"></i>
+                                <i class="fa fa-user"></i>
                                 <span class="title">用户列表</span>
                             </a>
                         </li>
@@ -197,7 +197,7 @@
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/nodeList', 'admin/addNode', 'admin/editNode', 'admin/groupList', 'admin/addGroup', 'admin/editGroup', 'admin/nodeMonitor']) ? 'active open' : ''}}">
                     <a href="javascript:;" class="nav-link nav-toggle">
-                        <i class="icon-list"></i>
+                        <i class="fa fa-list-alt"></i>
                         <span class="title">节点管理</span>
                         <span class="arrow"></span>
                     </a>
@@ -218,7 +218,7 @@
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/decompile', 'admin/convert', 'admin/import', 'admin/trafficLog', 'admin/analysis', 'admin/subscribeLog', 'emailLog/logList', 'payment/callbackList']) ? 'active open' : ''}}">
                     <a href="javascript:;" class="nav-link nav-toggle">
-                        <i class="icon-wrench"></i>
+                        <i class="fa fa-wrench"></i>
                         <span class="title">工具箱</span>
                         <span class="arrow"></span>
                     </a>
@@ -267,15 +267,15 @@
                         </li>
                         <li class="nav-item {{in_array(Request::path(), ['payment/callbackList']) ? 'active open' : ''}}">
                             <a href="{{url('payment/callbackList')}}" class="nav-link">
-                                <i class="fa fa-envelope-o"></i>
-                                <span class="title">有赞回调日志</span>
+                                <i class="fa fa-th"></i>
+                                <span class="title">有赞回调日志</span>
                             </a>
                         </li>
                     </ul>
                 </li>
                 <li class="nav-item {{in_array(Request::path(), ['admin/config', 'admin/addConfig', 'admin/system']) ? 'active open' : ''}}">
                     <a href="javascript:;" class="nav-link nav-toggle">
-                        <i class="icon-settings"></i>
+                        <i class="fa fa-gear"></i>
                         <span class="title">设置</span>
                         <span class="arrow"></span>
                     </a>

+ 1 - 1
resources/views/admin/system.blade.php

@@ -574,7 +574,7 @@
                                                             <label for="is_youzan" class="col-md-3 control-label">本功能</label>
                                                             <div class="col-md-9">
                                                                 <input type="checkbox" class="make-switch" @if($is_youzan) checked @endif id="is_youzan" data-on-color="success" data-off-color="danger" data-on-text="启用" data-off-text="关闭">
-                                                                <span class="help-block"> 启用前请先到<a href="https://console.youzanyun.com/dashboard">有赞云</a>申请client_id和client_secret并绑定店铺 </span>
+                                                                <span class="help-block"> 请先到<a href="https://console.youzanyun.com/dashboard">有赞云</a>申请client_id和client_secret并绑定店铺 </span>
                                                             </div>
                                                         </div>
                                                         <div class="col-md-6">

+ 1 - 1
resources/views/payment/detail.blade.php

@@ -11,7 +11,7 @@
         <div class="portlet light bordered">
             <div class="portlet-body">
                 <div class="alert alert-info" style="text-align: center;">
-                    请使用<strong>支付宝</strong>或<strong>微信</strong>扫描如下二维码
+                    请使用<strong style="color:red;">支付宝、QQ、微信</strong>扫描如下二维码
                 </div>
                 <div class="row" style="text-align: center; font-size: 1.05em;">
                     <div class="col-md-12">

+ 8 - 0
resources/views/user/addOrder.blade.php

@@ -122,6 +122,10 @@
             var goods_id = '{{$goods->id}}';
             var coupon_sn = $('#coupon_sn').val();
 
+            index = layer.load(1, {
+                shade: [0.7,'#CCC']
+            });
+
             $.ajax({
                 type: "POST",
                 url: "{{url('payment/create')}}",
@@ -153,6 +157,10 @@
             var goods_id = '{{$goods->id}}';
             var coupon_sn = $('#coupon_sn').val();
 
+            index = layer.load(1, {
+                shade: [0.7,'#CCC']
+            });
+
             $.ajax({
                 type: "POST",
                 url: "{{url('user/addOrder')}}",

+ 1 - 1
resources/views/user/index.blade.php

@@ -50,7 +50,7 @@
                                             @endif
                                         </div>
                                         <div class="widget-thumb-body">
-                                            <span class="widget-thumb-subtitle"><a data-toggle="modal" href="#txt_{{$node->id}}">{{$node->server}}</a></span>
+                                            <span class="widget-thumb-subtitle"><a data-toggle="modal" href="#txt_{{$node->id}}">{{$node->server ? $node->server : $node->ip}}</a></span>
                                             <span class="widget-thumb-body-stat">
                                                 <a class="btn btn-sm green btn-outline" data-toggle="modal" href="#link_{{$node->id}}"> <i class="fa fa-paper-plane"></i> </a>
                                                 <a class="btn btn-sm green btn-outline" data-toggle="modal" href="#qrcode_{{$node->id}}"> <i class="fa fa-qrcode"></i> </a>

+ 1 - 1
resources/views/user/layouts.blade.php

@@ -120,7 +120,7 @@
                         <span class="title">{{trans('home.invite_code')}}</span>
                     </a>
                 </li>
-                <li class="nav-item {{in_array(Request::path(), ['user/goodsList', 'user/addOrder']) ? 'active open' : ''}}">
+                <li class="nav-item {{in_array(Request::path(), ['user/goodsList', 'user/addOrder']) || Request::segment(1) == 'payment' ? 'active open' : ''}}">
                     <a href="{{url('user/goodsList')}}" class="nav-link nav-toggle">
                         <i class="icon-basket"></i>
                         <span class="title">{{trans('home.services')}}</span>

+ 1 - 1
resources/views/user/referral.blade.php

@@ -93,7 +93,7 @@
                         </div>
                         <div class="row">
                             <div class="col-md-5 col-sm-5">
-                                <div class="dataTables_info" role="status" aria-live="polite">共 {{$referralLogList->total()}} 条记录,合计返利<code>{{$canAmount}}</code>元,满 <code>{{$referral_money}}</code> 元可申请提现。</div>
+                                <div class="dataTables_info" role="status" aria-live="polite">共 {{$referralLogList->total()}} 条记录,合计返利 {{$canAmount}} 元,满 <span style="color:red;">{{$referral_money}}</span> 元可申请提现。</div>
                             </div>
                             <div class="col-md-7 col-sm-7">
                                 <div class="dataTables_paginate paging_bootstrap_full_number pull-right">

+ 1 - 1
resources/views/user/subscribe.blade.php

@@ -56,7 +56,7 @@
     <script type="text/javascript">
         // 更换订阅地址
         function exchangeSubscribe() {
-            layer.confirm('确定更换订阅地址吗?', {icon: 7, title:'警告'}, function(index) {
+            layer.confirm('更换订阅地址将导致:<br>1.旧地址立即失效;<br>2.连接密码被更改;', {icon: 7, title:'警告'}, function(index) {
                 $.post("{{url('user/exchangeSubscribe')}}", {_token:'{{csrf_token()}}'}, function (ret) {
                     layer.msg(ret.message, {time:1000}, function () {
                         if (ret.status == 'success') {

+ 29 - 29
sql/db.sql

@@ -24,38 +24,38 @@
 -- Table structure for `ss_node`
 -- ----------------------------
 CREATE TABLE `ss_node` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `name` varchar(128) NOT NULL DEFAULT '' COMMENT '名称',
-  `group_id` int(11) NOT NULL DEFAULT '0' COMMENT '所属分组',
-  `country_code` char(5) DEFAULT '' COMMENT '国家代码',
-  `server` varchar(255) DEFAULT '' COMMENT '服务器域名地址',
-  `ip` varchar(30) DEFAULT NULL COMMENT '服务器IP地址',
-  `desc` varchar(255) DEFAULT '' COMMENT '节点简单描述',
-  `method` varchar(32) NOT NULL DEFAULT 'aes-192-ctr' COMMENT '加密方式',
-  `protocol` varchar(128) NOT NULL DEFAULT 'auth_chain_a' COMMENT '协议',
-  `protocol_param` varchar(128) DEFAULT '' COMMENT '协议参数',
-  `obfs` varchar(128) NOT NULL DEFAULT 'tls1.2_ticket_auth' COMMENT '混淆',
-  `obfs_param` varchar(128) DEFAULT '' COMMENT '混淆参数',
-  `traffic_rate` float NOT NULL DEFAULT '1' COMMENT '流量比率',
-  `bandwidth` int(11) NOT NULL DEFAULT '100' COMMENT '出口带宽,单位M',
-  `traffic` bigint(20) NOT NULL DEFAULT '1000' COMMENT '每月可用流量,单位G',
-  `monitor_url` varchar(255) DEFAULT NULL COMMENT '监控地址',
-  `compatible` tinyint(4) DEFAULT '0' COMMENT '兼容SS',
-  `single` tinyint(4) DEFAULT '0' COMMENT '单端口多用户:0-否、1-是',
-  `single_force` tinyint(4) DEFAULT NULL COMMENT '模式:0-兼容模式、1-严格模式',
-  `single_port` varchar(50) DEFAULT '' COMMENT '端口号,用,号分隔',
-  `single_passwd` varchar(50) DEFAULT '' COMMENT '密码',
-  `single_method` varchar(50) DEFAULT '' COMMENT '加密方式',
-  `single_protocol` varchar(50) NOT NULL DEFAULT '' COMMENT '协议',
-  `single_obfs` varchar(50) NOT NULL DEFAULT '' COMMENT '混淆',
-  `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序值,值越大越靠前显示',
-  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态:0-维护、1-正常',
-  `created_at` datetime NOT NULL,
-  `updated_at` datetime NOT NULL,
+  `id` INT(11) NOT NULL AUTO_INCREMENT,
+  `name` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '名称',
+  `group_id` INT(11) NOT NULL DEFAULT '0' COMMENT '所属分组',
+  `country_code` CHAR(5) NULL DEFAULT '' COMMENT '国家代码',
+  `server` VARCHAR(128) NULL DEFAULT NULL COMMENT '服务器域名地址',
+  `ip` CHAR(15) NULL DEFAULT NULL COMMENT '服务器IPV4地址',
+  `ipv6` CHAR(128) NULL DEFAULT NULL COMMENT '服务器IPV6地址',
+  `desc` VARCHAR(255) NULL DEFAULT '' COMMENT '节点简单描述',
+  `method` VARCHAR(32) NOT NULL DEFAULT 'aes-192-ctr' COMMENT '加密方式',
+  `protocol` VARCHAR(128) NOT NULL DEFAULT 'auth_chain_a' COMMENT '协议',
+  `protocol_param` VARCHAR(128) NULL DEFAULT '' COMMENT '协议参数',
+  `obfs` VARCHAR(128) NOT NULL DEFAULT 'tls1.2_ticket_auth' COMMENT '混淆',
+  `obfs_param` VARCHAR(128) NULL DEFAULT '' COMMENT '混淆参数',
+  `traffic_rate` FLOAT NOT NULL DEFAULT '1' COMMENT '流量比率',
+  `bandwidth` INT(11) NOT NULL DEFAULT '100' COMMENT '出口带宽,单位M',
+  `traffic` BIGINT(20) NOT NULL DEFAULT '1000' COMMENT '每月可用流量,单位G',
+  `monitor_url` VARCHAR(255) NULL DEFAULT NULL COMMENT '监控地址',
+  `compatible` TINYINT(4) NULL DEFAULT '0' COMMENT '兼容SS',
+  `single` TINYINT(4) NULL DEFAULT '0' COMMENT '单端口多用户:0-否、1-是',
+  `single_force` TINYINT(4) NULL DEFAULT NULL COMMENT '模式:0-兼容模式、1-严格模式',
+  `single_port` VARCHAR(50) NULL DEFAULT '' COMMENT '端口号,用,号分隔',
+  `single_passwd` VARCHAR(50) NULL DEFAULT '' COMMENT '密码',
+  `single_method` VARCHAR(50) NULL DEFAULT '' COMMENT '加密方式',
+  `single_protocol` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '协议',
+  `single_obfs` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '混淆',
+  `sort` INT(11) NOT NULL DEFAULT '0' COMMENT '排序值,值越大越靠前显示',
+  `status` TINYINT(4) NOT NULL DEFAULT '1' COMMENT '状态:0-维护、1-正常',
+  `created_at` DATETIME NOT NULL,
+  `updated_at` DATETIME NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='节点信息表';
 
-
 -- ----------------------------
 -- Table structure for `ss_node_info`
 -- ----------------------------

+ 8 - 0
sql/update/20180403.sql

@@ -0,0 +1,8 @@
+-- 节点表 增加 ipv6 字段
+ALTER TABLE `ss_node`
+	ADD COLUMN `ipv6` VARCHAR(128) NULL DEFAULT '' COMMENT '服务器IPV6地址' AFTER `ip`;
+
+-- 节点表 修改字段长度
+ALTER TABLE `ss_node`
+	CHANGE COLUMN `server` `server` VARCHAR(128) NULL DEFAULT NULL COMMENT '服务器域名地址' AFTER `country_code`,
+	CHANGE COLUMN `ip` `ip` CHAR(15) NULL DEFAULT NULL COMMENT '服务器IPV4地址' AFTER `server`;