cauto před 1 rokem
rodič
revize
b6c8d960d2
100 změnil soubory, kde provedl 5397 přidání a 1358 odebrání
  1. 0 52
      .env.example
  2. 6 1
      app/Components/Client/Clash.php
  3. 16 1
      app/Components/Client/Surge.php
  4. 1 2
      app/Components/Client/Text.php
  5. 3 1
      app/Components/Client/URLSchemes.php
  6. 78 5
      app/Components/Helpers.php
  7. 2 2
      app/Components/NetworkDetection.php
  8. 1 1
      app/Console/Commands/AutoClearLog.php
  9. 23 2
      app/Console/Commands/AutoJob.php
  10. 3 3
      app/Console/Commands/DailyJob.php
  11. 20 0
      app/Console/Commands/NodeStatusDetection.php
  12. 1 1
      app/Console/Commands/ServiceTimer.php
  13. 1 1
      app/Console/Commands/UserExpireAutoWarning.php
  14. 67 0
      app/Console/Commands/UserFree.php
  15. 3 1
      app/Console/Kernel.php
  16. 84 5
      app/Exceptions/Handler.php
  17. 20 7
      app/Http/Controllers/Admin/AffiliateController.php
  18. 39 12
      app/Http/Controllers/Admin/LogsController.php
  19. 40 2
      app/Http/Controllers/Admin/NodeAuthController.php
  20. 22 0
      app/Http/Controllers/Admin/NodeController.php
  21. 15 1
      app/Http/Controllers/Admin/SubscribeController.php
  22. 8 0
      app/Http/Controllers/Admin/SystemController.php
  23. 13 3
      app/Http/Controllers/Admin/TicketController.php
  24. 27 6
      app/Http/Controllers/Admin/UserController.php
  25. 21 21
      app/Http/Controllers/AdminController.php
  26. 89 0
      app/Http/Controllers/Api/Client/CodeController.php
  27. 91 0
      app/Http/Controllers/Api/Client/PcController.php
  28. 260 22
      app/Http/Controllers/Api/Client/V1Controller.php
  29. 553 0
      app/Http/Controllers/Api/Client/V2Controller.php
  30. 438 0
      app/Http/Controllers/Api/Client/V3Controller.php
  31. 161 0
      app/Http/Controllers/Api/Client/V4Controller.php
  32. 96 0
      app/Http/Controllers/Api/Client/XrayRConfig.php
  33. 5 2
      app/Http/Controllers/Api/WebApi/BaseController.php
  34. 60 0
      app/Http/Controllers/Api/WebApi/SSController.php
  35. 1 0
      app/Http/Controllers/Api/WebApi/TrojanController.php
  36. 2 1
      app/Http/Controllers/Api/WebApi/V2RayController.php
  37. 245 8
      app/Http/Controllers/AuthController.php
  38. 168 0
      app/Http/Controllers/DownloadControllers.php
  39. 12 7
      app/Http/Controllers/Gateway/AbstractPayment.php
  40. 48 25
      app/Http/Controllers/Gateway/BitpayX.php
  41. 3 2
      app/Http/Controllers/Gateway/EPay.php
  42. 77 0
      app/Http/Controllers/Gateway/EPay1.php
  43. 77 0
      app/Http/Controllers/Gateway/EPayTT.php
  44. 68 0
      app/Http/Controllers/Gateway/Manual.php
  45. 54 28
      app/Http/Controllers/Gateway/PayBeaver.php
  46. 72 0
      app/Http/Controllers/Gateway/THeadPay.php
  47. 112 0
      app/Http/Controllers/Gateway/Zypay.php
  48. 183 0
      app/Http/Controllers/Gateway/bypay.php
  49. 16 4
      app/Http/Controllers/PaymentController.php
  50. 59 5
      app/Http/Controllers/User/AffiliateController.php
  51. 42 8
      app/Http/Controllers/UserController.php
  52. 1 0
      app/Http/Kernel.php
  53. 7 7
      app/Http/Requests/Admin/NodeRequest.php
  54. 2 2
      app/Http/Requests/Admin/UserUpdateRequest.php
  55. 7 2
      app/Jobs/VNet/addUser.php
  56. 1 1
      app/Jobs/VNet/delUser.php
  57. 20 10
      app/Jobs/VNet/editUser.php
  58. 1 1
      app/Jobs/VNet/reloadNode.php
  59. 12 0
      app/Models/AppUpdate.php
  60. 17 4
      app/Models/Node.php
  61. 27 2
      app/Models/Order.php
  62. 15 0
      app/Models/Sms.php
  63. 19 5
      app/Models/User.php
  64. 1 1
      app/Models/UserHourlyDataFlow.php
  65. 1 1
      app/Observers/UserObserver.php
  66. 50 11
      app/Services/OrderService.php
  67. 7 0
      bootstrap/app.php
  68. 8 3
      composer.json
  69. 413 207
      composer.lock
  70. 31 0
      config/common.php
  71. 2 2
      config/jwt.php
  72. 1 1
      queue.sh
  73. 2 0
      readme.md
  74. 1 1
      resources/lang/zh-CN.json
  75. 3 3
      resources/lang/zh-CN/common.php
  76. 3 3
      resources/lang/zh-CN/error.php
  77. 1 1
      resources/lang/zh-CN/passwords.php
  78. 18 18
      resources/lang/zh-CN/user.php
  79. 21 20
      resources/rules/app.clash.yaml
  80. 78 0
      resources/rules/config.yml
  81. 1 23
      resources/rules/default.clash.yaml
  82. 6 6
      resources/views/_layout.blade.php
  83. 3 0
      resources/views/admin/aff/detail.blade.php
  84. 11 8
      resources/views/admin/aff/index.blade.php
  85. 82 0
      resources/views/admin/config/system.blade.php
  86. 236 236
      resources/views/admin/index.blade.php
  87. 2 2
      resources/views/admin/layouts.blade.php
  88. 12 9
      resources/views/admin/logs/callback.blade.php
  89. 2 2
      resources/views/admin/logs/onlineIPMonitor.blade.php
  90. 34 24
      resources/views/admin/logs/order.blade.php
  91. 169 84
      resources/views/admin/node/auth.blade.php
  92. 70 9
      resources/views/admin/node/index.blade.php
  93. 389 377
      resources/views/admin/node/info.blade.php
  94. 17 1
      resources/views/admin/subscribe/index.blade.php
  95. 12 3
      resources/views/admin/ticket/index.blade.php
  96. 39 0
      resources/views/admin/ticket/reply.blade.php
  97. 6 6
      resources/views/admin/user/index.blade.php
  98. 15 5
      resources/views/admin/user/info.blade.php
  99. 1 1
      resources/views/auth/error.blade.php
  100. 14 14
      resources/views/auth/layouts.blade.php

+ 0 - 52
.env.example

@@ -1,52 +0,0 @@
-APP_NAME=ProxyPanel
-APP_ENV=production
-APP_KEY=
-APP_DEBUG=false
-APP_DEMO=false
-APP_URL=http://localhost
-APP_TIMEZONE=Asia/Shanghai
-APP_LOCALE=zh-CN
-APP_FALLBACK_LOCALE=en
-LOG_CHANNEL=daily
-
-# 数据库
-DB_CONNECTION=mysql
-DB_HOST=127.0.0.1
-DB_PORT=3306
-DB_DATABASE=ProxyPanel
-DB_USERNAME=root
-DB_PASSWORD=root
-DB_STRICT=false
-
-BROADCAST_DRIVER=redis
-CACHE_DRIVER=redis
-QUEUE_CONNECTION=redis
-SESSION_DRIVER=redis
-SESSION_LIFETIME=120
-SESSION_CONNECTION=session
-
-
-# Redis 设置
-REDIS_HOST=127.0.0.1
-REDIS_PASSWORD=null
-REDIS_PORT=6379
-
-MAIL_MAILER=smtp #或使用 mailgun
-
-# 发信方信息
-MAIL_FROM_ADDRESS=admin@proxypanel.ml
-MAIL_FROM_NAME=ProxyPanel
-
-# SMTP设置
-MAIL_HOST=smtp.exmail.qq.com
-MAIL_PORT=465
-MAIL_ENCRYPTION=ssl
-MAIL_USERNAME=admin@proxypanel.ml
-MAIL_PASSWORD=password
-
-# Mailgun设置
-MAILGUN_DOMAIN=
-MAILGUN_SECRET=
-
-REDIRECT_HTTPS=true
-BAIDU_APP_AK =

+ 6 - 1
app/Components/Client/Clash.php

@@ -55,7 +55,12 @@ class Clash
 
         if ($server['v2_tls']) {
             $array['tls'] = true;
-            $array['servername'] = $server['v2_host'];
+            if (! empty($server['sni'])) {
+                 $array['servername'] = $server['sni'];
+            } else if(!empty($server['v2_host'])){
+                $array['servername'] = $server['v2_host'];
+            }
+            
         }
         $array['network'] = $server['v2_net'];
 

+ 16 - 1
app/Components/Client/Surge.php

@@ -27,13 +27,28 @@ class Surge
             "{$server['host']}",
             "{$server['port']}",
             "username={$server['uuid']}",
+            'vmess-aead=true',
             'tfo=true',
             "udp-relay={$server['udp']}",
         ];
 
         if ($server['v2_tls']) {
             $config[] = 'tls=true';
-            $config[] = "sni={$server['v2_host']}";
+            if(!empty($server['v2_sni']))
+            {
+                $config[] = 'skip-cert-verify=false';
+                
+            }
+            else {
+                $config[] = 'skip-cert-verify=true';
+            }
+            
+            if(!empty($server['v2_host'])){
+                $config[] = "sni={$server['v2_host']}";
+            }
+            else {
+                 $config[] = "sni={$server['v2_sni']}";
+            }
         }
         if ($server['v2_net'] === 'ws') {
             $config[] = 'ws=true';

+ 1 - 2
app/Components/Client/Text.php

@@ -16,9 +16,8 @@ class Text
 
     public static function buildVmess($server)
     {
-        return '服务器:'.$server['host'].PHP_EOL.'端口:'.$server['port'].PHP_EOL.'加密方式:'.$server['method'].PHP_EOL.'用户ID:'.$server['uuid'].PHP_EOL.'额外ID:'.$server['v2_alter_id'].PHP_EOL.'传输协议:'.$server['v2_net'].PHP_EOL.'伪装类型:'.$server['v2_type'].PHP_EOL.'伪装域名:'.$server['v2_host'].PHP_EOL.'路径:'.$server['v2_path'].PHP_EOL.'TLS:'.$server['v2_tls'].PHP_EOL.'UDP:'.$server['udp'].PHP_EOL;
+        return '服务器:'.$server['host'].PHP_EOL.'端口:'.$server['port'].PHP_EOL.'加密方式:'.$server['method'].PHP_EOL.'用户ID:'.$server['uuid'].PHP_EOL.'额外ID:'.$server['v2_alter_id'].PHP_EOL.'传输协议:'.$server['v2_net'].PHP_EOL.'伪装类型:'.$server['v2_type'].PHP_EOL.'伪装域名:'.$server['v2_host'].PHP_EOL.'路径:'.$server['v2_path'].PHP_EOL.'TLS:'.$server['v2_tls'].PHP_EOL.'sni'.$server['v2_sni'].PHP_EOL.'UDP:'.$server['udp'].PHP_EOL;
     }
-
     public static function buildTrojan($server)
     {
         return '服务器:'.$server['host'].PHP_EOL.'端口:'.$server['port'].PHP_EOL.'密码:'.$server['passwd'].PHP_EOL.'SNI:'.$server['sni'].PHP_EOL.'UDP:'.$server['udp'].PHP_EOL;

+ 3 - 1
app/Components/Client/URLSchemes.php

@@ -9,7 +9,7 @@ class URLSchemes
     public static function buildShadowsocks($server)
     {
         $name = rawurlencode($server['name']);
-        $str = base64url_encode("{$server['method']}:{$server['method']}");
+        $str = base64url_encode("{$server['method']}:{$server['passwd']}");
 
         return "ss://{$str}@{$server['host']}:{$server['port']}#{$name}".PHP_EOL;
     }
@@ -50,6 +50,8 @@ class URLSchemes
             'host' => $server['v2_host'],
             'path' => $server['v2_path'],
             'tls' => $server['v2_tls'],
+            'sni' =>  $server['v2_sni'],
+            'ServerName' => $server['v2_sni'],
         ];
 
         return 'vmess://'.base64_encode(json_encode($config)).PHP_EOL;

+ 78 - 5
app/Components/Helpers.php

@@ -19,12 +19,12 @@ use DateTime;
 use NotificationChannels\BearyChat\BearyChatChannel;
 use NotificationChannels\Telegram\TelegramChannel;
 use Str;
-
+use Log;
 class Helpers
 {
     // 不生成的端口
     private static $denyPorts = [
-        1068, 1109, 1434, 3127, 3128, 3129, 3130, 3332, 4444, 5554, 6669, 8080, 8081, 8082, 8181, 8282, 9996, 17185, 24554, 35601, 60177, 60179,
+        1068, 1109, 1434, 3127, 3128, 3129, 3130, 3332, 4444, 5554, 6669, 8080, 8081, 8082, 8181, 8282, 9996, 17185, 24554, 35601, 60177, 60179,37886,
     ];
 
     // 加密方式
@@ -69,24 +69,52 @@ class Helpers
      */
     public static function addUser(string $email, string $password, int $transfer_enable, int $date = null, int $inviter_id = null, string $username = null): User
     {
+//        //判断端口是否重复
+        while (true){
+            $port = self::getPort();
+            if ($port == 37886){
+                continue;
+            }
+            $retcount = User::where('port', $port)->count();
+            if ($retcount > 0){
+                continue;
+            } else {
+                break;
+            }
+        }
+
         return User::create([
             'username'        => $username ?? $email,
             'email'           => $email,
             'password'        => $password,
-            'port'            => self::getPort(), // 生成一个可用端口
+            'port'            => 0, // 生成一个可用端口
             'passwd'          => Str::random(),
             'vmess_id'        => Str::uuid(),
             'method'          => self::getDefaultMethod(),
             'protocol'        => self::getDefaultProtocol(),
             'obfs'            => self::getDefaultObfs(),
             'transfer_enable' => $transfer_enable,
-            'expired_at'      => date('Y-m-d', strtotime('+'.$date.' days')),
+            'enable'          => 0,
+            'expired_at'      => date('Y-m-d H:i:s', strtotime('+'.$date.' days')),
             'user_group_id'   => null,
             'reg_ip'          => IP::getClientIp(),
             'inviter_id'      => $inviter_id,
         ]);
     }
 
+
+    public static function GetRandStr($length){
+        //字符组合
+        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+        $len = strlen($str)-1;
+        $randstr = '';
+        for ($i=0;$i<$length;$i++) {
+            $num=mt_rand(0,$len);
+            $randstr .= $str[$num];
+        }
+        return $randstr;
+    }
+
     // 获取一个有效端口
     public static function getPort(): int
     {
@@ -166,6 +194,7 @@ class Helpers
             Cache::tags('sysConfig')->put('is_onlinePay', $value);
         } else {
             if (in_array($name, $notifications, true)) {
+               // Log::info(json_decode(Config::find($name)->value, true));
                 $value = self::setChannel(json_decode(Config::find($name)->value, true));
             } else {
                 $value = Config::find($name)->value;
@@ -176,7 +205,7 @@ class Helpers
         return $value;
     }
 
-    private static function setChannel(array $channels)
+    private static function setChannel($channels)
     {
         $options = [
             'telegram'   => TelegramChannel::class,
@@ -184,6 +213,7 @@ class Helpers
             'bark'       => BarkChannel::class,
             'serverChan' => ServerChanChannel::class,
         ];
+
         foreach ($options as $option => $str) {
             if (($key = array_search($option, $channels, true)) !== false) {
                 $channels[$key] = $str;
@@ -336,4 +366,47 @@ class Helpers
 
         return $marketing->save();
     }
+
+    //重数组中找到最小的,和最大大
+    public static function phpMaxMin($arr = [],$keys = ''){
+        $max['key'] = '';
+        $max['value'] = '';
+        $min['key'] = '';
+        $min['value'] = '';
+
+        foreach ($arr as $key => $val){
+
+            if($max['key'] === ''){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if((int)$max['value'] < $val[$keys]){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if($min['key'] === ''){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+
+            }
+
+            if((int)$min['value'] > $val[$keys]){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+            }
+
+        }
+        $array['max'] = $max;
+        $array['min'] = $min;
+        return $array;
+
+    }
 }

+ 2 - 2
app/Components/NetworkDetection.php

@@ -71,7 +71,7 @@ class NetworkDetection
      */
     public function networkCheck(string $ip, bool $is_icmp, int $port = null)
     {
-        $round = 0;
+        $round = 1;
         // 依次尝试接口
         while (true) {
             switch ($round) {
@@ -110,7 +110,7 @@ class NetworkDetection
             $port = '/'.$port;
             $type_string = 'tcp_port/';
         }
-
+       //china-firewall/check/ip/ICMP-1.1.1.1-53
         $url = "https://api.50network.com/china-firewall/check/ip/{$type_string}{$ip}{$port}";
 
         $response = Http::timeout(15)->get($url);

+ 1 - 1
app/Console/Commands/AutoClearLog.php

@@ -66,7 +66,7 @@ class AutoClearLog extends Command
             RuleLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();
 
             // 清除用户连接IP
-            NodeOnlineIp::where('created_at', '<=', strtotime('-1 week'))->delete();
+            NodeOnlineIp::where('created_at', '<=', strtotime('-1 day'))->delete();
 
             // 清除用户封禁日志
             UserBanedLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();

+ 23 - 2
app/Console/Commands/AutoJob.php

@@ -6,6 +6,7 @@ use App\Components\Helpers;
 use App\Models\Config;
 use App\Models\Coupon;
 use App\Models\Invite;
+use App\Models\Node;
 use App\Models\Order;
 use App\Models\User;
 use App\Models\VerifyCode;
@@ -39,6 +40,8 @@ class AutoJob extends Command
         // 解封被封禁的账号
         $this->unblockUsers();
 
+       // $this->checkNodeWeihu();
+
         // 端口回收与分配
         if (sysConfig('auto_release_port')) {
             $this->dispatchPort();
@@ -141,7 +144,7 @@ class AutoJob extends Command
         $userList = User::whereEnable(0)
             ->where('status', '>=', 0)
             ->whereBanTime(null)
-            ->where('expired_at', '>=', date('Y-m-d'))
+            ->where('expired_at', '>=', date('Y-m-d H:i:s'))
             ->whereRaw('u + d < transfer_enable')
             ->get();
         foreach ($userList as $user) {
@@ -163,7 +166,25 @@ class AutoJob extends Command
         // 被封禁 / 过期一个月 的账号自动释放端口
         User::where('port', '<>', 0)
             ->whereStatus(-1)
-            ->orWhere('expired_at', '<=', date('Y-m-d', strtotime('-1 months')))
+            ->orWhere('expired_at', '<=', date('Y-m-d H:i:s', strtotime('-1 months')))
             ->update(['port' => 0]);
     }
+
+
+    private  function checkNodeWeihu(): void{
+        $query = Node::with(['onlineLogs', 'dailyDataFlows']);
+        $nodeList = $query->where("country_code","=","hk");
+        foreach ($nodeList as $node) {
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+            if ($online_log->online_user < 10){
+
+            } else {
+
+            }
+        }
+
+
+    }
 }

+ 3 - 3
app/Console/Commands/DailyJob.php

@@ -40,7 +40,7 @@ class DailyJob extends Command
     private function expireUser(): void
     {
         // 过期用户处理
-        $userList = User::activeUser()->where('expired_at', '<', date('Y-m-d'))->get();
+        $userList = User::activeUser()->where('expired_at', '<', date('Y-m-d H:i:s'))->get();
         $isBanStatus = sysConfig('is_ban_status');
         foreach ($userList as $user) {
             if ($isBanStatus) {
@@ -95,8 +95,8 @@ class DailyJob extends Command
     private function resetUserTraffic(): void
     {
         $userList = User::where('status', '<>', -1)
-            ->where('expired_at', '>', date('Y-m-d'))
-            ->where('reset_time', '<=', date('Y-m-d'))
+            ->where('expired_at', '>', date('Y-m-d H:i:s'))
+            ->where('reset_time', '<=', date('Y-m-d H:i:s'))
             ->get();
         foreach ($userList as $user) {
             // 跳过 没有重置日期的账号

+ 20 - 0
app/Console/Commands/NodeStatusDetection.php

@@ -37,12 +37,32 @@ class NodeStatusDetection extends Command
             }
         }
 
+        //$this->checkNodeWeihu();
+
         $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
         Log::info("---【{$this->description}】完成---,耗时 {$jobUsedTime} 秒");
     }
 
+    private  function checkNodeWeihu(){
+        $query = Node::with(['onlineLogs', 'dailyDataFlows']);
+        $nodeList = $query->where("country_code","=","hk");
+        foreach ($nodeList as $node) {
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+            Log::info("---【{$this->description}】节点名称{$node->name}---,在线人数 {$node->online_users} ----");
+//            // 已产生流量
+//            $node->transfer = flowAutoShow($node->dailyDataFlows()->sum('total'));
+//
+//            // 负载(10分钟以内)
+//            $node_info = $node->heartbeats()->recently()->first();
+//            $node->isOnline = empty($node_info) || empty($node_info->load) ? 0 : 1;
+//            $node->load = $node->isOnline ? $node_info->load : '离线';
+//            $node->uptime = empty($node_info) ? 0 : seconds2time($node_info->uptime);
+        }
+    }
     private function checkNodeStatus(): void
     {
         $offlineCheckTimes = sysConfig('offline_check_times');

+ 1 - 1
app/Console/Commands/ServiceTimer.php

@@ -17,7 +17,7 @@ class ServiceTimer extends Command
         $jobStartTime = microtime(true);
 
         // 扣减用户到期商品的流量
-        $this->decGoodsTraffic();
+        //$this->decGoodsTraffic();
 
         $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);

+ 1 - 1
app/Console/Commands/UserExpireAutoWarning.php

@@ -30,7 +30,7 @@ class UserExpireAutoWarning extends Command
     private function userExpireWarning(): void
     {
         // 只取SSR没被禁用的用户,其他不用管
-        foreach (User::whereEnable(1)->where('expired_at', '<', date('Y-m-d', strtotime(sysConfig('expire_days').' days')))->get() as $user) {
+        foreach (User::whereEnable(1)->where('expired_at', '<', date('Y-m-d H:i:s', strtotime(sysConfig('expire_days').' days')))->get() as $user) {
             // 用户名不是邮箱的跳过
             if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) {
                 continue;

+ 67 - 0
app/Console/Commands/UserFree.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace App\Console\Commands;
+use App\Models\User;
+use App\Components\Helpers;
+use App\Notifications\AccountExpire;
+use Illuminate\Console\Command;
+use Log;
+
+class UserFree extends Command
+{
+    protected $signature = 'userfree';
+    protected $description = '用户免费到期';
+
+    public function handle(): void
+    {
+        $jobStartTime = microtime(true);
+
+        // 扣减用户到期商品的流量
+        $this->decGoodsTraffic();
+
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    // 扣减用户到期商品的流量
+    private function decGoodsTraffic(): void
+    {
+
+        //获取用户10G的用户 定时改到期
+        foreach (User::whereEnable(1)->where("transfer_enable",'=',MB * ((int) sysConfig('default_traffic')))->get() as $user) {
+            // 用户名不是邮箱的跳过
+            if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) {
+                continue;
+            }
+           //$expired_at = strtotime('-1 day',$user->expired_at);
+
+
+            $user->update([
+                "expired_at" => date('y-m-d',strtotime('-2 day')),
+                "enable" => 0
+            ]);
+
+            $user->notify(new AccountExpire($user->expired_at));
+        }
+        //获取失效的套餐
+//        foreach (Order::activePlan()->where('expired_at', '<=', date('Y-m-d H:i:s'))->with('user')->whereHas('user')->get() as $order) {
+//            // 无用户订单,跳过
+//            // 清理全部流量,重置重置日期和等级
+//            $user = $order->user;
+//
+//            $user->update([
+//                'u' => 0,
+//                'd' => 0,
+//                'transfer_enable' => 0,
+//                'reset_time' => null,
+//                'level' => 0,
+//            ]);
+//            Helpers::addUserTrafficModifyLog($user->id, $order->id, $user->transfer_enable, 0, '[定时任务]用户所购商品到期,扣减商品对应的流量');
+//
+//            // 过期本订单
+//            $order->update(['is_expire' => 1]);
+//        }
+    }
+}

+ 3 - 1
app/Console/Kernel.php

@@ -13,6 +13,7 @@ use App\Console\Commands\DailyJob;
 use App\Console\Commands\NodeStatusDetection;
 use App\Console\Commands\ServiceTimer;
 use App\Console\Commands\UserExpireAutoWarning;
+use App\Console\Commands\UserFree;
 use App\Console\Commands\UserTrafficAbnormalAutoWarning;
 use App\Console\Commands\UserTrafficAutoWarning;
 use Illuminate\Console\Scheduling\Schedule;
@@ -39,6 +40,7 @@ class Kernel extends ConsoleKernel
         UserExpireAutoWarning::class,
         UserTrafficAbnormalAutoWarning::class,
         UserTrafficAutoWarning::class,
+        UserFree::class
     ];
 
     /**
@@ -56,7 +58,7 @@ class Kernel extends ConsoleKernel
         $schedule->command('autoStatisticsNodeHourlyTraffic')->hourly();
         $schedule->command('autoStatisticsUserHourlyTraffic')->hourly();
         $schedule->command('userTrafficAbnormalAutoWarning')->hourly();
-        $schedule->command('dailyJob')->daily();
+        $schedule->command('dailyJob')->everyFiveMinutes();
         $schedule->command('autoReportNode')->dailyAt('09:00');
         $schedule->command('userTrafficAutoWarning')->dailyAt('10:30');
         $schedule->command('userExpireAutoWarning')->dailyAt('20:00');

+ 84 - 5
app/Exceptions/Handler.php

@@ -3,6 +3,7 @@
 namespace App\Exceptions;
 
 use App\Components\IP;
+use Arr;
 use ErrorException;
 use Illuminate\Auth\AuthenticationException;
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
@@ -15,7 +16,12 @@ use ReflectionException;
 use Response;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
 use Throwable;
+use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
+use Tymon\JWTAuth\Exceptions\TokenExpiredException;
+use Tymon\JWTAuth\Exceptions\TokenInvalidException;
+
 
 class Handler extends ExceptionHandler
 {
@@ -49,12 +55,13 @@ class Handler extends ExceptionHandler
      */
     public function report(Throwable $exception)
     {
-        // 记录异常来源
-        Log::info('异常来源:'.get_class($exception));
+
 
         // 调试模式下记录错误详情
         if (config('app.debug') || config('app.demo')) {
             Log::debug('来自链接:'.url()->full());
+            // 记录异常来源
+            Log::info('异常来源:'.get_class($exception));
             Log::debug($exception);
         }
 
@@ -73,23 +80,76 @@ class Handler extends ExceptionHandler
     public function render($request, Throwable $exception)
     {
         // 调试模式下直接返回错误信息,非调试模式下渲染在返回
-        if (! config('app.debug')) {
+
+
+        if ($exception instanceof UnauthorizedHttpException) {
+            $preException = $exception->getPrevious();
+            if ($preException instanceof TokenExpiredException) {
+                return response()->json(['code'=>401,'ret'=>401,'error' => 'TOKEN_EXPIRED'],200);
+            }  else if ($preException instanceof TokenBlacklistedException) {
+                return response()->json(['code'=>402, 'ret' => 402, 'msg' => "TOKEN禁用,需要重新登陆"], 200);
+            }
+            if ($exception->getMessage() === 'Token not provided') {
+                return response()->json(['code'=>403,'ret' => 403, 'msg' => "TOKEN错误,需要重新登陆"], 200);
+            }
+        }
+
+         if (! config('app.debug')) {
             switch ($exception) {
+                case $exception instanceof ValidationException:
+                    if (strpos($request->fullUrl(),"client/v1") != false || strpos($request->fullUrl(),"client/v2") != false || strpos($request->fullUrl(),"client/v3") != false){
+                        return Response::json([
+                            'ret' => 404,
+                            'msg' => Arr::first(Arr::collapse($exception->errors()))
+                        ],404);
+                    }
+                    return Response::view(
+                        'auth.error',
+                        ['message' => Arr::first(Arr::collapse($exception->errors()))],
+                        500
+                    );
+                  //  return $this->response($code, Arr::first(Arr::collapse($exception->errors())));
+                  //  return Response::json(['status' => 'fail', 'message' => Arr::first(Arr::collapse($exception->errors()))], 409);
+                case $exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException:
+                   // Log::info('异常请求:'.$exception->getMessage());
+                    return Response::json(['status' => 'fail', 'message' => $exception->getMessage()], 408);
                 case $exception instanceof NotFoundHttpException: // 捕获访问异常
                     Log::info('异常请求:'.$request->fullUrl().',IP:'.IP::getClientIp());
+                    Log::info('异常请求 route:'.$request->route());
+
+                    if (strpos($request->fullUrl(),"client/v1") != false || strpos($request->fullUrl(),"client/v2") != false || strpos($request->fullUrl(),"client/v3") != false ){
+                        return Response::json([
+                            'ret' => 404,
+                            'msg' => empty($exception->getMessage()) ? '资源没找到~' : $exception->getMessage()
+                        ],404);
+                    }
 
                     if ($request->ajax() || $request->wantsJson()) {
-                        return Response::json(['status' => 'fail', 'message' => trans('error.missing_page')], 404);
+                       // return Response::json(['status' => 'fail', 'message' => trans('error.missing_page')], 404);
+                        return Response::json(['status' => 'fail', 'message' => empty($exception->getMessage()) ? '资源没找到~' : $exception->getMessage()], 407);
                     }
 
-                    return Response::view('auth.error', ['message' => trans('error.missing_page')], 404);
+
+
+                    return Response::view('auth.error', ['message' => $exception->getMessage()], 404);
                 case $exception instanceof AuthenticationException:  // 捕获身份校验异常
+
+                    if (strpos($request->fullUrl(),"client/v1") != false || strpos($request->fullUrl(),"client/v2") != false || strpos($request->fullUrl(),"client/v3") != false ){
+                        return Response::json([
+                            'ret' => 401,
+                            'msg' => "登陆失效,重新登陆下"
+                        ],200);
+                    }
+
+
                     if ($request->ajax() || $request->wantsJson()) {
                         return Response::json(['status' => 'fail', 'message' => trans('error.unauthorized')], 401);
                     }
 
                     return Response::view('auth.error', ['message' => trans('error.unauthorized')], 401);
                 case $exception instanceof TokenMismatchException: // 捕获CSRF异常
+
+
                     if ($request->ajax() || $request->wantsJson()) {
                         return Response::json([
                             'status' => 'fail',
@@ -109,6 +169,17 @@ class Handler extends ExceptionHandler
 
                     return Response::view('auth.error', ['message' => trans('error.system')], 500);
                 case $exception instanceof ErrorException: // 捕获系统错误异常
+
+
+                    if (strpos($request->fullUrl(),"client/v1") != false || strpos($request->fullUrl(),"client/v2") != false || strpos($request->fullUrl(),"client/v3") != false ){
+                        return Response::json([
+                            'ret' => 404,
+                            'msg' => empty($exception->getMessage()) ? '系统错误' : $exception->getMessage()
+                        ],404);
+                    }
+
+
+
                     if ($request->ajax() || $request->wantsJson()) {
                         return Response::json([
                             'status' => 'fail',
@@ -116,6 +187,7 @@ class Handler extends ExceptionHandler
                         ], 500);
                     }
 
+
                     return Response::view(
                         'auth.error',
                         ['message' => trans('error.system').', '.trans('error.visit').'<a href="'.route('admin.log.viewer').'" target="_blank">'.trans('error.log').'</a>'],
@@ -127,6 +199,13 @@ class Handler extends ExceptionHandler
                     }
 
                     return Response::view('auth.error', ['message' => $exception->getMessage()], 408);
+
+                default:
+                    return Response::json([
+                        'status' => 'fail',
+                        'ret' => 404,
+                        'msg' => $exception->getMessage()
+                    ],404);
             }
         }
 

+ 20 - 7
app/Http/Controllers/Admin/AffiliateController.php

@@ -6,7 +6,7 @@ use App\Http\Controllers\Controller;
 use App\Models\ReferralApply;
 use App\Models\ReferralLog;
 use Illuminate\Http\Request;
-
+ 
 class AffiliateController extends Controller
 {
     // 提现申请列表
@@ -39,18 +39,31 @@ class AffiliateController extends Controller
     }
 
     // 设置提现申请状态
-    public function setStatus(Request $request, ReferralApply $aff)
+    public function status(Request $request)
     {
-        $status = (int) $request->validate(['status' => 'required|numeric|between:-1,2']);
+        header('Access-Control-Allow-Origin: *');
+        header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
+        //$status = (int) $request->validate(['status' => 'required|numeric']);
+        $status = $request->input('status');
+        $id = $request->input('id');
+
+        $query =  ReferralApply::query();
+       //return response()->json(['status' => 'success', 'message' => $status]);
+
+        //return response()->json(['status' => 'update', 'message' => ]);
+        if ($query->where('id',$id )->update(['status' => $status])) {
 
-        if ($aff->update(['status' => $status])) {
             // 审核申请的时候将关联的
-            if ($status === 1 || $status === 2) {
-                $aff->referral_logs()->update(['status' => $status]);
+            if ($status == 1 || $status == 2) {
+                $nod = $query->where('id',$id )->get();
+                foreach ($nod as $nn) {
+                    $nn->referral_logs()->update(['status' => $status]);
+                }
+                
             }
         }
 
-        return response()->json(['status' => 'success', 'message' => '操作成功']);
+        return response()->json(['status' => 'success', 'message' => 'success']);
     }
 
     // 用户返利流水记录

+ 39 - 12
app/Http/Controllers/Admin/LogsController.php

@@ -15,6 +15,8 @@ use App\Models\UserCreditLog;
 use App\Models\UserDataFlowLog;
 use App\Models\UserDataModifyLog;
 use Illuminate\Http\Request;
+use phpseclib3\Crypt\EC\Curves\brainpoolP160r1;
+use function Matrix\diagonal;
 
 class LogsController extends Controller
 {
@@ -30,6 +32,9 @@ class LogsController extends Controller
         $range_time = $request->input('range_time');
         $sort = $request->input('sort'); // 0-按创建时间降序、1-按创建时间升序
         $order_id = $request->input('id');
+        $trade_no = $request->input('trade_no');
+
+
 
         $query = Order::with(['user:id,email', 'goods:id,name', 'coupon:id,name,sn']);
 
@@ -42,6 +47,8 @@ class LogsController extends Controller
             $query->where('sn', 'like', '%'.$sn.'%');
         }
 
+
+
         if (isset($is_coupon)) {
             if ($is_coupon) {
                 $query->where('coupon_id', '<>', null);
@@ -77,7 +84,22 @@ class LogsController extends Controller
             $query->orderByDesc('id');
         }
 
-        return view('admin.logs.order', ['orders' => $query->paginate(15)->appends($request->except('page'))]);
+        if (isset($trade_no)){
+           $query->whereHas('payment' , function ($q) use ($trade_no) {
+                $q->where('trade_no', 'like', '%'.$trade_no.'%');
+            });
+
+        }else {
+//            $query->payment();
+        }
+//        //dump( ['orders' => $query->latest()->paginate(15)->appends($request->except('page'))]); die();
+//        $data = $query->latest()->paginate(15)->appends($request->except('page'));
+//        foreach ($data as $key => $v){
+//            echo $v;
+//        }
+//        die();
+//        var_dump($query->latest()->paginate(15)->appends($request->except('page'))); die();
+        return view('admin.logs.order', ['orders' => $query->latest()->paginate(15)->appends($request->except('page'))]);
     }
 
     // 流量日志
@@ -192,15 +214,15 @@ class LogsController extends Controller
         }
 
         $onlineIPLogs = $query->groupBy('user_id', 'node_id')->latest()->paginate(20)->appends($request->except('page'));
-        foreach ($onlineIPLogs as $log) {
-            // 跳过上报多IP的
-            if ($log->ip === null || strpos($log->ip, ',') !== false) {
-                continue;
-            }
-            $ipInfo = IP::getIPInfo($log->ip);
-
-            $log->ipInfo = implode(' ', $ipInfo);
-        }
+//        foreach ($onlineIPLogs as $log) {
+//            // 跳过上报多IP的
+//            if ($log->ip === null || strpos($log->ip, ',') !== false) {
+//                continue;
+//            }
+//            //$ipInfo = IP::getIPInfo($log->ip);
+//
+//            //$log->ipInfo = implode(' ', $ipInfo);
+//        }
 
         return view('admin.logs.onlineIPMonitor', [
             'onlineIPLogs' => $onlineIPLogs,
@@ -304,13 +326,18 @@ class LogsController extends Controller
     public function callbackList(Request $request)
     {
         $status = $request->input('status', 0);
+        $out_trade_no = $request->input('out_trade_no', 0);
 
         $query = PaymentCallback::query();
 
         if (isset($status)) {
             $query->whereStatus($status);
         }
-
-        return view('admin.logs.callback', ['callbackLogs' => $query->latest()->paginate(10)->appends($request->except('page'))]);
+        if (isset($out_trade_no)){
+            $query->where('out_trade_no',"=",$out_trade_no);
+        }
+       $data = $query->latest()->paginate(10)->appends($request->except('page'));
+//        die();
+        return view('admin.logs.callback', ['callbackLogs' => $data]);
     }
 }

+ 40 - 2
app/Http/Controllers/Admin/NodeAuthController.php

@@ -6,15 +6,53 @@ use App\Http\Controllers\Controller;
 use App\Models\Node;
 use App\Models\NodeAuth;
 use Exception;
+use Illuminate\Http\Request;
 use Response;
 use Str;
 
 class NodeAuthController extends Controller
 {
     // 节点授权列表
-    public function index()
+    public function index(Request $request)
     {
-        return view('admin.node.auth', ['authorizations' => NodeAuth::orderBy('node_id')->paginate()->appends(request('page'))]);
+
+        $status = $request->input('status');
+
+        $node = $request->input('node');
+        $serverip = $request->input('serverip');
+
+         $query =  NodeAuth::with(['node']);
+
+
+
+        if (isset($status)) {
+//            $query->with('node',function($q) use ($status) {
+//                $q->where("status","=",$status);
+//            });
+
+            $query->whereHas('node',function ($q) use ($status){
+                $q->where("status","=",$status);
+            });
+        }
+
+        if (isset($node)){
+
+            $query->whereHas('node',function ($q) use ($node){
+                $q->where("name","like",'%'.$node.'%');
+            });
+        }
+
+        if (isset($serverip)){
+
+            $query->whereHas('node',function ($q) use ($serverip){
+                $q->where("ip","=",$serverip);
+            });
+           // $query->where("ip","=",$serverip);
+        }
+
+       $nodeList =  $query->orderBy('node_id')->paginate()->appends(request('page'));
+
+        return view('admin.node.auth', ['authorizations' => $nodeList]);
     }
 
     // 添加节点授权

+ 22 - 0
app/Http/Controllers/Admin/NodeController.php

@@ -26,12 +26,34 @@ class NodeController extends Controller
     {
         $status = $request->input('status');
 
+        $node = $request->input('node');
+        $serverip = $request->input('serverip');
+        $relay_server = $request->input('relay_server');
+        $server = $request->input('server');
+        $v2_sni = $request->input('v2_sni');
+        $type = $request->input('type');
         $query = Node::with(['onlineLogs', 'dailyDataFlows']);
 
         if (isset($status)) {
             $query->whereStatus($status);
         }
 
+        if (isset($node)){
+            $query->where("name","like",'%'.$node.'%');
+        }
+        if (isset($server)){
+            $query->where("server","like",'%'.$server.'%')->orWhere("v2_sni","like",$server.'%')->orwhere("relay_server","like",$server.'%')->orwhere("ip","like",$server.'%');
+        }
+        if (isset($serverip)){
+            $query->where("server","like",'%'.$serverip.'%');
+        }
+        
+        if (isset($v2_sni)){
+            $query->Where("v2_sni","like",'%'.$v2_sni.'%');
+        }
+        if (isset($type)){
+            $query->where("type","=",$type);
+        }
         $nodeList = $query->orderByDesc('sort')->orderBy('id')->paginate(15)->appends($request->except('page'));
         foreach ($nodeList as $node) {
             // 在线人数

+ 15 - 1
app/Http/Controllers/Admin/SubscribeController.php

@@ -22,7 +22,9 @@ class SubscribeController extends Controller
         $user_id = $request->input('user_id');
         $email = $request->input('email');
         $status = $request->input('status');
-
+        $times = $request->input('times');
+        $starttime = $request->input('starttime');
+        $endtime = $request->input('endtime');
         $query = UserSubscribe::with(['user:id,email']);
 
         if (isset($user_id)) {
@@ -35,6 +37,17 @@ class SubscribeController extends Controller
             });
         }
 
+        if (isset($times)){
+            $query->where('times','>',$times);
+        }
+
+        if (isset($starttime) && isset($endtime))
+        {
+            $query->whereBetween('updated_at', [$starttime,$endtime]);
+        }
+
+
+
         if (isset($status)) {
             $query->whereStatus($status);
         }
@@ -51,6 +64,7 @@ class SubscribeController extends Controller
             $query->whereUserSubscribeId($id);
         }
 
+
         $subscribeLogs = $query->latest()->paginate(20)->appends(\request('page'));
         foreach ($subscribeLogs as $log) {
             // 跳过上报多IP的

+ 8 - 0
app/Http/Controllers/Admin/SystemController.php

@@ -48,7 +48,15 @@ class SystemController extends Controller
         if (sysConfig('paybeaver_app_id') && sysConfig('paybeaver_app_secret')) {
             $payment[] = 'paybeaver';
         }
+        if (sysConfig('zpay_mch_id') && sysConfig('zpay_key')) {
+            $payment[] = 'zpay';
+            $payment[] = 'epaytt';
+        }
 
+        if (sysConfig('theadpay_mchid') && sysConfig('theadpay_key')) {
+            $payment[] = 'theadpay';
+        }
+        $payment[] = 'bypay';
         return $payment ?? [];
     }
 

+ 13 - 3
app/Http/Controllers/Admin/TicketController.php

@@ -12,6 +12,7 @@ use App\Notifications\TicketReplied;
 use Auth;
 use Illuminate\Http\Request;
 use Response;
+use Log;
 
 class TicketController extends Controller
 {
@@ -19,14 +20,19 @@ class TicketController extends Controller
     public function index(Request $request)
     {
         $email = $request->input('email');
-
+        $status = $request->input('status');
         $query = Ticket::whereAdminId(Auth::id())->orwhere('admin_id');
 
+
+
         if (isset($email)) {
             $query->whereHas('user', static function ($q) use ($email) {
                 $q->where('email', 'like', '%'.$email.'%');
             });
         }
+        if (isset($status)){
+            $query->whereStatus($status);
+        }
 
         return view('admin.ticket.index', ['ticketList' => $query->latest()->paginate(10)->appends($request->except('page'))]);
     }
@@ -72,7 +78,10 @@ class TicketController extends Controller
 
             // 通知用户
             if (in_array('mail', sysConfig('ticket_replied_notification'), true)) {
-                $ticket->user->notify(new TicketReplied($ticket->title, $content, route('replyTicket', $ticket), true));
+                Log::info(route('replyTicket')."?id=".$ticket->id);
+                Log::info($ticket);
+                //$ticket->user->notify(new TicketReplied($ticket->title, $content, route('replyTicket', $ticket), true));
+                $ticket->user->notify(new TicketReplied($ticket->title, $content, route('replyTicket')."?id=".$ticket->id, true));
             }
 
             return Response::json(['status' => 'success', 'message' => '回复成功']);
@@ -89,7 +98,8 @@ class TicketController extends Controller
         }
         // 通知用户
         if (in_array('mail', sysConfig('ticket_closed_notification'), true)) {
-            $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('replyTicket', $ticket), \request('reason'), true));
+           // $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('replyTicket', $ticket), \request('reason'), true));
+            $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('replyTicket')."?id=".$ticket->id, \request('reason'), true));
         }
 
         return Response::json(['status' => 'success', 'message' => '关闭成功']);

+ 27 - 6
app/Http/Controllers/Admin/UserController.php

@@ -87,7 +87,7 @@ class UserController extends Controller
 
         // 临近过期提醒
         if ($expireWarning) {
-            $query->whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime('+'.sysConfig('expire_days').' days'))]);
+            $query->whereBetween('expired_at', [date('Y-m-d H:i:s'), date('Y-m-d H:i:s', strtotime('+'.sysConfig('expire_days').' days'))]);
         }
 
         // 当前在线
@@ -145,10 +145,10 @@ class UserController extends Controller
         $data['vmess_id'] = $data['uuid'] ?? Str::uuid();
         Arr::forget($data, 'uuid');
         $data['transfer_enable'] *= GB;
-        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('+365 days'));
+        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d H:i:s', strtotime('+365 days'));
         $data['remark'] = str_replace(['atob', 'eval'], '', $data['remark']);
         $data['reg_ip'] = IP::getClientIp();
-        $data['reset_time'] = $data['reset_time'] > date('Y-m-d') ? $data['reset_time'] : null;
+        $data['reset_time'] = $data['reset_time'] > date('Y-m-d H:i:s') ? $data['reset_time'] : null;
         $user = User::create($data);
 
         $roles = $request->input('roles');
@@ -200,8 +200,10 @@ class UserController extends Controller
         Arr::forget($data, ['roles', 'uuid', 'password']);
         $data['transfer_enable'] *= GB;
         $data['enable'] = $data['status'] < 0 ? 0 : $data['enable'];
-        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('+365 days'));
+        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d H:i:s', strtotime('+365 days'));
         $data['remark'] = str_replace(['atob', 'eval'], '', $data['remark']);
+        $data['reset_time'] = $data['reset_time'] > date('Y-m-d H:i:s') ? $data['reset_time'] : null;
+
 
         // 只有超级管理员才能赋予超级管理员
         $roles = $request->input('roles');
@@ -213,7 +215,7 @@ class UserController extends Controller
 
             // Input checking for dummy
             if ($data['enable'] === '1') {
-                if ($data['status'] === '-1' || $data['transfer_enable'] === 0 || $data['expired_at'] < date('Y-m-d')) {
+                if ($data['status'] === '-1' || $data['transfer_enable'] === 0 ) {
                     $data['enable'] = 0;
                 }
             }
@@ -266,7 +268,7 @@ class UserController extends Controller
     {
         try {
             for ($i = 0; $i < (int) request('amount', 1); $i++) {
-                $user = Helpers::addUser(Str::random(8).'@auto.generate', Str::random(), 1024 * GB, 365);
+                $user = Helpers::addUser(Str::random(8).'b'.$i.'@auto.generate', 123456, 204800 * MB , 30);
                 // 写入用户流量变动记录
                 Helpers::addUserTrafficModifyLog($user->id, null, 0, 1024 * GB, '后台批量生成用户');
             }
@@ -335,4 +337,23 @@ class UserController extends Controller
 
         return Response::json(['status' => 'success', 'data' => $this->getUserNodeInfo($server, $request->input('type') !== 'text'), 'title' => $server['type']]);
     }
+    
+    
+    public function UserDis(Request $request){
+
+        $id = $request->input('id');
+
+        // 从请求中获取需要更新的数据
+        $data = [
+            'enable' => 0,
+            'expired_at' => '2020-05-01 15:35:19',
+            'remark' => '已经退款'
+        ];
+
+        // 使用Eloquent ORM查找对应的用户记录
+        $user = User::find($id);
+
+        // 使用update()方法更新用户记录
+        return $user->update($data);
+    }
 }

+ 21 - 21
app/Http/Controllers/AdminController.php

@@ -30,29 +30,29 @@ class AdminController extends Controller
 
         return view('admin.index', [
             'expireDays' => sysConfig('expire_days'),
-            'totalUserCount' => User::count(), // 总用户数
-            'todayRegister' => User::whereDate('created_at', date('Y-m-d'))->count(), // 今日注册用户
+            'totalUserCount' => 0, //User::count(), // 总用户数
+            'todayRegister' =>  User::whereDate('created_at', date('Y-m-d'))->count(), // 今日注册用户
             'enableUserCount' => User::whereEnable(1)->count(), // 有效用户数
-            'activeUserCount' => User::where('t', '>=', $past)->count(), // 活跃用户数,
-            'payingUserCount' => Order::whereStatus(2)->where('goods_id', '<>', 0)->whereIsExpire(0)->where('amount', '>', 0)->pluck('user_id')->unique()->count(), // 付费用户数
-            'unActiveUserCount' => User::whereEnable(1)->whereBetween('t', [1, $past])->count(), // 不活跃用户数
+            'activeUserCount' => 1, //User::where('t', '>=', $past)->count(), // 活跃用户数,
+            'payingUserCount' => 1, //Order::whereStatus(2)->where('goods_id', '<>', 0)->whereIsExpire(0)->where('amount', '>', 0)->pluck('user_id')->unique()->count(), // 付费用户数
+            'unActiveUserCount' => 1, //User::whereEnable(1)->whereBetween('t', [1, $past])->count(), // 不活跃用户数
             'onlineUserCount' => User::where('t', '>=', strtotime('-10 minutes'))->count(), // 10分钟内在线用户数
-            'expireWarningUserCount' => User::whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime('+'.sysConfig('expire_days').' days'))])->count(), // 临近过期用户数
-            'largeTrafficUserCount' => User::whereRaw('(u + d)/transfer_enable >= 0.9')->where('status', '<>', -1)->count(), // 流量使用超过90%的用户
-            'flowAbnormalUserCount' => count((new UserHourlyDataFlow)->trafficAbnormal()), // 1小时内流量异常用户
-            'nodeCount' => Node::count(),
-            'unnormalNodeCount' => Node::whereStatus(0)->count(),
-            'flowCount' => flowAutoShow(NodeDailyDataFlow::where('created_at', '>=', date('Y-m-d', strtotime('-30 days')))->sum('total')),
-            'todayFlowCount' => flowAutoShow(NodeDailyDataFlow::where('created_at', '>=', date('Y-m-d'))->sum('total')),
-            'totalFlowCount' => flowAutoShow(NodeDailyDataFlow::sum('total')),
-            'totalCredit' => User::where('credit', '<>', 0)->sum('credit') / 100,
-            'totalWaitRefAmount' => ReferralLog::whereIn('status', [0, 1])->sum('commission') / 100,
-            'todayWaitRefAmount' => ReferralLog::whereIn('status', [0, 1])->whereDate('created_at', date('Y-m-d'))->sum('commission') / 100,
-            'totalRefAmount' => ReferralApply::whereStatus(2)->sum('amount') / 100,
-            'totalOrder' => Order::count(),
-            'todayOrder' => Order::whereDate('created_at', date('Y-m-d'))->count(),
-            'totalOnlinePayOrder' => Order::where('pay_type', '<>', 0)->count(),
-            'todayOnlinePayOrder' => Order::where('pay_type', '<>', 0)->whereDate('created_at', date('Y-m-d'))->count(),
+            'expireWarningUserCount' => 1, //User::whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime('+'.sysConfig('expire_days').' days'))])->count(), // 临近过期用户数
+            'largeTrafficUserCount' => 1, //User::whereRaw('(u + d)/transfer_enable >= 0.9')->where('status', '<>', -1)->count(), // 流量使用超过90%的用户
+            'flowAbnormalUserCount' => 1, //count((new UserHourlyDataFlow)->trafficAbnormal()), // 1小时内流量异常用户
+            'nodeCount' => 1, //Node::count(),
+            'unnormalNodeCount' => 1, //Node::whereStatus(0)->count(),
+            'flowCount' => 1, //flowAutoShow(NodeDailyDataFlow::where('created_at', '>=', date('Y-m-d', strtotime('-30 days')))->sum('total')),
+            'todayFlowCount' => 1, //flowAutoShow(NodeDailyDataFlow::where('created_at', '>=', date('Y-m-d'))->sum('total')),
+            'totalFlowCount' => 1, //flowAutoShow(NodeDailyDataFlow::sum('total')),
+            'totalCredit' => 1, //User::where('credit', '<>', 0)->sum('credit') / 100,
+            'totalWaitRefAmount' => 1, //ReferralLog::whereIn('status', [0, 1])->sum('commission') / 100,
+            'todayWaitRefAmount' => 1, //ReferralLog::whereIn('status', [0, 1])->whereDate('created_at', date('Y-m-d'))->sum('commission') / 100,
+            'totalRefAmount' => 1, //ReferralApply::whereStatus(2)->sum('amount') / 100,
+            'totalOrder' => 1, //Order::count(),
+            'todayOrder' => 1, //Order::whereDate('created_at', date('Y-m-d'))->count(),
+            'totalOnlinePayOrder' => 1, //Order::where('pay_type', '<>', 0)->count(),
+            'todayOnlinePayOrder' => 1, //Order::where('pay_type', '<>', 0)->whereDate('created_at', date('Y-m-d'))->count(),
             'totalSuccessOrder' => Order::whereStatus(2)->count(),
             'todaySuccessOrder' => Order::whereStatus(2)->whereDate('created_at', date('Y-m-d'))->count(),
         ]);

+ 89 - 0
app/Http/Controllers/Api/Client/CodeController.php

@@ -0,0 +1,89 @@
+<?php
+
+namespace App\Http\Controllers\Api\Client;
+
+use App\Http\Controllers\Controller;
+use Illuminate\Http\Request;
+use Session;
+use Illuminate\Support\Facades\Redis;
+use App\Models\Sms;
+
+class CodeController  extends Controller
+{
+    public function __construct()
+    {
+
+    }
+
+    public function GetCode(){
+        $sql = Sms::where('created_at','>=',date('Y-m-d H:i:s', strtotime(' -10 minutes')))->get();
+        if (empty($sql)){
+            response()->json(['ret' => 0, 'code' => []], 200);
+        }
+        return response()->json(['ret' => 1, 'code' => $sql], 200);
+    }
+    /**
+     *
+     * {"msgType":"sms","fromNumber":"81961","toNumber":"15189013758","text":"Apple ID 代码为:971695。请勿与他人共享。","smsId":"1645061967890","time":"2022-02-17 01:39:27","direction":"in","linkType":"0","link":"smsPage","type":"notification","toTelCode":"1","toPhone":"5189013758","fromTelCode":"1","fromPhone":"81961","messageId":"1645061967893"}
+     * @param Request $request
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function Updatecode(Request $request){
+        $code = $request->input("code");
+
+        if(empty($code)){
+            return response()->json(['ret' => 400], 400);
+        }
+
+        $data = json_decode($code, true);
+
+        $ret = Sms::create(
+            [
+                'fromNumber' => $data["fromNumber"],
+                'codetext' => $data['text'],
+                'codetime' => $data['time'],
+                'toPhone'  => $data['toPhone'],
+                'created_at' => date('Y-m-d H:i:s', time()),
+            ]
+        );
+
+
+        return response()->json(['ret' => 1, 'code' => $data['text'] , 'slq' => $ret], 200);
+    }
+
+    /*
+     *
+     userId
+    app
+    from  app提供商的号码(有可能不是号码,是字符串)
+    to    接收号码
+    text  短信内容
+    time  时间
+    */
+    public function SmsCallback(Request $request)
+    {
+       // return response()->json(['ret' => 1, 'code' => "aaa"], 200);
+        $userId = $request->input('userId');
+        $app = $request->input('app');
+        $from = $request->input('from');
+        $to = $request->input('to');
+        $text = $request->input('text');
+        $time = $request->input('time');
+
+        $data = [
+            'fromNumber' => $from,
+            'codetext' => $text,
+            'codetime' => $time,
+            'toPhone'  => $to,
+            'created_at' => date('Y-m-d H:i:s', time()),
+        ];
+       // return response()->json(['ret' => 1, 'code' => $data], 200);
+        $ret = Sms::create(
+            $data
+        );
+
+
+        return response()->json(['ret' => 1, 'code' => $ret], 200);
+    }
+
+}

+ 91 - 0
app/Http/Controllers/Api/Client/PcController.php

@@ -0,0 +1,91 @@
+<?php
+
+namespace App\Http\Controllers\Api\Client;
+
+use App\Http\Controllers\ClientController;
+use App\Http\Controllers\Controller;
+use App\Models\User;
+use Arr;
+use Auth;
+use Illuminate\Http\Request;
+use Session;
+use Illuminate\Support\Facades\Redis;
+use App\Models\Sms;
+use Validator;
+
+class PcController  extends Controller
+{
+    public function __construct()
+    {
+        $this->middleware('auth:api')->except('login', 'register', 'shop', 'getConfig','version','versionwin','buy');
+        auth()->shouldUse('api');
+    }
+
+    public function login(Request $request)
+    {
+        $validator = Validator::make($request->all(), [
+            'email' => 'required|string',
+            'password' => 'required|string|min:6',
+        ]);
+
+        if ($validator->fails()) {
+            return response()->json(['ret' => 0, 'msg' => $validator->errors()->all()], 200);
+        }
+
+        $token = Auth::attempt($validator->validated());
+
+        if(empty($token)){
+            return response()->json(['ret' => 0, 'msg' => '登陆错误'], 200);
+        }
+
+        $user = auth()->user();
+        //判断到期
+        $expireTime = $user["expired_at"];
+
+        if ($expireTime < date('Y-m-d H:i:s')){
+            return response()->json(['ret' => 445, 'msg' => "用户到期,请即使续费"], 200);
+        }
+
+        $userinfo = $user->profile();
+        if (empty($userinfo)){
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+
+
+        // 获取这个账号可用节点
+        $query = $user->nodes()->whereIsSubscribe(1);
+
+        if ($this->subType === 1) {
+            $query = $query->whereIn('type', [1, 4]);
+        } elseif ($this->subType) {
+            $query = $query->whereType($this->subType);
+        }
+
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        if (empty($nodeList)) {
+            return $this->failed(trans('error.subscribe.none'));
+        }
+
+        $servers = [];
+        foreach ($nodeList as $node) {
+            $servers[] = $node->config($user);
+        }
+        $servers = Arr::shuffle($servers);
+
+        $clash_config = (new ClientController)->config("clash", $user, $servers);
+
+
+        $data = [
+            'ret'  => 1,
+            'data' => [
+                'access_token' => $token,
+                'user'         => auth()->user()->profile(),
+                'affurl' => route('register', ['aff' => Auth::id()]),
+                'tutorial' => 'https://ruanjian.xiazi.buzz/',
+                'swoftdownload' => 'https://ruanjian.xiazi.buzz/',
+                'clash_config' => $clash_config
+            ]];
+
+        return response()->json(['ret' => 1, 'msg' => "请求成功",'data'=>$data], 200);
+    }
+}

+ 260 - 22
app/Http/Controllers/Api/Client/V1Controller.php

@@ -2,20 +2,44 @@
 
 namespace App\Http\Controllers\Api\Client;
 
+use App\Components\Helpers;
+use App\Components\IP;
 use App\Http\Controllers\Controller;
+use App\Models\AppUpdate;
 use App\Models\Goods;
+use App\Models\Node;
+use App\Models\Order;
 use App\Models\User;
+use Auth;
 use Illuminate\Http\Request;
+use Redirect;
 use Validator;
+use Str;
+use function Matrix\diagonal;
 
 class V1Controller extends Controller
 {
     public function __construct()
     {
-        $this->middleware('auth:api', ['except' => ['login', 'register', 'shop']]);
+        $this->middleware('auth.jwt', ['except' => ['login', 'register', 'shop','version','versionwin','buy','test','updateNodelPass']]);
         auth()->shouldUse('api');
     }
 
+    public function test(Request $request){
+        $query = User::activeUser()->where('expired_at', '<', date('Y-m-d H:i:s', strtotime('-2 hour')))->toSql();
+        return response()->json(['ret' => 1, 'data' => $query,'datatime' => date('Y-m-d H:i:s', strtotime('-2 hour'))], 200);
+    }
+
+    public function version(Request $request){
+        $version = AppUpdate::where('appname','=','android')->first();
+        return response()->json(['ret' => 1, 'data' => $version], 200);
+    }
+
+    public function versionwin(Request $request){
+        $version = AppUpdate::where('appname','=','win')->first();
+        return response()->json(['ret' => 1, 'data' => $version], 200);
+    }
+
     public function login(Request $request)
     {
         $validator = Validator::make($request->all(), [
@@ -24,52 +48,214 @@ class V1Controller extends Controller
         ]);
 
         if ($validator->fails()) {
-            return response()->json(['ret' => 0, 'msg' => $validator->errors()->all()], 422);
+            return response()->json(['ret' => 0, 'msg' => "账号密码错误(账号是邮箱)"], 200);
         }
 
         if ($token = auth()->attempt($validator->validated())) {
             return $this->createNewToken($token);
         }
 
-        return response()->json(['ret' => 0, 'msg' => '登录信息错误'], 401);
+        return response()->json(['ret' => 0, 'msg' => '账号密码错误'], 200);
     }
 
     protected function createNewToken($token)
     {
+        $userinfo  = auth()->user()->profile();
+
+
         return response()->json([
             'ret' => 1,
-            'access_token' => $token,
-            'token_type' => 'bearer',
-            'expires_in' => auth()->factory()->getTTL() * 60,
-            'user' => auth()->user()->profile(),
+            'data' => [
+                'access_token' => $token,
+                'token_type' => 'bearer',
+                'expires_in' => auth()->factory()->getTTL() * 60,
+                'user' => $userinfo,
+                'affurl' => route('register', ['aff' => Auth::id()]),
+                'tutorial' => 'https://ruanjian.xiazi.buzz/',
+                'swoftdownload' => 'https://ruanjian.xiazi.buzz/',
+            ]
         ]);
     }
 
     public function register(Request $request)
     {
         $validator = Validator::make($request->all(), [
-            'name' => 'required|string|between:2,100',
-            'email' => 'required|string|email|max:100|unique:users',
-            'password' => 'required|string|confirmed|min:6',
+            'username' => 'required|string|between:2,100',
+            'email' => 'required|string|email|max:100|unique:user',
+            'password' => 'required|string|min:6',
         ]);
 
+
+
+
         if ($validator->fails()) {
-            return response()->json($validator->errors()->all(), 400);
+            return response()->json(['ret' => 0, 'msg' => implode("", $validator->errors()->all())]);
         }
+        $transfer_enable = MB * ((int) sysConfig('default_traffic'));
 
-        $user = User::create(array_merge(
-            $validator->validated(),
-            ['password' => $request->password]
-        ));
+        // 创建新用户
+        $user = Helpers::addUser($request->email, $request->password, $transfer_enable, sysConfig('default_days'), null, $request->username);
 
-        return response()->json(['ret' => 1, 'user' => $user], 201);
+        // 注册失败,抛出异常
+        if (!$user) {
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+        if ($token = auth()->attempt($validator->validated())) {
+            return $this->createNewToken($token);
+        }
+        return response()->json(['ret' => 0, 'msg' => "错误"]);
     }
 
     public function logout()
     {
         auth()->logout();
 
-        return response()->json(['ret' => 1]);
+        return response()->json(['ret' => 0,'data'=>'ok']);
+    }
+
+    public function authUser(){
+
+        $user = auth()->user();
+       $userinfo = $user->profile();
+       if (empty($userinfo)){
+         return response()->json(['ret' => 0, 'msg' => "错误"]);
+       }
+
+       //判断到期
+        $expireTime = $user["expired_at"];
+
+       if ($expireTime < date('Y-m-d H:i:s')){
+           return response()->json(['ret' => 445, 'msg' => "用户到期,请即使续费"], 200);
+       }
+
+       $usedTraffic =  $user->usedTraffic();
+       if ($usedTraffic >= $userinfo["transfer_enable"]){
+           return response()->json(['ret' => 446, 'msg' => "流量已经用完,联系客服免费重置流量"], 200);
+       }
+       //获取节点
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+
+        $nodeList = $query->where(function ($q){
+            $q->where('type','=',0)->orwhere('type','=',4);
+        })->orderByDesc('sort')->orderBy('id')->get();
+
+        $firstnode = [];
+        $is_hk = false;
+
+        $temp = array();
+        $result = array();
+
+
+        foreach ($nodeList as  $node) {
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+
+
+            if ($node->country_code == "hk" && $node->online_users != 0){
+
+                $firstnode[] = $node;
+                $is_hk = true;
+            } else {
+                if (!$is_hk){
+
+                    $firstnode[] = $node;
+                }
+
+            }
+        }
+
+        //找到人数最小的
+        $min["key"] = "";
+        $min["value"] = 0;
+        $keys = "online_users";
+
+        $midormax = $this->phpMaxMin($firstnode,$keys);
+
+        // foreach ($firstnode as $key => $val){
+
+        //     if($min['key'] === ''){
+
+        //         $min['key'] = $key;
+        //         $min['value'] = $val[$keys];
+        //         //$temp[$key] =  $val[$keys];
+        //     }
+        //     if($min['value'] > $val[$keys]){
+        //         $result[$key] = $val;
+
+        //         $min['key'] = $key;
+        //         $min['value'] = $val[$keys];
+        //     }
+        // }
+
+        // if (empty($result)  ){
+        //   return  response()->json(['ret' => 0, 'msg' => "数据为空"], 201);
+        // }
+
+        foreach ($firstnode as $key => $v ){
+            if($key == $midormax["min"]["key"])
+            {
+                $servers = $v->config($user);
+                $servers[$keys] = $firstnode[$key][$keys];
+            }
+        }
+
+
+        return response()->json(['ret' => 1, 'data' => $servers], 200);
+    }
+    function getMinAndMaxInArray($arr,$keys = '') {
+        if(empty($arr)) {
+            return array(10,10);
+        }
+        $disArr = array();
+        foreach($arr as $value) {
+            $disArr[] = floatval($value[$keys]);
+        }
+        sort($disArr);
+        $resArr = !empty($disArr) ? array($disArr[0],$disArr[count($disArr)-1]) : array(10,10);
+        unset($disArr);
+        return $resArr;
+    }
+    public function phpMaxMin($arr = [],$keys = ''){
+        $max['key'] = '';
+        $max['value'] = '';
+        $min['key'] = '';
+        $min['value'] = '';
+
+        foreach ($arr as $key => $val){
+
+            if($max['key'] === ''){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if((int)$max['value'] < $val[$keys]){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if($min['key'] === ''){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+
+            }
+
+            if((int)$min['value'] > $val[$keys]){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+            }
+
+        }
+        $array['max'] = $max;
+        $array['min'] = $min;
+        return $array;
+
     }
 
     public function refresh()
@@ -79,14 +265,48 @@ class V1Controller extends Controller
 
     public function userProfile()
     {
-        return response()->json(auth()->user()->profile());
+        return response()->json(['ret' => 1, 'data' => auth()->user()->profile()]);
+    }
+
+    public function iosprofile(Request $request){
+
+        $zfversion = $request->input("zfversion");
+        $version = "1.0.6"; //比客户端大才能返回正确大数据
+
+        $data = auth()->user()->profile();
+        if(version_compare($zfversion,$version,"<")){
+            $data["zfshow"] = 1;
+        } else {
+            $data["zfshow"] = 0;
+        }
+
+        return response()->json(['ret' => 1, 'data' => $data]);
+    }
+    public function  updateNodelPass(){
+       //$nodelist = Node::where('single','=',1)->where('ip','=','192.248.167.49')->get();
+        $nodelist = Node::where('single','=',1)->update([
+            "passwd" => Str::random()
+        ]);
+       //Vc6ykqt49zUD39R2
+
+        return response()->json(['ret' => 1, 'data' => $nodelist]);
+
+
     }
 
     public function nodeList(int $id = null)
     {
         $user = auth()->user();
-        $nodes = $user->nodes()->get();
+       // $nodes = $user->nodes()->get();
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $nodeList = $query->where(function ($q){
+            $q->where('type','=',0)->orwhere('type','=',4);
+        })->orderByDesc('sort')->orderBy('id')->get();
+
+        //$nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        //var_dump($nodes); die();
         if (isset($id)) {
+            $nodes = $user->nodes()->get();
             $node = $nodes->find($id);
 
             if (empty($node)) {
@@ -95,12 +315,30 @@ class V1Controller extends Controller
 
             return response()->json($node->config($user));
         }
+
+        $temp = array();
         $servers = [];
-        foreach ($nodes as $node) {
-            $servers[] = $node->config($user);
+        $firstnode = [];
+        foreach ($nodeList as $node) {
+
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+            $firstnode[] = $node;
+
         }
 
-        return response()->json($servers);
+        foreach ($firstnode as $key => $val){
+            $servers[] = $val->config($user);
+            $servers[$key]["online_users"] = $firstnode[$key]["online_users"];
+        }
+
+        return response()->json(['ret' => 1, 'data' => $servers]);
+    }
+
+    public function buy(Request $request){
+
+        return Redirect::route('login');
     }
 
     public function shop()

+ 553 - 0
app/Http/Controllers/Api/Client/V2Controller.php

@@ -0,0 +1,553 @@
+<?php
+
+namespace App\Http\Controllers\Api\Client;
+
+use App\Components\Helpers;
+use App\Components\IP;
+use App\Http\Controllers\Controller;
+use App\Http\Controllers\PaymentController;
+use App\Models\AppUpdate;
+use App\Models\Goods;
+use App\Models\GoodsCategory;
+use App\Models\Node;
+use App\Models\Order;
+use App\Models\ReferralLog;
+use App\Models\User;
+use Auth;
+use Cache;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Redirect;
+use Validator;
+use Str;
+use function Matrix\diagonal;
+
+class V2Controller extends Controller
+{
+    private static $method;
+
+    public function __construct()
+    {
+        $this->middleware('auth:api')->except('login', 'register', 'shop', 'getConfig','version','versionwin','buy','getsys');
+        auth()->shouldUse('api');
+    }
+
+    /**
+     * @param  Request  $request
+     * @return JsonResponse
+     */
+    public static function getStatus(Request $request): JsonResponse
+    {
+        $order_id = $request->input('order_id');
+        $payment = Order::query()->find($order_id)->payment;
+        if ($payment) {
+            if ($payment->status === 1) {
+                return response()->json(['ret' => 1, 'msg' => '支付成功']);
+            }
+
+            if ($payment->status === -1) {
+                return response()->json(['ret' => 0, 'msg' => '订单超时未支付,已自动关闭']);
+            }
+
+            return response()->json(['ret' => 0, 'msg' => '等待支付']);
+        }
+
+        return response()->json(['ret' => 0, 'msg' => '未知订单']);
+    }
+
+    public function login(Request $request)
+    {
+        $validator = Validator::make($request->all(), [
+            'email' => 'required|string',
+            'password' => 'required|string|min:6',
+        ]);
+
+        if ($validator->fails()) {
+            return response()->json(['ret' => 0, 'msg' => $validator->errors()->all()], 200);
+        }
+
+        if ($token = auth()->attempt($validator->validated())) {
+            return $this->createNewToken($token,$request);
+        }
+
+        return response()->json(['ret' => 0, 'msg' => "账号或密码错误"], 200);
+    }
+
+    protected function createNewToken($token,$request)
+    {
+        $user = auth()->user();
+        return response()->json([
+                'ret'  => 1,
+                'data' => [
+                    'access_token' => $token,
+                    'token_type'   => 'bearer',
+                    'expires_in'   => auth()->factory()->getTTL() * 60,
+                    'user'         => auth()->user()->profile(),
+                    'affurl' => route('register', ['aff' => Auth::id()]),
+                    'tutorial' => 'https://ruanjian.xiazi.buzz/',
+                    'swoftdownload' => 'https://app.xiazai1.xyz/',
+                    'user_login_url' => 'https://user.viptwo.xyz/logina?email='.$request->input('email') . '&password='.$request->input('password'),
+                    'user_buy' => 'https://user.viptwo.xyz/logina?email='.$request->input('email') . '&password='.$request->input('password'),
+                    'user_ticket' => 'https://user.viptwo.xyz/logintoticket?email='.$request->input('email') . '&password='.$request->input('password'),
+                    'clash_config' => route('SProxy_config', ['code'=>$user['code']]),
+                ],
+        ]);
+    }
+
+
+
+    public function iosprofile(Request $request){
+
+        $zfversion = $request->input("zfversion");
+        $version = "1.0.6"; //比客户端大才能返回正确大数据
+
+        $data = auth()->user()->profile();
+        if(version_compare($zfversion,$version,"<")){
+            $data["zfshow"] = 1;
+        } else {
+            $data["zfshow"] = 0;
+        }
+
+        return response()->json(['ret' => 1, 'data' => $data]);
+    }
+
+    public function register(Request $request)
+    {
+        $validator = Validator::make($request->all(), [
+            'email' => 'required|string|email|max:100|unique:user',
+            'password' => 'required|string|min:6',
+        ]);
+
+        $username = Helpers::GetRandStr(6);
+
+        if ($validator->fails()) {
+            return response()->json(['ret' => 0, 'msg' => implode("", $validator->errors()->all())],200);
+        }
+        $transfer_enable = MB * ((int) sysConfig('default_traffic'));
+
+        // 创建新用户
+        $user = Helpers::addUser($request->email, $request->password, $transfer_enable, sysConfig('default_days'), null, $username);
+
+        // 注册失败,抛出异常
+        if (!$user) {
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+        if ($token = auth()->attempt($validator->validated())) {
+            return $this->createNewToken($token,$request);
+        }
+        return response()->json(['ret' => 0, 'msg' => "错误"]);
+    }
+
+    public function logout()
+    {
+        auth()->logout();
+
+        return response()->json(['ret' => 1]);
+    }
+
+    public function refresh()
+    {
+        return $this->createNewToken(auth()->refresh());
+    }
+    public function authUser(){
+
+        $user = auth()->user();
+        $userinfo = $user->profile();
+        if (empty($userinfo)){
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+
+        //判断到期
+        $expireTime = $user["expired_at"];
+
+        if ($expireTime < date('Y-m-d H:i:s')){
+            return response()->json(['ret' => 445, 'msg' => "用户到期,请续费"], 200);
+        }
+
+        $usedTraffic =  $user->usedTraffic();
+        if ($usedTraffic >= $userinfo["transfer_enable"]){
+            return response()->json(['ret' => 446, 'msg' => "流量已经用完,联系客服免费重置流量"], 200);
+        }
+        //获取节点
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+
+//        $nodeList = $query->where(function ($q){
+//            $q->where('type','=',0)->orwhere('type','=',4);
+//        })->orderByDesc('sort')->orderBy('id')->get();
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        $firstnode = [];
+        $is_hk = false;
+
+        $temp = array();
+        $result = array();
+
+
+        foreach ($nodeList as  $node) {
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-1 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+
+
+            if ($node->country_code == "hk" && $node->online_users > 1){
+
+                $firstnode[] = $node;
+                $is_hk = true;
+            } else {
+                if (!$is_hk){
+
+                    $firstnode[] = $node;
+                }
+
+            }
+        }
+
+        //找到人数最小的
+        $min["key"] = "";
+        $min["value"] = 0;
+        $keys = "online_users";
+
+        $midormax = $this->phpMaxMin($firstnode,$keys);
+
+        // foreach ($firstnode as $key => $val){
+
+        //     if($min['key'] === ''){
+
+        //         $min['key'] = $key;
+        //         $min['value'] = $val[$keys];
+        //         //$temp[$key] =  $val[$keys];
+        //     }
+        //     if($min['value'] > $val[$keys]){
+        //         $result[$key] = $val;
+
+        //         $min['key'] = $key;
+        //         $min['value'] = $val[$keys];
+        //     }
+        // }
+
+        // if (empty($result)  ){
+        //   return  response()->json(['ret' => 0, 'msg' => "数据为空"], 201);
+        // }
+
+        foreach ($firstnode as $key => $v ){
+            if($key == $midormax["min"]["key"])
+            {
+                $servers = $v->config($user);
+                $servers[$keys] = $firstnode[$key][$keys];
+            }
+        }
+
+
+        return response()->json(['ret' => 1, 'data' => $servers], 200);
+    }
+    public function userProfile()
+    {
+         return response()->json(['ret' => 1, 'data' => auth()->user()->profile()]);
+        $user = auth()->user();
+        $userInfo = $user->profile();
+        $userInfo['subUrl'] = $user->subUrl();
+        $totalTransfer = $user->transfer_enable;
+        $usedTransfer = $user->used_traffic;
+        $unusedTraffic = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;
+        $userInfo['unusedTraffic'] = flowAutoShow($unusedTraffic);
+
+        return response()->json(['ret' => 1, 'data' => $userInfo]);
+    }
+
+    //获取节点
+    public function nodeList(int $id = null)
+    {
+        $user = auth()->user();
+        // $nodes = $user->nodes()->get();
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        //var_dump($nodes); die();
+        if (isset($id)) {
+            $nodes = $user->nodes()->get();
+            $node = $nodes->find($id);
+
+            if (empty($node)) {
+                return response()->json([], 204);
+            }
+
+            return response()->json($node->config($user));
+        }
+
+        $temp = array();
+        $servers = [];
+        $firstnode = [];
+        foreach ($nodeList as $node) {
+
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+            $firstnode[] = $node;
+
+        }
+
+        foreach ($firstnode as $key => $val){
+            $servers[] = $val->config($user);
+            $servers[$key]["ip"] = $firstnode[$key]["ip"];
+            $servers[$key]["online_users"] = $firstnode[$key]["online_users"];
+        }
+
+        return response()->json(['ret' => 1, 'data' => $servers]);
+    }
+
+
+    public function buy(Request $request){
+
+        return Redirect::route('login');
+    }
+    //版本
+    public function version(Request $request){
+        $version = AppUpdate::where('appname','=','android')->first();
+        return response()->json(['ret' => 1, 'data' => $version], 200);
+    }
+
+    public function versionwin(Request $request){
+        $version = AppUpdate::where('appname','=','win')->first();
+        return response()->json(['ret' => 1, 'data' => $version], 200);
+    }
+    //商品关系
+    public function shop()
+    {
+        $shops = [
+            'keys' => [],
+            'data' => [],
+        ];
+        foreach (GoodsCategory::query()->whereStatus(1)->get() as $item) {
+            $shops['keys'][] = $item['name'];
+            $shops['data'][$item['name']] = $item->goods()->get()->append('traffic_label')->toArray();
+        }
+
+        return response()->json(['ret' => 1, 'data' => $shops]);
+    }
+
+    public function getConfig()
+    {
+        $config = config('bobclient');
+        $config['website_name'] = sysConfig('website_name');
+        $config['website_url'] = sysConfig('website_url');
+        $config['payment'] = [
+            'alipay' => sysConfig('is_AliPay'),
+            'wechat' => sysConfig('is_WeChatPay'),
+        ];
+
+        return response()->json(['ret' => 1, 'data' => $config]);
+    }
+
+    public function purchase(Request $request)
+    {
+        $goods_id = $request->input('goods_id');
+        $coupon_sn = $request->input('coupon_sn');
+        self::$method = $request->input('method');
+        $credit = $request->input('amount');
+        $pay_type = $request->input('pay_type');
+        $amount = 0;
+
+        if ($credit) { // 充值余额
+            if (! is_numeric($credit) || $credit <= 0) {
+                return response()->json(['ret' => 0, 'msg' => trans('user.payment.error')]);
+            }
+            $amount = $credit;
+        } elseif ($goods_id && self::$method) { // 购买服务
+            $goods = Goods::find($goods_id);
+            if (! $goods || ! $goods->status) {
+                return response()->json(['ret' => 0, 'msg' => '订单创建失败:商品已下架']);
+            }
+            $amount = $goods->price;
+
+            // 是否有生效的套餐
+            $activePlan = Order::userActivePlan()->doesntExist();
+
+            // 无生效套餐,禁止购买加油包
+            if ($goods->type === 1 && $activePlan) {
+                return response()->json(['ret' => 0, 'msg' => '购买加油包前,请先购买套餐']);
+            }
+
+            // 单个商品限购
+            if ($goods->limit_num) {
+                $count = Order::uid()->where('status', '>=', 0)->whereGoodsId($goods_id)->count();
+                if ($count >= $goods->limit_num) {
+                    return response()->json(['ret' => 0, 'msg' => '此商品限购'.$goods->limit_num.'次,您已购买'.$count.'次']);
+                }
+            }
+
+            // 使用优惠券
+            if ($coupon_sn) {
+                $coupon = Coupon::whereStatus(0)->whereIn('type', [1, 2])->whereSn($coupon_sn)->first();
+                if (! $coupon) {
+                    return response()->json(['ret' => 0, 'msg' => '订单创建失败:优惠券不存在']);
+                }
+
+                // 计算实际应支付总价
+                $amount = $coupon->type === 2 ? $goods->price * $coupon->value / 100 : $goods->price - $coupon->value;
+                $amount = $amount > 0 ? round($amount, 2) : 0; // 四舍五入保留2位小数,避免无法正常创建订单
+            }
+
+            //非余额付款下,检查在线支付是否开启
+            if (self::$method !== 'credit') {
+                // 判断是否开启在线支付
+                if (! sysConfig('is_onlinePay')) {
+                    return response()->json(['ret' => 0, 'msg' => '订单创建失败:系统并未开启在线支付功能']);
+                }
+
+                // 判断是否存在同个商品的未支付订单
+                if (Order::uid()->whereStatus(0)->exists()) {
+                    return response()->json(['ret' => 0, 'msg' => '订单创建失败:尚有未支付的订单,请先去支付']);
+                }
+            } elseif (Auth::getUser()->credit < $amount) { // 验证账号余额是否充足
+                return response()->json(['ret' => 0, 'msg' => '您的余额不足,请先充值']);
+            }
+
+            // 价格异常判断
+            if ($amount < 0) {
+                return response()->json(['ret' => 0, 'msg' => '订单创建失败:订单总价异常']);
+            }
+
+            if ($amount === 0 && self::$method !== 'credit') {
+                return response()->json(['ret' => 0, 'msg' => '订单创建失败:订单总价为0,无需使用在线支付']);
+            }
+        }
+
+        // 生成订单
+        try {
+            $newOrder = Order::create([
+                'sn'            => date('ymdHis').random_int(100000, 999999),
+                'user_id'       => auth()->id(),
+                'goods_id'      => $credit ? null : $goods_id,
+                'coupon_id'     => $coupon->id ?? null,
+                'origin_amount' => $credit ?: ($goods->price ?? 0),
+                'amount'        => $amount,
+                'pay_type'      => $pay_type,
+                'pay_way'       => self::$method,
+            ]);
+
+            // 使用优惠券,减少可使用次数
+            if (! empty($coupon)) {
+                if ($coupon->usable_times > 0) {
+                    $coupon->decrement('usable_times', 1);
+                }
+
+                Helpers::addCouponLog('订单支付使用', $coupon->id, $goods_id, $newOrder->id);
+            }
+
+            $request->merge(['id' => $newOrder->id, 'type' => $pay_type, 'amount' => $amount]);
+            PaymentController::$method = self::$method;
+            // 生成支付单
+            $data = PaymentController::getClient()->purchase($request);
+            $data = $data->getData(true);
+            $data['order_id'] = $newOrder->id;
+
+            return response()->json($data);
+        } catch (Exception $e) {
+            Log::error('订单生成错误:'.$e->getMessage());
+        }
+
+        return response()->json(['ret' => 0, 'msg' => '订单创建失败']);
+    }
+
+    public function gift(Request $request)
+    {
+        $user = $request->user('api');
+        $referral_traffic = flowAutoShow(sysConfig('referral_traffic') * MB);
+        $referral_percent = sysConfig('referral_percent');
+        // 邀请码
+        $code = $user->invites()->whereStatus(1)->value('code');
+
+        $data['invite_gift'] = trans('user.invite.promotion', [
+            'traffic'          => $referral_traffic,
+            'referral_percent' => $referral_percent * 100,
+        ]);
+        $affSalt = sysConfig('aff_salt');
+        if (isset($affSalt)) {
+            $aff_link = route('register', ['aff' => (new Hashids($affSalt, 8))->encode($user->id)]);
+        } else {
+            $aff_link = route('register', ['aff' => $user->id]);
+        }
+        $data['invite_url'] = $aff_link;
+        $data['invite_text'] = $aff_link.'&(复制整段文字到浏览器打开即可访问),找梯子最重要的就是稳定,这个已经上线三年了,一直稳定没有被封过,赶紧下载备用吧!安装后打开填写我的邀请码【'.$code.'】,你还能多得3天会员.';
+        // 累计数据
+        $data['back_sum'] = ReferralLog::query()->where('inviter_id', $user->id)->sum('commission') / 100;
+        $data['user_sum'] = $user->invitees()->count();
+        $data['list'] = $user->invitees()->selectRaw('username, UNIX_TIMESTAMP(created_at) as created_at')->limit(10)->get();
+
+        return response()->json(['ret' => 1, 'data' => $data]);
+    }
+
+    public function checkIn(Request $request): JsonResponse
+    {
+        $user = $request->user();
+        // 系统开启登录加积分功能才可以签到
+        if (! sysConfig('is_checkin')) {
+            return response()->json(['ret' => 0, 'title' => trans('common.failed'), 'msg' => trans('user.home.attendance.disable')]);
+        }
+
+        // 已签到过,验证是否有效
+        if (Cache::has('userCheckIn_'.$user->id)) {
+            return response()->json(['ret' => 0, 'title' => trans('common.success'), 'msg' => trans('user.home.attendance.done')]);
+        }
+
+        $traffic = random_int((int) sysConfig('min_rand_traffic'), (int) sysConfig('max_rand_traffic')) * MB;
+
+        if (! $user->incrementData($traffic)) {
+            return response()->json(['ret' => 0, 'title' => trans('common.failed'), 'msg' => trans('user.home.attendance.failed')]);
+        }
+
+        // 写入用户流量变动记录
+        Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, $user->transfer_enable + $traffic, trans('user.home.attendance.attribute'));
+
+        // 多久后可以再签到
+        $ttl = sysConfig('traffic_limit_time') ? sysConfig('traffic_limit_time') * Minute : Day;
+        Cache::put('userCheckIn_'.$user->id, '1', $ttl);
+
+        return response()->json(['ret' => 1, 'msg' => trans('user.home.attendance.success', ['data' => flowAutoShow($traffic)])]);
+    }
+
+
+
+    public function phpMaxMin($arr = [],$keys = ''){
+        $max['key'] = '';
+        $max['value'] = '';
+        $min['key'] = '';
+        $min['value'] = '';
+
+        foreach ($arr as $key => $val){
+
+            if($max['key'] === ''){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if((int)$max['value'] < $val[$keys]){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if($min['key'] === ''){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+
+            }
+
+            if((int)$min['value'] > $val[$keys]){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+            }
+
+        }
+        $array['max'] = $max;
+        $array['min'] = $min;
+        return $array;
+
+    }
+
+}

+ 438 - 0
app/Http/Controllers/Api/Client/V3Controller.php

@@ -0,0 +1,438 @@
+<?php
+
+namespace App\Http\Controllers\Api\Client;
+
+use App\Http\Controllers\ClientController;
+use App\Http\Controllers\Controller;
+use App\Models\AppUpdate;
+use App\Models\Node;
+use App\Models\User;
+use App\Models\UserSubscribe;
+use Arr;
+use Auth;
+use Helpers;
+use Illuminate\Http\Request;
+use Session;
+use Illuminate\Support\Facades\Redis;
+use App\Models\Sms;
+use Validator;
+use Hash;
+use App\Models\NodeOnlineLog;
+use DB;
+
+class V3Controller  extends Controller
+{
+    public function __construct()
+    {
+        $this->middleware('auth:api')->except('login','refreshByUser', 'register', 'shop', 'getConfig','version','buy','ClashConfig','getsysconfig');
+        auth()->shouldUse('api');
+    }
+    //生成配置
+    public function ClashConfig(Request $request){
+       $code =  $request->input('code');
+        // 检查订阅码是否有效
+        $subscribe = UserSubscribe::whereCode($code)->first();
+        if (! $subscribe) {
+            return  response()->json(['ret' => 0, 'msg' => trans('error.subscribe.unknown')], 200);
+        }
+
+        if ($subscribe->status !== 1) {
+            return response()->json(['ret' => 0, 'msg' => trans('error.subscribe.sub_baned')], 200);
+        }
+        // 检查用户是否有效
+        $user = $subscribe->user;
+        if (!$user) {
+            return response()->json(['ret' => 0, 'msg' => trans('error.subscribe.user')], 200);
+        }
+
+        if ($user->status === -1) {
+            return response()->json(['ret' => 0, 'msg' => trans('error.subscribe.user_disable')], 200);
+        }
+        // 获取这个账号可用节点
+        $query = $user->nodes()->whereIsSubscribe(1);
+
+//        if ($this->subType === 1) {
+//            $query = $query->whereIn('type', [1, 4]);
+//        } elseif ($this->subType) {
+//            $query = $query->whereType($this->subType);
+//        }
+
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        if (empty($nodeList)) {
+            return $this->failed(trans('error.subscribe.none'));
+        }
+
+        $servers = [];
+        foreach ($nodeList as $node) {
+            $servers[] = $node->config($user);
+        }
+        $servers = Arr::shuffle($servers);
+
+        return (new ClientController)->config("clash", $user, $servers);
+    }
+
+    //登陆
+    public function login(Request $request)
+    {
+        $validator = Validator::make($request->all(), [
+            'email' => 'required|email',
+            'password' => 'required|string|min:6',
+        ]);
+        if ($validator->fails()) {
+            return response()->json(['ret' => 0, 'msg' => $validator->errors()->all()], 200);
+        }
+
+        if ($token = auth()->attempt($validator->validated())) {
+            return $this->createNewToken($request,$token);
+        }
+
+        return response()->json(['ret' => 0, 'msg' => "账号或密码错误"], 200);
+    }
+
+
+    protected function createNewToken($request,$token)
+    {
+        $user = auth()->user();
+        //判断到期
+        $expireTime = $user["expired_at"];
+
+//        if ($expireTime < date('Y-m-d H:i:s')){
+//            return response()->json(['ret' => 445, 'msg' => "用户到期,请即使续费"], 200);
+//        }
+
+//        $usedTraffic = $user->usedTraffic();
+//        if ($usedTraffic >= $user["transfer_enable"]){
+//            return response()->json(['ret' => 446, 'msg' => "流量已经用完,联系客服免费重置流量"], 200);
+//        }
+
+        $userinfo = $user->profile();
+        if (empty($userinfo)){
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+
+        $data = [
+            'access_token' => $token,
+            'user'         => $userinfo,
+            'tutorial' => 'https://ruanjian.xiazi.buzz/',
+            'swoftdownload' => 'https://app.xiazai1.xyz/',
+            'affurl' => 'https://user.viptwo.xyz/logintoreferral?email='.$request->input('email') . '&password='.$request->input('password'),
+            'user_login_url' => 'https://user.viptwo.xyz/logina?email='.$request->input('email') . '&password='.$request->input('password'),
+            'user_buy' => 'https://user.viptwo.xyz/logina?email='.$request->input('email') . '&password='.$request->input('password'),
+            'user_ticket' => 'https://user.viptwo.xyz/logintoticket?email='.$request->input('email') . '&password='.$request->input('password'),
+            'clash_config' => route('SProxy_config', ['code'=>$userinfo['code']]),
+        ];
+
+        return response()->json(['ret' => 1, 'msg' => "请求成功",'data'=>$data], 200);
+    }
+
+    //正在获取系统配置
+    public function getsysconfig(Request $request){
+
+        $url = "rj.viptwo.top";
+
+        $tag = $request->input('email');
+        if (!isset($tag)){
+            $data = [
+                'affurl' => 'https://user.vipthree.xyz/logintoreferral', //推广
+                'user_login_url' => 'https://'.$url.'/logina', //购买 和登陆
+                'user_login_url_ke' => 'https://'.$url.'/logina', //购买和登陆
+                'user_buy' => 'https://'.$url.'/logina', //
+                'user_ticket' => 'https://'.$url.'/logintoticket',
+                'user_reg' => 'https://'.$url.'/register',
+                'user_reset' => 'https://'.$url.'/reset',
+                'user_tutorial' => 'https://app.xiazai1.xyz/',  //在线客服
+                'user_rofile' => 'https://'.$url.'/Loginprofile',
+                'user_download' => 'https://app.xiazai1.xyz/',
+                'tag' => 0,
+            ];
+            return response()->json(['ret' => 1, 'msg' => "请求成功",'data'=>$data], 200);
+        }
+        else {
+            $data = [
+                'affurl' => 'https://user.vipthree.xyz/logintoreferral?email='.$request->input('email') . '&password='.$request->input('password'),
+                'affurl_ke' => 'https://user.vipthree.xyz/logintoreferral',
+                'user_login_url' => 'https://'.$url.'/logina?email='.$request->input('email') . '&password='.$request->input('password'),
+                'user_login_url_ke' => 'https://'.$url.'/logina',
+                'user_buy' => 'https://'.$url.'/logina?email='.$request->input('email') . '&password='.$request->input('password'),
+                'user_ticket' => 'https://'.$url.'/logintoticket?email='.$request->input('email') . '&password='.$request->input('password'),
+                'user_ticket_ke' => 'https://'.$url.'/logintoticket',
+                'user_reg' => 'https://'.$url.'/register',
+                'user_reset' => 'https://'.$url.'/reset',
+                'user_tutorial' => 'https://app.xiazai1.xyz/',
+                'user_rofile' => 'https://'.$url.'/Loginprofile',
+                'user_download' => 'https://app.xiazai1.xyz/',
+                'tag' => 1,
+            ];
+            return response()->json(['ret' => 1, 'msg' => "请求成功",'data'=>$data], 200);
+        }
+    }
+
+
+    //刷新token
+    public function refresh()
+    {
+        $user = auth()->user();
+        $userinfo = $user->profile();
+        if (empty($userinfo)){
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+        $data = [
+            'access_token' => auth()->refresh(),
+            'user'         =>  $userinfo,
+            'affurl' => route('register', ['aff' => Auth::id()]),
+            'tutorial' => 'https://user.viptwo.xyz/',
+            'swoftdownload' => 'https://app.xiazai1.xyz/',
+            'clash_config' => route('SProxy_config', ['code'=>$userinfo['code']]),
+        ];
+
+        return response()->json(['ret' => 1, 'msg' => "请求成功",'data'=>$data], 200);
+    }
+
+    public function refreshByUser(Request $request)
+    {
+
+        $email = $request->input("email");
+        $password = $request->input("password");
+        $userinfo = User::where('email','=',$email)->first();
+        if (empty($userinfo)){
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+        $users = [
+            'email' => $email,
+            'password' =>$password
+        ];
+
+
+
+        $token = auth()->attempt($users);
+        $data = [
+            'access_token' => $token,
+            'user'         =>  $userinfo,
+            'affurl' => route('register', ['aff' => $userinfo["id"]]),
+            'tutorial' => 'https://user.viptwo.xyz/',
+            'swoftdownload' => 'https://app.xiazai1.xyz/',
+            'clash_config' => route('SProxy_config', ['code'=>$userinfo['code']]),
+        ];
+
+        return response()->json(['ret' => 1, 'msg' => "请求成功",'data'=>$data], 200);
+    }
+
+    public function version(Request $request){
+        $tag = $request->input("tag");
+        $appversion = $request->input("appverion");
+        $version = AppUpdate::where('appname','=',$tag)->first();
+        if (empty($version)){
+            return response()->json(['ret' => 0, 'msg' => "获取版本失败"]);
+        }
+
+        if(version_compare($version["appversion"],$appversion,">")){
+            $version["versionupdate"] = 1;
+            return response()->json(['ret' => 1, 'data' => $version], 200);
+        }
+        return response()->json(['ret' => 0, 'msg' => "没有新版本"]);
+    }
+    //用户验证
+    public function authUser(Request $request){
+
+        $user = auth()->user();
+        $userinfo = $user->profile();
+        $is_debug = $request->input('debug');
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        if ($is_debug == 1){
+            //return $nodeList[0]["status"] == 1;
+            $firstnode = [];
+            foreach ($nodeList as  $node) {
+                // 在线人数
+                $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-1 minutes'))->latest('log_time')->first();
+                $node->online_users = $online_log->online_user ?? 0;
+
+                if (strpos($node->country_code,'hk') !== false && $node->status == 1){
+                    $firstnode[] = $node;
+                }
+            }
+
+            if (empty($firstnode)) {
+                // 查找其他国家的第一个
+                foreach ($nodeList as  $node) {
+                    // 在线人数
+                    $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-1 minutes'))->latest('log_time')->first();
+                    $node->online_users = $online_log->online_user ?? 0;
+
+                    if ( $node->status == 1){
+                        $firstnode[] = $node;
+                    }
+                }
+            }
+            //找到人数最小的
+            $min["key"] = "";
+            $min["value"] = 0;
+            $keys = "online_users";
+
+            $midormax = $this->phpMaxMin($firstnode,$keys);
+
+
+            $servers = [];
+            foreach ($firstnode as $key => $v ){
+                if($key == $midormax["min"]["key"])
+                {
+                    $servers = $v->config($user);
+                    $servers[$keys] = $firstnode[$key][$keys];
+                }
+            }
+            return $servers;
+
+
+        }
+
+
+        if (empty($userinfo)){
+            return response()->json(['ret' => 0, 'msg' => "错误"]);
+        }
+
+
+        //判断到期
+        $expireTime = $user["expired_at"];
+
+        if ($expireTime < date('Y-m-d H:i:s')){
+            return response()->json(['ret' => 445, 'msg' => "用户到期,请续费"], 200);
+        }
+
+        $usedTraffic =  $user->usedTraffic();
+        if ($usedTraffic >= $userinfo["transfer_enable"]){
+            return response()->json(['ret' => 446, 'msg' => "流量已经用完,联系客服免费重置流量"], 200);
+        }
+
+        if ($userinfo["enable"] == 0){
+            return response()->json(['ret' => 446, 'msg' => "账号禁用1个小时内流量超过30G,1个小时后自动解封"], 200);
+        }
+
+        //获取节点
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        $firstnode = [];
+        foreach ($nodeList as  $node) {
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-1 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+
+            if (strpos($node->country_code,'hk') !== false && $node->status == 1){
+                $firstnode[] = $node;
+            }
+        }
+
+        if (empty($firstnode)) {
+            // 查找其他国家的第一个
+            foreach ($nodeList as  $node) {
+                // 在线人数
+                $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-1 minutes'))->latest('log_time')->first();
+                $node->online_users = $online_log->online_user ?? 0;
+
+                if ( $node->status == 1){
+                    $firstnode[] = $node;
+                }
+            }
+        }
+        //找到人数最小的
+        $min["key"] = "";
+        $min["value"] = 0;
+        $keys = "online_users";
+
+        $midormax = $this->phpMaxMin($firstnode,$keys);
+
+
+        $servers = [];
+        foreach ($firstnode as $key => $v ){
+            if($key == $midormax["min"]["key"])
+            {
+                $servers = $v->config($user);
+                $servers[$keys] = $firstnode[$key][$keys];
+            }
+        }
+        return response()->json(['ret' => 1, 'data' => $servers], 200);
+    }
+
+    //获取节点
+    public function nodeList(int $id = null)
+    {
+        $user = auth()->user();
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $nodeList = $query->where("type",'!=',2)->orderByDesc('sort')->orderBy('id')->get();
+        //var_dump($nodes); die();
+        if (isset($id)) {
+            $nodes = $user->nodes()->get();
+            $node = $nodes->find($id);
+
+            if (empty($node)) {
+                return response()->json([], 204);
+            }
+
+            return response()->json($node->config($user));
+        }
+
+        $temp = array();
+        $servers = [];
+        $firstnode = [];
+        foreach ($nodeList as $node) {
+
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+            $firstnode[] = $node;
+
+        }
+
+        foreach ($firstnode as $key => $val){
+            $servers[] = $val->config($user);
+            $servers[$key]["ip"] = $firstnode[$key]["ip"];
+            $servers[$key]["online_users"] = $firstnode[$key]["online_users"];
+            $servers[$key]["country_code"] = $firstnode[$key]["country_code"];
+        }
+
+        return response()->json(['ret' => 1, 'data' => $servers]);
+    }
+
+
+    public function phpMaxMin($arr = [],$keys = ''){
+        $max['key'] = '';
+        $max['value'] = '';
+        $min['key'] = '';
+        $min['value'] = '';
+
+        foreach ($arr as $key => $val){
+
+            if($max['key'] === ''){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if((int)$max['value'] < $val[$keys]){
+
+                $max['key'] = $key;
+                $max['value'] = $val[$keys];
+
+            }
+
+            if($min['key'] === ''){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+
+            }
+
+            if((int)$min['value'] > $val[$keys]){
+
+                $min['key'] = $key;
+                $min['value'] = $val[$keys];
+            }
+
+        }
+        $array['max'] = $max;
+        $array['min'] = $min;
+        return $array;
+
+    }
+
+}

+ 161 - 0
app/Http/Controllers/Api/Client/V4Controller.php

@@ -0,0 +1,161 @@
+<?php
+
+namespace App\Http\Controllers\Api\Client;
+
+use App\Http\Controllers\ClientController;
+use App\Http\Controllers\Controller;
+use App\Models\Node;
+use App\Models\User;
+use Illuminate\Http\Request;
+use DB;
+
+class V4Controller  extends Controller
+{
+    public function __construct()
+    {
+        $this->middleware('auth:api')->except('login', 'register', 'shop', 'getConfig','version','buy','ClashConfig','getsysconfig','GetV2rayNode','checkNodeWeihu','UserDis');
+        auth()->shouldUse('api');
+    }
+
+    public function  checkNodeWeihu() {
+        $query = Node::with(['onlineLogs', 'dailyDataFlows']);
+        $nodeList = $query->where("country_code","=","hk")->get();
+        $nodeOlin = [];
+
+        foreach ($nodeList as $key => $node) {
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $online_users = $online_log->online_user ?? 0;
+            $nodeOlin[$key]["name"] =$node->name;
+            $nodeOlin[$key]["id"] =$node->id;
+            $nodeOlin[$key]["online_user"] = $online_users;
+        }
+
+       // var_dump($nodeOlin); die();
+        $logInfo = [];
+        foreach ($nodeOlin as $key => $vva) {
+            $input = [
+                "status" => $vva["online_user"] > 10 ? 1 : 0
+            ];
+            $post = Node::find($vva["id"]);
+//            var_dump($post["name"]);
+//            var_dump($post["status"]); die();
+            if($post->update($input)){
+                $logInfo[$key]["id"] = $vva["id"];
+                $logInfo[$key]["name"] =$vva["name"];
+                $logInfo[$key]["status"] = "{$input["status"]}更新成功";
+            }else{
+                $logInfo[$key]["id"] = $vva["id"];
+                $logInfo[$key]["name"] =$vva["name"];
+                $logInfo[$key]["status"] = "{$input["status"]}更新失败";
+            }
+//            var_dump($logInfo);
+//            die();
+        }
+
+        return response()->json(['ret' => 1, 'data' => $logInfo], 200);
+    }
+
+    public function GetV2rayNode(Request  $request){
+
+        $user = User::query();
+        $node = Node::query();
+        $userinfo = $user->where('email','=','17624688@qq.com')->get();
+
+        //$query = $query->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $retlist = $node->where('type','=',2)->get();
+        $servers = [];
+        foreach ($retlist as $key => $v ){
+            $servers[] =  $v->config($userinfo[0]);
+        }
+        return (new ClientController)->config("", $userinfo[0], $servers);
+       //return response()->json(['ret' => 1, 'data' => $servers]);
+        //return response()->json(['ret' => 1, 'data' => ['userinfo'=>$userinfo,'servers'=>$servers],'']);
+    }
+
+
+    public function AutoNode(Request $request){
+        $auth_user = auth()->user();
+        //select b.node_id, max(b.online_user) as online_user from node_online_log as b group by b.node_id
+        $sub_query = 'select b.node_id, max(b.online_user) as online_user from node_online_log as b group by b.node_id';
+        $query =  Node::query();
+        //select aa.online_user, aa.node_id, bb.* from (select b.node_id, max(log_time), b.online_user from node_online_log as b group by b.node_id) as aa left join node as bb on bb.id = aa.node_id where bb.country_code = 'hk' group by aa.online_user
+        //limit 1
+        $nodeList = $query->from(DB::raw('('.$sub_query.') as a'))
+            ->leftJoin('node as bb','bb.id','=','a.node_id')
+            ->where('bb.country_code','=','hk')
+            ->groupBy('a.online_user')
+            ->limit(1)
+            ->get(['a.online_user','bb.*']);
+        $keys = "online_users";
+        foreach ($nodeList as $key => $v ){
+            $servers = $v->config($auth_user);
+            $servers[$keys] = $v["online_user"];
+        }
+        return response()->json(['ret' => 1, 'data' => $servers], 200);
+    }
+
+    /**
+     * 获取全部节点
+     * @param int|null $id
+     * @return \Illuminate\Http\JsonResponse
+     */
+    public function nodeList(int $id = null)
+    {
+        $user = auth()->user();
+        $query = $user->nodes()->with(['labels', 'level_table','onlineLogs']);
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get();
+        //var_dump($nodes); die();
+        if (isset($id)) {
+            $nodes = $user->nodes()->get();
+            $node = $nodes->find($id);
+
+            if (empty($node)) {
+                return response()->json([], 204);
+            }
+
+            return response()->json($node->config($user));
+        }
+
+        $temp = array();
+        $servers = [];
+        $firstnode = [];
+        foreach ($nodeList as $node) {
+
+            // 在线人数
+            $online_log = $node->onlineLogs()->where('log_time', '>=', strtotime('-5 minutes'))->latest('log_time')->first();
+            $node->online_users = $online_log->online_user ?? 0;
+            $firstnode[] = $node;
+
+        }
+
+        foreach ($firstnode as $key => $val){
+            $servers[] = $val->config($user);
+            $servers[$key]["ip"] = $firstnode[$key]["ip"];
+            $servers[$key]["online_users"] = $firstnode[$key]["online_users"];
+            $servers[$key]["country_code"] = $firstnode[$key]["country_code"];
+        }
+
+        return response()->json(['ret' => 1, 'data' => $servers]);
+    }
+
+    public function UserDis(Request $request){
+
+        $id = $request->input('id');
+
+        // 从请求中获取需要更新的数据
+        $data = [
+            'enable' => 0,
+            'expired_at' => '2023-05-01 15:35:19',
+            'remark' => '已经退款'
+        ];
+
+        // 使用Eloquent ORM查找对应的用户记录
+        $user = User::find($id);
+
+        // 使用update()方法更新用户记录
+        return $user->update($data);
+    }
+
+
+}

+ 96 - 0
app/Http/Controllers/Api/Client/XrayRConfig.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Http\Controllers\Api\Client;
+
+use App\Http\Controllers\Controller;
+use File;
+use Illuminate\Http\Request;
+use Symfony\Component\Yaml\Yaml;
+use function Matrix\diagonal;
+
+class XrayRConfig extends Controller
+{
+    public function GetConfig(Request $request){
+        $level  = $request->input("level");
+        $host = $request->input("host");
+        $id = $request->input("id");
+        $ptype = $request->input("ptype");
+        $key = $request->input("key");
+        $type = $request->input("type");
+
+
+        $yaml = <<<EOD
+        Log:
+          Level: none # Log level: none, error, warning, info, debug
+          AccessPath: # /etc/XrayR/access.Log
+          ErrorPath: # /etc/XrayR/error.log
+        DnsConfigPath: # /etc/XrayR/dns.json # Path to dns config, check https://xtls.github.io/config/base/dns/ for help
+        RouteConfigPath: # /etc/XrayR/route.json # Path to route config, check https://xtls.github.io/config/base/route/ for help
+        OutboundConfigPath: # /etc/XrayR/custom_outbound.json # Path to custom outbound config, check https://xtls.github.io/config/base/outbound/ for help
+        ConnetionConfig:
+          Handshake: 4 # Handshake time limit, Second
+          ConnIdle: 30 # Connection idle time limit, Second
+          UplinkOnly: 2 # Time limit when the connection downstream is closed, Second
+          DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second
+          BufferSize: 64 # The internal cache size of each connection, kB
+        Nodes:
+          -
+            PanelType: "$ptype" # Panel type: SSpanel, V2board, PMpanel, , Proxypanel
+            ApiConfig:
+              ApiHost: "$host"
+              ApiKey: "$key"
+              NodeID: $id
+              NodeType: $type # Node type: V2ray, Shadowsocks, Trojan, Shadowsocks-Plugin
+              Timeout: 30 # Timeout for the api request
+              EnableVless: false # Enable Vless for V2ray Type
+              EnableXTLS: false # Enable XTLS for V2ray and Trojan
+              SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable
+              DeviceLimit: 0 # Local settings will replace remote settings, 0 means disable
+              RuleListPath: # ./rulelist Path to local rulelist file
+            ControllerConfig:
+              ListenIP: 0.0.0.0 # IP address you want to listen
+              SendIP: 0.0.0.0 # IP address you want to send pacakage
+              UpdatePeriodic: 60 # Time to update the nodeinfo, how many sec.
+              EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well
+              DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
+              EnableProxyProtocol: false # Only works for WebSocket and TCP
+              EnableFallback: false # Only support for Trojan and Vless
+              FallBackConfigs:  # Support multiple fallbacks
+                -
+                  SNI: # TLS SNI(Server Name Indication), Empty for any
+                  Path: # HTTP PATH, Empty for any
+                  Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/fallback/ for details.
+                  ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for dsable
+              CertConfig:
+                CertMode: dns # Option about how to get certificate: none, file, http, dns. Choose "none" will forcedly disable the tls config.
+                CertDomain: "node1.test.com" # Domain to cert
+                CertFile: ./cert/node1.test.com.cert # Provided if the CertMode is file
+                KeyFile: ./cert/node1.test.com.key
+                Provider: alidns # DNS cert provider, Get the full support list here: https://go-acme.github.io/lego/dns/
+                Email: test@me.com
+                DNSEnv: # DNS ENV option used by DNS provider
+                  ALICLOUD_ACCESS_KEY: aaa
+                  ALICLOUD_SECRET_KEY: bbb
+        EOD;
+//        $defaultConfig = base_path().'/resources/rules/config.yml';
+//        //$config = [];
+//        if (File::exists($defaultConfig)) {
+//            $config = yaml_parse_file($defaultConfig);
+//        }
+
+        //https://api.ruanjian.buzz/api/client/v1/getConfig?level=debug&ptype=Proxypanel&host=http://apitx.naiyout.buzz&key=p47fTOcWKOvKuZBP&id=22&type=Shadowsocks
+        //var_dump(urlencode("http://apitx.naiyout.buzz"));
+
+//        $config["Log"]["Level"] = $request->input("level");
+//        $config["Nodes"][0]["PanelType"] =  $ptype;
+//        $config["Nodes"][0]["ApiConfig"]["ApiHost"] = $host;
+//        $config["Nodes"][0]["ApiConfig"]["ApiKey"] = $key;
+//        $config["Nodes"][0]["ApiConfig"]["NodeID"] = (int)$id;
+//        $config["Nodes"][0]["ApiConfig"]["NodeType"] = $type;
+
+        echo  $yaml;
+        die();
+
+        return Yaml::dump($config,6,4,0);
+    }
+}

+ 5 - 2
app/Http/Controllers/Api/WebApi/BaseController.php

@@ -6,6 +6,7 @@ use App\Models\Node;
 use App\Models\User;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
+use Log;
 use Response;
 use Validator;
 
@@ -14,6 +15,8 @@ class BaseController
     // 上报节点心跳信息
     public function setNodeStatus(Request $request, Node $node): JsonResponse
     {
+
+        //Log::info('上报节点心跳信息-'.var_export($request->all(), true));
         $validator = Validator::make($request->all(), ['cpu' => 'required', 'mem' => 'required', 'disk' => 'required', 'uptime' => 'required|numeric']);
 
         if ($validator->fails()) {
@@ -21,9 +24,9 @@ class BaseController
         }
 
         $data = array_map('intval', $validator->validated());
-
+      //
         if ($node->heartbeats()->create([
-            'uptime' => $data['uptime'],
+            'uptime' => $data['uptime'],//
             'load' => implode(' ', [$data['cpu'] / 100, $data['mem'] / 100, $data['disk'] / 100]),
             'log_time' => time(),
         ])) {

+ 60 - 0
app/Http/Controllers/Api/WebApi/SSController.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace App\Http\Controllers\Api\WebApi;
+
+use App\Models\Node;
+use Illuminate\Http\JsonResponse;
+
+class SSController extends BaseController
+{
+    // 获取节点信息
+    public function getNodeInfo(Node $node): JsonResponse
+    {
+        $data = [
+            'id' => $node->id,
+            'method' => $node->method,
+            'protocol' => $node->protocol,
+            'obfs' => $node->obfs,
+            'obfs_param' => $node->obfs_param ?? '',
+            'is_udp' => $node->is_udp,
+            'speed_limit' => $node->getRawOriginal('speed_limit'),
+            'client_limit' => $node->client_limit,
+            'sinlge' => $node->single,
+            'port' => $node->port,
+            'passwd' => $node->passwd ?? '',
+            'push_port' => $node->push_port
+        ];
+
+//        i['port'] = $node->port;
+//        }f ($node->single) {
+//    $data
+
+        return $this->returnData('获取节点信息成功', 'success', 200, $data);
+    }
+
+    // 获取节点可用的用户列表
+    public function getUserList(Node $node): JsonResponse
+    {
+        foreach ($node->users() as $user) {
+//            $data[] = [
+//                'uid'         => $user->id,
+//                'port'        => $user->port,
+//                'passwd'      => $node->passwd,
+//                'speed_limit' => $user->getRawOriginal('speed_limit'),
+//                'enable'      => $user->enable,
+//            ];
+            $data[] = [
+                'uid' => $user->id,
+                'port' => $user->port,
+                'passwd' => $user->passwd,
+                'method' => $node->method,
+                'protocol' => $user->protocol,
+                'speed_limit' => $user->getRawOriginal('speed_limit'),
+                'enable' => $user->enable,
+                'client_limit' => $user->client_limit,
+            ];
+        }
+
+        return $this->returnData('获取用户列表成功', 'success', 200, $data ?? [], ['updateTime' => time()]);
+    }
+}

+ 1 - 0
app/Http/Controllers/Api/WebApi/TrojanController.php

@@ -31,6 +31,7 @@ class TrojanController extends BaseController
                 'uid' => $user->id,
                 'password' => $user->passwd,
                 'speed_limit' => $user->getRawOriginal('speed_limit'),
+                'client_limit' => $user->client_limit,
             ];
         }
 

+ 2 - 1
app/Http/Controllers/Api/WebApi/V2RayController.php

@@ -29,7 +29,7 @@ class V2RayController extends BaseController
             'pem' => $cert->pem ?? '',
             'v2_license' => (string) sysConfig('v2ray_license'),
             'v2_alter_id' => $node->v2_alter_id,
-            'v2_port' => $node->v2_port,
+            'v2_port' => $node->port,
             'v2_method' => $node->v2_method,
             'v2_net' => $node->v2_net,
             'v2_type' => $node->v2_type,
@@ -48,6 +48,7 @@ class V2RayController extends BaseController
                 'uid' => $user->id,
                 'vmess_uid' => $user->vmess_id,
                 'speed_limit' => $user->getRawOriginal('speed_limit'),
+                'client_limit' => $user->client_limit,
             ];
         }
 

+ 245 - 8
app/Http/Controllers/AuthController.php

@@ -40,7 +40,8 @@ class AuthController extends Controller
                 return Redirect::route('admin.index');
             }
 
-            return Redirect::route('home');
+         return Redirect::route('home');
+            //return Redirect::route('down');
         }
 
         return view('auth.login');
@@ -100,6 +101,227 @@ class AuthController extends Controller
 
         return redirect()->back();
     }
+    public function logina(Request $request)
+    {
+        $validator = Validator::make($request->all(), ['email' => 'required|email', 'password' => 'required']);
+
+        if ($validator->fails()) {
+            return Redirect::back()->withInput()->withErrors($validator->errors());
+        }
+
+        // 是否校验验证码
+        $captcha = $this->check_captcha($request);
+        if ($captcha !== false) {
+            return $captcha;
+        }
+
+        // 验证账号并创建会话
+        if (! Auth::attempt($validator->validated(), $request->input('remember'))) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_failed'));
+        }
+        $user = Auth::getUser();
+
+        if (! $user) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_error'));
+        }
+
+        if ($request->routeIs('admin.login.post') && $user->cannot('admin.index')) {
+            // 管理页面登录
+            // 非权限者清场
+            Auth::logout();
+
+            return Redirect::route('login');
+        }
+
+        // 校验普通用户账号状态
+        if ($user->status === -1) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.account_baned'));
+        }
+
+        if ($user->status === 0 && sysConfig('is_activate_account')) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.active.promotion.0').'<a href="'.route('active').'?email='.$user->email.
+                '" target="_blank">👉【'.trans('common.active_item', ['attribute' => trans('common.account')]).'】👈</span></a><br>'.trans('auth.active.promotion.1'));
+        }
+
+        // 写入登录日志
+        $this->addUserLoginLog($user->id, IP::getClientIp());
+
+        // 更新登录信息
+        $user->update(['last_login' => time()]);
+
+        return Redirect::route('shop');
+    }
+
+    //登陆并到工单
+    public function logintoticket(Request $request)
+    {
+        $validator = Validator::make($request->all(), ['email' => 'required|email', 'password' => 'required']);
+
+        if ($validator->fails()) {
+            return Redirect::back()->withInput()->withErrors($validator->errors());
+        }
+
+        // 是否校验验证码
+        $captcha = $this->check_captcha($request);
+        if ($captcha !== false) {
+            return $captcha;
+        }
+
+        // 验证账号并创建会话
+        if (! Auth::attempt($validator->validated(), $request->input('remember'))) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_failed'));
+        }
+        $user = Auth::getUser();
+
+        if (! $user) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_error'));
+        }
+
+        if ($request->routeIs('admin.login.post') && $user->cannot('admin.index')) {
+            // 管理页面登录
+            // 非权限者清场
+            Auth::logout();
+
+            return Redirect::route('login');
+        }
+
+        // 校验普通用户账号状态
+        if ($user->status === -1) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.account_baned'));
+        }
+
+        if ($user->status === 0 && sysConfig('is_activate_account')) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.active.promotion.0').'<a href="'.route('active').'?email='.$user->email.
+                '" target="_blank">👉【'.trans('common.active_item', ['attribute' => trans('common.account')]).'】👈</span></a><br>'.trans('auth.active.promotion.1'));
+        }
+
+        // 写入登录日志
+        $this->addUserLoginLog($user->id, IP::getClientIp());
+
+        // 更新登录信息
+        $user->update(['last_login' => time()]);
+
+        return Redirect::route('ticket');
+    }
+    //登陆并到工单
+    public function Loginprofile(Request $request)
+    {
+        $validator = Validator::make($request->all(), ['email' => 'required|email', 'password' => 'required']);
+
+        if ($validator->fails()) {
+            return Redirect::back()->withInput()->withErrors($validator->errors());
+        }
+
+        // 是否校验验证码
+        $captcha = $this->check_captcha($request);
+        if ($captcha !== false) {
+            return $captcha;
+        }
+
+        // 验证账号并创建会话
+        if (! Auth::attempt($validator->validated(), $request->input('remember'))) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_failed'));
+        }
+        $user = Auth::getUser();
+
+        if (! $user) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_error'));
+        }
+
+        if ($request->routeIs('admin.login.post') && $user->cannot('admin.index')) {
+            // 管理页面登录
+            // 非权限者清场
+            Auth::logout();
+
+            return Redirect::route('login');
+        }
+
+        // 校验普通用户账号状态
+        if ($user->status === -1) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.account_baned'));
+        }
+
+        if ($user->status === 0 && sysConfig('is_activate_account')) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.active.promotion.0').'<a href="'.route('active').'?email='.$user->email.
+                '" target="_blank">👉【'.trans('common.active_item', ['attribute' => trans('common.account')]).'】👈</span></a><br>'.trans('auth.active.promotion.1'));
+        }
+
+        // 写入登录日志
+        $this->addUserLoginLog($user->id, IP::getClientIp());
+
+        // 更新登录信息
+        $user->update(['last_login' => time()]);
+
+        return Redirect::route('profile');
+    }
+
+    //登陆并到工单
+    public function logintoreferral(Request $request)
+    {
+        $validator = Validator::make($request->all(), ['email' => 'required|email', 'password' => 'required']);
+
+        if ($validator->fails()) {
+            return Redirect::back()->withInput()->withErrors($validator->errors());
+        }
+
+        // 是否校验验证码
+        $captcha = $this->check_captcha($request);
+        if ($captcha !== false) {
+            return $captcha;
+        }
+
+        // 验证账号并创建会话
+        if (! Auth::attempt($validator->validated(), $request->input('remember'))) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_failed'));
+        }
+        $user = Auth::getUser();
+
+        if (! $user) {
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.login_error'));
+        }
+
+        if ($request->routeIs('admin.login.post') && $user->cannot('admin.index')) {
+            // 管理页面登录
+            // 非权限者清场
+            Auth::logout();
+
+            return Redirect::route('login');
+        }
+
+        // 校验普通用户账号状态
+        if ($user->status === -1) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.error.account_baned'));
+        }
+
+        if ($user->status === 0 && sysConfig('is_activate_account')) {
+            Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+            return Redirect::back()->withInput()->withErrors(trans('auth.active.promotion.0').'<a href="'.route('active').'?email='.$user->email.
+                '" target="_blank">👉【'.trans('common.active_item', ['attribute' => trans('common.account')]).'】👈</span></a><br>'.trans('auth.active.promotion.1'));
+        }
+
+        // 写入登录日志
+        $this->addUserLoginLog($user->id, IP::getClientIp());
+
+        // 更新登录信息
+        $user->update(['last_login' => time()]);
+
+        return Redirect::route('commission');
+    }
 
     // 校验验证码
     private function check_captcha(Request $request)
@@ -213,6 +435,12 @@ class AuthController extends Controller
 
         Session::forget('register_token');
 
+        if ($aff < 0){
+            var_dump($aff);
+            die();
+        }
+        Session::put("register_aff",strval($aff));
+
         // 是否开启注册
         if (! sysConfig('is_register')) {
             return Redirect::back()->withErrors(trans('auth.register.error.disable'));
@@ -276,7 +504,6 @@ class AuthController extends Controller
         // 获取aff
         $affArr = $this->getAff($code, $aff);
         $inviter_id = $affArr['inviter_id'];
-
         $transfer_enable = MB * ((int) sysConfig('default_traffic') + ($inviter_id ? (int) sysConfig('referral_traffic') : 0));
 
         // 创建新用户
@@ -395,12 +622,22 @@ class AuthController extends Controller
         // 没有用邀请码或者邀请码是管理员生成的,则检查cookie或者url链接
         if (! $data['inviter_id']) {
             // 检查一下cookie里有没有aff
-            $cookieAff = \Request::hasCookie('register_aff');
-            if ($cookieAff) {
-                $data['inviter_id'] = User::find($cookieAff) ? $cookieAff : null;
-            } elseif ($aff) { // 如果cookie里没有aff,就再检查一下请求的url里有没有aff,因为有些人的浏览器会禁用了cookie,比如chrome开了隐私模式
-                $data['inviter_id'] = User::find($aff) ? $aff : null;
-            }
+//            $cookieAff = \Request::hasCookie('register_aff');
+//            if ($cookieAff) {
+//                $data['inviter_id'] = User::find($cookieAff) ? $cookieAff : null;
+//            } elseif ($aff) { // 如果cookie里没有aff,就再检查一下请求的url里有没有aff,因为有些人的浏览器会禁用了cookie,比如chrome开了隐私模式
+//                $data['inviter_id'] = User::find($aff) ? $aff : null;
+//            }
+
+//            if ($aff)
+//            {
+//                $varr =  User::find($aff) ? $aff : null;
+//                var_dump($aff);
+//                var_dump($varr);
+//                die();
+//            }
+
+            $data['inviter_id'] = User::find($aff) ? $aff : null;
         }
 
         return $data;

+ 168 - 0
app/Http/Controllers/DownloadControllers.php

@@ -0,0 +1,168 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Controllers\Controller;
+use App\Models\Node;
+use App\Models\Article;
+use Helpers;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Illuminate\Validation\Rule;
+use Illuminate\Support\Facades\Redis;
+use Auth;
+use Session;
+use App\Models\Sms;
+
+class DownloadControllers extends Controller
+{
+    public  function index(){
+        if(Auth::check()){
+            // 用户转换
+            if (Session::has('user')) {
+                auth()->loginUsingId(Session::get('user'));
+                Session::forget('user');
+            }
+            $user = auth()->user();
+            $totalTransfer = $user->transfer_enable;
+            $usedTransfer = $user->usedTraffic();
+            $unusedTraffic = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;
+            $expireTime = $user->expired_at;
+            $profile= auth()->user()->profile();
+            $data = [];
+            if (Node::whereIn('type', [1, 4])->whereStatus(1)->exists()) {
+                $data[] = 'ss';
+                //array_push
+            }
+            if (Node::whereType(2)->whereStatus(1)->exists()) {
+                $data[] = 'v2';
+            }
+            if (Node::whereType(3)->whereStatus(1)->exists()) {
+                $data[] = 'trojan';
+            }
+
+            $subscribe = auth()->user()->subscribe;
+            //$subscribe_link = route('sub', $subscribe->code);
+            $subscribe_link = sysConfig('subscribe_domain') . "/s/" . $subscribe->code;
+            $subscribe_linkA = "https://user.vipsix.top" . "/s/" . $subscribe->code;
+            $subscribe_linkB = "https://user.vipfive.top" . "/s/" . $subscribe->code;
+            $subscribe_linkC = "http://user.vipfive.top" . "/s/" . $subscribe->code;
+
+//            $subarr = ["A"=>"","B"=>""];
+
+            return view('down.dowload', [
+                "islogin"                 => 1,
+                'remainDays'       => $expireTime < date('Y-m-d') ? -1 : Helpers::daysToNow($expireTime),
+                'username'                  => $profile["account"],
+                'unusedTraffic'             => flowAutoShow($unusedTraffic),
+                'totalTransfer'             => flowAutoShow($totalTransfer),
+                'expireTime'                => $expireTime,
+                'banedTime'                 => $user->ban_time,
+                'unusedPercent'             => $totalTransfer > 0 ? round($unusedTraffic / $totalTransfer, 2) * 100 : 0,
+                "android"                 => Article::whereId(8)->first(),
+                "ios"                     => Article::whereId(7)->first(),
+                "windows"                 => Article::whereId(9)->first(),
+                "game"                 => Article::whereId(5)->first(),
+                "mac"                   => Article::whereId(6)->first(),
+                "wx"                   => Article::whereId(10)->first(),
+                "v2"                   => Article::whereId(11)->first(),
+                "pg"                   => Article::whereId(7)->first(),
+                "sp"                   => Article::whereId(13)->first(),
+                'subUrl'                  => sysConfig('subscribe_domain') . "/s/" . $subscribe->code,
+                'sub'                     => $data,
+                'paying_user'             => auth()->user()->activePayingUser(), // 付费用户判断
+                'Shadowrocket_install'    => 'itms-services://?action=download-manifest&url='.sysConfig('website_url').'/clients/Shadowrocket.plist', // 客户端安装
+                'Quantumult_install'      => 'itms-services://?action=download-manifest&url='.sysConfig('website_url').'/clients/Quantumult.plist', // 客户端安装
+                'subscribe_status'        => $subscribe->status, // 订阅连接
+                'link'                    => $subscribe_link,
+                'subscribe_link'          => 'sub://'.base64url_encode($subscribe_link),
+                'Shadowrocket_link'       => 'shadowrocket://add/sub://'.base64url_encode($subscribe_link).'?remarks='.sysConfig('website_name'),
+                'Shadowrocket_linkA'       => 'shadowrocket://add/sub://'.base64url_encode($subscribe_linkA).'?remarks='.sysConfig('website_name'),
+                'Shadowrocket_linkB'       => 'shadowrocket://add/sub://'.base64url_encode($subscribe_linkB).'?remarks='.sysConfig('website_name'),
+                'Shadowrocket_linkC'       => 'shadowrocket://add/sub://'.base64url_encode($subscribe_linkC).'?remarks='.sysConfig('website_name'),
+
+
+                'Shadowrocket_linkQrcode' => 'sub://'.base64url_encode($subscribe_link).'#'.base64url_encode(sysConfig('website_name')),
+                'Clash_link'              => "clash://install-config?url={$subscribe_link}",
+                'Clash_linkA'              => "clash://install-config?url={$subscribe_linkA}",
+                'Clash_linkB'              => "clash://install-config?url={$subscribe_linkB}",
+                'Clash_linkC'              => "clash:///install-config?url={$subscribe_linkC}",
+                'Quantumultx'             => 'quantumult-x:///update-configuration?remote-resource='.json_encode([
+                        'server_remote'  => "{$subscribe_link},  tag=".urlencode(sysConfig('website_name').' '.sysConfig('website_url')),
+                        'filter_remote'  => '',
+                        'rewrite_remote' => '',
+                    ]),
+                'Quantumult_linkOut'      => 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/Pro.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/Rejection.conf'),
+                'Quantumult_linkIn'       => 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/BacktoCN.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/Rejection.conf'),
+            ]);
+        } else {
+            return view('down.dowIndex',[
+                "islogin"  => 0,
+                "android"                 => Article::whereId(8)->first(),
+                "ios"                     => Article::whereId(7)->first(),
+                "windows"                 => Article::whereId(9)->first(),
+                 "game"                 => Article::whereId(5)->first(),
+                "mac"                   => Article::whereId(6)->first(),
+                  "wx"                   => Article::whereId(10)->first(),
+                  "v2"                   => Article::whereId(11)->first(),
+                "pg"                   => Article::whereId(7)->first(),
+                "sp"                   => Article::whereId(13)->first(),
+                ]);
+        }
+    }
+
+    public function down(){
+
+    }
+
+    public function article(Request $request)
+    {
+        $id = $request->input("id");
+
+        $query = Article::whereId($id)->first();
+
+        //var_dump($query); die();
+
+        return view('down.article',["article" => $query]);
+    }
+
+    /**
+   $values = Redis::lrange('dxzym',0,-1); //获取所有
+    if(!empty($values)){
+    foreach ($values as $key => $value){
+
+    $data = json_decode($value, true);
+    $datas[$key]["fromNumber"] = $data["fromNumber"];
+    $datas[$key]["text"] = $data["text"];
+    $datas[$key]["time"] = $data["time"];
+
+    Redis::lrem('dxzym',$key,$value);
+
+    }
+    }
+     * @param Request $request
+     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     */
+    public function ShowCode(Request  $request){
+//        $datas = [];
+//
+//        $values = Redis::lrange('dxzym',0,-1); //获取所有
+//        if(!empty($values)){
+//            foreach ($values as $key => $value){
+//
+//                $data = json_decode($value, true);
+//                $datas[$key]["fromNumber"] = $data["fromNumber"];
+//                $datas[$key]["text"] = $data["text"];
+//                $datas[$key]["time"] = $data["time"];
+//
+//               Redis::lrem('dxzym',$key,$value);
+//
+//            }
+//        }
+
+        $sql = Sms::where('created_at','>=',date('Y-m-d H:i:s', strtotime(' -10 minutes')))->orderByDesc('created_at')->get();
+
+        //return response()->json(['ret' => 1, 'code' => $sql], 200);
+        return view('down.zym',['CodeList' => $sql]);
+    }
+}

+ 12 - 7
app/Http/Controllers/Gateway/AbstractPayment.php

@@ -30,18 +30,23 @@ abstract class AbstractPayment
     /**
      * @param  string  $trade_no  本地订单号
      * @param  string  $out_trade_no  外部订单号
-     * @param  int  $amount  交易金额
+     * @param  string  $amount  交易金额
      *
      * @return int
      */
-    protected function addPamentCallback(string $trade_no, string $out_trade_no, int $amount): int
+    protected function addPamentCallback(string $trade_no, string $out_trade_no,$amount = ""): int
     {
-        $log = new PaymentCallback();
-        $log->trade_no = $trade_no;
-        $log->out_trade_no = $out_trade_no;
-        $log->amount = $amount;
+        $payment = Payment::whereTradeNo($trade_no)->with('order')->first();
+        if ($payment) {
+            $log = new PaymentCallback();
+            $log->trade_no = $payment->order->sn;
+            $log->out_trade_no = $out_trade_no;
+            $log->amount = $amount == "" ? (string)$payment->order->amount : $amount;
+            return $log->save();
+        }
+
+        return -1;
 
-        return $log->save();
     }
 
     // MD5验签

+ 48 - 25
app/Http/Controllers/Gateway/BitpayX.php

@@ -3,7 +3,6 @@
 namespace App\Http\Controllers\Gateway;
 
 use Auth;
-use Http;
 use Illuminate\Http\JsonResponse;
 use Log;
 use Response;
@@ -16,15 +15,20 @@ class BitpayX extends AbstractPayment
 
         $data = [
             'merchant_order_id' => $payment->trade_no,
-            'price_amount'      => $payment->amount,
+            'price_amount'      => (float) $payment->amount,
             'price_currency'    => 'CNY',
             'title'             => '支付单号:'.$payment->trade_no,
             'description'       => sysConfig('subject_name') ?: sysConfig('website_name'),
             'callback_url'      => route('payment.notify', ['method' => 'bitpayx']),
             'success_url'       => route('invoice'),
             'cancel_url'        => route('invoice'),
-            'token'             => $this->sign($payment->trade_no),
+            'token'             => $this->sign($this->prepareSignId($payment->trade_no)),
         ];
+        if ($request->input('type') == 1) {
+            $data['pay_currency'] = 'ALIPAY';
+        } elseif ($request->input('type') == 3) {
+            $data['pay_currency'] = 'WECHAT';
+        }
         $result = $this->sendRequest($data);
 
         if ($result['status'] === 200 || $result['status'] === 201) {
@@ -34,54 +38,73 @@ class BitpayX extends AbstractPayment
             return Response::json(['status' => 'success', 'url' => $result['payment_url'], 'message' => '创建订单成功!']);
         }
 
-        Log::warning('创建订单错误:'.var_export($result, true));
+        Log::alert('【BitpayX】创建订单错误:'.var_export($result, true));
 
-        return Response::json(['status' => 'fail', 'message' => '创建订单失败!'.$result['error']]);
+        return Response::json(['status' => 'fail', 'message' => '创建订单失败! 请联系管理员']);
     }
 
-    private function sign($tradeNo): string
+    private function sign($data)
+    {
+        return strtolower(md5(md5($data).sysConfig('bitpay_secret')));
+    }
+
+    private function prepareSignId($tradeNo): string
     {
         $data = [
             'merchant_order_id' => $tradeNo,
             'secret'            => sysConfig('bitpay_secret'),
             'type'              => 'FIAT',
         ];
+        ksort($data, SORT_STRING);
 
-        return $this->aliStyleSign($data, sysConfig('bitpay_secret'));
+        return http_build_query($data);
     }
 
     private function sendRequest($data, $type = 'createOrder')
     {
-        $client = Http::baseUrl('https://api.mugglepay.com/v1/')
-            ->timeout(15)
-            ->withHeaders([
-                'token'        => sysConfig('bitpay_secret'),
-                'content-type' => 'application/json',
-            ]);
-
-        if ($type === 'query') {
-            $response = $client->get('orders/merchant_order_id/status?id='.$data['merchant_order_id']);
-        } else {// Create Order
-            $response = $client->post('orders', ['body' => json_encode($data)]);
-        }
-        if ($response->failed()) {
-            Log::error('BitPayX请求支付错误:'.var_export($response, true));
+        $bitpayGatewayUri = 'https://api.mugglepay.com/v1/';
+        $headers = ['content-type: application/json', 'token: '.sysConfig('bitpay_secret')];
+        $curl = curl_init();
+        if ($type === 'createOrder') {
+            $bitpayGatewayUri .= 'orders';
+            curl_setopt($curl, CURLOPT_URL, $bitpayGatewayUri);
+            curl_setopt($curl, CURLOPT_POST, 1);
+            $data_string = json_encode($data);
+            curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
+        } elseif ($type === 'query') {
+            $bitpayGatewayUri .= 'orders/merchant_order_id/status?id='.$data['merchant_order_id'];
+            curl_setopt($curl, CURLOPT_URL, $bitpayGatewayUri);
+            curl_setopt($curl, CURLOPT_HTTPGET, 1);
         }
+        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+        $result = curl_exec($curl);
+        curl_close($curl);
 
-        return $response->json();
+        return json_decode($result, true);
     }
 
-    //Todo: Postman虚拟测试通过,需要真实数据参考验证
     public function notify($request): void
     {
         $tradeNo = $request->input(['merchant_order_id']);
-        if ($request->input(['status']) === 'PAID' && hash_equals($this->sign($tradeNo), $request->input(['token']))) {
+        // 准备待签名数据
+        $str_to_sign = $this->prepareSignId($tradeNo);
+        if ($request->input(['status']) === 'PAID' && $this->verify_bit($str_to_sign, $request->input(['token']))) {
             if ($this->paymentReceived($tradeNo)) {
                 exit(json_encode(['status' => 200]));
             }
         } else {
-            Log::info('BitpayX:交易失败');
+            Log::error('【BitpayX】交易失败:'.var_export($request->all(), true));
         }
         exit(json_encode(['status' => 400]));
     }
+
+    private function verify_bit($data, $signature)
+    {
+        $mySign = $this->sign($data);
+
+        return $mySign === $signature;
+    }
 }

+ 3 - 2
app/Http/Controllers/Gateway/EPay.php

@@ -17,14 +17,14 @@ class EPay extends AbstractPayment
 
         switch ($request->input('type')) {
             case 2:
-                $type = 'qqpay';
+                $type = 'bank';
                 break;
             case 3:
                 $type = 'wxpay';
                 break;
             case 1:
             default:
-                $type = 'alipay';
+                $type = 'wxpay';
                 break;
         }
 
@@ -51,6 +51,7 @@ class EPay extends AbstractPayment
         if ($request->input('trade_status') === 'TRADE_SUCCESS' && $request->has('out_trade_no')
             && $this->verify($request->except('method'), sysConfig('epay_key'), $request->input('sign'))) {
             if ($this->paymentReceived($request->input('out_trade_no'))) {
+                $this->addPamentCallback($request->input('out_trade_no'),$request->input('trade_no'),$request->input('money'));
                 exit('SUCCESS');
             }
         } else {

+ 77 - 0
app/Http/Controllers/Gateway/EPay1.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use Auth;
+use Http;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class EPay1 extends AbstractPayment
+{
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+        switch ($request->input('type')) {
+            case 2:
+                $type = 'alipay';
+                break;
+            case 3:
+                $type = 'wxpay';
+                break;
+            case 1:
+            default:
+                $type = 'alipay';
+                break;
+        }
+
+        $data = [
+            'pid'          => sysConfig('epay_mch_id'),
+            'type'         => $type,
+            'notify_url'   => route('payment.notify', ['method' => 'epay']),
+            'return_url'   => route('invoice'),
+            'out_trade_no' => $payment->trade_no,
+            'name'         => sysConfig('subject_name') ?: sysConfig('website_name'),
+            'money'        => $payment->amount,
+            'sign_type'    => 'MD5',
+        ];
+        $data['sign'] = $this->aliStyleSign($data, sysConfig('epay_key'));
+
+        $url = sysConfig('epay_url').'submit.php?'.http_build_query($data);
+        $payment->update(['url' => $url]);
+
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+    }
+
+    public function notify(Request $request): void
+    {
+        if ($request->input('trade_status') === 'TRADE_SUCCESS' && $request->has('out_trade_no')
+            && $this->verify($request->except('method'), sysConfig('epay_key'), $request->input('sign'))) {
+            if ($this->paymentReceived($request->input('out_trade_no'))) {
+                $this->addPamentCallback($request->input('out_trade_no'),$request->input('trade_no'),$request->input('money'));
+                exit('SUCCESS');
+            }
+        } else {
+            Log::info('易支付:交易失败');
+        }
+        exit('FAIL');
+    }
+
+    public function queryInfo(): JsonResponse
+    {
+        $response = Http::get(sysConfig('epay_url').'api.php', [
+            'act' => 'query',
+            'pid' => sysConfig('epay_mch_id'),
+            'key' => sysConfig('epay_key'),
+        ]);
+
+        if ($response->ok()) {
+            return Response::json(['status' => 'success', 'data' => $response->json()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '获取失败!请检查配置信息']);
+    }
+}

+ 77 - 0
app/Http/Controllers/Gateway/EPayTT.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use Auth;
+use Http;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class EPayTT extends AbstractPayment
+{
+    private  $epay_mch_id =  "1010";
+    private  $epay_key = "S6Eys6MyIyyUs76eV6UUf4fUvUqYLIq6";
+    private $epay_url = "https://payruitu.top/";
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+        switch ($request->input('type')) {
+            case 4:
+                $type = 'wxpay';
+                break;
+            case 1:
+            default:
+                $type = 'wxpay';
+                break;
+        }
+
+        $data = [
+            'pid'          => $this->epay_mch_id,
+            'type'         => $type,
+            'notify_url'   => route('payment.notify', ['method' => 'epaytt']),
+            'return_url'   => route('invoice'),
+            'out_trade_no' => $payment->trade_no,
+            'name'         => sysConfig('subject_name') ?: sysConfig('website_name'),
+            'money'        => $payment->amount,
+            'sign_type'    => 'MD5',
+        ];
+        $data['sign'] = $this->aliStyleSign($data, $this->epay_key);
+
+        $url = $this->epay_url.'submit.php?'.http_build_query($data);
+        $payment->update(['url' => $url]);
+
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+    }
+
+    public function notify(Request $request): void
+    {
+        if ($request->input('trade_status') === 'TRADE_SUCCESS' && $request->has('out_trade_no')
+            && $this->verify($request->except('method'), $this->epay_key, $request->input('sign'))) {
+            if ($this->paymentReceived($request->input('out_trade_no'))) {
+                $this->addPamentCallback($request->input('out_trade_no'),$request->input('trade_no'),$request->input('money'));
+                exit('SUCCESS');
+            }
+        } else {
+            Log::info('易支付2:交易失败');
+        }
+        exit('FAIL');
+    }
+
+    public function queryInfo(): JsonResponse
+    {
+        $response = Http::get($this->epay_url.'api.php', [
+            'act' => 'query',
+            'pid' => $this->epay_mch_id,
+            'key' => $this->epay_key,
+        ]);
+
+        if ($response->ok()) {
+            return Response::json(['status' => 'success', 'data' => $response->json()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '获取失败!请检查配置信息']);
+    }
+}

+ 68 - 0
app/Http/Controllers/Gateway/Manual.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use App\Models\Payment;
+use Auth;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Response;
+
+class Manual extends AbstractPayment
+{
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+        if ($payment) {
+            $url = route('manual.checkout', ['payment' => $payment->trade_no]);
+            $payment->update(['url' => $url]);
+
+            return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '购买失败,请尝试其他方式']);
+    }
+
+    public function redirectPage($trade_no)
+    {
+        $payment = Payment::uid()->with(['order', 'order.goods'])->whereTradeNo($trade_no)->firstOrFail();
+        $goods = $payment->order->goods;
+
+        return view('user.components.payment.manual', [
+            'payment'       => $payment,
+            'name'          => $goods->name ?? trans('user.recharge_credit'),
+            'days'          => $goods->days ?? 0,
+            'pay_type'      => $payment->order->pay_type_label ?: 0,
+            'pay_type_icon' => $payment->order->pay_type_icon,
+        ]);
+    }
+
+    public function inform($trade_no)
+    {
+        $payment = Payment::uid()->with(['order'])->whereTradeNo($trade_no)->firstOrFail();
+        $payment->order->update(['status' => 1]);
+
+        return Response::json(['status' => 'success', 'message' => '我们将在【24小时】内对购买/充值的款项进行开通!请耐心等待']);
+    }
+
+    public function notify(Request $request): void
+    {
+        $code = $request->input('sign');
+        $status = $request->input('status');
+        if (isset($status, $code)) {
+            $payment = Payment::findOrFail((int) string_decrypt($code));
+            if ($payment && $payment->order && $payment->order->status === 1) {
+                if ($status) {
+                    $payment->order->complete();
+                } else {
+                    $payment->order->close();
+                }
+
+                exit('success');
+            }
+            exit('fail');
+        }
+        exit('No enough information');
+    }
+}

+ 54 - 28
app/Http/Controllers/Gateway/PayBeaver.php

@@ -17,7 +17,7 @@ class PayBeaver extends AbstractPayment
 {
     private $appId;
     private $appSecret;
-    private $url = 'https://api.paybeaver.com/api/v1/developer';
+    private $url = 'https://api.citipay.net/api/v1/developer';
 
     public function __construct()
     {
@@ -29,22 +29,17 @@ class PayBeaver extends AbstractPayment
     {
         $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
-        $result = $this->createOrder([
-            'app_id'            => $this->appId,
-            'merchant_order_id' => $payment->trade_no,
-            'price_amount'      => $payment->amount * 100,
-            'notify_url'        => route('payment.notify', ['method' => 'paybeaver']),
-            'return_url'        => route('invoice'),
-        ]);
+        $result = $this->createOrder($payment);
 
+        //Log::alert('$this->createOrder【海狸支付】创建订单错误:'.var_export($result, true));
         if (isset($result['message'])) {
-            Log::warning('创建订单错误:'.$result['message']);
+           // Log::alert('【海狸支付】创建订单错误:'.$result['message']);
 
             return Response::json(['status' => 'fail', 'message' => '创建订单失败:'.$result['message']]);
         }
 
         if (! isset($result['data']['pay_url'])) {
-            Log::warning('创建订单错误:未知错误');
+           // Log::alert('【海狸支付】创建订单错误:未获取到支付链接'.var_export($result, true));
 
             return Response::json(['status' => 'fail', 'message' => '创建订单失败:未知错误']);
         }
@@ -53,48 +48,79 @@ class PayBeaver extends AbstractPayment
 
         return Response::json(['status' => 'success', 'url' => $result['data']['pay_url'], 'message' => '创建订单成功!']);
     }
-
-    private function createOrder($params)
+    private function post($data)
     {
-        $params['sign'] = $this->sign($params);
-
-        $response = Http::post($this->url.'/orders', $params);
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_URL, $this->url . '/v1/gateway/fetch');
+        curl_setopt($curl, CURLOPT_HEADER, 0);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+        curl_setopt($curl, CURLOPT_POST, 1);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+        $data = curl_exec($curl);
+        curl_close($curl);
+        return $data;
+    }
+    private function createOrder($payment)
+    {
+        $params = [
+            'out_trade_no'      => $payment->trade_no,
+            'total_amount'      => $payment->amount * 100,
+            'notify_url'        => route('payment.notify', ['method' => 'paybeaver']),
+            'return_url'        => route('invoice'),
+        ];
+        $params['app_id'] = $this->appId;
 
-        if ($response->ok()) {
-            return $response->json();
+        ksort($params);
+        $str = http_build_query($params) . $this->appSecret;
+        $params['sign'] = md5($str);
+        $response = $this->post(http_build_query($params));
+        Log::info('【海狸支付】订单放回结果:'.var_export($response, true));
+        $response = json_decode($response,true);
+        if (!isset($response['data'])) {
+            Log::info('【海狸支付】创建订单失败:'.var_export(['code' => -1, 'msg' => '支付网关处理失败'], true));
+            return ['status' => 'fail', 'message' => '获取失败!请检查配置信息'];
         }
-
-        return Response::json(['status' => 'fail', 'message' => '获取失败!请检查配置信息']);
+        return $response;
     }
 
     private function sign($params)
     {
-        if (isset($params['sign'])) {
-            unset($params['sign']);
-        }
+//        if (isset($params['sign'])) {
+//            unset($params['sign']);
+//        }
         ksort($params);
-        reset($params);
 
-        return strtolower(md5(http_build_query($params).$this->appSecret));
+        return md5(http_build_query($params).$this->appSecret);
     }
 
     public function notify($request): void
     {
+        Log::info('【海狸支付】回调接口:'.var_export($request->all(), true));
         if (! $this->paybeaverVerify($request->post())) {
             exit(json_encode(['status' => 400]));
         }
 
-        if ($request->has(['merchant_order_id']) && $this->paymentReceived($request->input(['merchant_order_id']))) {
+        if ($request->has(['out_trade_no']) && $this->paymentReceived($request->input(['out_trade_no']))  ) {
+            $this->addPamentCallback($request->input('out_trade_no'),$request->input('trade_no'),$request->input('money'));
+            Log::info('【海狸支付】paymentReceived:'.var_export($request->all(), true));
             exit(json_encode(['status' => 200]));
         }
 
-        Log::info('海狸支付:交易失败');
+
 
         exit(json_encode(['status' => 500]));
     }
 
     private function paybeaverVerify($params)
     {
-        return hash_equals($params['sign'], $this->sign($params));
+        $sign = $params['sign'];
+        unset($params['sign']);
+        ksort($params);
+        reset($params);
+        $str = http_build_query($params) . $this->appSecret;
+        return $sign === md5($str);
+        //return hash_equals($params['sign'], $this->sign($params));
     }
-}
+}

+ 72 - 0
app/Http/Controllers/Gateway/THeadPay.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use Auth;
+use Http;
+use Illuminate\Http\JsonResponse;
+use Log;
+use Response;
+
+class THeadPay extends AbstractPayment
+{
+    public function purchase($request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+        $data = [
+            'mchid'        => sysConfig('theadpay_mchid'),
+            'out_trade_no' => $payment->trade_no,
+            'total_fee'    => (string) ($payment->amount * 100),
+            'notify_url'   => route('payment.notify', ['method' => 'theadpay']),
+        ];
+        $data['sign'] = $this->sign($data);
+        Log::error('【平头哥支付】 返 '.sysConfig('theadpay_url'));
+        $response = Http::post(sysConfig('theadpay_url').'/orders', $data);
+        if ($response->ok()) {
+            $result = $response->json();
+            if ($result['status'] === 'success') {
+                $payment->update(['qr_code' => 1, 'url' => $result['code_url']]);
+
+                return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
+            }
+
+            Log::error('【平头哥支付】 返回错误信息:'.$result['message']);
+        }
+
+        Log::alert('【平头哥支付】 支付渠道建立订单出现问题!'.$response->body());
+
+        return Response::json(['status' => 'fail', 'message' => '创建在线订单失败,请工单通知管理员!']);
+    }
+
+    private function sign($params)
+    {
+        unset($params['sign']);
+        ksort($params, SORT_STRING);
+        reset($params);
+        $params['key'] = sysConfig('theadpay_key');
+
+        return strtoupper(md5(http_build_query($params)));
+    }
+
+    public function notify($request): void
+    {
+        if ($this->verify_notify($request->post())) {
+            $tradeNo = $request->input('out_trade_no');
+            if ($tradeNo) {
+                if ($this->paymentReceived($tradeNo)) {
+                    exit(200);
+                }
+            } else {
+                Log::error('【平头哥支付】交易失败:订单信息-'.var_export($request->all(), true));
+            }
+        }
+
+        exit('fail');
+    }
+
+    private function verify_notify($params)
+    {
+        return $params['sign'] === $this->sign($params);
+    }
+}

+ 112 - 0
app/Http/Controllers/Gateway/Zypay.php

@@ -0,0 +1,112 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use App\Models\Payment;
+use Auth;
+
+
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Response;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+
+
+class Zypay extends AbstractPayment
+{
+
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+//        switch ($request->input('type')) {
+//            case 2:
+//                $type = 'qqpay';
+//                break;
+//            case 3:
+//                $type = 'wxpay';
+//                break;
+//            case 1:
+//            default:
+//                $type = 'alipay';
+//                break;
+//        }
+        $key = "6f13dd44826918a5fc7ab6baa255d99c51b505b3";
+        $data = [
+            'app_id' => "WTQwSt5Dytzs",
+            'out_trade_no' => $payment->trade_no,
+            'total_amount' => $payment->amount * 100,
+            'notify_url' => route('payment.notify', ['method' => 'zpay']),
+            'return_url' => route('invoice'),
+        ];
+        ksort($data);
+        $str = http_build_query($data);
+        $data['sign'] = strtolower(md5($str .  $key));
+
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_URL, "https://api.hmcheckout.com" . '/api/v1/tron');
+        curl_setopt($curl, CURLOPT_HEADER, 0);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+        curl_setopt($curl, CURLOPT_POST, 1);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
+        curl_setopt($curl, CURLOPT_HTTPHEADER, ['User-Agent: Alpha']);
+        $res = curl_exec($curl);
+        curl_close($curl);
+        $result = json_decode($res, true);
+        if (!$result) {
+            return Response::json(['status' => 'success', 'url' => "", 'message' => '网络异常!']);
+        }
+
+        Log::info("[河马支付]请求支付接口". var_export($result, true));
+        if ($result["code"] === 0 ){
+            return Response::json(['status' => 'fail', 'message' => '创建订单失败!'.$result['error']]);
+        }
+        return Response::json(['status' => 'success', 'url' => $result['url'], 'message' => '创建订单成功!']);
+
+
+    }
+
+    public function notify(Request $request): void
+    {
+        if ($this->verifySign($request->post())){
+            exit('SIGN FAIL');
+        }
+        if ($request->has(['out_trade_no']) && $this->paymentReceived($request->input(['out_trade_no']))  ) {
+            $this->addPamentCallback($request->input('out_trade_no'),$request->input('trade_no'),"");
+            Log::info('【河马支付】paymentReceived:'.var_export($request->all(), true));
+            exit(json_encode(['status' => 200]));
+        }
+    }
+
+    function verifySign($params)
+    {
+        $key = "6e13274fe90055e38f0751c3e242af1882abc849";
+        $sign = $params['sign'];
+        unset($params['sign']);
+        ksort($params);
+        $str = strtolower(http_build_query($params) . $key);
+        if ($sign !== md5($str)) {
+            return false;
+        }
+        return $str;
+
+        // 剃离sign,sign_type,空值
+//        unset($data['sign'], $data['sign_type'] , $data["method"]);
+
+
+//    if ($filter) {
+//        $data = array_filter($data);
+//    }
+
+        // 排序
+//        ksort($data, SORT_STRING);
+//        reset($data);
+//
+//
+//        $data["key"] = $key;
+//        return strtoupper(md5(urldecode(http_build_query($data))));
+    }
+}

+ 183 - 0
app/Http/Controllers/Gateway/bypay.php

@@ -0,0 +1,183 @@
+<?php
+
+namespace App\Http\Controllers\Gateway;
+
+use App\Models\Payment;
+use Auth;
+
+
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Response;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Log;
+
+
+class bypay extends AbstractPayment
+{
+
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+//        switch ($request->input('type')) {
+//            case 2:
+//                $type = 'qqpay';
+//                break;
+//            case 3:
+//                $type = 'wxpay';
+//                break;
+//            case 1:
+//            default:
+//                $type = 'alipay';
+//                break;
+//        }
+
+        /*
+        merchantId	商户号-平台统一提供的唯一ID号	true	string
+merchantOrderId	商户订单号[自行维护唯一性]	true	string
+payCode	支付编码[alipay]|JD|zfb|wx]	true	string
+amount	支付金额(单位:元) 可以0.01元	true	string
+callbackUrl	异步通知地址	true	string
+notifyUrl	同步跳转地址	false	string
+userLocalIp	用户IP	true	string
+sign	签名[参考平台签名算法]	true	string
+ext	附加参数[异步通知原路返回]	false	string
+SHA256 签名介绍
+第一步,设所有发送或者接收到的数据为集合M,将集合M内的[参数名]按照参 ASCII 码从小到大排序(字典序)
+第二步,使用 URL 键值对的格式(即 key1=value1&key2=value2…),将集合M内参数值,拼接成字符串 stringA; 参数中 sign 不参与签名
+第三步,在 stringA 的最后拼接上 "&key=商户密钥值",得到字符串 stringB
+第四步,对 stringB 进行 SHA256 运算,得到 stringC
+第五步,将字符串 stringC 转换为大写,最后得到 签名值 sign
+*/
+        $key = "e7c359e9146345de86a41a099cacd67f";
+        $data = [
+            'merchantId' => "1654045635701374976",
+            'merchantOrderId' => $payment->trade_no,
+            'payCode' => "wgzfbsm",
+            'amount' => $payment->amount,
+            'userLocalIp' => "192.178.31.34",
+            'notifyUrl' => route('invoice'),
+            'callbackUrl' => route('payment.notify', ['method' => 'bypay']),
+        ];
+    
+        $str = $this->sortParams($data) . '&key=' . $key; //stringB
+        Log::info("[BYPZ]请求支付接口". var_export($str, true));
+   
+        $StringC = strtolower($this->sha256($str));
+        Log::info("[BYPZ]请求支付接口". var_export($StringC, true));
+        $data['sign'] = strtoupper($StringC); //stringC
+     
+        Log::info("[BYPZ]请求支付接口". var_export($data, true));
+        $postData = json_encode($data);
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_URL, "https://bjzf88.vip/api/unifiedOrder/v2");
+        curl_setopt($curl, CURLOPT_HEADER, 0);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
+        curl_setopt($curl, CURLOPT_POST, 1);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
+            curl_setopt($curl, CURLOPT_HTTPHEADER, array(
+            'Content-Type: application/json',
+            'Content-Length: ' . strlen($postData))
+        );
+ 
+        $res = curl_exec($curl);
+        curl_close($curl);
+        $result = json_decode($res, true);
+        if (!$result) {
+            return Response::json(['status' => 'success', 'url' => "", 'message' => '网络异常!']);
+        }
+
+        Log::info("[BYPZ]请求支付接口". var_export($result, true));
+        if ($result["status"] != 200){
+            return Response::json(['status' => 'fail', 'message' => '创建订单失败!'.$result['error']]);
+        }
+        return Response::json(['status' => 'success', 'url' => $result['data'], 'message' => '创建订单成功!']);
+
+
+    }
+
+    public function notify(Request $request): void
+    {
+        $postData = file_get_contents('php://input'); 
+        $result = json_decode($postData,true);
+        Log::info("[BYPZ]回调内容1". var_export($result, true));
+        $notifyData = [
+          'merchantId'=>$result['merchantId'],
+          'merchantOrderId'=>$result['merchantOrderId'],
+          'orderId'=>$result['orderId'],
+          'amount'=>$result['amount'],
+          'factAmount'=>$result['factAmount'],
+          'ext'=>$result['ext'],
+          'state'=>$result['state'],
+          'sign'=>$result['sign']
+        ];
+        if ($this->verifySign($notifyData)){
+            exit('fail');
+        }
+        
+        Log::info("[BYPZ]回调内容". var_export($notifyData, true));
+        
+        if ($this->paymentReceived($notifyData['merchantOrderId'])  ) {
+            $this->addPamentCallback($notifyData['merchantOrderId'] ,$notifyData['orderId'] ,"");
+            Log::info('【BYPZ】paymentReceived:'.var_export($request->all(), true));
+            exit('success');
+        }
+    }
+
+    function ASCII($params = array()){
+		//ksort()对数组按照键名进行升序排序
+		ksort($params);
+        //reset()内部指针指向数组中的第一个元素
+		reset($params);
+		$str = http_build_query($params);
+		return $str;
+	}
+ 
+    function verifySign($params)
+    {
+        $key = "e7c359e9146345de86a41a099cacd67f";
+        $sign = $params['sign'];
+        unset($params['sign']);
+        ksort($params);
+        $str = $this->sortParams($params) . '&key='.$key;
+        $StringC = strtolower($this->sha256($str));
+        if ($sign !== strtoupper($StringC)) {
+            return false;
+        }
+        return $str;
+
+        // 剃离sign,sign_type,空值
+//        unset($data['sign'], $data['sign_type'] , $data["method"]);
+
+
+//    if ($filter) {
+//        $data = array_filter($data);
+//    }
+
+        // 排序
+//        ksort($data, SORT_STRING);
+//        reset($data);
+//
+//
+//        $data["key"] = $key;
+//        return strtoupper(md5(urldecode(http_build_query($data))));
+    }
+    function sortParams($params) {
+        ksort($params);
+        $str = '';
+        foreach ($params as $key => $value) {
+            $str .= $key . '=' . $value . '&';
+        }
+       
+        return rtrim($str, '&');
+    }
+   function sha256($str) {
+    $hash = hash('sha256', $str, true);
+    $encdeStr = bin2hex($hash);
+    return strtolower($encdeStr);
+    }
+
+}

+ 16 - 4
app/Http/Controllers/PaymentController.php

@@ -6,12 +6,16 @@ use App\Components\Helpers;
 use App\Http\Controllers\Gateway\BitpayX;
 use App\Http\Controllers\Gateway\CodePay;
 use App\Http\Controllers\Gateway\EPay;
+use App\Http\Controllers\Gateway\EPayTT;
 use App\Http\Controllers\Gateway\F2Fpay;
 use App\Http\Controllers\Gateway\Local;
 use App\Http\Controllers\Gateway\PayBeaver;
 use App\Http\Controllers\Gateway\PayJs;
 use App\Http\Controllers\Gateway\PayPal;
 use App\Http\Controllers\Gateway\Stripe;
+use App\Http\Controllers\Gateway\THeadPay;
+use App\Http\Controllers\Gateway\Zypay;
+use App\Http\Controllers\Gateway\bypay;
 use App\Models\Coupon;
 use App\Models\Goods;
 use App\Models\Order;
@@ -25,7 +29,7 @@ use Response;
 
 class PaymentController extends Controller
 {
-    private static $method;
+    public static $method;
 
     public static function notify(Request $request): int
     {
@@ -58,6 +62,14 @@ class PaymentController extends Controller
                 return new Stripe();
             case 'paybeaver':
                 return new PayBeaver();
+            case 'zpay':
+                return new Zypay();
+            case 'theadpay':
+                return new THeadPay();
+            case 'epaytt':
+                return new EPayTT();
+            case 'bypay':
+                return new bypay();
             default:
                 Log::warning('未知支付:'.self::$method);
 
@@ -123,9 +135,9 @@ class PaymentController extends Controller
                 }
 
                 // 判断是否存在同个商品的未支付订单
-                if (Order::uid()->whereStatus(0)->exists()) {
-                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:尚有未支付的订单,请先去支付']);
-                }
+//                if (Order::uid()->whereStatus(0)->exists()) {
+//                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:尚有未支付的订单,请先去支付']);
+//                }
             } elseif (Auth::getUser()->credit < $amount) { // 验证账号余额是否充足
                 return Response::json(['status' => 'fail', 'message' => '您的余额不足,请先充值']);
             }

+ 59 - 5
app/Http/Controllers/User/AffiliateController.php

@@ -7,7 +7,9 @@ use App\Models\Order;
 use App\Models\ReferralApply;
 use App\Models\ReferralLog;
 use Auth;
+use Illuminate\Http\Request;
 use Illuminate\Http\JsonResponse;
+
 use Response;
 
 class AffiliateController extends Controller
@@ -15,9 +17,10 @@ class AffiliateController extends Controller
     // 推广返利
     public function referral()
     {
-        if (ReferralLog::uid()->doesntExist() && Order::uid()->whereStatus(2)->doesntExist()) {
-            return Response::view('auth.error', ['message' => trans('user.purchase_required').'<a class="btn btn-sm btn-danger" href="/">'.trans('common.back').'</a>'], 402);
-        }
+        //&& Order::uid()->whereStatus(2)->doesntExist()
+        // if (ReferralLog::uid()->doesntExist() ) {
+        //     return Response::view('auth.error', ['message' => trans('user.purchase_required').'<a class="btn btn-sm btn-danger" href="/">'.trans('common.back').'</a>'], 402);
+        // }
 
         return view('user.referral', [
             'referral_traffic' => flowAutoShow(sysConfig('referral_traffic') * MB),
@@ -26,6 +29,7 @@ class AffiliateController extends Controller
             'totalAmount' => ReferralLog::uid()->sum('commission') / 100,
             'canAmount' => ReferralLog::uid()->whereStatus(0)->sum('commission') / 100,
             'aff_link' => route('register', ['aff' => Auth::id()]),
+          //  'aff_link' => "https://apitx.naiyout.buzz/register?aff=" .Auth::id(),
             'referralLogList' => ReferralLog::uid()->with('invitee:id,email')->latest()->paginate(10, ['*'], 'log_page'),
             'referralApplyList' => ReferralApply::uid()->latest()->paginate(10, ['*'], 'apply_page'),
             'referralUserList' => Auth::getUser()->invitees()->select(['email', 'created_at'])->latest()->paginate(10, ['*'], 'user_page'),
@@ -33,8 +37,21 @@ class AffiliateController extends Controller
     }
 
     // 申请提现
-    public function extractMoney(): JsonResponse
+    public function extractMoney(Request $request): JsonResponse
     {
+         $zfb_name = $request->input('zfb_name');
+         $zfb_card = $request->input('zfb_card');
+
+         if(empty($zfb_card))
+         {
+             return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => '支付宝名称必须填写']);
+         }
+
+         if(empty($zfb_card)){
+             return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => "支付宝账号必须填写"]);
+         }
+
+
         // 判断账户是否过期
         if (Auth::getUser()->expired_at < date('Y-m-d')) {
             return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.account')]);
@@ -51,13 +68,50 @@ class AffiliateController extends Controller
         $commission /= 100;
         if ($commission < sysConfig('referral_money')) {
             return Response::json([
-                'status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.unfulfilled', ['amount' => sysConfig('referral_money')]),
+                'status' => 'fail', 'zfbname' => $zfb_name,'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.unfulfilled', ['amount' => sysConfig('referral_money')]),
+            ]);
+        }
+
+        $ref = new ReferralApply();
+        $ref->user_id = Auth::id();
+        $ref->zfb_name = $zfb_name;
+        $ref->zfb_card = $zfb_card;
+        $ref->before = $commission;
+        $ref->amount = $commission;
+        $ref->link_logs = ReferralLog::uid()->whereStatus(0)->pluck('id')->toArray();
+        if ($ref->save()) {
+            return Response::json(['status' => 'success', 'title' => trans('user.referral.success'), 'message' => trans('user.referral.msg.wait')]);
+        }
+
+        return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.error')]);
+    }
+
+    public function extractBalance(Request $request): JsonResponse
+    {
+        // 判断账户是否过期
+        if (Auth::getUser()->expired_at < date('Y-m-d')) {
+            return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.account')]);
+        }
+
+        // 判断是否已存在申请
+        $referralApply = ReferralApply::uid()->whereIn('status', [0, 1])->first();
+        if ($referralApply) {
+            return Response::json(['status' => 'fail', 'title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.appliedd')]);
+        }
+
+        // 校验可以提现金额是否超过系统设置的阀值
+        $commission = ReferralLog::uid()->whereStatus(0)->sum('commission');
+        $commission /= 100;
+        if ($commission > sysConfig('referral_money')) {
+            return Response::json([
+                'status' => 'fail','title' => trans('user.referral.failed'), 'message' => trans('user.referral.msg.unfulfilled', ['amount' => sysConfig('referral_money')]),
             ]);
         }
 
         $ref = new ReferralApply();
         $ref->user_id = Auth::id();
         $ref->before = $commission;
+        $ref->zfb_name = "提现到余额";
         $ref->amount = $commission;
         $ref->link_logs = ReferralLog::uid()->whereStatus(0)->pluck('id')->toArray();
         if ($ref->save()) {

+ 42 - 8
app/Http/Controllers/UserController.php

@@ -69,7 +69,8 @@ class UserController extends Controller
             'userLoginLog'     => $user->loginLogs()->latest()->first(), // 近期登录日志
             'subscribe_status' => $user->subscribe->status,
             'subType'          => $subType,
-            'subUrl'           => route('sub', $user->subscribe->code),
+            'subUrl'           => sysConfig('subscribe_domain') . "/s/" . $user->subscribe->code,
+           // 'subUrl'           => route('sub', $user->subscribe->code),
         ], $this->dataFlowChart($user->id)));
     }
 
@@ -205,6 +206,26 @@ class UserController extends Controller
             'goodsList'       => Goods::whereStatus(1)->where('type', '<=', '2')->orderByDesc('type')->orderByDesc('sort')->paginate(10)->appends($request->except('page')),
             'renewTraffic'    => $renewPrice->renew ?? 0,
             'dataPlusDays'    => $dataPlusDays > date('Y-m-d') ? Helpers::daysToNow($dataPlusDays) : 0,
+            'username'        => $user->profile()["account"],
+        ]);
+    }
+
+    // 商品列表
+    public function services1(Request $request)
+    {
+        $user = auth()->user();
+        // 余额充值商品,只取10个
+        $renewOrder = Order::userActivePlan($user->id)->first();
+        $renewPrice = $renewOrder->goods ?? 0;
+        // 有重置日时按照重置日为标准,否者就以过期日为标准
+        $dataPlusDays = $user->reset_time ?? $user->expired_at;
+
+        return view('user.services1', [
+            'chargeGoodsList' => Goods::type(3)->whereStatus(1)->orderBy('price')->limit(10)->get(),
+            'goodsList'       => Goods::whereStatus(1)->where('type', '<=', '2')->orderByDesc('type')->orderByDesc('sort')->paginate(10)->appends($request->except('page')),
+            'renewTraffic'    => $renewPrice->renew ?? 0,
+            'dataPlusDays'    => $dataPlusDays > date('Y-m-d') ? Helpers::daysToNow($dataPlusDays) : 0,
+            'username'        => $user->profile()["account"],
         ]);
     }
 
@@ -228,7 +249,14 @@ class UserController extends Controller
 
         return Response::json(['status' => 'success', 'message' => trans('user.reset_data.success')]);
     }
-
+    // 工单中间网页
+    public function ticketop(Request $request)
+    {
+        return view('user.ticketop', [
+            'onurl' => "http://www.baidu.com",
+            'tickets' => route('ticket1'),
+        ]);
+    }
     // 工单
     public function ticketList(Request $request)
     {
@@ -341,12 +369,16 @@ class UserController extends Controller
     // 关闭工单
     public function closeTicket(Request $request): ?JsonResponse
     {
+            //   return Response::json(['status' => 'success', 'message' => trans('common.close_item', ['attribute' => trans('common.success')])]);
+         
         $id = $request->input('id');
-
-        if (Ticket::uid()->whereId($id)->close()) {
-            return Response::json(['status' => 'success', 'message' => trans('common.close_item', ['attribute' => trans('common.success')])]);
-        }
-
+//   return Response::json(['status' => 'success', 'message' => $id]);
+ 
+        $ticket = Ticket::uid()->whereId($id)->first();
+        if ($ticket) {
+            $ticket->close();
+           return Response::json(['status' => 'success', 'message' => trans('common.close_item', ['attribute' => trans('common.success')])]);
+        }  
         return Response::json(['status' => 'fail', 'message' => trans('common.close_item', ['attribute' => trans('common.failed')])]);
     }
 
@@ -448,6 +480,7 @@ class UserController extends Controller
         $dataPlusDays = $user->reset_time ?? $user->expired_at;
 
         return view('user.buy', [
+            'username'  => $user->email,
             'dataPlusDays' => $dataPlusDays > date('Y-m-d') ? Helpers::daysToNow($dataPlusDays) : 0,
             'activePlan'   => Order::userActivePlan()->exists(),
             'goods'        => $good,
@@ -471,7 +504,8 @@ class UserController extends Controller
         }
 
         $subscribe = auth()->user()->subscribe;
-        $subscribe_link = route('sub', $subscribe->code);
+        //$subscribe_link = route('sub', $subscribe->code);
+        $subscribe_link = sysConfig('subscribe_domain') . "/s/" . $subscribe->code;
 
         return view('user.help', [
             'sub'                     => $data,

+ 1 - 0
app/Http/Kernel.php

@@ -97,6 +97,7 @@ class Kernel extends HttpKernel
     protected $routeMiddleware = [
         'auth' => Authenticate::class,
         'auth.basic' => AuthenticateWithBasicAuth::class,
+        'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
         'bindings' => SubstituteBindings::class,
         'cache.headers' => SetCacheHeaders::class,
         'can' => Authorize::class,

+ 7 - 7
app/Http/Requests/Admin/NodeRequest.php

@@ -12,8 +12,8 @@ class NodeRequest extends FormRequest
             'is_ddns' => 'required|boolean',
             'name' => 'required|string',
             'server' => 'required_if:is_ddns,1|nullable|ends_with:'.implode(',', config('domains')),
-            'ip' => 'ipv4|required_if:is_ddns,0|nullable',
-            'ipv6' => 'nullable|ipv6',
+            'ip' => 'required_if:is_ddns,0|nullable',
+            'ipv6' => 'nullable',
             'push_port' => 'numeric|between:0,65535',
             'traffic_rate' => 'required|numeric|min:0',
             'level' => 'required|numeric|exists:level,level',
@@ -26,8 +26,8 @@ class NodeRequest extends FormRequest
             'sort' => 'required|numeric|between:0,255',
             'is_udp' => 'required|boolean',
             'status' => 'required|boolean',
-            'type' => 'required|numeric|between:1,4',
-            'method' => 'required_if:type,1,4|exists:ss_config,name',
+            'type' => 'required|numeric|between:0,4',
+            'method' => 'required|exists:ss_config,name',
             'protocol' => 'required_if:type,1,4|exists:ss_config,name',
             'protocol_param' => 'nullable|string',
             'obfs' => 'required_if:type,1,4|exists:ss_config,name',
@@ -36,15 +36,15 @@ class NodeRequest extends FormRequest
             'is_subscribe' => 'required|boolean',
             'detection_type' => 'required|numeric|between:0,3',
             'single' => 'required|boolean',
-            'port' => 'required_if:single,1|numeric|between:1,65535|nullable',
-            'passwd' => 'required_if:single,1|string|nullable',
+            'port' => 'required_if:single,1,type,2,type,3|numeric|between:1,65535|nullable',
+            'passwd' => 'exclude_unless:type,1,type,4|required_if:single,1|string|nullable',
             'v2_alter_id' => 'required_if:type,2|numeric|between:0,65535',
-            'v2_port' => 'required_if:type,2|numeric|between:0,65535',
             'v2_method' => 'required_if:type,2',
             'v2_net' => 'required_if:type,2',
             'v2_type' => 'required_if:type,2',
             'v2_host' => 'string|nullable',
             'v2_path' => 'string|nullable',
+            'v2_sni' => 'string|nullable',
             'v2_tls' => 'required_if:type,2|boolean',
             'tls_provider' => 'json|nullable',
             'is_relay' => 'required|boolean',

+ 2 - 2
app/Http/Requests/Admin/UserUpdateRequest.php

@@ -23,12 +23,12 @@ class UserUpdateRequest extends FormRequest
             'speed_limit' => 'required|numeric|min:0',
             'wechat' => 'nullable|string',
             'qq' => 'nullable|string',
-            'expired_at' => 'required|date_format:Y-m-d',
+            'expired_at' => 'nullable',
             'remark' => 'nullable|string',
             'level' => 'required|exists:level,level',
             'user_group_id' => 'nullable|exists:user_group,id',
             'roles' => 'nullable|exists:roles,name',
-            'reset_time' => 'nullable|date_format:Y-m-d',
+            'reset_time' => 'nullable',
             'invite_num' => 'required|numeric|min:0',
             'status' => 'required|numeric|between:-1,1',
         ];

+ 7 - 2
app/Jobs/VNet/addUser.php

@@ -44,13 +44,18 @@ class addUser implements ShouldQueue
     public function handle(): void
     {
         foreach ($this->nodes as $node) {
-            $this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
+            if ($node->type == 0){
+                Log::info('【新增用户】推送成功 这个是SS 后端不一样不用推送');
+            } else {
+                $this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
+            }
+
         }
     }
 
     private function send($host, $secret): void
     {
-        $request = Http::baseUrl($host)->timeout(20)->withHeaders(['secret' => $secret]);
+        $request = Http::baseUrl($host)->withoutVerifying()->timeout(20)->withHeaders(['secret' => $secret]);
 
         $response = $request->post('api/v2/user/add/list', $this->data);
         $message = $response->json();

+ 1 - 1
app/Jobs/VNet/delUser.php

@@ -37,7 +37,7 @@ class delUser implements ShouldQueue
 
     private function send($host, $secret): void
     {
-        $request = Http::baseUrl($host)->timeout(15)->withHeaders(['secret' => $secret]);
+        $request = Http::baseUrl($host)->withoutVerifying()->timeout(15)->withHeaders(['secret' => $secret]);
 
         if (is_array($this->userIds)) {
             $response = $request->post('api/v2/user/del/list', $this->userIds);

+ 20 - 10
app/Jobs/VNet/editUser.php

@@ -38,22 +38,32 @@ class editUser implements ShouldQueue
     public function handle(): void
     {
         foreach ($this->nodes as $node) {
-            $host = ($node->server ?: $node->ip).':'.$node->push_port;
-            $secret = $node->auth->secret;
 
-            // 如果用户已存在节点内,则执行修改;否者为添加
-            $list = $this->list($host, $secret);
-            if ($list && in_array($this->data['uid'], $list)) {
-                $this->send($host, $secret);
-            } else {
-                addUser::dispatch($this->data['uid'], $node->id);
+            if ($node->type == 0){
+
+                $host = ($node->server ?: $node->ip).':'.$node->push_port;
+                $secret = $node->auth->secret;
+
+                // 如果用户已存在节点内,则执行修改;否者为添加
+                $list = $this->list($host, $secret);
+                if ($list && in_array($this->data['uid'], $list)) {
+                    //$this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
+                    $this->send($host, $secret);
+                } else {
+                    addUser::dispatch($this->data['uid'], $node->id);
+                }
+
+                //$this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
             }
+
+
+
         }
     }
 
     private function list($host, $secret)
     {
-        $request = Http::baseUrl($host)->timeout(20)->withHeaders(['secret' => $secret]);
+        $request = Http::baseUrl($host)->withoutVerifying()->timeout(20)->withHeaders(['secret' => $secret]);
 
         $response = $request->get('api/user/list');
         $message = $response->json();
@@ -68,7 +78,7 @@ class editUser implements ShouldQueue
 
     private function send($host, $secret): void
     {
-        $request = Http::baseUrl($host)->timeout(20)->withHeaders(['secret' => $secret]);
+        $request = Http::baseUrl($host)->withoutVerifying()->timeout(20)->withHeaders(['secret' => $secret]);
 
         $response = $request->post('api/user/edit', $this->data);
         $message = $response->json();

+ 1 - 1
app/Jobs/VNet/reloadNode.php

@@ -62,7 +62,7 @@ class reloadNode implements ShouldQueue
 
     public function send($host, $secret, $data): bool
     {
-        $request = Http::baseUrl($host)->timeout(15)->withHeaders(['secret' => $secret]);
+        $request = Http::baseUrl($host)->withoutVerifying()->timeout(15)->withHeaders(['secret' => $secret]);
 
         $response = $request->post('api/v2/node/reload', $data);
         $message = $response->json();

+ 12 - 0
app/Models/AppUpdate.php

@@ -0,0 +1,12 @@
+<?php
+
+
+namespace App\Models;
+
+
+use Illuminate\Database\Eloquent\Model;
+
+class AppUpdate extends Model
+{
+    protected $table = 'appupdate';
+}

+ 17 - 4
app/Models/Node.php

@@ -110,25 +110,35 @@ class Node extends Model
             'group' => sysConfig('website_name'),
         ];
         switch ($this->type) {
+            case 0:
+                $config = array_merge($config, [
+                    'type'       => 'shadowsocks',
+                    'method'     => $this->method,
+                    'udp'        => $this->is_udp,
+                    'port'       => $this->is_relay ? $this->relay_port : $this->port,
+                    'passwd'     => $user->passwd
+                ]);
+                break;
             case 2:
                 $config = array_merge($config, [
                     'type'        => 'v2ray',
-                    'port'        => $this->is_relay ? $this->relay_port : $this->v2_port,
+                    'port'        => $this->is_relay ? $this->relay_port : $this->port,
                     'uuid'        => $user->vmess_id,
                     'method'      => $this->v2_method,
                     'v2_alter_id' => $this->v2_alter_id,
                     'v2_net'      => $this->v2_net,
                     'v2_type'     => $this->v2_type,
-                    'v2_host'     => $this->v2_host,
-                    'v2_path'     => $this->v2_path,
+                    'v2_host'     => $this->v2_host == null ? '':$this->v2_host,
+                    'v2_path'     => $this->v2_path == null ? '':$this->v2_path,
                     'v2_tls'      => $this->v2_tls ? 'tls' : '',
+                    'v2_sni'      => $this->v2_sni == null ? '':$this->v2_sni,
                     'udp'         => $this->is_udp,
                 ]);
                 break;
             case 3:
                 $config = array_merge($config, [
                     'type'   => 'trojan',
-                    'port'   => $this->is_relay ? $this->relay_port : $this->v2_port,
+                    'port'   => $this->is_relay ? $this->relay_port : 443,
                     'passwd' => $user->passwd,
                     'sni'    => $this->is_relay ? $this->server : '',
                     'udp'    => $this->is_udp,
@@ -179,6 +189,9 @@ class Node extends Model
     public function getTypeLabelAttribute(): string
     {
         switch ($this->attributes['type']) {
+            case 0:
+                $type_label = 'shadowsocks';
+                break;
             case 1:
                 $type_label = 'ShadowsocksR';
                 break;

+ 27 - 2
app/Models/Order.php

@@ -163,7 +163,7 @@ class Order extends Model
                 $pay_type_label = trans('common.payment.alipay');
                 break;
             case 2:
-                $pay_type_label = 'QQ';
+                $pay_type_label = '支付宝支付';
                 break;
             case 3:
                 $pay_type_label = trans('common.payment.wechat');
@@ -177,6 +177,9 @@ class Order extends Model
             case 6:
                 $pay_type_label = 'Stripe';
                 break;
+            case 7:
+                trans('common.payment.manual');
+                break;
             default:
                 $pay_type_label = '';
         }
@@ -187,6 +190,9 @@ class Order extends Model
     // 支付图标
     public function getPayTypeIconAttribute(): string
     {
+
+       // return '/assets/images/payment/'.config('common.payment.icon')[$this->attributes['pay_type']] ?? 'coin.png';
+
         $base_path = '/assets/images/payment/';
 
         switch ($this->attributes['pay_type']) {
@@ -194,7 +200,7 @@ class Order extends Model
                 $pay_type_icon = $base_path.'alipay.png';
                 break;
             case 2:
-                $pay_type_icon = $base_path.'qq.png';
+                $pay_type_icon = $base_path.'alipay-other.png';
                 break;
             case 3:
                 $pay_type_icon = $base_path.'wechat.png';
@@ -215,6 +221,10 @@ class Order extends Model
     // 支付方式
     public function getPayWayLabelAttribute(): string
     {
+
+        //return config('common.payment.labels')[$this->attributes['pay_way']] ?? '未知';
+
+
         switch ($this->attributes['pay_way']) {
             case 'credit':
                 $pay_way_label = '余额';
@@ -243,6 +253,21 @@ class Order extends Model
             case 'paybeaver':
                 $pay_way_label = '海狸支付';
                 break;
+            case 'zpay':
+                $pay_way_label = 'zpay';
+                break;
+            case 'epay':
+                $pay_way_label = '易支付';
+                break;
+            case 'theadpay':
+                $pay_way_label = '平头哥';
+                break;
+            case 'epaytt':
+                $pay_way_label = 'epaytt';
+                break;
+            case 'bypay':
+                $pay_way_label = 'bypay';
+                break;
             default:
                 $pay_way_label = '未知';
         }

+ 15 - 0
app/Models/Sms.php

@@ -0,0 +1,15 @@
+<?php
+
+
+namespace App\Models;
+
+
+use Illuminate\Database\Eloquent\Model;
+
+class Sms extends Model
+{
+    // 加上对应的字段
+    protected $fillable = ['fromNumber','codetext','codetime','toPhone'];
+
+    protected $table = 'sms';
+}

+ 19 - 5
app/Models/User.php

@@ -20,7 +20,7 @@ class User extends Authenticatable implements JWTSubject
     use Notifiable, HasRoles;
 
     protected $table = 'user';
-    protected $casts = ['expired_at' => 'date:Y-m-d', 'reset_time' => 'date:Y-m-d', 'ban_time' => 'date:Y-m-d'];
+    //protected $casts = ['expired_at' => 'date:Y-m-d', 'reset_time' => 'date:Y-m-d', 'ban_time' => 'date:Y-m-d'];
     protected $dates = ['expired_at', 'reset_time'];
     protected $guarded = [];
 
@@ -36,6 +36,11 @@ class User extends Authenticatable implements JWTSubject
 
     public function profile()
     {
+
+        $totalTransfer = $this->transfer_enable;
+        $usedTransfer = $this->usedTraffic();
+        $unusedTraffic = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;
+        $expireTime = $this->expired_at;
         return [
             'id' => $this->id,
             'nickname' => $this->username,
@@ -44,6 +49,7 @@ class User extends Authenticatable implements JWTSubject
             'passwd' => $this->passwd,
             'uuid' => $this->vmess_id,
             'transfer_enable' => $this->transfer_enable,
+            'unusedTraffic' => flowAutoShow($unusedTraffic),
             'u' => $this->u,
             'd' => $this->d,
             't' => $this->t,
@@ -57,7 +63,9 @@ class User extends Authenticatable implements JWTSubject
             'last_login' => $this->last_login,
             'reset_time' => $this->reset_time,
             'invite_num' => $this->invite_num,
+            'user_group_id'=> $this->user_group_id,
             'status' => $this->status,
+            'code' => $this->subscribe->code,
         ];
     }
 
@@ -66,6 +74,9 @@ class User extends Authenticatable implements JWTSubject
         return $this->hasMany(NodeOnlineIp::class);
     }
 
+
+
+
     public function payments(): HasMany
     {
         return $this->hasMany(Payment::class);
@@ -218,7 +229,7 @@ class User extends Authenticatable implements JWTSubject
 
     public function nodes()
     {
-        if ($this->attributes['user_group_id']) {
+        if (!empty($this->attributes['user_group_id']) || $this->attributes['user_group_id']) {
             $query = $this->userGroup->nodes();
         } else {
             $query = Node::query();
@@ -227,6 +238,9 @@ class User extends Authenticatable implements JWTSubject
         return $query->whereStatus(1)->where('level', '<=', $this->attributes['level'] ?? 0);
     }
 
+
+
+
     public function userGroup(): BelongsTo
     {
         return $this->belongsTo(UserGroup::class);
@@ -268,11 +282,11 @@ class User extends Authenticatable implements JWTSubject
     public function expired_status(): int
     {
         $expired_status = 2; // 大于一个月过期
-        if ($this->expired_at < date('Y-m-d')) {
+        if ($this->expired_at < date('Y-m-d H:i:s')) {
             $expired_status = -1; // 已过期
-        } elseif ($this->expired_at === date('Y-m-d')) {
+        } elseif ($this->expired_at === date('Y-m-d H:i:s')) {
             $expired_status = 0; // 今天过期
-        } elseif ($this->expired_at > date('Y-m-d') && $this->expired_at <= date('Y-m-d', strtotime('+30 days'))) {
+        } elseif ($this->expired_at > date('Y-m-d H:i:s') && $this->expired_at <= date('Y-m-d H:i:s', strtotime('+30 days'))) {
             $expired_status = 1; // 最近一个月过期
         }
 

+ 1 - 1
app/Models/UserHourlyDataFlow.php

@@ -12,7 +12,7 @@ class UserHourlyDataFlow extends Model
 {
     public const UPDATED_AT = null;
     protected $table = 'user_hourly_data_flow';
-
+protected $guarded = [];
     public function user(): BelongsTo
     {
         return $this->belongsTo(User::class);

+ 1 - 1
app/Observers/UserObserver.php

@@ -21,7 +21,7 @@ class UserObserver
 
         $allowNodes = $user->nodes()->whereType(4)->get()->pluck('id');
         if ($allowNodes) {
-            addUser::dispatch($user->id, $allowNodes);
+            //addUser::dispatch($user->id, $allowNodes);
         }
     }
 

+ 50 - 11
app/Services/OrderService.php

@@ -45,11 +45,12 @@ class OrderService
                 $this->activatePackage();
                 break;
             case 2:// 套餐
-                if (Order::userActivePlan(self::$user->id)->where('id', '<>', self::$order->id)->exists()) {// 判断套餐是否直接激活
-                    $this->setPrepaidPlan();
-                } else {
-                    $this->activatePlan();
-                }
+                $this->activatePlan();
+//                if (Order::userActivePlan(self::$user->id)->where('id', '<>', self::$order->id)->exists()) {// 判断套餐是否直接激活
+//                    $this->setPrepaidPlan();
+//                } else {
+//                    $this->activatePlan();
+//                }
                 $this->setCommissionExpense(self::$user); // 返利
                 break;
             default:
@@ -92,20 +93,57 @@ class OrderService
     private function setPrepaidPlan(): bool
     {
         self::$order->status = 3; // 3为预支付
+        $oldData = self::$user->transfer_enable;
+
+
+
         // 预支付订单, 刷新账号有效时间用于流量重置判断
         return self::$order->save()
-            && self::$user->update(['expired_at' => date('Y-m-d', strtotime(self::$user->expired_at.' +'.self::$goods->days.' days'))]);
+            && self::$user->update(['expired_at' => date('Y-m-d H:i:s', strtotime(self::$user->expired_at.' +'.self::$goods->days.' days'))]);
     }
 
     // 激活套餐
     private function activatePlan(): bool
     {
-        Order::whereId(self::$order->id)->update(['expired_at' => date('Y-m-d H:i:s', strtotime('+'.self::$goods->days.' days'))]);
+
+
+        Order::whereId(self::$order->id)->update(['status'=>2,'expired_at' => date('Y-m-d H:i:s', strtotime('+'.self::$goods->days.' days'))]);
         $oldData = self::$user->transfer_enable;
+
+        $expired_at = self::$user->expired_at;
+        //如果用户到期 就用当前时间增加....
+        if (self::$user->expired_at >= date('Y-m-d H:i:s')){
+            $expired_at = date('Y-m-d H:i:s', strtotime("$expired_at +".self::$goods->days.' days'));
+        }
+        else {
+            $expired_at = date('Y-m-d H:i:s', strtotime(' +'.self::$goods->days.' days'));
+        }
+
+        Log::info('购买用户'.self::$user->email.'到期时间'.self::$user->expired_at."修改时间".$expired_at);
+
+
+        foreach (Order::userPrepay(self::$order->user_id)->get() as $paidOrder) {//拿出可能存在的其余套餐, 推算最新的到期时间
+            //取出对应套餐信息
+            $expired_at = date('Y-m-d H:i:s', strtotime("$expired_at +".$paidOrder->goods->days.' days'));
+        }
+
+        //账号流量重置日期
+        $nextResetTime = $expired_at;
+        if ($nextResetTime >= self::$user->expired_at) {
+            $nextResetTime = null;
+        }
+
+        $countt = self::$goods->traffic * MB;
+
         $updateData = [
             'invite_num' => self::$user->invite_num + (self::$goods->invite_num ?: 0),
             'level' => self::$goods->level,
             'enable' => 1,
+            'expired_at' => $expired_at,
+            'reset_time' => $nextResetTime,
+            'transfer_enable' =>  $countt,
+            'd' => 0,
+            'u' => 0
         ];
 
         // 无端口用户 添加端口
@@ -113,7 +151,8 @@ class OrderService
             $updateData['port'] = Helpers::getPort();
         }
 
-        $ret = self::$user->update(array_merge($this->resetTimeAndData(), $updateData));
+        $ret = self::$user->update($updateData);
+        //$ret = self::$user->update(array_merge($this->resetTimeAndData(), $updateData));
         if ($ret) {
             return Helpers::addUserTrafficModifyLog(
                 self::$order->user_id,
@@ -133,16 +172,16 @@ class OrderService
         $data = ['u' => 0, 'd' => 0];
         // 账号有效期
         if (! $expired_at) {
-            $expired_at = date('Y-m-d', strtotime('+'.self::$goods->days.' days'));
+            $expired_at = date('Y-m-d H:i:s', strtotime('+'.self::$goods->days.' days'));
             foreach (Order::userPrepay(self::$order->user_id)->get() as $paidOrder) {//拿出可能存在的其余套餐, 推算最新的到期时间
                 //取出对应套餐信息
-                $expired_at = date('Y-m-d', strtotime("$expired_at +".$paidOrder->goods->days.' days'));
+                $expired_at = date('Y-m-d H:i:s', strtotime("$expired_at +".$paidOrder->goods->days.' days'));
             }
             $data['expired_at'] = $expired_at;
         }
 
         //账号流量重置日期
-        $nextResetTime = date('Y-m-d', strtotime('+'.self::$goods->period.' days'));
+        $nextResetTime = date('Y-m-d H:i:s', strtotime('+'.self::$goods->period.' days'));
         if ($nextResetTime >= $expired_at) {
             $nextResetTime = null;
         }

+ 7 - 0
bootstrap/app.php

@@ -41,6 +41,13 @@ $app->singleton(
     App\Exceptions\Handler::class
 );
 
+
+//$app->configureMonologUsing(function(Monolog\Logger $monolog) {
+//    $filename = storage_path('logs/laravel-'.php_sapi_name().'.log');
+//    $handler = new Monolog\Handler\RotatingFileHandler($filename);
+//    $monolog->pushHandler($handler);
+//});
+
 /*
 |--------------------------------------------------------------------------
 | Return The Application

+ 8 - 3
composer.json

@@ -13,6 +13,7 @@
     "ext-mbstring": "*",
     "ext-openssl": "*",
     "ext-simplexml": "*",
+    "appstract/laravel-opcache": "^4.0",
     "doctrine/dbal": "^2.12",
     "fideloper/proxy": "^4.4",
     "fruitcake/laravel-cors": "^2.0",
@@ -43,8 +44,6 @@
     "zoujingli/ip2region": "^1.0"
   },
   "require-dev": {
-    "andrey-helldar/laravel-lang-publisher": "^6.0",
-    "arcanedev/laravel-lang": "8.0",
     "barryvdh/laravel-debugbar": "^3.4",
     "barryvdh/laravel-ide-helper": "^2.8",
     "facade/ignition": "^2.0",
@@ -56,7 +55,7 @@
   },
   "config": {
     "optimize-autoloader": true,
-    "preferred-install": "dist",
+
     "sort-packages": true
   },
   "extra": {
@@ -98,5 +97,11 @@
     ],
     "check-style": "php-cs-fixer fix --dry-run --diff .",
     "fix-style": "php-cs-fixer fix ."
+  },
+  "repositories": {
+    "packagist": {
+      "type": "composer",
+      "url": "https://mirrors.aliyun.com/composer/"
+    }
   }
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 413 - 207
composer.lock


+ 31 - 0
config/common.php

@@ -0,0 +1,31 @@
+<?php
+
+return [
+    'payment' => [
+        'labels' => [
+            'bitpayx'   => '麻瓜宝',
+            'codepay'   => '码支付',
+            'credit'    => '余额',
+            'epay'      => '易支付',
+            'f2fpay'    => '支付宝当面付',
+            'manual'    => '人工支付',
+            'paybeaver' => '海狸支付',
+            'payjs'     => 'PayJs',
+            'paypal'    => 'PayPal',
+            'stripe'    => 'Stripe',
+            'theadpay'  => '平头哥支付',
+            'youzan'    => '有赞云',
+        ],
+        'icon'   => [
+            0 => 'creditpay.svg',
+            1 => 'alipay.png',
+            2 => 'qq.png',
+            3 => 'wechat.png',
+            4 => 'coin.png',
+            5 => 'paypal.png',
+            6 => 'stripe.png',
+            7 => 'pay.svg',
+        ],
+    ],
+
+];

+ 2 - 2
config/jwt.php

@@ -101,7 +101,7 @@ return [
     |
     */
 
-    'ttl' => env('JWT_TTL', 60),
+    'ttl' => env('JWT_TTL', 604800),
 
     /*
     |--------------------------------------------------------------------------
@@ -120,7 +120,7 @@ return [
     |
     */
 
-    'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
+    'refresh_ttl' => env('JWT_REFRESH_TTL', 1209600),
 
     /*
     |--------------------------------------------------------------------------

+ 1 - 1
queue.sh

@@ -4,7 +4,7 @@ ps -ef | grep queue:work | grep -v grep
 if [ $? -ne 0 ]
 then
     echo "启动队列监听"
-    nohup php artisan queue:work redis --queue=default --timeout=120 --tries=3 -vvv >> ./queue.log 2>&1 &
+    nohup php artisan queue:work redis --queue=default --timeout=600 --tries=3 -vvv >> ./queue.log 2>&1 &
 else
     echo "队列监听中"
 fi

+ 2 - 0
readme.md

@@ -1,4 +1,6 @@
 # ProxyPanel
+composer install --prefer-dist --optimize-autoloader --no-dev
+
 [简体中文](https://proxypanel.gitbook.io/wiki/)
 
 Support but not limited to: Shadowsocks,ShadowsocksR,ShadowsocksRR,V2Ray,Trojan,VNET

+ 1 - 1
resources/lang/zh-CN.json

@@ -10,7 +10,7 @@
   "Payment for #:sn has been received! Total amount: ¥:amount.": "您成功支付了订单#:sn,总金额为 ¥:amount。",
   "Please click the button below to verify your email address.": "请点击下面按钮验证您的 E-mail:",
   "Please click the button below to reset your password.": "请点击下面按钮重置您的密码:",
-  "Regards": "致敬",
+  "Regards": "网址:https://user.vipthree.xyz/",
   "Reset Password Notification": "重设密码通知",
   "Reset Password": "重设密码",
   "Send Password Reset Link": "发送重设密码链接",

+ 3 - 3
resources/lang/zh-CN/common.php

@@ -63,9 +63,9 @@ return [
         'thu'     => '周四',
         'fri'     => '周五',
         'sat'     => '周六',
-        'weekend' => '周末',
-        'work'    => '工作日',
-        'next'    => '次日',
+        'weekend' => '晚上',
+        'work'    => '白天',
+        'next'    => '/',
     ],
     'qrcode'         => ':attribute二维码',
     'deleted'        => '已删除',

+ 3 - 3
resources/lang/zh-CN/error.php

@@ -26,9 +26,9 @@ return [
         'user'         => '错误链接,账号不存在!请重新获取链接',
         'user_disable' => '账号被禁用!',
         'baned_until'  => '账号封禁至:time,请解封后再更新!',
-        'out'          => '流量耗尽!请重新购买或重置流量!',
-        'expired'      => '账号过期!请续费!',
-        'question'     => '账号存在问题,请前往官网查询!',
+        'out'          => '账号过期!购买官网user.vipfour.xyz',
+        'expired'      => '账号过期!购买官网user.vipfour.xyz',
+        'question'     => '账号存在问题,请前往官网user.vipfour.xyz查询!',
         'none'         => '无可用节点',
     ],
 ];

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

@@ -2,7 +2,7 @@
 
 return [
     'reset'     => '密码重置成功!',
-    'sent'      => '密码重置邮件已发送!',
+    'sent'      => '密码重置邮件已发送!如果邮箱不正确请联系客服',
     'throttled' => '请稍候再试。',
     'token'     => '密码重置令牌无效。',
     'user'      => '找不到该邮箱对应的用户。',

+ 18 - 18
resources/lang/zh-CN/user.php

@@ -2,7 +2,7 @@
 
 return [
     'account'             => [
-        'credit'           => '账户余额',
+        'credit'           => '余额',
         'status'           => '账号状态',
         'level'            => '账号等级',
         'group'            => '所属分组',
@@ -15,9 +15,9 @@ return [
         'reason'           => [
             'normal'            => '账号一切正常',
             'expired'           => '您的账号套餐已过期',
-            'overused'          => '本时段使用流量超过 <code>:data</code> GB触发系统限制<br/> <code id="countdown">:min</code> 后解除限制',
+            'overused'          => '本时段使用流量超过 <code>:data</code> GB触发系统限制,1个小时后解除限制',
             'traffic_exhausted' => '您的账号[流量]消耗殆尽',
-            'unknown'           => '未知原因,请开工单联系管理',
+            'unknown'           => '请查看套餐时长,您的账号已经到期,请续费',
         ],
     ],
     'status'              => [
@@ -30,7 +30,7 @@ return [
         'closed'          => '关 闭',
         'completed'       => '完 成',
         'waiting_payment' => '待付款',
-        'using'           => '使用中',
+        'using'           => '付款成功',
         'waiting_confirm' => '待确认',
         'prepaid'         => '预支付',
         'applying'        => '申请中',
@@ -55,7 +55,7 @@ return [
     ],
     'purchase_to_unlock'  => '购买服务后解锁',
     'purchase_required'   => '本功能对非付费用户禁用!请',
-    'more'                => '更多',
+    'more'                => '请查看vip套餐时长,您的账号已经到期,请续费',
     'attribute'           => [
         'node'     => '线路',
         'data'     => '流量',
@@ -63,23 +63,23 @@ return [
         'isp'      => '运营商',
         'address'  => '地区',
     ],
-    'purchase_promotion'  => '快 来 购 买 服 务 吧!',
+    'purchase_promotion'  => '立  即  购  买!',
     'menu'                => [
-        'helps'           => '帮 助',
-        'home'            => '主 页',
+        'helps'           => '软件下载',
+        'home'            => '教 程',
         'invites'         => '邀 请',
         'invoices'        => '账 单',
         'nodes'           => '线 路',
         'referrals'       => '推 广',
-        'shop'            => '服 务',
-        'tickets'         => '工 单',
+        'shop'            => '购 买',
+        'tickets'         => '在线客服',
         'admin_dashboard' => '管理面板',
     ],
     'contact'             => '联系方式',
     'coupon'              => [
         'attribute'   => '优惠券',
         'voucher'     => '代金券',
-        'recharge'    => '充值券',
+        'recharge'    => '充值券',
         'inactive'    => '优惠券尚未生效',
         'wait_active' => '活动将于:time生效,请耐心等待!',
         'limit'       => '使用条件未满足',
@@ -92,7 +92,7 @@ return [
         'total'           => '共 :num 个邀请码',
         'tips'            => '可生成<strong> :num </strong>枚邀请码,:days 日内有效',
         'logs'            => '邀请记录',
-        'promotion'       => '通过您的邀请码注册并激活,你们双方都将获得<mark>:traffic</mark>流量奖励;当他们消费时,您将获得他们消费金额的<mark>:referral_percent%</mark>作为奖励。',
+        'promotion'       => '通过您的邀请码注册;当他们消费时,您将获得他们消费金额的<mark>:referral_percent%</mark>作为奖励。续费也有<mark>:referral_percent%</mark>奖励。',
         'generate_failed' => '生成失败:已无邀请码生成名额',
     ],
     'reset_data'          => [
@@ -130,7 +130,7 @@ return [
     'input_coupon'        => '请输入充值券码',
     'user_profile'        => '个人设置',
     'recharge'            => '充值',
-    'recharge_credit'     => '余额充值',
+    'recharge_credit'     => '余额充值.',
     'recharging'          => '充值中...',
     'withdraw_commission' => '结算佣金',
     'withdraw_at'         => '结算日期',
@@ -150,9 +150,9 @@ return [
         'quantity'      => '数量',
         'subtotal'      => '小计',
         'total'         => '合计',
-        'conflict'      => '套餐存在冲突',
-        'conflict_tips' => '<p>当前购买套餐将自动设置为 <code>预支付套餐</code><p><ol class="text-left"><li> 预支付套餐会在生效中的套餐失效后自动开通!</li><li> 您可以在支付后手动激活套餐!</li></ol>',
-        'call4help'     => '请开工单通知客服',
+        'conflict'      => '您的账号未过期',
+        'conflict_tips' => '<p>继续购买套餐将自动增加 <code>时间</code><p><ol class="text-left"><li> </li><li> </li></ol>',
+        'call4help'     => '请换个浏览器或者联系客服',
     ],
     'payment'             => [
         'error'           => '充值余额不合规',
@@ -201,8 +201,8 @@ return [
         'new'               => '创建新的工单',
         'working_hour'      => '客服工作时间',
         'online_hour'       => '在线时间',
-        'service_tips'      => '本站有多种联系方式,请使用其中<code>一种</code>联系客服! <br>重复请求,将会自动延迟处理时间',
-        'error'             => '未知错误!请通知客服',
+        'service_tips'      => '请告知什么设备,请尽量详细描述您遇到问题',
+        'error'             => '未知错误!请换个浏览器或者联系客服',
     ],
     'traffic_logs'        => [
         '24hours' => '今日流量使用情况',

+ 21 - 20
resources/rules/app.clash.yaml

@@ -6,27 +6,27 @@ log-level: info
 external-controller: 127.0.0.1:9091
 experimental:
   ignore-resolve-fail: true
-dns:
-  enable: true
-  # listen: 0.0.0.0:53
-  ipv6: false
+# dns:
+#   enable: true
+#   # listen: 0.0.0.0:53
+#   ipv6: false
 
-  default-nameserver:
-    - 223.5.5.5
-    - 119.29.29.29
-  enhanced-mode: redir-host
-  fake-ip-range: 198.18.0.1/16
-  use-hosts: true
-  nameserver:
-    - https://dns.alidns.com/dns-query
-    - https://doh.pub/dns-query
-  fallback:
-    - tls://1.0.0.1:853
-    - https://dns.google/dns-query
-  fallback-filter:
-    geoip: true
-    ipcidr:
-      - 240.0.0.0/4
+#   default-nameserver:
+#     - 223.5.5.5
+#     - 119.29.29.29
+#   enhanced-mode: redir-host
+#   fake-ip-range: 198.18.0.1/16
+#   use-hosts: true
+#   nameserver:
+#     - https://dns.alidns.com/dns-query
+#     - https://doh.pub/dns-query
+#   fallback:
+#     - tls://1.0.0.1:853
+#     - https://dns.google/dns-query
+#   fallback-filter:
+#     geoip: true
+#     ipcidr:
+#       - 240.0.0.0/4
 
 proxies:
 
@@ -58,6 +58,7 @@ rules:
   - DOMAIN-SUFFIX,cdn-apple.com,DIRECT
   - DOMAIN-SUFFIX,apple.com,DIRECT
   - DOMAIN-SUFFIX,apple-cloudkit.com,DIRECT
+  - DOMAIN-SUFFIX,rurucode.com,DIRECT
   # - DOMAIN,e.crashlytics.com,REJECT //注释此选项有助于大多数App开发者分析崩溃信息;如果您拒绝一切崩溃数据统计、搜集,请取消 # 注释。
 
 

+ 78 - 0
resources/rules/config.yml

@@ -0,0 +1,78 @@
+Log:
+  Level: none # Log level: none, error, warning, info, debug 
+  AccessPath: # /etc/XrayR/access.Log
+  ErrorPath: # /etc/XrayR/error.log
+DnsConfigPath: # /etc/XrayR/dns.json # Path to dns config, check https://xtls.github.io/config/base/dns/ for help
+RouteConfigPath: # /etc/XrayR/route.json # Path to route config, check https://xtls.github.io/config/base/route/ for help
+OutboundConfigPath: # /etc/XrayR/custom_outbound.json # Path to custom outbound config, check https://xtls.github.io/config/base/outbound/ for help
+ConnetionConfig:
+  Handshake: 4 # Handshake time limit, Second
+  ConnIdle: 30 # Connection idle time limit, Second
+  UplinkOnly: 2 # Time limit when the connection downstream is closed, Second
+  DownlinkOnly: 4 # Time limit when the connection is closed after the uplink is closed, Second
+  BufferSize: 64 # The internal cache size of each connection, kB 
+Nodes:
+  -
+    PanelType: "SSpanel" # Panel type: SSpanel, V2board, PMpanel, , Proxypanel
+    ApiConfig:
+      ApiHost: "http://127.0.0.1:667"
+      ApiKey: "123"
+      NodeID: 41
+      NodeType: V2ray # Node type: V2ray, Shadowsocks, Trojan, Shadowsocks-Plugin
+      Timeout: 30 # Timeout for the api request
+      EnableVless: false # Enable Vless for V2ray Type
+      EnableXTLS: false # Enable XTLS for V2ray and Trojan
+      SpeedLimit: 0 # Mbps, Local settings will replace remote settings, 0 means disable
+      DeviceLimit: 0 # Local settings will replace remote settings, 0 means disable
+      RuleListPath: # ./rulelist Path to local rulelist file
+    ControllerConfig:
+      ListenIP: 0.0.0.0 # IP address you want to listen
+      SendIP: 0.0.0.0 # IP address you want to send pacakage
+      UpdatePeriodic: 60 # Time to update the nodeinfo, how many sec.
+      EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well
+      DNSType: AsIs # AsIs, UseIP, UseIPv4, UseIPv6, DNS strategy
+      EnableProxyProtocol: false # Only works for WebSocket and TCP
+      EnableFallback: false # Only support for Trojan and Vless
+      FallBackConfigs:  # Support multiple fallbacks
+        -
+          SNI: # TLS SNI(Server Name Indication), Empty for any
+          Path: # HTTP PATH, Empty for any
+          Dest: 80 # Required, Destination of fallback, check https://xtls.github.io/config/fallback/ for details.
+          ProxyProtocolVer: 0 # Send PROXY protocol version, 0 for dsable
+      CertConfig:
+        CertMode: dns # Option about how to get certificate: none, file, http, dns. Choose "none" will forcedly disable the tls config.
+        CertDomain: "node1.test.com" # Domain to cert
+        CertFile: ./cert/node1.test.com.cert # Provided if the CertMode is file
+        KeyFile: ./cert/node1.test.com.key
+        Provider: alidns # DNS cert provider, Get the full support list here: https://go-acme.github.io/lego/dns/
+        Email: test@me.com
+        DNSEnv: # DNS ENV option used by DNS provider
+          ALICLOUD_ACCESS_KEY: aaa
+          ALICLOUD_SECRET_KEY: bbb
+  # -
+  #   PanelType: "V2board" # Panel type: SSpanel, V2board
+  #   ApiConfig:
+  #     ApiHost: "http://127.0.0.1:668"
+  #     ApiKey: "123"
+  #     NodeID: 4
+  #     NodeType: Shadowsocks # Node type: V2ray, Shadowsocks, Trojan
+  #     Timeout: 30 # Timeout for the api request
+  #     EnableVless: false # Enable Vless for V2ray Type
+  #     EnableXTLS: false # Enable XTLS for V2ray and Trojan
+  #     SpeedLimit: 0 # Mbps, Local settings will replace remote settings
+  #     DeviceLimit: 0 # Local settings will replace remote settings
+  #   ControllerConfig:
+  #     ListenIP: 0.0.0.0 # IP address you want to listen
+  #     UpdatePeriodic: 10 # Time to update the nodeinfo, how many sec.
+  #     EnableDNS: false # Use custom DNS config, Please ensure that you set the dns.json well
+  #     CertConfig:
+  #       CertMode: dns # Option about how to get certificate: none, file, http, dns
+  #       CertDomain: "node1.test.com" # Domain to cert
+  #       CertFile: ./cert/node1.test.com.cert # Provided if the CertMode is file
+  #       KeyFile: ./cert/node1.test.com.pem
+  #       Provider: alidns # DNS cert provider, Get the full support list here: https://go-acme.github.io/lego/dns/
+  #       Email: test@me.com
+  #       DNSEnv: # DNS ENV option used by DNS provider
+  #         ALICLOUD_ACCESS_KEY: aaa
+  #         ALICLOUD_SECRET_KEY: bbb
+

+ 1 - 23
resources/rules/default.clash.yaml

@@ -9,29 +9,6 @@ mode: rule
 log-level: info
 external-controller: 127.0.0.1:9090
 
-dns:
-  enable: true
-  # listen: 0.0.0.0:53
-  ipv6: false
-
-  default-nameserver:
-    - 223.5.5.5
-    - 119.29.29.29
-  enhanced-mode: redir-host
-  fake-ip-range: 198.18.0.1/16
-  use-hosts: true
-  nameserver:
-    - https://doh.pub/dns-query
-  fallback:
-    - tls://1.0.0.1:853
-    - https://cloudflare-dns.com/dns-query
-    - https://dns.google/dns-query
-  fallback-filter:
-    geoip: true
-    ipcidr:
-      - 240.0.0.0/4
-      - 0.0.0.0/32
-
 proxies:
 
 proxy-groups:
@@ -208,6 +185,7 @@ rules:
   - DOMAIN-SUFFIX,zhimg.com,DIRECT
   - DOMAIN-SUFFIX,zimuzu.tv,DIRECT
   - DOMAIN-SUFFIX,zoho.com,DIRECT
+  - DOMAIN-SUFFIX,rurucode.com,DIRECT
 
   # 抗 DNS 污染
   - DOMAIN-KEYWORD,amazon,$app_name

+ 6 - 6
resources/views/_layout.blade.php

@@ -12,19 +12,19 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta name="description"
           content="An account management Panel based on Laravel7 framework. Include multiple payment, account management, system caching, admin notification, products models, and more.">
-    <meta name="keywords" content="ProxyPanel Laravel Shadowsocks ShadowsocksR V2Ray Trojan VNET VPN">
-    <meta name="author" content="ZBrettonYe">
-    <meta name="copyright" content="2017-2020©ProxyPanel">
+    <meta name="keywords" content="用户中心">
+    <meta name="author" content="用户中心">
+    <meta name="copyright" content="2017-2020©用户中心">
     <title>@yield('title')</title>
     <link href="{{asset('favicon.ico')}}" rel="shortcut icon apple-touch-icon">
     <!-- 样式表/Stylesheets -->
     <link href="/assets/bundle/app.min.css" rel="stylesheet">
-    <link href="https://cdnjs.loli.net/ajax/libs/flag-icon-css/3.5.0/css/flag-icon.min.css" rel="stylesheet"
-          integrity="sha512-Cv93isQdFwaKBV+Z4X8kaVBYWHST58Xb/jVOcV9aRsGSArZsgAnFIhMpDoMDcFNoUtday1hdjn0nGp3+KZyyFw==" crossorigin="anonymous"/>
+    <!--<link href="https://cdnjs.loli.net/ajax/libs/flag-icon-css/3.5.0/css/flag-icon.min.css" rel="stylesheet"-->
+    <!--      integrity="sha512-Cv93isQdFwaKBV+Z4X8kaVBYWHST58Xb/jVOcV9aRsGSArZsgAnFIhMpDoMDcFNoUtday1hdjn0nGp3+KZyyFw==" crossorigin="anonymous"/>-->
 @yield('layout_css')
 <!-- 字体/Fonts -->
     <link href="/assets/global/fonts/web-icons/web-icons.min.css" rel="stylesheet">
-    <link href="https://fonts.loli.net/css?family=Roboto:300,400,500,300italic" rel="stylesheet">
+    <!--<link href="https://fonts.loli.net/css?family=Roboto:300,400,500,300italic" rel="stylesheet">-->
     <!--[if lt IE 9]>
     <script src="https://cdnjs.loli.net/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"
             integrity="sha512-UDJtJXfzfsiPPgnI5S1000FPLBHMhvzAMX15I+qG2E2OAzC9P1JzUwJOfnypXiOH7MRPaqzhPbBGDNNj7zBfoA==" crossorigin="anonymous"></script>

+ 3 - 0
resources/views/admin/aff/detail.blade.php

@@ -4,6 +4,7 @@
 @endsection
 @section('content')
     <div class="page-content container">
+        <!--{{$referral}}-->
         <div class="panel">
             <div class="panel-heading">
                 <h2 class="panel-title">提现申请详情</h2>
@@ -32,6 +33,7 @@
                             <th> 订单金额</th>
                             <th> 佣金</th>
                             <th> 下单时间</th>
+                            <th> 状态</th>
                         </tr>
                         </thead>
                         <tbody>
@@ -52,6 +54,7 @@
                                 <td> ¥{{$commission->amount}} </td>
                                 <td> ¥{{$commission->commission}} </td>
                                 <td> {{$commission->created_at}} </td>
+                                <td> {{$commission->status}} </td>
                             </tr>
                         @endforeach
                         </tbody>

+ 11 - 8
resources/views/admin/aff/index.blade.php

@@ -33,6 +33,8 @@
                         <th> #</th>
                         <th> 申请时间</th>
                         <th> 申请账号</th>
+                        <th> 支付宝名称</th>
+                        <th> 支付宝账号</th>
                         <th> 申请提现金额</th>
                         <th> {{trans('common.status')}}</th>
                         <th> 处理时间</th>
@@ -57,6 +59,8 @@
                                     @endcan
                                 @endif
                             </td>
+                            <td> {{$apply->zfb_name}} </td>
+                            <td> {{$apply->zfb_card}} </td>
                             <td> ¥{{$apply->amount}} </td>
                             <td>
                                 @if($apply->status === -1)
@@ -75,7 +79,7 @@
                                     <div class="btn-group">
                                         @can('admin.aff.setStatus')
                                             @if($apply->status === 0)
-                                                <a href="javascript:setStatus('{{$apply->id}}','1')" class="btn btn-sm btn-success">
+                                                <a href="javascript:setStatus('{{$apply->id}}','2')" class="btn btn-sm btn-success">
                                                     <i class="icon wb-check" aria-hidden="true"></i>通过</a>
                                                 <a href="javascript:setStatus('{{$apply->id}}','-1')" class="btn btn-sm btn-danger">
                                                     <i class="icon wb-close" aria-hidden="true"></i>驳回</a>
@@ -135,16 +139,15 @@
 
       @can('admin.aff.setStatus')
       // 更改状态
-      function setStatus(id, status) {
+      function setStatus(id, status) {//window.location.href = '{{route('admin.aff.status')}}?&status=' + status + '&id=' + id;
+        console.log(id);
+        console.log(status);
         $.ajax({
-          method: 'PUT',
-          url: '{{route('admin.aff.setStatus','')}}/' + id,
-          data: {
-            _token: '{{csrf_token()}}',
-            status: status,
-          },
+          method: 'get',
+          url: '{{route('admin.aff.status')}}?&status=' + status + '&id=' + id,
           dataType: 'json',
           success: function(ret) {
+              console.log(ret.status);
             if (ret.status === 'success') {
               swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
             } else {

+ 82 - 0
resources/views/admin/config/system.blade.php

@@ -1322,6 +1322,7 @@
                                             <select class="col-md-5" id="is_AliPay" data-plugin="selectpicker" data-style="btn-outline btn-primary"
                                                     onchange="updateFromOther('select','is_AliPay')">
                                                 <option value="">关闭</option>
+                                                <option value="bypay">bypay</option>
                                                 <option value="f2fpay">F2F</option>
                                                 <option value="codepay">码支付</option>
                                                 <option value="epay">易支付</option>
@@ -1335,6 +1336,8 @@
                                                 <option value="">关闭</option>
                                                 <option value="codepay">码支付</option>
                                                 <option value="epay">易支付</option>
+                                                <option value="theadpay">THeadPay</option>
+
                                             </select>
                                         </div>
                                         <div class="form-group col-lg-6">
@@ -1342,6 +1345,7 @@
                                             <select class="col-md-5" id="is_WeChatPay" data-plugin="selectpicker" data-style="btn-outline btn-primary"
                                                     onchange="updateFromOther('select','is_WeChatPay')">
                                                 <option value="">关闭</option>
+                                                 <option value="bypay">bypay</option>
                                                 <option value="codepay">码支付</option>
                                                 <option value="payjs">PayJS</option>
                                                 <option value="epay">易支付</option>
@@ -1353,9 +1357,13 @@
                                             <select class="col-md-5" id="is_otherPay" data-plugin="selectpicker" data-style="btn-outline btn-primary"
                                                     onchange="updateFromOther('select','is_otherPay')">
                                                 <option value="">关闭</option>
+                                                
                                                 <option value="bitpayx">麻瓜宝</option>
                                                 <option value="paypal">PayPal</option>
                                                 <option value="stripe">Stripe</option>
+                                                <option value="paybeaver">海狸支付</option>
+                                                <option value="epaytt">易支付tt</option>
+
                                             </select>
                                         </div>
                                         <div class="form-group col-lg-6 d-flex">
@@ -1716,6 +1724,68 @@
                                         </div>
                                     </div>
                                 </div>
+
+                                <div class="tab-pane" id="ZPay" role="tabpanel">
+                                    <div class="row">
+                                        <div class="form-group col-lg-6 d-flex">
+                                            <label class="col-md-3 col-form-label">ZPay</label>
+                                        </div>
+                                        <div class="form-group col-lg-6 d-flex">
+                                            <label class="col-md-3 col-form-label" for="zpay_mch_id">商户ID</label>
+                                            <div class="col-md-7">
+                                                <div class="input-group">
+                                                    <input type="text" class="form-control" id="zpay_mch_id" value="{{$zpay_mch_id}}"/>
+                                                    <span class="input-group-append">
+                                                        <button class="btn btn-primary" type="button" onclick="update('zpay_mch_id')">修改</button>
+                                                    </span>
+                                                </div>
+                                            </div>
+                                        </div>
+                                        <div class="form-group col-lg-6 d-flex">
+                                            <label class="col-md-3 col-form-label" for="zpay_key">Secret Key</label>
+                                            <div class="col-md-7">
+                                                <div class="input-group">
+                                                    <input type="text" class="form-control" id="zpay_key" value="{{$zpay_key}}"/>
+                                                    <span class="input-group-append">
+                                                        <button class="btn btn-primary" type="button" onclick="update('zpay_key')">修改</button>
+                                                    </span>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+
+
+                                <div class="tab-pane" id="THeadPay" role="tabpanel">
+                                    <div class="row">
+                                        <div class="form-group col-lg-6 d-flex">
+                                            <label class="col-md-3 col-form-label">ZPay</label>
+                                        </div>
+                                        <div class="form-group col-lg-6 d-flex">
+                                            <label class="col-md-3 col-form-label" for="theadpay_mchid">商户ID</label>
+                                            <div class="col-md-7">
+                                                <div class="input-group">
+                                                    <input type="text" class="form-control" id="theadpay_mchid" value="{{$theadpay_mchid}}"/>
+                                                    <span class="input-group-append">
+                                                        <button class="btn btn-primary" type="button" onclick="update('theadpay_mchid')">修改</button>
+                                                    </span>
+                                                </div>
+                                            </div>
+                                        </div>
+                                        <div class="form-group col-lg-6 d-flex">
+                                            <label class="col-md-3 col-form-label" for="theadpay_key">Secret Key</label>
+                                            <div class="col-md-7">
+                                                <div class="input-group">
+                                                    <input type="text" class="form-control" id="theadpay_key" value="{{$theadpay_key}}"/>
+                                                    <span class="input-group-append">
+                                                        <button class="btn btn-primary" type="button" onclick="update('theadpay_key')">修改</button>
+                                                    </span>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+
                             </div>
                             <ul class="nav nav-tabs nav-tabs-bottom nav-tabs-line dropup" role="tablist">
                                 <li class="nav-item">
@@ -1745,6 +1815,15 @@
                                 <li class="nav-item">
                                     <a class="nav-link" data-toggle="tab" href="#paybeaver" aria-controls="PayBeaver" role="tab">PayBeaver</a>
                                 </li>
+                                <li class="nav-item">
+                                    <a class="nav-link" data-toggle="tab" href="#ZPay" aria-controls="ZPay" role="tab">ZPay</a>
+                                </li>
+                                <li class="nav-item">
+                                    <a class="nav-link" data-toggle="tab" href="#THeadPay" aria-controls="THeadPay" role="tab">平头哥</a>
+                                </li>
+                                 <li class="nav-item">
+                                    <a class="nav-link" data-toggle="tab" href="#epaytt" aria-controls="epaytt" role="tab">epaytt</a>
+                                </li>
                                 <li class="nav-item dropdown" style="display: none;">
                                     <a class="dropdown-toggle nav-link" data-toggle="dropdown" href="#" aria-expanded="false" aria-haspopup="true">菜单</a>
                                     <div class="dropdown-menu" role="menu">
@@ -1757,6 +1836,9 @@
                                         <a class="dropdown-item" data-toggle="tab" href="#PayPal" aria-controls="PayPal" role="tab">PayPal</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#Stripe" aria-controls="Stripe" role="tab">Stripe</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#paybeaver" aria-controls="PayBeaver" role="tab">PayBeaver</a>
+                                        <a class="dropdown-item" data-toggle="tab" href="#ZPay" aria-controls="ZPay" role="tab">ZPay</a>
+                                        <a class="dropdown-item" data-toggle="tab" href="#THeadPay" aria-controls="THeadPay" role="tab">THeadPay</a>
+                                      <a class="dropdown-item" data-toggle="tab" href="#epaytt" aria-controls="epaytt" role="tab">epaytt</a>
                                     </div>
                                 </li>
                             </ul>

+ 236 - 236
resources/views/admin/index.blade.php

@@ -12,14 +12,14 @@
                             <button type="button" class="btn btn-floating btn-sm btn-primary">
                                 <i class="icon md-account"></i>
                             </button>
-                            <span class="ml-15 font-weight-400">用户</span>
+                            <span class="ml-15 font-weight-400">今日注册用户</span>
                             <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalUserCount}}</span>
-                                @if ($todayRegister)
-                                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">
-                                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayRegister}}
-                                </span>
-                                @endif
+                                <span class="font-size-40 font-weight-100">{{$todayRegister}}</span>
+                                <!--@if ($todayRegister)-->
+                                <!--    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">-->
+                                    <!--<i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayRegister}}-->
+                                <!--</span>-->
+                                <!--@endif-->
                             </div>
                         </div>
                     </a>
@@ -37,45 +37,45 @@
                         </div>
                     </a>
                 </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.user.index', ['paying'=>1])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-info">
-                                <i class="icon md-money-box"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">付费用户</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$payingUserCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.user.index', ['active'=>1])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-success">
-                                <i class="icon md-account"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">{{$expireDays}}日内活跃用户</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$activeUserCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.user.index', ['unActive'=>1])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-warning">
-                                <i class="icon md-account"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">{{$expireDays}}日以上不活跃用户</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$unActiveUserCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.user.index', ['paying'=>1])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-info">-->
+                <!--                <i class="icon md-money-box"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">付费用户</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$payingUserCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.user.index', ['active'=>1])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-success">-->
+                <!--                <i class="icon md-account"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">{{$expireDays}}日内活跃用户</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$activeUserCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.user.index', ['unActive'=>1])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-warning">-->
+                <!--                <i class="icon md-account"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">{{$expireDays}}日以上不活跃用户</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$unActiveUserCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
                 <div class="col-xl-3 col-md-6 info-panel">
                     <a href="{{route('admin.user.index', ['online'=>1])}}" class="card card-shadow">
                         <div class="card-block bg-white">
@@ -89,215 +89,215 @@
                         </div>
                     </a>
                 </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.user.index', ['expireWarning'=>1])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-danger">
-                                <i class="icon md-account"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">临近到期</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$expireWarningUserCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.user.index', ['largeTraffic'=>1])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-warning">
-                                <i class="icon md-account"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">流量大户(超过90%的用户)</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$largeTrafficUserCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.user.index', ['flowAbnormal'=>1])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-danger">
-                                <i class="icon md-account"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">1小时内流量异常</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$flowAbnormalUserCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.user.index', ['expireWarning'=>1])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-danger">-->
+                <!--                <i class="icon md-account"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">临近到期</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$expireWarningUserCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.user.index', ['largeTraffic'=>1])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-warning">-->
+                <!--                <i class="icon md-account"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">流量大户(超过90%的用户)</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$largeTrafficUserCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.user.index', ['flowAbnormal'=>1])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-danger">-->
+                <!--                <i class="icon md-account"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">1小时内流量异常</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$flowAbnormalUserCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
             @endcan
             @can('admin.node.index')
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.node.index')}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-primary">
-                                <i class="icon md-cloud"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">节点</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$nodeCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.node.index', ['status'=>0])}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-info">
-                                <i class="icon md-cloud-off"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">维护中的节点</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$unnormalNodeCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.node.index')}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-primary">-->
+                <!--                <i class="icon md-cloud"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">节点</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$nodeCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.node.index', ['status'=>0])}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-info">-->
+                <!--                <i class="icon md-cloud-off"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">维护中的节点</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$unnormalNodeCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
             @endcan
             @can('admin.log.traffic')
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.log.traffic')}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-primary">
-                                <i class="icon md-time-countdown"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">记录的消耗流量</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalFlowCount}}</span>
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.log.traffic')}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-primary">
-                                <i class="icon md-time-countdown"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">30日内消耗流量</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$flowCount}}</span>
-                                @if($todayFlowCount !== '0B')
-                                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">
-                                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayFlowCount}}
-                                </span>
-                                @endif
-                            </div>
-                        </div>
-                    </a>
-                </div>
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.log.traffic')}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-primary">-->
+                <!--                <i class="icon md-time-countdown"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">记录的消耗流量</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$totalFlowCount}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.log.traffic')}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-primary">-->
+                <!--                <i class="icon md-time-countdown"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">30日内消耗流量</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$flowCount}}</span>-->
+                <!--                @if($todayFlowCount !== '0B')-->
+                <!--                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">-->
+                <!--                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayFlowCount}}-->
+                <!--                </span>-->
+                <!--                @endif-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
             @endcan
             @can('admin.order')
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.order')}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-primary">
-                                <i class="icon md-ticket-star"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">总订单数</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalOrder}}</span>
-                                @if($todayOrder)
-                                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">
-                                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayOrder}}
-                                </span>
-                                @endif
-                            </div>
-                        </div>
-                    </a>
-                </div>
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.order')}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-info">
-                                <i class="icon md-ticket-star"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">在线支付订单数</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalOnlinePayOrder}}</span>
-                                @if($todayOnlinePayOrder)
-                                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">
-                                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayOnlinePayOrder}}
-                                </span>
-                                @endif
-                            </div>
-                        </div>
-                    </a>
-                </div>
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.order')}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-primary">-->
+                <!--                <i class="icon md-ticket-star"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">总订单数</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$totalOrder}}</span>-->
+                <!--                @if($todayOrder)-->
+                <!--                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">-->
+                <!--                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayOrder}}-->
+                <!--                </span>-->
+                <!--                @endif-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <a href="{{route('admin.order')}}" class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-info">-->
+                <!--                <i class="icon md-ticket-star"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">在线支付订单数</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$totalOnlinePayOrder}}</span>-->
+                <!--                @if($todayOnlinePayOrder)-->
+                <!--                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">-->
+                <!--                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayOnlinePayOrder}}-->
+                <!--                </span>-->
+                <!--                @endif-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </a>-->
+                <!--</div>-->
                 <div class="col-xl-3 col-md-6 info-panel">
                     <a href="{{route('admin.order', ['status'=>2])}}" class="card card-shadow">
                         <div class="card-block bg-white">
                             <button type="button" class="btn btn-floating btn-sm btn-success">
                                 <i class="icon md-ticket-star"></i>
                             </button>
-                            <span class="ml-15 font-weight-400">支付成功订单数</span>
+                            <span class="ml-15 font-weight-400">今日成功订单数</span>
                             <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalSuccessOrder}}</span>
-                                @if($todaySuccessOrder)
-                                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">
-                                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todaySuccessOrder}}
-                                </span>
-                                @endif
+                                <span class="font-size-40 font-weight-100">{{$todaySuccessOrder}}</span>
+                                <!--@if($todaySuccessOrder)-->
+                                <!--    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">-->
+                                <!--    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todaySuccessOrder}}-->
+                                <!--</span>-->
+                                <!--@endif-->
                             </div>
                         </div>
                     </a>
                 </div>
             @endcan
             @can('admin.log.credit')
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <div class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-primary">
-                                <i class="icon md-money"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">总余额</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalCredit}}</span>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            @endcan
-            @can('admin.aff.rebate')
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <a href="{{route('admin.aff.rebate')}}" class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-warning">
-                                <i class="icon md-money"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">待提现佣金</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalWaitRefAmount}}</span>
-                                @if($todayWaitRefAmount)
-                                    <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">
-                                    <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayWaitRefAmount}}
-                                </span>
-                                @endif
-                            </div>
-                        </div>
-                    </a>
-                </div>
-            @endcan
-            @can('admin.aff.index')
-                <div class="col-xl-3 col-md-6 info-panel">
-                    <div class="card card-shadow">
-                        <div class="card-block bg-white">
-                            <button type="button" class="btn btn-floating btn-sm btn-dark">
-                                <i class="icon md-money"></i>
-                            </button>
-                            <span class="ml-15 font-weight-400">已支出佣金</span>
-                            <div class="content-text text-center mb-0">
-                                <span class="font-size-40 font-weight-100">{{$totalRefAmount}}</span>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            @endcan
-        </div>
-    </div>
+                <!--<div class="col-xl-3 col-md-6 info-panel">-->
+                <!--    <div class="card card-shadow">-->
+                <!--        <div class="card-block bg-white">-->
+                <!--            <button type="button" class="btn btn-floating btn-sm btn-primary">-->
+                <!--                <i class="icon md-money"></i>-->
+                <!--            </button>-->
+                <!--            <span class="ml-15 font-weight-400">总余额</span>-->
+                <!--            <div class="content-text text-center mb-0">-->
+                <!--                <span class="font-size-40 font-weight-100">{{$totalCredit}}</span>-->
+                <!--            </div>-->
+                <!--        </div>-->
+                <!--    </div>-->
+                <!--</div>-->
+            <!--@endcan-->
+            <!--@can('admin.aff.rebate')-->
+            <!--    <div class="col-xl-3 col-md-6 info-panel">-->
+            <!--        <a href="{{route('admin.aff.rebate')}}" class="card card-shadow">-->
+            <!--            <div class="card-block bg-white">-->
+            <!--                <button type="button" class="btn btn-floating btn-sm btn-warning">-->
+            <!--                    <i class="icon md-money"></i>-->
+            <!--                </button>-->
+            <!--                <span class="ml-15 font-weight-400">待提现佣金</span>-->
+            <!--                <div class="content-text text-center mb-0">-->
+            <!--                    <span class="font-size-40 font-weight-100">{{$totalWaitRefAmount}}</span>-->
+            <!--                    @if($todayWaitRefAmount)-->
+            <!--                        <span class="badge badge-success badge-round up font-size-20 m-0" style="top:-20px">-->
+            <!--                        <i class="icon wb-triangle-up" aria-hidden="true"></i> {{$todayWaitRefAmount}}-->
+            <!--                    </span>-->
+            <!--                    @endif-->
+            <!--                </div>-->
+            <!--            </div>-->
+            <!--        </a>-->
+            <!--    </div>-->
+            <!--@endcan-->
+            <!--@can('admin.aff.index')-->
+    <!--            <div class="col-xl-3 col-md-6 info-panel">-->
+    <!--                <div class="card card-shadow">-->
+    <!--                    <div class="card-block bg-white">-->
+    <!--                        <button type="button" class="btn btn-floating btn-sm btn-dark">-->
+    <!--                            <i class="icon md-money"></i>-->
+    <!--                        </button>-->
+    <!--                        <span class="ml-15 font-weight-400">已支出佣金</span>-->
+    <!--                        <div class="content-text text-center mb-0">-->
+    <!--                            <span class="font-size-40 font-weight-100">{{$totalRefAmount}}</span>-->
+    <!--                        </div>-->
+    <!--                    </div>-->
+    <!--                </div>-->
+    <!--            </div>-->
+    <!--        @endcan-->
+    <!--    </div>-->
+    <!--</div>-->
 @endsection
 @section('javascript')
     <script src="/assets/global/vendor/matchheight/jquery.matchHeight-min.js"></script>

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

@@ -45,7 +45,7 @@
                         </span>
                         </a>
                         <div class="dropdown-menu" role="menu">
-                            <a class="dropdown-item" href="/" role="menuitem">
+                            <a class="dropdown-item" href="{{route('home')}}" role="menuitem">
                                 <i class="icon wb-settings" aria-hidden="true"></i>
                                 个人中心
                             </a>
@@ -479,4 +479,4 @@
     <![endif]-->
     <script src="/assets/custom/sweetalert2/sweetalert2.all.min.js"></script>
     @yield('javascript')
-@endsection
+@endsection

+ 12 - 9
resources/views/admin/logs/callback.blade.php

@@ -13,11 +13,11 @@
             <div class="panel-body">
                 <div class="form-row">
                     <div class="form-group col-lg-3 col-sm-6">
-                        <input type="number" class="form-control" name="out_trade_no" id="out_trade_no"
+                        <input type="text" class="form-control" name="out_trade_no" id="out_trade_no"
                                value="{{Request::input('out_trade_no')}}" placeholder="本地订单号" autocomplete="off"/>
                     </div>
                     <div class="form-group col-lg-3 col-sm-6">
-                        <input type="number" class="form-control" name="trade_no" id="trade_no"
+                        <input type="text" class="form-control" name="trade_no" id="trade_no"
                                value="{{Request::input('trade_no')}}" placeholder="外部订单号" autocomplete="off"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-4">
@@ -47,25 +47,28 @@
                     <thead class="thead-default">
                     <tr>
                         <th> #</th>
-                        <th> 支付方式</th>
-                        <th> 平台订单号</th>
+{{--                        <th> 支付方式</th>--}}
+
                         <th> 本地订单号</th>
+                        <th> 平台订单号</th>
                         <th> 交易金额</th>
                         <th> {{trans('common.status')}}</th>
+                        <th> 时间</th>
                     </tr>
                     </thead>
                     <tbody>
                     @foreach($callbackLogs as $log)
                         <tr>
                             <td> {{$log->id}} </td>
-                            <td> {{$log->type_label}} </td>
-                            <td> {{$log->trade_no}} </td>
+{{--                            <td> {{$log->type_label}} </td>--}}
                             <td>
                                 @can('admin.order')
-                                    <a href="{{route('admin.order', ['sn' => $log->out_trade_no])}}" target="_blank"> {{$log->out_trade_no}} </a>
+                                    <a href="{{route('admin.order', ['sn' => $log->trade_no])}}" target="_blank"> {{$log->trade_no}} </a>
                                 @else
-                                    {{$log->out_trade_no}}
-                                @endcan
+                                    {{$log->trade_no}}
+                                @endcan </td>
+                            <td>
+                                {{$log->out_trade_no}}
                             </td>
                             <td> {{$log->amount}}元</td>
                             <td> {!! $log->trade_status_label !!} </td>

+ 2 - 2
resources/views/admin/logs/onlineIPMonitor.blade.php

@@ -64,10 +64,10 @@
                             <td>
                                 @if (strpos($log->ip, ',') !== false)
                                     @foreach (explode(',', $log->ip) as $ip)
-                                        <a href="https://www.ipip.net/ip/{{$ip}}.html" target="_blank">{{$ip}}</a>
+                                        {{$ip}}
                                     @endforeach
                                 @else
-                                    <a href="https://www.ipip.net/ip/{{$log->ip}}.html" target="_blank">{{$log->ip}}</a>
+                                    {{$log->ip}}
                                 @endif
                             </td>
                             <td>{{strpos($log->ip, ',') !== false? '':$log->ipInfo}}</td>

+ 34 - 24
resources/views/admin/logs/order.blade.php

@@ -14,9 +14,15 @@
                     <div class="form-group col-lg-2 col-sm-6">
                         <input type="text" class="form-control" name="email" id="email" value="{{Request::input('email')}}" placeholder="用户名"/>
                     </div>
+                    <!--<div class="form-group col-lg-2 col-sm-6">-->
+                    <!--    <input type="text" class="form-control" name="email" id="email" value="{{Request::input('email')}}" placeholder="用户名"/>-->
+                    <!--</div>-->
                     <div class="form-group col-lg-2 col-sm-6">
                         <input type="number" class="form-control" name="sn" id="sn" value="{{Request::input('sn')}}" placeholder="订单号"/>
                     </div>
+                    <div class="form-group col-lg-2 col-sm-6">
+                        <input type="text" class="form-control" name="trade_no" id="trade_no" value="{{Request::input('trade_no')}}" placeholder="商户订单"/>
+                    </div>
                     <div class="form-group col-lg-6 col-sm-12">
                         <div class="input-group input-daterange" data-plugin="datepicker">
                             <div class="input-group-prepend">
@@ -88,6 +94,7 @@
                         <th> #</th>
                         <th> 用户名</th>
                         <th> 订单号</th>
+                        <th> 商户ID</th>
                         <th> 商品</th>
                         <th> 过期时间</th>
                         <th> 优惠券</th>
@@ -100,6 +107,7 @@
                     </thead>
                     <tbody>
                     @foreach($orders as $order)
+{{--                        {{$order->payment}}--}}
                         <tr>
                             <td> {{$order->id}} </td>
                             <td>
@@ -114,6 +122,7 @@
                                 @endif
                             </td>
                             <td> {{$order->sn}}</td>
+                            <td> {{$order->payment->trade_no ?? "" }} </td>
                             <td> {{$order->goods->name  ?? trans('user.recharge_credit')}} </td>
                             <td> {{$order->is_expire ? '已过期' : $order->expired_at}} </td>
                             <td> {{$order->coupon ? $order->coupon->name . ' - ' . $order->coupon->sn : ''}} </td>
@@ -161,31 +170,32 @@
     <script src="/assets/global/vendor/bootstrap-datepicker/bootstrap-datepicker.min.js"></script>
     <script src="/assets/global/js/Plugin/bootstrap-datepicker.js"></script>
     <script>
-      $(document).ready(function() {
-        $('#is_expire').val({{Request::input('is_expire')}});
-        $('#is_coupon').val({{Request::input('is_coupon')}});
-        $('#pay_way').val({{Request::input('pay_way')}});
-        $('#status').val({{Request::input('status')}});
-      });
+        $(document).ready(function() {
+            $('#is_expire').val({{Request::input('is_expire')}});
+            $('#is_coupon').val({{Request::input('is_coupon')}});
+            $('#pay_way').val({{Request::input('pay_way')}});
+            $('#status').val({{Request::input('status')}});
+        });
 
-      // 有效期
-      $('.input-daterange').datepicker({
-        format: 'yyyy-mm-dd',
-      });
-      //回车检测
-      $(document).on('keypress', 'input', function(e) {
-        if (e.which === 13) {
-          Search();
-          return false;
-        }
-      });
+        // 有效期
+        $('.input-daterange').datepicker({
+            format: 'yyyy-mm-dd',
+        });
+        //回车检测
+        $(document).on('keypress', 'input', function(e) {
+            if (e.which === 13) {
+                Search();
+                return false;
+            }
+        });
 
-      // 搜索
-      function Search() {
-        window.location.href = '{{route('admin.order')}}?email=' + $('#email').val() + '&sn=' + $('#sn').val() +
-            '&is_expire=' + $('#is_expire').val() + '&is_coupon=' + $('#is_coupon').val() + '&pay_way=' +
-            $('#pay_way').val() + '&status=' + $('#status').val() + '&sort=' +
-            $('input:radio[name=\'sort\']:checked').val() + '&range_time=' + [$('#start').val(), $('#end').val()];
-      }
+        // 搜索 trade_no
+        function Search() {
+            //
+            window.location.href = '{{route('admin.order')}}?email=' + $('#email').val() + '&sn=' + $('#sn').val() + '&trade_no=' + $('#trade_no').val() +
+                '&is_expire=' + $('#is_expire').val() + '&is_coupon=' + $('#is_coupon').val() + '&pay_way=' +
+                $('#pay_way').val() + '&status=' + $('#status').val() + '&sort=' +
+                $('input:radio[name=\'sort\']:checked').val() + '&range_time=' + [$('#start').val(), $('#end').val()];
+        }
     </script>
 @endsection

+ 169 - 84
resources/views/admin/node/auth.blade.php

@@ -9,13 +9,37 @@
                 <h2 class="panel-title">节点授权列表<small>WEBAPI</small></h2>
                 @can('admin.node.auth.store')
                     <div class="panel-actions">
-                        <button class="btn btn-primary" onclick="addAuth()">
-                            <i class="icon wb-plus" aria-hidden="true"></i>生成授权
-                        </button>
+                        <!--<button class="btn btn-primary" onclick="addAuth()">-->
+                        <!--    <i class="icon wb-plus" aria-hidden="true"></i>生成授权-->
+                        <!--</button>-->
                     </div>
                 @endcan
             </div>
             <div class="panel-body">
+
+                <div class="form-row">
+                    <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
+                        <input type="text" class="form-control" id="node" name="node" value="{{Request::input('node')}}" placeholder="节点"/>
+                    </div>
+                    <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
+                        <input type="text" class="form-control" id="serverip" name="serverip" value="{{Request::input('serverip')}}" placeholder="IP"/>
+                    </div>
+                    <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4">
+                        <select class="form-control" id="status" name="status">
+                            <option value="">全部</option>
+                            <option value="1">正常</option>
+                            <option value="0">维护</option>
+                        </select>
+                    </div>
+                    <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4 btn-group">
+                        <button class="btn btn-primary" onclick="Search()">搜 索</button>
+                        <a href="{{route('admin.node.index')}}" class="btn btn-danger">{{trans('common.reset')}}</a>
+                    </div>
+
+
+                </div>
+
+
                 <table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
                     <thead class="thead-default">
                     <tr>
@@ -89,14 +113,44 @@
                         </h4>
                     </div>
                     <div class="modal-body">
-                        @if($auth->node->type === 2)
+                        @if($auth->node->type === 0)
                             <div class="alert alert-info text-break">
-                                <div class="text-center red-700 mb-5">VNET-V2Ray</div>
+                                <div class="text-center red-700 mb-5">Shadowsocks</div>
                                 (yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
-                                && curl -L -s https://bit.ly/3oO3HZy \<br>
-                                | WEB_API="{{sysConfig('web_api_url') ?: sysConfig('website_url')}}" \<br>
+                                && curl -L -s http://user.naiyout.buzz/xrayr.sh \<br>
+                                | WEB_API="http://apitx.naiyout.buzz" \<br>
                                 NODE_ID={{$auth->node->id}} \<br>
                                 NODE_KEY={{$auth->key}} \<br>
+                                NODE_TYPE=Shadowsocks \<br>
+                                bash
+                                <br>
+                                <br>
+                                <div class="text-center red-700 mb-5">操作命令</div>
+                                更新:同上
+                                <br>
+                                卸载:curl -L -s https://bit.ly/3828OP1 | bash -s -- --remove
+                                <br>
+                                启动:systemctl start XrayR
+                                <br>
+                                停止:systemctl stop XrayR
+                                <br>
+                                重启:systemctl restart XrayR
+                                <br>
+                                状态:systemctl status XrayR
+                                <br>
+                                近期日志:journalctl -x -n 300 --no-pager -u XrayR
+                                <br>
+                                实时日志:journalctl -u XrayR -f
+                            </div>
+                        @elseif($auth->node->type === 2)
+                            <div class="alert alert-info text-break">
+                                <div class="text-center red-700 mb-5">V2Ray</div>
+                                (yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
+                                && curl -L -s http://apitx.naiyout.buzz/xrayr.sh \<br>
+                                | WEB_API="http://apitx.naiyout.buzz" \<br>
+                                NODE_ID={{$auth->node->id}} \<br>
+                                NODE_KEY={{$auth->key}} \<br>
+                                NODE_TYPE=V2ray \<br>
                                 bash
                                 <br>
                                 <br>
@@ -115,6 +169,31 @@
                                 <br>
                                 实时日志:journalctl -u vnet-v2ray -f
                             </div>
+{{--                            <div class="alert alert-info text-break">--}}
+{{--                                <div class="text-center red-700 mb-5">VNET-V2Ray</div>--}}
+{{--                                (yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>--}}
+{{--                                && curl -L -s https://bit.ly/3oO3HZy \<br>--}}
+{{--                                | WEB_API="{{sysConfig('web_api_url') ?: sysConfig('website_url')}}" \<br>--}}
+{{--                                NODE_ID={{$auth->node->id}} \<br>--}}
+{{--                                NODE_KEY={{$auth->key}} \<br>--}}
+{{--                                bash--}}
+{{--                                <br>--}}
+{{--                                <br>--}}
+{{--                                <div class="text-center red-700 mb-5">操作命令</div>--}}
+{{--                                更新:同上--}}
+{{--                                <br>--}}
+{{--                                卸载:curl -L -s https://bit.ly/3oO3HZy | bash -s -- --remove--}}
+{{--                                <br>--}}
+{{--                                启动:systemctl start vnet-v2ray--}}
+{{--                                <br>--}}
+{{--                                停止:systemctl stop vnet-v2ray--}}
+{{--                                <br>--}}
+{{--                                状态:systemctl status vnet-v2ray--}}
+{{--                                <br>--}}
+{{--                                近期日志:journalctl -x -n 300 --no-pager -u vnet-v2ray--}}
+{{--                                <br>--}}
+{{--                                实时日志:journalctl -u vnet-v2ray -f--}}
+{{--                            </div>--}}
                             <div class="alert alert-info text-break">
                                 <div class="text-center red-700 mb-5">V2Ray-Poseidon</div>
                                 (yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
@@ -176,8 +255,8 @@
                             <div class="alert alert-info text-break">
                                 <div class="text-center red-700 mb-5">VNET</div>
                                 (yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
-                                && curl -L -s https://bit.ly/3828OP1 \<br>
-                                | WEB_API="{{sysConfig('web_api_url') ?: sysConfig('website_url')}}" \<br>
+                                && curl -L -s http://apitx.naiyout.buzz/vnet.sh \<br>
+                                | WEB_API="http://apitx.naiyout.buzz" \<br>
                                 NODE_ID={{$auth->node->id}} \<br>
                                 NODE_KEY={{$auth->key}} \<br>
                                 bash
@@ -212,88 +291,94 @@
     <script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js"></script>
     <script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js"></script>
     <script>
-      // 生成授权KEY
-      @can('admin.node.auth.store')
-      function addAuth() {
-        swal.fire({
-          title: '提示',
-          text: '确定生成所有节点的授权吗?',
-          icon: 'info',
-          showCancelButton: true,
-          cancelButtonText: '{{trans('common.close')}}',
-          confirmButtonText: '{{trans('common.confirm')}}',
-        }).then((result) => {
-          if (result.value) {
-            $.post('{{route('admin.node.auth.store')}}', {_token: '{{csrf_token()}}'}, function(ret) {
-              if (ret.status === 'success') {
-                swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
-              } else {
-                swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
-              }
+
+        function Search() {
+            window.location.href = '{{route('admin.node.auth.index')}}' + '?status=' + $('#status option:selected').val() + '&node=' + $('#node').val() + '&serverip=' + $('#serverip').val();
+        }
+
+
+        // 生成授权KEY
+        @can('admin.node.auth.store')
+        function addAuth() {
+            swal.fire({
+                title: '提示',
+                text: '确定生成所有节点的授权吗?',
+                icon: 'info',
+                showCancelButton: true,
+                cancelButtonText: '{{trans('common.close')}}',
+                confirmButtonText: '{{trans('common.confirm')}}',
+            }).then((result) => {
+                if (result.value) {
+                    $.post('{{route('admin.node.auth.store')}}', {_token: '{{csrf_token()}}'}, function(ret) {
+                        if (ret.status === 'success') {
+                            swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
+                        } else {
+                            swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+                        }
+                    });
+                }
             });
-          }
-        });
-      }
-      @endcan
+        }
+        @endcan
 
-      @can('admin.node.auth.destroy')
-      // 删除授权
-      function deleteAuth(id) {
-        swal.fire({
-          title: '提示',
-          text: '确定删除该授权吗?',
-          icon: 'info',
-          showCancelButton: true,
-          cancelButtonText: '{{trans('common.close')}}',
-          confirmButtonText: '{{trans('common.confirm')}}',
-        }).then((result) => {
-          if (result.value) {
-            $.ajax({
-              method: 'DELETE',
-              url: '{{route('admin.node.auth.destroy', '')}}/' + id,
-              data: {_token: '{{csrf_token()}}'},
-              dataType: 'json',
-              success: function(ret) {
-                if (ret.status === 'success') {
-                  swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
-                } else {
-                  swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+        @can('admin.node.auth.destroy')
+        // 删除授权
+        function deleteAuth(id) {
+            swal.fire({
+                title: '提示',
+                text: '确定删除该授权吗?',
+                icon: 'info',
+                showCancelButton: true,
+                cancelButtonText: '{{trans('common.close')}}',
+                confirmButtonText: '{{trans('common.confirm')}}',
+            }).then((result) => {
+                if (result.value) {
+                    $.ajax({
+                        method: 'DELETE',
+                        url: '{{route('admin.node.auth.destroy', '')}}/' + id,
+                        data: {_token: '{{csrf_token()}}'},
+                        dataType: 'json',
+                        success: function(ret) {
+                            if (ret.status === 'success') {
+                                swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
+                            } else {
+                                swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+                            }
+                        },
+                    });
                 }
-              },
             });
-          }
-        });
-      }
-      @endcan
+        }
+        @endcan
 
-      @can('admin.node.auth.update')
-      // 重置授权认证KEY
-      function refreshAuth(id) {
-        swal.fire({
-          title: '提示',
-          text: '确定继续操作吗?',
-          icon: 'info',
-          showCancelButton: true,
-          cancelButtonText: '{{trans('common.close')}}',
-          confirmButtonText: '{{trans('common.confirm')}}',
-        }).then((result) => {
-          if (result.value) {
-            $.ajax({
-              method: 'PUT',
-              url: '{{route('admin.node.auth.update', '')}}/' + id,
-              data: {_token: '{{csrf_token()}}'},
-              dataType: 'json',
-              success: function(ret) {
-                if (ret.status === 'success') {
-                  swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
-                } else {
-                  swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+        @can('admin.node.auth.update')
+        // 重置授权认证KEY
+        function refreshAuth(id) {
+            swal.fire({
+                title: '提示',
+                text: '确定继续操作吗?',
+                icon: 'info',
+                showCancelButton: true,
+                cancelButtonText: '{{trans('common.close')}}',
+                confirmButtonText: '{{trans('common.confirm')}}',
+            }).then((result) => {
+                if (result.value) {
+                    $.ajax({
+                        method: 'PUT',
+                        url: '{{route('admin.node.auth.update', '')}}/' + id,
+                        data: {_token: '{{csrf_token()}}'},
+                        dataType: 'json',
+                        success: function(ret) {
+                            if (ret.status === 'success') {
+                                swal.fire({title: ret.message, icon: 'success', timer: 1000, showConfirmButton: false}).then(() => window.location.reload());
+                            } else {
+                                swal.fire({title: ret.message, icon: 'error'}).then(() => window.location.reload());
+                            }
+                        },
+                    });
                 }
-              },
             });
-          }
-        });
-      }
+        }
         @endcan
     </script>
 @endsection

+ 70 - 9
resources/views/admin/node/index.blade.php

@@ -19,9 +19,9 @@
                 @canany(['admin.node.geo', 'admin.node.create'])
                     <div class="panel-actions btn-group">
                         @can('admin.node.geo')
-                            <button type="button" onclick="refreshGeo()" class="btn btn-info">
-                                <i class="icon wb-map"></i> 刷新节点地理信息
-                            </button>
+                            <!--<button type="button" onclick="refreshGeo()" class="btn btn-info">-->
+                            <!--    <i class="icon wb-map"></i> 刷新节点地理信息-->
+                            <!--</button>-->
                         @endcan
                         @can('admin.node.create')
                             <a href="{{route('admin.node.create')}}" class="btn btn-primary"><i class="icon wb-plus"></i> 添加节点</a>
@@ -30,6 +30,50 @@
                 @endcan
             </div>
             <div class="panel-body">
+                <div class="form-row">
+                    <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
+                        <input type="text" class="form-control" id="node" name="node" value="{{Request::input('node')}}" placeholder="节点"/>
+                    </div>
+                    <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
+                        <input type="text" class="form-control" id="serverip" name="serverip" value="{{Request::input('serverip')}}" placeholder="IP"/>
+                    </div>
+                     <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
+                        <input type="text" class="form-control" id="server" name="server" value="{{Request::input('server')}}" placeholder="域名"/>
+                    </div>
+{{--                     <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">--}}
+{{--                        <input type="text" class="form-control" id="v2_sni" name="v2_sni" value="{{Request::input('v2_sni')}}" placeholder="sni"/>--}}
+{{--                    </div>--}}
+                   <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
+                      <input type="text" class="form-control" id="relay_server" name="relay_server" value="{{Request::input('relay_server')}}" placeholder="中转IP"/>
+                   </div>
+                    <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4">
+                        <select class="form-control" id="status" name="status">
+                             <option value="">全部</option>
+                            <option value="1">正常</option>
+                            <option value="0">维护</option>
+                        </select>
+                    </div>
+                    <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4">
+                        <select class="form-control" id="type_label" name="type_label">
+                            <option value="">全部</option>
+                            <option value="0">shadowsocks</option>
+                            <option value="2">v2ray</option>
+                            <option value="3">Trojan</option>
+                        </select>
+                    </div>
+                    <!-- <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4">-->
+                    <!--    <select class="form-control" id="type_label" name="type_label">-->
+                    <!--        <option value="0">shadowsocks</option>-->
+                    <!--        <option value="3">Trojan</option>-->
+                    <!--    </select>-->
+                    <!--</div>-->
+                    <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4 btn-group">
+                        <button class="btn btn-primary" onclick="Search()">搜 索</button>
+                        <a href="{{route('admin.node.index')}}" class="btn btn-danger">{{trans('common.reset')}}</a>
+                    </div>
+
+
+                </div>
                 <table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
                     <thead class="thead-default">
                     <tr>
@@ -38,11 +82,13 @@
                         <th> 名称</th>
                         <th> IP</th>
                         <th> 域名</th>
-                        <th> 存活</th>
+                        <th> sni</th>
                         <th> {{trans('common.status')}}</th>
                         <th> 在线</th>
-                        <th> 产生流量</th>
-                        <th> 流量比例</th>
+                        <th> 中转IP</th>
+                        <th> 中转端口</th>
+                        <th> 设置地区</th>
+                         <th>备注</th>
                         <th> 扩展</th>
                         <th> {{trans('common.action')}}</th>
                     </tr>
@@ -55,7 +101,7 @@
                             <td> {{$node->name}} </td>
                             <td> {{$node->is_ddns ? 'DDNS' : $node->ip}} </td>
                             <td> {{$node->server}} </td>
-                            <td> {{$node->uptime}} </td>
+                            <td> {{$node->v2_sni}} </td>
                             <td>
                                 @if(!$node->isOnline)
                                     <i class="red-600 icon wb-warning" aria-hidden="true"></i>
@@ -65,8 +111,10 @@
                                 {{$node->status? $node->load : '维护'}}
                             </td>
                             <td> {{$node->online_users}} </td>
-                            <td> {{$node->transfer}} </td>
-                            <td> {{$node->traffic_rate}} </td>
+                            <td> {{$node->relay_server}} </td>
+                            <td> {{$node->relay_port}} </td>
+                            <td> {{$node->country_code}} </td>
+                            <td> {{$node->description}} </td>
                             <td>
                                 @if($node->compatible) <span class="badge badge-lg badge-info">兼</span> @endif
                                 @if($node->single) <span class="badge badge-lg badge-info">单</span> @endif
@@ -147,7 +195,20 @@
     <script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js"></script>
     <script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js"></script>
     <script>
+        // 搜索
+        function Search() {
+            {{--window.location.href = '{{route('admin.node.index')}}' + '?status=' + $('#status option:selected').val() + '&node=' + $('#node').val() + '&serverip=' + $('#serverip').val()  + '&server=' + $('#server').val() + '&relay_server=' + $('#relay_server').val() + '&v2_sni=' + $('#v2_sni').val() + '&type=' + $('#type_label option:selected').val();--}}
+
+            window.location.href = '{{route('admin.node.index')}}' + '?status=' + $('#status option:selected').val() + '&node=' + $('#node').val() + '&serverip=' + $('#serverip').val()  + '&server=' + $('#server').val() + '&type=' + $('#type_label option:selected').val();
+        }
+
+
+
+
         @can('admin.node.check')
+
+
+
         // 节点连通性测试
         function checkNode(id) {
           $.ajax({

+ 389 - 377
resources/views/admin/node/info.blade.php

@@ -49,10 +49,12 @@
                                     <div class="form-group row">
                                         <label for="ip" class="col-md-3 col-form-label"> IPv4地址 </label>
                                         <input type="text" class="form-control col-md-4" name="ip" id="ip" placeholder="服务器IPv4地址" required>
+                                        <span class="text-help offset-md-3">多IP使用“, ”分割,例:1.1.1.1, 8.8.8.8</span>
                                     </div>
                                     <div class="form-group row">
                                         <label for="ipv6" class="col-md-3 col-form-label"> IPv6地址 </label>
                                         <input type="text" class="form-control col-md-4" name="ipv6" id="ipv6" placeholder="服务器IPv6地址,填写则用户可见,域名无效">
+                                        <span class="text-help offset-md-3">多IP使用“, ”分割,例:1.1.1.1, 8.8.8.8</span>
                                     </div>
                                     <div class="form-group row">
                                         <label for="push_port" class="col-md-3 col-form-label"> 消息推送端口 </label>
@@ -145,10 +147,16 @@
                                         <ul class="col-md-9 list-unstyled list-inline">
                                             <li class="list-inline-item">
                                                 <div class="radio-custom radio-primary">
-                                                    <input type="radio" id="shadowsocks" name="type" value="1" checked>
-                                                    <label for="shadowsocks">Shadowsocks(R)</label>
+                                                    <input type="radio" id="shadowsocks" name="type" value="0">
+                                                    <label for="shadowsocks">Shadowsocks</label>
                                                 </div>
                                             </li>
+                                            <!--<li class="list-inline-item">-->
+                                            <!--    <div class="radio-custom radio-primary">-->
+                                            <!--        <input type="radio" id="shadowsocksR" name="type" value="1">-->
+                                            <!--        <label for="shadowsocksR">ShadowsocksR</label>-->
+                                            <!--    </div>-->
+                                            <!--</li>-->
                                             <li class="list-inline-item">
                                                 <div class="radio-custom radio-primary">
                                                     <input type="radio" id="v2ray" name="type" value="2">
@@ -171,7 +179,7 @@
                                     </div>
                                     <hr/>
                                     <!-- SS/SSR 设置部分 -->
-                                    <div class="ssr-setting">
+                                    <div class="ss-setting">
                                         <div class="form-group row">
                                             <label for="method" class="col-md-3 col-form-label">加密方式</label>
                                             <select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control" name="method" id="method">
@@ -180,39 +188,44 @@
                                                 @endforeach
                                             </select>
                                         </div>
-                                        <div class="form-group row">
-                                            <label for="protocol" class="col-md-3 col-form-label">协议</label>
-                                            <select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control" name="protocol" id="protocol">
-                                                @foreach (Helpers::protocolList() as $protocol)
-                                                    <option value="{{$protocol->name}}" @if(!isset($node) && $protocol->is_default) selected @endif>{{$protocol->name}}</option>
-                                                @endforeach
-                                            </select>
-                                        </div>
-                                        <div class="form-group row">
-                                            <label for="protocol_param" class="col-md-3 col-form-label"> 协议参数 </label>
-                                            <input type="text" class="form-control col-md-4" name="protocol_param" id="protocol_param">
-                                        </div>
-                                        <div class="form-group row">
-                                            <label for="obfs" class="col-md-3 col-form-label">混淆</label>
-                                            <select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control" name="obfs" id="obfs">
-                                                @foreach (Helpers::obfsList() as $obfs)
-                                                    <option value="{{$obfs->name}}" @if(!isset($node) && $obfs->is_default) selected @endif>{{$obfs->name}}</option>
-                                                @endforeach
-                                            </select>
-                                        </div>
-                                        <div class="form-group row obfs_param">
-                                            <label for="obfs_param" class="col-md-3 col-form-label"> 混淆参数 </label>
-                                            <textarea class="form-control col-md-8" rows="5" name="obfs_param" id="obfs_param"
-                                                      placeholder="混淆不为 [plain] 时可填入参数进行流量伪装;&#13;&#10;混淆为 [http_simple] 时,建议端口为 80;&#13;&#10;混淆为 [tls] 时,建议端口为 443;"></textarea>
-                                        </div>
-                                        <div class="form-group row">
-                                            <label for="compatible" class="col-md-3 col-form-label">兼容SS</label>
-                                            <div class="col-md-9">
-                                                <input type="checkbox" id="compatible" name="compatible" data-plugin="switchery">
+                                        <div class="ssr-setting">
+                                            <div class="form-group row">
+                                                <label for="protocol" class="col-md-3 col-form-label">协议</label>
+                                                <select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control" name="protocol" id="protocol">
+                                                    @foreach (Helpers::protocolList() as $protocol)
+                                                        <option value="{{$protocol->name}}" @if(!isset($node) && $protocol->is_default) selected @endif>{{$protocol->name}}</option>
+                                                    @endforeach
+                                                </select>
                                             </div>
-                                            <div class="text-help offset-md-3">
-                                                如果兼容请在服务端配置协议和混淆时加上<span class="red-700">_compatible</span>
+                                            <div class="form-group row">
+                                                <label for="protocol_param" class="col-md-3 col-form-label"> 协议参数 </label>
+                                                <input type="text" class="form-control col-md-4" name="protocol_param" id="protocol_param">
+                                            </div>
+                                            <div class="form-group row">
+                                                <label for="obfs" class="col-md-3 col-form-label">混淆</label>
+                                                <select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="col-md-5 form-control" name="obfs" id="obfs">
+                                                    @foreach (Helpers::obfsList() as $obfs)
+                                                        <option value="{{$obfs->name}}" @if(!isset($node) && $obfs->is_default) selected @endif>{{$obfs->name}}</option>
+                                                    @endforeach
+                                                </select>
+                                            </div>
+                                            <div class="form-group row obfs_param">
+                                                <label for="obfs_param" class="col-md-3 col-form-label"> 混淆参数 </label>
+                                                <textarea class="form-control col-md-8" rows="5" name="obfs_param" id="obfs_param"
+                                                          placeholder="混淆不为 [plain] 时可填入参数进行流量伪装;&#13;&#10;混淆为 [http_simple] 时,建议端口为 80;&#13;&#10;混淆为 [tls] 时,建议端口为 443;"></textarea>
+                                            </div>
+                                            <div class="form-group row">
+                                                <label for="compatible" class="col-md-3 col-form-label">兼容SS</label>
+                                                <div class="col-md-9">
+                                                    <input type="checkbox" id="compatible" name="compatible" data-plugin="switchery">
+                                                </div>
+                                                <div class="text-help offset-md-3">
+                                                    如果兼容请在服务端配置协议和混淆时加上<span class="red-700">_compatible</span>
+                                                </div>
                                             </div>
+
+
+
                                         </div>
                                         <hr/>
                                         <div class="form-group row">
@@ -224,32 +237,28 @@
                                                 如果启用请配置服务端的<span class="red-700"><a href="javascript:showTnc();">additional_ports</a></span>信息
                                             </div>
                                         </div>
-                                        <div class="single-setting hidden">
+                                        <div class="single-setting">
                                             <div class="form-group row">
                                                 <label for="single_port" class="col-md-3 col-form-label">[单] 端口</label>
                                                 <input type="number" class="form-control col-md-4" name="port" value="443" id="single_port"/>
                                                 <span class="text-help offset-md-3"> 推荐80或443,服务端需要配置 <br>
                                                     严格模式:用户的端口无法连接,只能通过以下指定的端口进行连接(<a href="javascript:showPortsOnlyConfig();">如何配置</a>)</span>
                                             </div>
-                                            <div class="form-group row">
+                                            <div class="form-group row ss-setting">
                                                 <label for="passwd" class="col-md-3 col-form-label">[单] 密码</label>
                                                 <input type="text" class="form-control col-md-4" name="passwd" id="passwd" placeholder="password">
                                             </div>
                                         </div>
                                     </div>
                                     <!-- V2ray 设置部分 -->
-                                    <div class="v2ray-setting hidden">
+                                    <div class="v2ray-setting">
                                         <div class="form-group row">
                                             <label for="v2_alter_id" class="col-md-3 col-form-label">额外ID</label>
                                             <input type="text" class="form-control col-md-4" name="v2_alter_id" value="16" id="v2_alter_id" required/>
                                         </div>
-                                        <div class="form-group row">
-                                            <label for="v2ray_port" class="col-md-3 col-form-label">连接端口</label>
-                                            <input type="number" class="form-control col-md-4" name="port" id="v2ray_port" value="443"/>
-                                        </div>
                                         <div class="form-group row">
                                             <label for="v2_port" class="col-md-3 col-form-label">服务端口</label>
-                                            <input type="number" class="form-control col-md-4" name="v2_port" id="v2_port" value="10053" required/>
+                                            <input type="number" class="form-control col-md-4" name="port" id="v2_port" value="10053" required/>
                                         </div>
                                         <div class="form-group row">
                                             <label for="v2_method" class="col-md-3 col-form-label">加密方式</label>
@@ -291,17 +300,6 @@
                                             <label for="v2_host" class="col-md-3 col-form-label">伪装域名</label>
                                             <div class="col-md-4 pl-0">
                                                 <input type="text" class="form-control" name="v2_other" id="v2_host">
-                                                <div name="v2_ws">
-                                                    <select data-plugin="selectpicker" data-style="btn-outline btn-primary" class="form-control" id="v2_ws">
-                                                        <option value="" hidden></option>
-                                                        @foreach($certs as $cert)
-                                                            <option value="{{$cert->domain}}"
-                                                                    @if(isset($node) && $node->v2_net === "ws" && $node->v2_host === $cert->domain) selected @endif>
-                                                                {{$cert->domain}}
-                                                            </option>
-                                                        @endforeach
-                                                    </select>
-                                                </div>
                                             </div>
                                             <div class="text-help offset-md-3">
                                                 伪装类型为http时多个伪装域名逗号隔开,使用WebSocket传输协议时只允许单个
@@ -311,6 +309,10 @@
                                             <label for="v2_path" class="col-md-3 col-form-label">路径 | 密钥</label>
                                             <input type="text" class="form-control col-md-4" name="v2_path" id="v2_path">
                                         </div>
+                                        <div class="form-group row">
+                                            <label for="v2_sni" class="col-md-3 col-form-label">SNI</label>
+                                            <input type="text" class="form-control col-md-4" name="v2_sni" id="v2_sni">
+                                        </div>
                                         <div class="form-group row">
                                             <label for="v2_tls" class="col-md-3 col-form-label">连接TLS</label>
                                             <div class="col-md-9">
@@ -328,7 +330,7 @@
                                         </div>
                                     </div>
                                     <!-- Trojan 设置部分 -->
-                                    <div class="trojan-setting hidden">
+                                    <div class="trojan-setting">
                                         <div class="form-group row">
                                             <label for="trojan_port" class="col-md-3 col-form-label">连接端口</label>
                                             <input type="number" class="form-control col-md-4" name="port" id="trojan_port" value="443"/>
@@ -378,7 +380,7 @@
                                             <input type="checkbox" id="is_relay" name="is_relay" data-plugin="switchery" onchange="switchSetting('is_relay')">
                                         </div>
                                     </div>
-                                    <div class="relay-setting hidden">
+                                    <div class="relay-setting">
                                         <div class="form-group row">
                                             <label for="relay_port" class="col-md-3 col-form-label"> 中转端口 </label>
                                             <input type="number" class="form-control col-md-4" name="relay_port" id="relay_port" value="443">
@@ -409,346 +411,356 @@
     <script src="/assets/global/vendor/switchery/switchery.min.js"></script>
     <script src="/assets/global/js/Plugin/switchery.js"></script>
     <script>
-      const string = "{{strtolower(Str::random())}}";
-      $(document).ready(function() {
-        let v2_path = $('#v2_path');
-          @isset($node)
+        const string = "{{strtolower(Str::random())}}";
+        $(document).ready(function() {
+            let v2_path = $('#v2_path');
+            switchSetting('single');
+            switchSetting('is_relay');
+            switchSetting('is_ddns');
+            @isset($node)
 
-          @if($node->is_ddns)
-          $('#is_ddns').click();
-          @endif
-          $('#name').val('{{$node->name}}');
-        $('#server').val('{{$node->server}}');
-        $('#ip').val('{{$node->ip}}');
-        $('#ipv6').val('{{$node->ipv6}}');
-        $('#push_port').val('{{$node->push_port}}');
-        $('#traffic_rate').val('{{$node->traffic_rate}}');
-        $('#level').selectpicker('val', '{{$node->level}}');
-        $('#ruleGroup').selectpicker('val', '{{$node->rule_group_id}}');
-        $('#speed_limit').val('{{$node->speed_limit}}');
-        $('#client_limit').val('{{$node->client_limit}}');
-        $('#labels').selectpicker('val', {{$node->labels->pluck('id')}});
-        $('#country_code').selectpicker('val', '{{$node->country_code}}');
-        $('#description').val('{{$node->description}}');
-        $('#sort').val('{{$node->sort}}');
-          @if($node->is_udp)
-          $('#is_udp').click();
-          @endif
-          @if($node->status)
-          $('#status').click();
-          @endif
-          @if($node->is_subscribe)
-          $('#is_subscribe').click();
-          @endif
-          $("input[name='detection_type'][value='{{$node->detection_type}}']").click();
-          @if($node->single)
-          $('#single').click();
-          @endif
-          $('input[name = port]').val('{{$node->port}}');
-        $('#passwd').val('{{$node->passwd}}');
-        $("input[name='type'][value='{{$node->type}}']").click();
+            @if($node->is_ddns)
+            $('#is_ddns').click();
+            @endif
+            $('#name').val('{{$node->name}}');
+            $('#server').val('{{$node->server}}');
+            $('#ip').val('{{$node->ip}}');
+            $('#ipv6').val('{{$node->ipv6}}');
+            $('#push_port').val('{{$node->push_port}}');
+            $('#traffic_rate').val('{{$node->traffic_rate}}');
+            $('#level').selectpicker('val', '{{$node->level}}');
+            $('#ruleGroup').selectpicker('val', '{{$node->rule_group_id}}');
+            $('#speed_limit').val('{{$node->speed_limit}}');
+            $('#client_limit').val('{{$node->client_limit}}');
+            $('#labels').selectpicker('val', {{$node->labels->pluck('id')}});
+            $('#country_code').selectpicker('val', '{{$node->country_code}}');
+            $('#description').val('{{$node->description}}');
+            $('#sort').val('{{$node->sort}}');
+            @if($node->is_udp)
+            $('#is_udp').click();
+            @endif
+            @if($node->status)
+            $('#status').click();
+            @endif
+            @if($node->is_subscribe)
+            $('#is_subscribe').click();
+            @endif
+            $("input[name='detection_type'][value='{{$node->detection_type}}']").click();
+            @if($node->single)
+            $('#single').click();
+            @endif
+            $('input[name = port]').val('{{$node->port}}');
+            $('#passwd').val('{{$node->passwd}}');
+            $("input[name='type'][value='{{$node->type}}']").click();
 
-          @if($node->type == 1 || $node->type == 4)
-        // ShadowsocksR
-        $('#method').selectpicker('val', '{{$node->method}}');
-        $('#protocol').selectpicker('val', '{{$node->protocol}}');
-        $('#protocol_param').val('{{$node->protocol_param}}');
-        $('#obfs').selectpicker('val', '{{$node->obfs}}');
-        $('#obfs_param').val('{{$node->obfs_param}}');
-          @if($node->compatible)
-          $('#compatible').click();
-          @endif
-          @endif
+            switch ({{$node->type}}) {
+                case 1:
+                case 4:
+                    @if ($node->compatible)
+                    $('#compatible').click();
+                    @endif
+                    $('#protocol').selectpicker('val', '{{$node->protocol}}');
+                    $('#protocol_param').val('{{$node->protocol_param}}');
+                    $('#obfs').selectpicker('val', '{{$node->obfs}}');
+                    $('#obfs_param').val('{{$node->obfs_param}}');
+                case 0:
+                    $('#method').selectpicker('val', '{{$node->method}}');
+                    break;
+                case 2:
+                    //V2Ray
+                    $('#v2_alter_id').val('{{$node->v2_alter_id}}');
+                    $('#v2_method').selectpicker('val', '{{$node->v2_method}}');
+                    $('#v2_net').selectpicker('val', '{{$node->v2_net}}');
+                    $('#v2_type').selectpicker('val', '{{$node->v2_type}}');
+                    $('#v2_host').val('{{$node->v2_host}}');
+                    $('#v2_port').val('{{$node->port}}');
+                    $('#v2_sni').val('{{$node->v2_sni}}');
+                    v2_path.val('{{$node->v2_path}}');
+                    @if($node->v2_tls)
+                    $('#v2_tls').click();
+                    @endif
+                    $('#tls_provider').val('{!! $node->tls_provider !!}');
+                    break;
+                case 3:
+                    $('#trojan_port').val('{{$node->port}}');
+                    break;
+                default:
+            }
 
-          @if($node->type === 2)
-        //V2Ray
-        $('#v2_alter_id').val('{{$node->v2_alter_id}}');
-        $('#v2_port').val('{{$node->v2_port}}');
-        $('#v2_method').selectpicker('val', '{{$node->v2_method}}');
-        $('#v2_net').selectpicker('val', '{{$node->v2_net}}');
-        $('#v2_type').selectpicker('val', '{{$node->v2_type}}');
-        $('#v2_host').val('{{$node->v2_host}}');
-        v2_path.val('{{$node->v2_path}}');
-          @if($node->v2_tls)
-          $('#v2_tls').click();
-          @endif
-          $('#tls_provider').val('{!! $node->tls_provider !!}');
-          @endif
+            @if($node->is_relay)
+            // 中转
+            $('#is_relay').click();
+            $('#relay_port').val('{{$node->relay_port}}');
+            $('#relay_server').val('{{$node->relay_server}}');
+            @endif
+            @else
+            $('input[name=\'type\'][value=\'0\']').click();
+            $('#status').click();
+            $('#is_udp').click();
+            $('#is_subscribe').click();
+            v2_path.val('/' + string);
+            @endisset
+            if ($('#obfs').val() === 'plain') {
+                $('.obfs_param').hide();
+            }
+        });
 
-          @if($node->is_relay)
-        // 中转
-        $('#is_relay').click();
-        $('#relay_port').val('{{$node->relay_port}}');
-        $('#relay_server').val('{{$node->relay_server}}');
-          @endif
-          @else
-          $('#status').click();
-        $('#is_udp').click();
-        $('#is_subscribe').click();
-        v2_path.val('/' + string);
-          @endisset
-          if ($('#obfs').val() === 'plain') {
-            $('.obfs_param').hide();
-          }
-      });
+        // ajax同步提交
+        function Submit() {
+            const type = $('input[name=\'type\']:checked').val();
+            let port;
+            switch (type) {
+                case '2':
+                    port = $('#v2_port').val();
+                    break;
+                case '3':
+                    port = $('#trojan_port').val();
+                    break;
+                case '0':
+                case '1':
+                case '4':
+                default:
+                    port = $('#single_port').val();
+            }
+            $.ajax({
+                method: @isset($node) 'PUT' @else 'POST' @endisset,
+                url: '{{isset($node)? route('admin.node.update', $node) : route('admin.node.store')}}',
+                dataType: 'json',
+                data: {
+                    _token: '{{csrf_token()}}',
+                    is_ddns: document.getElementById('is_ddns').checked ? 1 : 0,
+                    name: $('#name').val(),
+                    server: $('#server').val(),
+                    ip: $('#ip').val(),
+                    ipv6: $('#ipv6').val(),
+                    push_port: $('#push_port').val(),
+                    traffic_rate: $('#traffic_rate').val(),
+                    level: $('#level').val(),
+                    rule_group_id: $('#ruleGroup').val(),
+                    speed_limit: $('#speed_limit').val(),
+                    client_limit: $('#client_limit').val(),
+                    labels: $('#labels').val(),
+                    country_code: $('#country_code option:selected').val(),
+                    description: $('#description').val(),
+                    sort: $('#sort').val(),
+                    is_udp: document.getElementById('is_udp').checked ? 1 : 0,
+                    status: document.getElementById('status').checked ? 1 : 0,
+                    type: type,
+                    method: $('#method').val(),
+                    protocol: $('#protocol').val(),
+                    protocol_param: $('#protocol_param').val(),
+                    obfs: $('#obfs').val(),
+                    obfs_param: $('#obfs_param').val(),
+                    compatible: document.getElementById('compatible').checked ? 1 : 0,
+                    is_subscribe: document.getElementById('is_subscribe').checked ? 1 : 0,
+                    detection_type: $('input[name=\'detection_type\']:checked').val(),
+                    single: document.getElementById('single').checked ? 1 : 0,
+                    port: port,
+                    passwd: $('#passwd').val(),
+                    v2_alter_id: $('#v2_alter_id').val(),
+                    v2_method: $('#v2_method').val(),
+                    v2_net: $('#v2_net').val(),
+                    v2_type: $('#v2_type').val(),
+                    v2_host: $('#v2_host').val(),
+                    v2_path: $('#v2_path').val(),
+                    v2_sni: $('#v2_sni').val(),
+                    v2_port: $('#v2_port').val(),
+                    v2_tls: document.getElementById('v2_tls').checked ? 1 : 0,
+                    tls_provider: $('#tls_provider').val(),
+                    is_relay: document.getElementById('is_relay').checked ? 1 : 0,
+                    relay_port: $('#relay_port').val(),
+                    relay_server: $('#relay_server').val(),
+                },
+                success: function(ret) {
+                    if (ret.status === 'success') {
+                        swal.fire({
+                            title: ret.message,
+                            icon: 'success',
+                            timer: 1000,
+                            showConfirmButton: false,
+                        }).then(() => window.location.href = '{{route('admin.node.index').(Request::getQueryString()?('?'.Request::getQueryString()):'') }}');
+                    } else {
+                        swal.fire({title: '[错误 | Error]', text: ret.message, icon: 'error'});
+                    }
+                },
+                error: function(data) {
+                    let str = '';
+                    const errors = data.responseJSON;
+                    if ($.isEmptyObject(errors) === false) {
+                        $.each(errors.errors, function(index, value) {
+                            str += '<li>' + value + '</li>';
+                        });
+                        swal.fire({title: '提示', html: str, icon: 'error', confirmButtonText: '{{trans('common.confirm')}}'});
+                    }
+                },
+            });
 
-      // ajax同步提交
-      function Submit() {
-        const type = $('input[name=\'type\']:checked').val();
-        let port;
-        switch (type) {
-          case '2':
-            port = $('#v2ray_port').val();
-            break;
-          case '3':
-            port = $('#trojan_port').val();
-            break;
-          case '1':
-          case '4':
-          default:
-            port = $('#single_port').val();
+            return false;
         }
-        $.ajax({
-          method: @isset($node) 'PUT' @else 'POST' @endisset,
-          url: '{{isset($node)? route('admin.node.update', $node) : route('admin.node.store')}}',
-          dataType: 'json',
-          data: {
-            _token: '{{csrf_token()}}',
-            is_ddns: document.getElementById('is_ddns').checked ? 1 : 0,
-            name: $('#name').val(),
-            server: $('#server').val(),
-            ip: $('#ip').val(),
-            ipv6: $('#ipv6').val(),
-            push_port: $('#push_port').val(),
-            traffic_rate: $('#traffic_rate').val(),
-            level: $('#level').val(),
-            rule_group_id: $('#ruleGroup').val(),
-            speed_limit: $('#speed_limit').val(),
-            client_limit: $('#client_limit').val(),
-            labels: $('#labels').val(),
-            country_code: $('#country_code option:selected').val(),
-            description: $('#description').val(),
-            sort: $('#sort').val(),
-            is_udp: document.getElementById('is_udp').checked ? 1 : 0,
-            status: document.getElementById('status').checked ? 1 : 0,
-            type: type,
-            method: $('#method').val(),
-            protocol: $('#protocol').val(),
-            protocol_param: $('#protocol_param').val(),
-            obfs: $('#obfs').val(),
-            obfs_param: $('#obfs_param').val(),
-            compatible: document.getElementById('compatible').checked ? 1 : 0,
-            is_subscribe: document.getElementById('is_subscribe').checked ? 1 : 0,
-            detection_type: $('input[name=\'detection_type\']:checked').val(),
-            single: document.getElementById('single').checked ? 1 : 0,
-            port: port,
-            passwd: $('#passwd').val(),
-            v2_alter_id: $('#v2_alter_id').val(),
-            v2_port: $('#v2_port').val(),
-            v2_method: $('#v2_method').val(),
-            v2_net: $('#v2_net').val(),
-            v2_type: $('#v2_type').val(),
-            v2_host: $('#v2_host').val(),
-            v2_path: $('#v2_path').val(),
-            v2_tls: document.getElementById('v2_tls').checked ? 1 : 0,
-            tls_provider: $('#tls_provider').val(),
-            is_relay: document.getElementById('is_relay').checked ? 1 : 0,
-            relay_port: $('#relay_port').val(),
-            relay_server: $('#relay_server').val(),
-          },
-          success: function(ret) {
-            if (ret.status === 'success') {
-              swal.fire({
-                title: ret.message,
-                icon: 'success',
-                timer: 1000,
-                showConfirmButton: false,
-              }).then(() => window.location.href = '{{route('admin.node.index').(Request::getQueryString()?('?'.Request::getQueryString()):'') }}');
-            } else {
-              swal.fire({title: '[错误 | Error]', text: ret.message, icon: 'error'});
+
+        function switchSetting(id) {
+            let check = document.getElementById(id).checked ? 1 : 0;
+            switch (id) {
+                // 设置单端口多用户
+                case 'single':
+                    if (check) {
+                        $('.single-setting').show();
+                        $('#single_port').attr('required', true);
+                    } else {
+                        $('#single_port').val('').removeAttr('required');
+                        $('#passwd').val('');
+                        $('.single-setting').hide();
+                    }
+                    break;
+                //设置中转
+                case 'is_relay':
+                    if (check) {
+                        $('.relay-setting').show();
+                        $('#relay_port').attr('required', true);
+                        $('#relay_server').attr('required', true);
+                    } else {
+                        $('.relay-setting').hide();
+                        $('#relay_port').removeAttr('required');
+                        $('#relay_server').removeAttr('required');
+                    }
+                    break;
+                // 设置是否使用DDNS
+                case 'is_ddns':
+                    if (check) {
+                        $('#ip').val('').attr('readonly', true);
+                        $('#ipv6').val('').attr('readonly', true);
+                        $('#server').attr('required', true);
+                    } else {
+                        $('#ip').removeAttr('readonly');
+                        $('#ipv6').removeAttr('readonly');
+                        $('#server').removeAttr('required');
+                    }
+                    break;
+                default:
+                    break;
             }
-          },
-          error: function(data) {
-            let str = '';
-            const errors = data.responseJSON;
-            if ($.isEmptyObject(errors) === false) {
-              if ($.isEmptyObject(errors.message) === false && typeof errors.message === 'string') {
-                str += errors.message;
-              } else {
-                $.each(errors.errors, function(index, value) {
-                  str += '<li>' + value + '</li>';
-                });
-              }
-              swal.fire({title: '提示', html: str, icon: 'error', confirmButtonText: '{{trans('common.confirm')}}'});
+        }
+
+        // 设置服务类型
+        $('input:radio[name=\'type\']').on('change', function() {
+            const type = parseInt($(this).val());
+            const $ss_setting = $('.ss-setting');
+            const $ssr_setting = $('.ssr-setting');
+            const $v2ray_setting = $('.v2ray-setting');
+            const $trojan_setting = $('.trojan-setting');
+            $ssr_setting.hide();
+            $ss_setting.hide();
+            $v2ray_setting.hide();
+            $trojan_setting.hide();
+            $('#v2_port').removeAttr('required');
+            $('#trojan_port').removeAttr('required');
+            switch (type) {
+                case 0:
+                    $ss_setting.show();
+                    break;
+                case 2:
+                    $v2ray_setting.show();
+                    $('#v2_port').val('').attr('required', true);
+                    $('#v2_net').selectpicker('val', 'tcp');
+                    break;
+                case 3:
+                    $trojan_setting.show();
+                    $('#trojan_port').val('').attr('required', true);
+                    break;
+                case 1:
+                case 4:
+                    $ss_setting.show();
+                    $ssr_setting.show();
+                    break;
+                default:
             }
-          },
         });
 
-        return false;
-      }
-
-      function switchSetting(id) {
-        let check = document.getElementById(id).checked ? 1 : 0;
-        switch (id) {
-            // 设置单端口多用户
-          case 'single':
-            if (check) {
-              $('.single-setting').show();
+        $('#obfs').on('changed.bs.select', function() {
+            const obfs_param = $('.obfs_param');
+            if ($('#obfs').val() === 'plain') {
+                $('#obfs_param').val('');
+                obfs_param.hide();
             } else {
-              $('#single_port').val('');
-              $('#passwd').val('');
-              $('.single-setting').hide();
+                obfs_param.show();
             }
-            break;
-            //设置中转
-          case 'is_relay':
-            if (check) {
-              $('.relay-setting').show();
-              $('#relay_port').attr('required', true);
-              $('#relay_server').attr('required', true);
-            } else {
-              $('.relay-setting').hide();
-              $('#relay_port').removeAttr('required');
-              $('#relay_server').removeAttr('required');
-            }
-            break;
-            // 设置是否使用DDNS
-          case 'is_ddns':
-            if (check) {
-              $('#ip').val('').attr('readonly', true);
-              $('#ipv6').val('').attr('readonly', true);
-              $('#server').attr('required', true);
-            } else {
-              $('#ip').removeAttr('readonly');
-              $('#ipv6').removeAttr('readonly');
-              $('#server').removeAttr('required');
+        });
+
+        // 设置V2Ray详细设置
+        $('#v2_net').on('changed.bs.select', function() {
+            const type = $('.v2_type');
+            const type_option = $('#type_option');
+            const host = $('.v2_host');
+            const path = $('#v2_path');
+            const v2_other = $('[name="v2_other"]');
+            type.show();
+            host.show();
+            v2_other.show();
+            path.val('/' + string);
+            switch ($(this).val()) {
+                case 'kcp':
+                    type_option.attr('disabled', false);
+                    break;
+                case 'ws':
+                    type.hide();
+                    break;
+                case 'http':
+                    type.hide();
+                    break;
+                case 'domainsocket':
+                    type.hide();
+                    host.hide();
+                    break;
+                case 'quic':
+                    type_option.attr('disabled', false);
+                    path.val(string);
+                    break;
+                case 'tcp':
+                default:
+                    type_option.attr('disabled', true);
+                    break;
             }
-            break;
-          default:
-            break;
-        }
-      }
+            $('#v2_type').selectpicker('refresh');
+        });
 
-      // 设置服务类型
-      $('input:radio[name=\'type\']').on('change', function() {
-        const type = parseInt($(this).val());
-        const $ssr_setting = $('.ssr-setting');
-        const $v2ray_setting = $('.v2ray-setting');
-        const $trojan_setting = $('.trojan-setting');
-        $ssr_setting.hide();
-        $v2ray_setting.hide();
-        $trojan_setting.hide();
-        switch (type) {
-          case 1:
-            $ssr_setting.show();
-            break;
-          case 2:
-            $v2ray_setting.show();
-            $('#v2_net').selectpicker('val', 'tcp');
-            break;
-          case 3:
-            $trojan_setting.show();
-            break;
-          case 4:
-            $ssr_setting.show();
-            break;
-          default:
-        }
-      });
+        // 服务条款
+        function showTnc() {
+            const content =
+                '<ol>' +
+                '<li>请勿直接复制黏贴以下配置,SSR(R)会报错的</li>' +
+                '<li>确保服务器时间为CST</li>' +
+                '</ol>' +
+                '&emsp;&emsp;"additional_ports" : {<br />' +
+                '&emsp;&emsp;&emsp;"443": {<br />' +
+                '&emsp;&emsp;&emsp;&emsp;"passwd": "ProxyPanel",<br />' +
+                '&emsp;&emsp;&emsp;&emsp;"method": "none",<br />' +
+                '&emsp;&emsp;&emsp;&emsp;"protocol": "auth_chain_a",<br />' +
+                '&emsp;&emsp;&emsp;&emsp;"protocol_param": "#",<br />' +
+                '&emsp;&emsp;&emsp;&emsp;"obfs": "plain",<br />' +
+                '&emsp;&emsp;&emsp;&emsp;"obfs_param": "fe2.update.microsoft.com"<br />' +
+                '&emsp;&emsp;&emsp;}<br />' +
+                '&emsp;&emsp;},';
 
-      $('#obfs').on('changed.bs.select', function() {
-        const obfs_param = $('.obfs_param');
-        if ($('#obfs').val() === 'plain') {
-          $('#obfs_param').val('');
-          obfs_param.hide();
-        } else {
-          obfs_param.show();
+            swal.fire({
+                title: '[节点 user-config.json 配置示例]',
+                html: '<div class="p-10 bg-grey-900 text-white font-weight-300 text-left" style="line-height: 22px;">' +
+                    content + '</div>',
+                icon: 'info',
+            });
         }
-      });
 
-      $('#v2_ws').on('changed.bs.select', function() {
-        $('#v2_host').val($('#v2_ws').val());
-      });
+        // 模式提示
+        function showPortsOnlyConfig() {
+            const content = '严格模式:"additional_ports_only": "true"'
+                + '<br><br>'
+                + '兼容模式:"additional_ports_only": "false"';
 
-      // 设置V2Ray详细设置
-      $('#v2_net').on('changed.bs.select', function() {
-        const type = $('.v2_type');
-        const type_option = $('#type_option');
-        const host = $('.v2_host');
-        const path = $('#v2_path');
-        const v2_ws = $('[name="v2_ws"]');
-        const v2_other = $('[name="v2_other"]');
-        type.show();
-        host.show();
-        v2_other.show();
-        v2_ws.hide();
-        path.val('/' + string);
-        switch ($(this).val()) {
-          case 'kcp':
-            type_option.attr('disabled', false);
-            break;
-          case 'ws':
-            v2_ws.show();
-            type.hide();
-            v2_other.hide();
-            break;
-          case 'http':
-            type.hide();
-            break;
-          case 'domainsocket':
-            type.hide();
-            host.hide();
-            break;
-          case 'quic':
-            type_option.attr('disabled', false);
-            path.val(string);
-            break;
-          case 'tcp':
-          default:
-            type_option.attr('disabled', true);
-            break;
+            swal.fire({
+                title: '[节点 user-config.json 配置示例]',
+                html: '<div class="p-10 bg-grey-900 text-white font-weight-300 text-left" style="line-height: 22px;">' +
+                    content + '</div>',
+                icon: 'info',
+            });
         }
-        $('#v2_type').selectpicker('refresh');
-      });
-
-      // 服务条款
-      function showTnc() {
-        const content =
-            '<ol>' +
-            '<li>请勿直接复制黏贴以下配置,SSR(R)会报错的</li>' +
-            '<li>确保服务器时间为CST</li>' +
-            '</ol>' +
-            '&emsp;&emsp;"additional_ports" : {<br />' +
-            '&emsp;&emsp;&emsp;"443": {<br />' +
-            '&emsp;&emsp;&emsp;&emsp;"passwd": "ProxyPanel",<br />' +
-            '&emsp;&emsp;&emsp;&emsp;"method": "none",<br />' +
-            '&emsp;&emsp;&emsp;&emsp;"protocol": "auth_chain_a",<br />' +
-            '&emsp;&emsp;&emsp;&emsp;"protocol_param": "#",<br />' +
-            '&emsp;&emsp;&emsp;&emsp;"obfs": "plain",<br />' +
-            '&emsp;&emsp;&emsp;&emsp;"obfs_param": "fe2.update.microsoft.com"<br />' +
-            '&emsp;&emsp;&emsp;}<br />' +
-            '&emsp;&emsp;},';
-
-        swal.fire({
-          title: '[节点 user-config.json 配置示例]',
-          html: '<div class="p-10 bg-grey-900 text-white font-weight-300 text-left" style="line-height: 22px;">' +
-              content + '</div>',
-          icon: 'info',
-        });
-      }
-
-      // 模式提示
-      function showPortsOnlyConfig() {
-        const content = '严格模式:"additional_ports_only": "true"'
-            + '<br><br>'
-            + '兼容模式:"additional_ports_only": "false"';
-
-        swal.fire({
-          title: '[节点 user-config.json 配置示例]',
-          html: '<div class="p-10 bg-grey-900 text-white font-weight-300 text-left" style="line-height: 22px;">' +
-              content + '</div>',
-          icon: 'info',
-        });
-      }
     </script>
 @endsection

+ 17 - 1
resources/views/admin/subscribe/index.blade.php

@@ -18,6 +18,22 @@
                         <input type="text" class="form-control" name="email" id="email"
                                value="{{Request::input('email')}}" placeholder="用户名"/>
                     </div>
+
+                    <div class="form-group col-lg-2 col-sm-6">
+                        <input type="number" class="form-control" name="times" id="times"
+                               value="{{Request::input('times')}}" placeholder="输入一个大于几的数"/>
+                    </div>
+
+                    <div class="form-group col-lg-4 col-sm-6">
+                        <input type="text" class="form-control" name="starttime" id="starttime"
+                               value="{{Request::input('starttime')}}" placeholder="开始时间"/>
+                    </div>
+
+                    <div class="form-group col-lg-4 col-sm-6">
+                        <input type="text" class="form-control" name="endtime" id="endtime"
+                               value="{{Request::input('endtime')}}" placeholder="结束时间"/>
+                    </div>
+
                     <div class="form-group col-lg-3 col-sm-6">
                         <select name="status" id="status" class="form-control" onChange="Search()">
                             <option value="" hidden>状态</option>
@@ -114,7 +130,7 @@
       // 搜索
       function Search() {
         window.location.href = '{{route('admin.subscribe.index')}}' + '?user_id=' + $('#user_id').val() + '&email=' + $('#email').val() + '&status=' +
-            $('#status option:selected').val();
+            $('#status option:selected').val() + '&times=' + $('#times').val() + '&starttime=' + $('#starttime').val() + '&endtime=' + $('#endtime').val();
       }
 
       @can('admin.subscribe.set')

+ 12 - 3
resources/views/admin/ticket/index.blade.php

@@ -22,6 +22,14 @@
                     <div class="form-group col-lg-3 col-sm-6">
                         <input type="text" class="form-control" name="email" id="email" value="{{Request::input('email')}}" placeholder="用户名" autocomplete="off"/>
                     </div>
+                    <div class="form-group col-lg-3 col-sm-6">
+                        <select class="form-control" id="status" name="status">
+                            <option value="">全部</option>
+                            <option value="0">待回复</option>
+                            <option value="1">已回复</option>
+                            <option value="2">关闭</option>
+                        </select>
+                    </div>
                     <div class="form-group col-lg-2 col-sm-6 btn-group">
                         <button class="btn btn-primary" onclick="Search()">搜 索</button>
                         <a href="{{route('admin.ticket.index')}}" class="btn btn-danger">{{trans('common.reset')}}</a>
@@ -46,9 +54,9 @@
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
                                     @can('admin.user.index')
-                                        <a href="{{route('admin.user.index', ['id'=>$ticket->user->id])}}" target="_blank">{{$ticket->user->email}}</a>
+                                        <a href="{{route('admin.user.index', ['id'=>$ticket->user->id])}}" target="_blank">{{$ticket->user->email}} {{$ticket->user->remark}}</a>
                                     @else
-                                        {{$ticket->user->email}}
+                                        {{$ticket->user->email}} {{$ticket->user->remark}}
                                     @endcan
                                 @endif
                             </td>
@@ -143,7 +151,8 @@
 
       // 搜索
       function Search() {
-        window.location.href = '{{route('admin.ticket.index')}}?email=' + $('#email').val();
+        window.location.href = '{{route('admin.ticket.index')}}?email=' + $('#email').val()+'&status=' + $('#status option:selected').val();
+
       }
 
       @can('admin.ticket.store')

+ 39 - 0
resources/views/admin/ticket/reply.blade.php

@@ -26,13 +26,52 @@
             @if($ticket->status !== 2)
                 @can('admin.ticket.update')
                     <div class="panel-footer pb-30">
+                         <a href="{{route('admin.user.index', ['id'=>$ticket->user->id])}}" target="_blank">{{$ticket->user->email}}</a>
+                          <a href="{{route('admin.order', ['email'=>$ticket->user->email,'sn'=>"",'trade_no'=>"",'is_expire'=>"",'is_coupon'=>"",'pay_way'=>"",'status'=>"",'sort'=>"",'range_time'=>""])}}" target="_blank">订单查询:{{$ticket->user->email}}</a>
+                          
+                          {{$ticket->user->remark}}  
+                          {{$ticket->user->expired_at}} 
+                          
+                    @if($ticket->user->enable == 0)
+                       <span class="input-group-btn">代理状态:禁用</span>
+                    @else
+                        <span class="input-group-btn">代理状态:正常</span>
+                    @endif
+                    
+                      <a href="{{route('admin.user.UserDis', ['id'=>$ticket->user->id])}}" target="_blank">一键退款</a>
+                    
                         <form>
                             <div class="input-group">
+
                                 <input type="text" class="form-control" id="editor" placeholder="{{trans('user.ticket.reply_placeholder')}}"/>
                                 <span class="input-group-btn">
                                 <button type="button" class="btn btn-primary" onclick="replyTicket()"> {{trans('common.send')}}</button>
                             </span>
+                           
                             </div>
+                            <p>你可以截图给我们,将图片通过<a href="https://prnt.sc/">https://prnt.sc/</a>上传图片生成链接发送给我们。</p>
+                            
+                            <p>已经提交原路退款申请,账号已停用.退款会在72小时内由支付平台处理,如果未收到,请回复此工单。注:每个账号只退一次</p>
+                            <p> windows视频教程:https://down.rjuser.top/mp4/windows.zip</p>
+                             <p>我已经成功了使用了chatGPT ,注意事项,最好用无痕模式 vpn使用美国节点和全局就行了。</p>
+                            <p>苹果shadowrocket视频教程 https://down.viptwo.xyz/mp4/shadowrocket/pingguo.html</p>
+                            <p>苹果Spectre vpn视频教程:https://down.viptwo.xyz/mp4//spectre/Spectre.html</p>
+                            <p>部分节点被封,我们正在努力恢复中...请大家手动选择节点</p>
+                            <p>请问用的什么设备和软件?。如果是mac和ios系统或者v2客户端,请更新订阅.或者查看教程 app.xiazai1.xyz</p>
+                             <p>手动ios更新订阅方法:按住“user.vipxxx.xyz”向右滑-更新。自动更新请看教程第四步。</p>
+                             <p>大部分客户都是冲错账号或者没有重启软件或者更新订阅,如果真的遇到了,打开支付宝-"我的"-“账单”-“账单详情”-展开“更多”-复制"商户订单号" 联系人工客服. 微信支付通过下单邮箱可以查询(充值卡网站首页-订单查询).另外如果你是充值的余额,一定要使用余额支付购买vip套餐才会生效!</p>
+                             <p>请提供商户订单号,例如支付宝:b3f688d6253041998322168cda0021b1 备用支付宝 例如2023021301455459967 微信支付提供下单邮箱
+                            
+</p>
+                             <p>你可以下载一个向日葵远程,提供识别码 我们帮你远程看看</p>
+                              <p>您可以发送视频或者图片到邮箱:support@naiyoujsq.com</p>
+                               <p>微信和usdt支付教程 https://user.vipthree.xyz/#wx_client</p>
+                             <p>请查看教程排错.软件下载地址和教程 app.xiazai1.xyz 或者 app.xiazai2.xyz</p>
+                             <p>windows。请查看教程排除https://user.vipthree.xyz/#windows_client</p>
+                             <p>切换网卡模式或者重启试试</p>
+                             <p>这个问题是因为没有正常关闭加速器!(重启或者关机时,请先停止加速)
+解决方法一:开启加速软件,连接一次然后关闭即可.
+解决方法二:找到右下角的网卡图标-点击网络设置-代理-手动设置代理,使用代理服务器。关闭它。</p>
                         </form>
                     </div>
                 @endcan

+ 6 - 6
resources/views/admin/user/index.blade.php

@@ -88,7 +88,7 @@
                         <th> #</th>
                         <th> 用户名</th>
                         <th> 余额</th>
-                        <th> 端口</th>
+                        <th> 备注</th>
                         <th> 订阅码</th>
                         <th> 流量使用</th>
                         <th> 最后使用</th>
@@ -105,7 +105,7 @@
                             <td> {{$user->email}} </td>
                             <td> {{$user->credit}} </td>
                             <td>
-                                {!!$user->port? : '<span class="badge badge-lg badge-danger"> 未分配 </span>'!!}
+                              {{$user->remark}}
                             </td>
                             <td>
                                 <a href="javascript:" class="copySubscribeLink" data-clipboard-action="copy"
@@ -115,11 +115,11 @@
                             <td> {{$user->t? date('Y-m-d H:i', $user->t): '未使用'}} </td>
 
                             <td>
-                                @if ($user->expired_at < date('Y-m-d'))
+                                @if ($user->expired_at < date('Y-m-d H:i:s'))
                                     <span class="badge badge-lg badge-danger"> {{$user->expired_at}} </span>
-                                @elseif ($user->expired_at === date('Y-m-d'))
+                                @elseif ($user->expired_at === date('Y-m-d H:i:s'))
                                     <span class="badge badge-lg badge-warning"> {{$user->expired_at}} </span>
-                                @elseif ($user->expired_at <= date('Y-m-d', strtotime('+30 days')))
+                                @elseif ($user->expired_at <= date('Y-m-d H:i:s', strtotime('+30 days')))
                                     <span class="badge badge-lg badge-default"> {{$user->expired_at}} </span>
                                 @else
                                     {{$user->expired_at}}
@@ -245,7 +245,7 @@
         swal.fire({
           title: '用户生成数量',
           input: 'range',
-          inputAttributes: {min: 1, max: 10},
+          inputAttributes: {min: 1, max: 100},
           inputValue: 1,
           icon: 'question',
           showCancelButton: true,

+ 15 - 5
resources/views/admin/user/info.blade.php

@@ -1,7 +1,7 @@
 @extends('admin.layouts')
 @section('css')
     <link href="/assets/global/vendor/bootstrap-select/bootstrap-select.min.css" rel="stylesheet">
-    <link href="/assets/global/vendor/bootstrap-datepicker/bootstrap-datepicker.min.css" rel="stylesheet">
+    <link href="/assets/global/vendor/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css" rel="stylesheet">
 @endsection
 @section('content')
     <div class="page-content container-fluid">
@@ -86,7 +86,7 @@
                             <div class="form-group row">
                                 <label class="col-md-2 col-sm-3 col-form-label" for="reset_time">重置日</label>
                                 <div class="col-xl-4 col-sm-4">
-                                    <div class="input-group input-daterange" data-plugin="datepicker">
+                                    <div class="input-group input-daterange">
                                         <div class="input-group-prepend">
                                             <span class="input-group-text">
                                                 <i class="icon wb-calendar" aria-hidden="true"></i>
@@ -99,8 +99,17 @@
                             </div>
                             <div class="form-group row">
                                 <label class="col-md-2 col-sm-3 col-form-label" for="expired_at">过期日</label>
+
+
                                 <div class="col-xl-4 col-sm-4">
-                                    <div class="input-group input-daterange" data-plugin="datepicker">
+
+
+{{--                                    <div class="input-append date" id="datetimepicker" data-date="12-02-2012" data-date-format="dd-mm-yyyy">--}}
+{{--                                        <input type="text" class="form-control" name="expired_at" id="expired_at"/>--}}
+{{--                                        <span class="add-on"><i class="icon-remove"></i></span>--}}
+{{--                                        <span class="add-on"><i class="icon-th"></i></span>--}}
+{{--                                    </div>--}}
+                                    <div class="input-group input-daterange form_datetime" id="datetimepicker">
                                         <div class="input-group-prepend">
                                             <span class="input-group-text">
                                                 <i class="icon wb-calendar" aria-hidden="true"></i>
@@ -336,6 +345,7 @@
 @section('javascript')
     <script src="/assets/global/vendor/bootstrap-select/bootstrap-select.min.js"></script>
     <script src="/assets/global/vendor/bootstrap-datepicker/bootstrap-datepicker.min.js"></script>
+    <script src="/assets/global/vendor/bootstrap-datetimepicker/js/bootstrap-datetimepicker.js"></script>
     <script src="/assets/global/js/Plugin/bootstrap-select.js"></script>
     <script src="/assets/global/js/Plugin/bootstrap-datepicker.js"></script>
     <script>
@@ -367,8 +377,8 @@
           @endisset
       });
 
-      $('.input-daterange>input').datepicker({
-        format: 'yyyy-mm-dd',
+      $('.input-daterange>input').datetimepicker({
+        format: 'yyyy-mm-dd hh:ii:ss', language : 'zh-CN',todayBtn:  1,weekStart: 1,
       });
 
       @isset($user)

+ 1 - 1
resources/views/auth/error.blade.php

@@ -14,4 +14,4 @@
             <code class="error-advise">{!! $message !!}</code>
         </div>
     </div>
-@endsection
+@endsection

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

@@ -29,23 +29,23 @@
                     <div class="panel-heading">
                         <div class="panel-title">
                             <div class="brand">
-                                <img src="{{sysConfig('website_home_logo')? asset(sysConfig('website_home_logo')) :'/assets/images/logo64.png'}}" class="brand-img" alt="logo"/>
+                                <!--<img src="{{sysConfig('website_home_logo')? asset(sysConfig('website_home_logo')) :'/assets/images/logo64.png'}}" class="brand-img" alt="logo"/>-->
                                 <h3 class="brand-text">{{sysConfig('website_name')}}</h3>
                             </div>
                         </div>
-                        <div class="ribbon ribbon-reverse ribbon-info ribbon-clip">
-                            <button class="ribbon-inner btn dropdown-toggle pt-0" id="language" data-toggle="dropdown" aria-expanded="false">
-                                <i class="font-size-20 wb-globe"></i>
-                            </button>
-                            <div class="dropdown-menu dropdown-menu-bullet" aria-labelledby="language" role="menu">
-                                <a class="dropdown-item" href="{{route('lang', ['locale' => 'en'])}}" role="menuitem">
-                                    <i class="flag-icon flag-icon-gb"></i>
-                                    <span style="padding: inherit;">English</span></a>
-                                <a class="dropdown-item" href="{{route('lang', ['locale' => 'zh-CN'])}}" role="menuitem">
-                                    <i class="flag-icon flag-icon-cn"></i>
-                                    <span style="padding: inherit;">简体中文</span></a>
-                            </div>
-                        </div>
+                        <!--<div class="ribbon ribbon-reverse ribbon-info ribbon-clip">-->
+                        <!--    <button class="ribbon-inner btn dropdown-toggle pt-0" id="language" data-toggle="dropdown" aria-expanded="false">-->
+                        <!--        <i class="font-size-20 wb-globe"></i>-->
+                        <!--    </button>-->
+                        <!--    <div class="dropdown-menu dropdown-menu-bullet" aria-labelledby="language" role="menu">-->
+                        <!--        <a class="dropdown-item" href="{{route('lang', ['locale' => 'en'])}}" role="menuitem">-->
+                        <!--            <i class="flag-icon flag-icon-gb"></i>-->
+                        <!--            <span style="padding: inherit;">English</span></a>-->
+                        <!--        <a class="dropdown-item" href="{{route('lang', ['locale' => 'zh-CN'])}}" role="menuitem">-->
+                        <!--            <i class="flag-icon flag-icon-cn"></i>-->
+                        <!--            <span style="padding: inherit;">简体中文</span></a>-->
+                        <!--    </div>-->
+                        <!--</div>-->
                     </div>
                     <div class="panel-body">
                     <!--[if lt IE 8]><p class="browserupgrade">{{trans('common.update_browser.0')}}<strong>{{trans('common.update_browser.1')}}</strong>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů