瀏覽代碼

2.5.a 管理路由全面改写 与 代码拆分

1. 全面改写项目-管理面板的路由;
2. 拆分过于Contoller;
3. 优化了按钮过多的图表的显示;
4. 初步应用 Laravel的 表单验证功能;
5. 初步应用 Laravel的 component 功能 拆分/模块化前端代码;
6. 优化部分系统的判断逻辑;
7. 针对2.4.0以前的面板,追加辅助矫正数据库的sql文件;
兔姬桑 4 年之前
父節點
當前提交
ce9618236f
共有 100 個文件被更改,包括 3649 次插入5871 次删除
  1. 0 2
      app/Components/CaptchaVerify.php
  2. 58 115
      app/Components/Helpers.php
  3. 25 57
      app/Components/IP.php
  4. 19 75
      app/Components/Namesilo.php
  5. 16 26
      app/Components/NetworkDetection.php
  6. 10 34
      app/Components/PushNotification.php
  7. 6 10
      app/Components/QQInfo.php
  8. 16 59
      app/Console/Commands/AutoClearLog.php
  9. 40 80
      app/Console/Commands/AutoJob.php
  10. 9 16
      app/Console/Commands/AutoPingNode.php
  11. 6 22
      app/Console/Commands/AutoReportNode.php
  12. 9 16
      app/Console/Commands/AutoStatisticsNodeDailyTraffic.php
  13. 9 16
      app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php
  14. 9 16
      app/Console/Commands/AutoStatisticsUserDailyTraffic.php
  15. 9 16
      app/Console/Commands/AutoStatisticsUserHourlyTraffic.php
  16. 40 88
      app/Console/Commands/DailyJob.php
  17. 26 58
      app/Console/Commands/NodeBlockedDetection.php
  18. 12 29
      app/Console/Commands/ServiceTimer.php
  19. 10 28
      app/Console/Commands/UserExpireAutoWarning.php
  20. 13 35
      app/Console/Commands/UserTrafficAbnormalAutoWarning.php
  21. 6 22
      app/Console/Commands/UserTrafficAutoWarning.php
  22. 39 90
      app/Console/Commands/fixDailyTrafficLogError.php
  23. 2 8
      app/Console/Commands/updateCoupon.php
  24. 6 20
      app/Console/Commands/updateTextToJson.php
  25. 8 22
      app/Console/Commands/updateTicket.php
  26. 7 21
      app/Console/Commands/updateUserLevel.php
  27. 7 17
      app/Console/Commands/updateUserName.php
  28. 14 30
      app/Console/Commands/upgradeUserResetTime.php
  29. 1 2
      app/Console/Kernel.php
  30. 31 88
      app/Exceptions/Handler.php
  31. 31 58
      app/Http/Controllers/Admin/AffiliateController.php
  32. 113 0
      app/Http/Controllers/Admin/ArticleController.php
  33. 88 0
      app/Http/Controllers/Admin/CertController.php
  34. 106 0
      app/Http/Controllers/Admin/Config/CountryController.php
  35. 68 0
      app/Http/Controllers/Admin/Config/EmailFilterController.php
  36. 54 0
      app/Http/Controllers/Admin/Config/LabelController.php
  37. 94 0
      app/Http/Controllers/Admin/Config/LevelController.php
  38. 79 0
      app/Http/Controllers/Admin/Config/SsConfigController.php
  39. 107 187
      app/Http/Controllers/Admin/CouponController.php
  40. 0 75
      app/Http/Controllers/Admin/EmailFilterController.php
  41. 325 0
      app/Http/Controllers/Admin/LogsController.php
  42. 20 35
      app/Http/Controllers/Admin/MarketingController.php
  43. 295 0
      app/Http/Controllers/Admin/NodeController.php
  44. 22 48
      app/Http/Controllers/Admin/RuleController.php
  45. 32 48
      app/Http/Controllers/Admin/RuleGroupController.php
  46. 44 107
      app/Http/Controllers/Admin/ShopController.php
  47. 16 32
      app/Http/Controllers/Admin/SubscribeController.php
  48. 198 0
      app/Http/Controllers/Admin/SystemController.php
  49. 64 106
      app/Http/Controllers/Admin/TicketController.php
  50. 44 79
      app/Http/Controllers/Admin/ToolsController.php
  51. 378 0
      app/Http/Controllers/Admin/UserController.php
  52. 11 30
      app/Http/Controllers/Admin/UserGroupController.php
  53. 41 1383
      app/Http/Controllers/AdminController.php
  54. 34 57
      app/Http/Controllers/Api/WebApi/BaseController.php
  55. 13 26
      app/Http/Controllers/Api/WebApi/TrojanController.php
  56. 12 28
      app/Http/Controllers/Api/WebApi/V2RayController.php
  57. 7 18
      app/Http/Controllers/Api/WebApi/VNetController.php
  58. 200 435
      app/Http/Controllers/AuthController.php
  59. 70 215
      app/Http/Controllers/Controller.php
  60. 12 23
      app/Http/Controllers/Gateway/AbstractPayment.php
  61. 21 48
      app/Http/Controllers/Gateway/BitpayX.php
  62. 8 24
      app/Http/Controllers/Gateway/CodePay.php
  63. 19 46
      app/Http/Controllers/Gateway/EPay.php
  64. 18 44
      app/Http/Controllers/Gateway/F2Fpay.php
  65. 3 14
      app/Http/Controllers/Gateway/Local.php
  66. 9 29
      app/Http/Controllers/Gateway/PayJs.php
  67. 27 72
      app/Http/Controllers/Gateway/PayPal.php
  68. 0 650
      app/Http/Controllers/NodeController.php
  69. 53 125
      app/Http/Controllers/PaymentController.php
  70. 24 73
      app/Http/Controllers/User/AffiliateController.php
  71. 25 78
      app/Http/Controllers/User/SubscribeController.php
  72. 152 394
      app/Http/Controllers/UserController.php
  73. 0 2
      app/Http/Kernel.php
  74. 0 2
      app/Http/Middleware/Affiliate.php
  75. 4 6
      app/Http/Middleware/Authenticate.php
  76. 0 2
      app/Http/Middleware/CheckForMaintenanceMode.php
  77. 0 2
      app/Http/Middleware/EncryptCookies.php
  78. 2 4
      app/Http/Middleware/RedirectIfAuthenticated.php
  79. 0 2
      app/Http/Middleware/SetLocale.php
  80. 0 2
      app/Http/Middleware/TrimStrings.php
  81. 0 2
      app/Http/Middleware/TrustHosts.php
  82. 0 2
      app/Http/Middleware/TrustProxies.php
  83. 0 2
      app/Http/Middleware/VerifyCsrfToken.php
  84. 7 11
      app/Http/Middleware/WebApi.php
  85. 1 3
      app/Http/Middleware/isAdmin.php
  86. 0 2
      app/Http/Middleware/isAdminlogin.php
  87. 15 53
      app/Http/Middleware/isForbidden.php
  88. 0 2
      app/Http/Middleware/isLogin.php
  89. 4 9
      app/Http/Middleware/isMaintenance.php
  90. 9 11
      app/Http/Middleware/isSecurity.php
  91. 20 0
      app/Http/Requests/Admin/ArticleRequest.php
  92. 22 0
      app/Http/Requests/Admin/CouponRequest.php
  93. 53 0
      app/Http/Requests/Admin/NodeRequest.php
  94. 20 0
      app/Http/Requests/Admin/ShopStoreRequest.php
  95. 17 0
      app/Http/Requests/Admin/ShopUpdateRequest.php
  96. 16 0
      app/Http/Requests/Admin/UserStoreRequest.php
  97. 33 0
      app/Http/Requests/Admin/UserUpdateRequest.php
  98. 8 15
      app/Jobs/VNet/addUser.php
  99. 8 15
      app/Jobs/VNet/delUser.php
  100. 10 17
      app/Jobs/VNet/editUser.php

+ 0 - 2
app/Components/CaptchaVerify.php

@@ -9,7 +9,6 @@ namespace App\Components;
  */
 class CaptchaVerify
 {
-
     //从后台获取 hcaptcha_sitekey 和 hcaptcha_secret
     public static function hCaptchaGetConfig(): array
     {
@@ -38,5 +37,4 @@ class CaptchaVerify
             "options" => [],
         ];
     }
-
 }

+ 58 - 115
app/Components/Helpers.php

@@ -18,29 +18,8 @@ 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,
+    private static array $denyPorts = [
+        1068, 1109, 1434, 3127, 3128, 3129, 3130, 3332, 4444, 5554, 6669, 8080, 8081, 8082, 8181, 8282, 9996, 17185, 24554, 35601, 60177, 60179,
     ];
 
     // 加密方式
@@ -83,34 +62,26 @@ class Helpers
      *
      * @return int
      */
-    public static function addUser(
-        string $email,
-        string $password,
-        string $transfer_enable,
-        int $data,
-        $inviter_id = null
-    ): int {
-        $user           = new User();
+    public static function addUser(string $email, string $password, string $transfer_enable, int $data, $inviter_id = null): int
+    {
+        $user = new User();
         $user->username = $email;
-        $user->email    = $email;
+        $user->email = $email;
         $user->password = $password;
         // 生成一个可用端口
-        $user->port            = self::getPort();
-        $user->passwd          = Str::random();
-        $user->vmess_id        = Str::uuid();
-        $user->enable          = 1;
-        $user->method          = self::getDefaultMethod();
-        $user->protocol        = self::getDefaultProtocol();
-        $user->obfs            = self::getDefaultObfs();
+        $user->port = self::getPort();
+        $user->passwd = Str::random();
+        $user->vmess_id = Str::uuid();
+        $user->enable = 1;
+        $user->method = self::getDefaultMethod();
+        $user->protocol = self::getDefaultProtocol();
+        $user->obfs = self::getDefaultObfs();
         $user->transfer_enable = $transfer_enable;
-        $user->expired_at      = date(
-            'Y-m-d',
-            strtotime("+" . $data . " days")
-        );
-        $user->reg_ip          = IP::getClientIp();
-        $user->inviter_id      = $inviter_id;
-        $user->reset_time      = null;
-        $user->status          = 0;
+        $user->expired_at = date('Y-m-d', strtotime("+".$data." days"));
+        $user->reg_ip = IP::getClientIp();
+        $user->inviter_id = $inviter_id;
+        $user->reset_time = null;
+        $user->status = 0;
         $user->save();
 
         return $user->id;
@@ -122,11 +93,8 @@ class Helpers
         if (sysConfig('is_rand_port')) {
             $port = self::getRandPort();
         } else {
-            $port        = (int)sysConfig('min_port');
-            $exists_port = array_merge(
-                User::where('port', '>=', $port)->pluck('port')->toArray(),
-                self::$denyPorts
-            );
+            $port = (int) sysConfig('min_port');
+            $exists_port = array_merge(User::where('port', '>=', $port)->pluck('port')->toArray(), self::$denyPorts);
 
             while (in_array($port, $exists_port, true)) {
                 ++$port;
@@ -139,7 +107,7 @@ class Helpers
     // 获取一个随机端口
     private static function getRandPort(): int
     {
-        $port        = random_int(sysConfig('min_port'), sysConfig('max_port'));
+        $port = random_int(sysConfig('min_port'), sysConfig('max_port'));
         $exists_port = array_merge(
             User::where('port', '<>', 0)->pluck('port')->toArray(),
             self::$denyPorts
@@ -157,7 +125,7 @@ class Helpers
     {
         $config = SsConfig::default()->type(1)->first();
 
-        return $config ? $config->name : 'aes-256-cfb';
+        return $config->name ?? 'aes-256-cfb';
     }
 
     // 获取默认协议
@@ -165,7 +133,7 @@ class Helpers
     {
         $config = SsConfig::default()->type(2)->first();
 
-        return $config ? $config->name : 'origin';
+        return $config->name ?? 'origin';
     }
 
     // 获取默认混淆
@@ -173,24 +141,18 @@ class Helpers
     {
         $config = SsConfig::default()->type(3)->first();
 
-        return $config ? $config->name : 'plain';
+        return $config->name ?? 'plain';
     }
 
     // 获取系统配置
     public static function cacheSysConfig($name)
     {
         if ($name === 'is_onlinePay') {
-            $value = ! empty(
-            array_filter(
-                Cache::many(
-                    ['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay']
-                )
-            )
-            );
+            $value = !empty(array_filter(Cache::many(['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay'])));
             Cache::tags('sysConfig')->put('is_onlinePay', $value);
         } else {
             $value = Config::find($name)->value;
-            Cache::tags('sysConfig')->put($name, $value ?: false);
+            Cache::tags('sysConfig')->put($name, $value ?? false);
         }
 
         return $value;
@@ -213,21 +175,15 @@ class Helpers
      *
      * @return int
      */
-    public static function addNotificationLog(
-        string $title,
-        string $content,
-        int $type,
-        string $address = 'admin',
-        int $status = 1,
-        string $error = ''
-    ): int {
-        $log          = new NotificationLog();
-        $log->type    = $type;
+    public static function addNotificationLog(string $title, string $content, int $type, $address = 'admin', $status = 1, $error = ''): int
+    {
+        $log = new NotificationLog();
+        $log->type = $type;
         $log->address = $address;
-        $log->title   = $title;
+        $log->title = $title;
         $log->content = $content;
-        $log->status  = $status;
-        $log->error   = $error;
+        $log->status = $status;
+        $log->error = $error;
         $log->save();
 
         return $log->id;
@@ -243,16 +199,12 @@ class Helpers
      *
      * @return bool
      */
-    public static function addCouponLog(
-        string $description,
-        int $couponId,
-        $goodsId = 0,
-        $orderId = 0
-    ): bool {
-        $log              = new CouponLog();
-        $log->coupon_id   = $couponId;
-        $log->goods_id    = $goodsId;
-        $log->order_id    = $orderId;
+    public static function addCouponLog(string $description, int $couponId, $goodsId = 0, $orderId = 0): bool
+    {
+        $log = new CouponLog();
+        $log->coupon_id = $couponId;
+        $log->goods_id = $goodsId;
+        $log->order_id = $orderId;
         $log->description = $description;
 
         return $log->save();
@@ -270,22 +222,16 @@ class Helpers
      *
      * @return bool
      */
-    public static function addUserCreditLog(
-        int $userId,
-        int $orderId,
-        int $before,
-        int $after,
-        int $amount,
-        $description = ''
-    ): bool {
-        $log              = new UserCreditLog();
-        $log->user_id     = $userId;
-        $log->order_id    = $orderId;
-        $log->before      = $before;
-        $log->after       = $after;
-        $log->amount      = $amount;
+    public static function addUserCreditLog(int $userId, int $orderId, int $before, int $after, int $amount, $description = ''): bool
+    {
+        $log = new UserCreditLog();
+        $log->user_id = $userId;
+        $log->order_id = $orderId;
+        $log->before = $before;
+        $log->after = $after;
+        $log->amount = $amount;
         $log->description = $description;
-        $log->created_at  = date('Y-m-d H:i:s');
+        $log->created_at = date('Y-m-d H:i:s');
 
         return $log->save();
     }
@@ -301,24 +247,20 @@ class Helpers
      *
      * @return bool
      */
-    public static function addUserTrafficModifyLog(
-        int $userId,
-        int $orderId,
-        int $before,
-        int $after,
-        $description = ''
-    ): bool {
-        $log              = new UserDataModifyLog();
-        $log->user_id     = $userId;
-        $log->order_id    = $orderId;
-        $log->before      = $before;
-        $log->after       = $after;
+    public static function addUserTrafficModifyLog(int $userId, int $orderId, int $before, int $after, $description = ''): bool
+    {
+        $log = new UserDataModifyLog();
+        $log->user_id = $userId;
+        $log->order_id = $orderId;
+        $log->before = $before;
+        $log->after = $after;
         $log->description = $description;
 
         return $log->save();
     }
 
-    public static function abortIfNotModified($data): string {
+    public static function abortIfNotModified($data): string
+    {
         $req = request();
         // Only for "GET" method
         if (!$req->isMethod('GET')) {
@@ -329,6 +271,7 @@ class Helpers
         if ($etag == $req->header("IF-NONE-MATCH")) {
             abort(304);
         }
+
         return $etag;
     }
 }

+ 25 - 57
app/Components/IP.php

@@ -14,19 +14,18 @@ use MaxMind\Db\Reader\InvalidDatabaseException;
 
 class IP
 {
-
     // 获取IP地址信息
     public static function getIPInfo($ip)
     {
         // IPv6 推荐使用ip.sb
         if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
-            Log::info('识别到IPv6,尝试解析:' . $ip);
-            $ipInfo = IP::IPSB($ip);
+            Log::info('识别到IPv6,尝试解析:'.$ip);
+            $ipInfo = self::IPSB($ip);
         } else {
-            $ipInfo = IP::ip2Region($ip);
-            if ( ! $ipInfo) {
-                Log::info('无法识别,尝试使用【IPIP库】库解析:' . $ip);
-                $ipInfo = IP::ip2Location($ip);
+            $ipInfo = self::ip2Region($ip);
+            if (!$ipInfo) {
+                Log::info('无法识别,尝试使用【IPIP库】库解析:'.$ip);
+                $ipInfo = self::ip2Location($ip);
             }
         }
 
@@ -36,15 +35,14 @@ class IP
     // 通过api.ip.sb查询IP地址的详细信息
     public static function IPSB($ip)
     {
-        $request = (new Client(['timeout' => 15]))
-            ->get('https://api.ip.sb/geoip/' . $ip);
+        $request = (new Client(['timeout' => 15]))->get('https://api.ip.sb/geoip/'.$ip);
         $message = json_decode($request->getBody(), true);
 
-        if ($request->getStatusCode() == 200) {
+        if ($request->getStatusCode() === 200) {
             return $message;
         }
 
-        Log::error('解析IPv6异常:' . $ip . PHP_EOL . var_export($request, true));
+        Log::error('解析IPv6异常:'.$ip.PHP_EOL.var_export($request, true));
 
         return false;
     }
@@ -56,7 +54,7 @@ class IP
         try {
             $ipInfo = (new Ip2Region())->memorySearch($ip);
         } catch (Exception $e) {
-            Log::error('【淘宝IP库】错误信息:' . $e->getMessage());
+            Log::error('【淘宝IP库】错误信息:'.$e->getMessage());
         }
 
         if ($ipInfo) {
@@ -78,14 +76,7 @@ class IP
         $filePath = database_path('IP2LOCATION-LITE-DB3.IPV6.BIN');
         try {
             $location = (new Database($filePath, Database::FILE_IO))
-                ->lookup(
-                    $ip,
-                    [
-                        Database::CITY_NAME,
-                        Database::REGION_NAME,
-                        Database::COUNTRY_NAME,
-                    ]
-                );
+                ->lookup($ip, [Database::CITY_NAME, Database::REGION_NAME, Database::COUNTRY_NAME,]);
 
             return [
                 'country'  => $location['countryName'],
@@ -93,7 +84,7 @@ class IP
                 'city'     => $location['cityName'],
             ];
         } catch (Exception $e) {
-            Log::error('【ip2Location】错误信息:' . $e->getMessage());
+            Log::error('【ip2Location】错误信息:'.$e->getMessage());
         }
 
         return false;
@@ -116,13 +107,10 @@ class IP
     public static function TaoBao(string $ip)
     {
         // 依据 http://ip.taobao.com/instructions 开发
-        $request = (new Client(['timeout' => 15]))
-            ->get(
-                'http://ip.taobao.com/outGetIpInfo?ip=' . $ip . '&accessKey=alibaba-inc'
-            );
+        $request = (new Client(['timeout' => 15]))->get('http://ip.taobao.com/outGetIpInfo?ip='.$ip.'&accessKey=alibaba-inc');
         $message = json_decode($request->getBody(), true);
 
-        if ($request->getStatusCode() == 200) {
+        if ($request->getStatusCode() === 200) {
             if ($message['code'] === 0) {
                 return [
                     'country'  => $message['data']['country'] === "XX" ? '' : $message['data']['country'],
@@ -131,16 +119,9 @@ class IP
                 ];
             }
 
-            Log::error(
-                '【淘宝IP库】返回错误信息:' . $ip . PHP_EOL . var_export(
-                    $message['msg'],
-                    true
-                )
-            );
+            Log::error('【淘宝IP库】返回错误信息:'.$ip.PHP_EOL.var_export($message['msg'], true));
         } else {
-            Log::error(
-                '【淘宝IP库】解析异常:' . $ip . PHP_EOL . var_export($request, true)
-            );
+            Log::error('【淘宝IP库】解析异常:'.$ip.PHP_EOL.var_export($request, true));
         }
 
         return false;
@@ -149,21 +130,16 @@ class IP
     // 通过api.map.baidu.com查询IP地址的详细信息
     public static function Baidu(string $ip)
     {
-        if ( ! env('BAIDU_APP_AK')) {
+        if (!env('BAIDU_APP_AK')) {
             Log::error('【百度IP库】AK信息缺失');
 
             return false;
         }
         // 依据 http://lbsyun.baidu.com/index.php?title=webapi/ip-api 开发
-        $request = (new Client(['timeout' => 15]))
-            ->get(
-                'https://api.map.baidu.com/location/ip?ak=' . env(
-                    'BAIDU_APP_AK'
-                ) . '&' . $ip . '&coor=bd09ll'
-            );
+        $request = (new Client(['timeout' => 15]))->get('https://api.map.baidu.com/location/ip?ak='.env('BAIDU_APP_AK').'&'.$ip.'&coor=bd09ll');
         $message = json_decode($request->getBody(), true);
 
-        if ($request->getStatusCode() == 200) {
+        if ($request->getStatusCode() === 200) {
             if ($message['status'] === 0) {
                 return [
                     'country'  => $message['content']['address_detail']['country'],
@@ -172,16 +148,9 @@ class IP
                 ];
             }
 
-            Log::error(
-                '【百度IP库】返回错误信息:' . $ip . PHP_EOL . var_export(
-                    $message['message'],
-                    true
-                )
-            );
+            Log::error('【百度IP库】返回错误信息:'.$ip.PHP_EOL.var_export($message['message'], true));
         } else {
-            Log::error(
-                '【百度IP库】解析异常:' . $ip . PHP_EOL . var_export($request, true)
-            );
+            Log::error('【百度IP库】解析异常:'.$ip.PHP_EOL.var_export($request, true));
         }
 
         return false;
@@ -200,9 +169,9 @@ class IP
                 'city'     => $location->city->name ?? '',
             ];
         } catch (AddressNotFoundException $e) {
-            Log::error('【GeoIP2】查询失败:' . $ip);
+            Log::error('【GeoIP2】查询失败:'.$ip);
         } catch (InvalidDatabaseException $e) {
-            Log::error('【GeoIP2】数据库无效:' . $ip);
+            Log::error('【GeoIP2】数据库无效:'.$ip);
         }
 
         return false;
@@ -219,7 +188,7 @@ class IP
         if (isset($_SERVER)) {
             if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
                 $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_CF_CONNECTING_IP'];
-                $ip                     = $_SERVER['REMOTE_ADDR'];
+                $ip = $_SERVER['REMOTE_ADDR'];
             } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
             } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
@@ -243,5 +212,4 @@ class IP
 
         return $ip;
     }
-
-}
+}

+ 19 - 75
app/Components/Namesilo.php

@@ -8,8 +8,7 @@ use LSS\XML2Array;
 
 class Namesilo
 {
-
-    private static $host = 'https://www.namesilo.com/api/';
+    private static string $host = 'https://www.namesilo.com/api/';
 
     // 列出账号下所有域名 Todo Debug测试
     public function listDomains()
@@ -25,52 +24,28 @@ class Namesilo
             'type'    => 'xml',
             'key'     => sysConfig('namesilo_key'),
         ];
-        $query  = array_merge($params, $data);
+        $query = array_merge($params, $data);
 
-        $content = '请求操作:[' . $operation . '] --- 请求数据:[' . http_build_query(
-                $query
-            ) . ']';
+        $content = '请求操作:['.$operation.'] --- 请求数据:['.http_build_query($query).']';
 
-        $request = (new Client(['timeout' => 15]))->get(
-            self::$host . $operation . '?' . http_build_query($query)
-        );
-        $result  = XML2Array::createArray(
-            json_decode($request->getBody(), true)
-        );
+        $request = (new Client(['timeout' => 15]))->get(self::$host.$operation.'?'.http_build_query($query));
+        $result = XML2Array::createArray(json_decode($request->getBody(), true));
 
-        if ($request->getStatusCode() != 200) {
-            Log::error('请求失败:' . var_export($request, true));
-            Helpers::addNotificationLog(
-                '[Namesilo API] - [' . $operation . ']',
-                $content,
-                1,
-                sysConfig('webmaster_email'),
-                0,
-                var_export($request, true)
-            );
+        if ($request->getStatusCode() !== 200) {
+            Log::error('请求失败:'.var_export($request, true));
+            Helpers::addNotificationLog('[Namesilo API] - ['.$operation.']', $content, 1, sysConfig('webmaster_email'),
+                0, var_export($request, true));
 
             return false;
         }
 
         // 出错
         if (empty($result['namesilo']) || $result['namesilo']['reply']['code'] != 300 || $result['namesilo']['reply']['detail'] !== 'success') {
-            Helpers::addNotificationLog(
-                '[Namesilo API] - [' . $operation . ']',
-                $content,
-                1,
-                sysConfig('webmaster_email'),
-                0,
-                $result['namesilo']['reply']['detail']
-            );
+            Helpers::addNotificationLog('[Namesilo API] - ['.$operation.']', $content, 1, sysConfig('webmaster_email'),
+                0, $result['namesilo']['reply']['detail']);
         } else {
-            Helpers::addNotificationLog(
-                '[Namesilo API] - [' . $operation . ']',
-                $content,
-                1,
-                sysConfig('webmaster_email'),
-                1,
-                $result['namesilo']['reply']['detail']
-            );
+            Helpers::addNotificationLog('[Namesilo API] - ['.$operation.']', $content, 1, sysConfig('webmaster_email'),
+                1, $result['namesilo']['reply']['detail']);
         }
 
         return $result['namesilo']['reply'];
@@ -79,55 +54,24 @@ class Namesilo
     // 列出指定域名的所有DNS记录
     public function dnsListRecords($domain)
     {
-        $query = [
-            'domain' => $domain,
-        ];
-
-        return $this->send('dnsListRecords', $query);
+        return $this->send('dnsListRecords', ['domain' => $domain]);
     }
 
     // 为指定域名添加DNS记录
-    public function dnsAddRecord(
-        $domain,
-        $host,
-        $value,
-        $type = 'A',
-        $ttl = 7207
-    ) {
-        $query = [
-            'domain'  => $domain,
-            'rrtype'  => $type,
-            'rrhost'  => $host,
-            'rrvalue' => $value,
-            'rrttl'   => $ttl,
-        ];
-
-        return $this->send('dnsAddRecord', $query);
+    public function dnsAddRecord($domain, $host, $value, $type = 'A', $ttl = 7207)
+    {
+        return $this->send('dnsAddRecord', ['domain' => $domain, 'rrtype' => $type, 'rrhost' => $host, 'rrvalue' => $value, 'rrttl' => $ttl]);
     }
 
     // 更新DNS记录
     public function dnsUpdateRecord($domain, $id, $host, $value, $ttl = 7207)
     {
-        $query = [
-            'domain'  => $domain,
-            'rrid'    => $id,
-            'rrhost'  => $host,
-            'rrvalue' => $value,
-            'rrttl'   => $ttl,
-        ];
-
-        return $this->send('dnsUpdateRecord', $query);
+        return $this->send('dnsUpdateRecord', ['domain' => $domain, 'rrid' => $id, 'rrhost' => $host, 'rrvalue' => $value, 'rrttl' => $ttl]);
     }
 
     // 删除DNS记录
     public function dnsDeleteRecord($domain, $id)
     {
-        $data = [
-            'domain' => $domain,
-            'rrid'   => $id,
-        ];
-
-        return $this->send('dnsDeleteRecord', $data);
+        return $this->send('dnsDeleteRecord', ['domain' => $domain, 'rrid' => $id]);
     }
-
 }

+ 16 - 26
app/Components/NetworkDetection.php

@@ -7,7 +7,6 @@ use Log;
 
 class NetworkDetection
 {
-
     /**
      * 用api.50network.com进行节点阻断检测
      *
@@ -19,33 +18,27 @@ class NetworkDetection
      */
     public static function networkCheck(string $ip, bool $type, $port = null)
     {
-        $url       = 'https://api.50network.com/china-firewall/check/ip/' . ($type ? 'icmp/' : ($port ? 'tcp_port/' : 'tcp_ack/')) . $ip . ($port ? '/' . $port : '');
+        $url = 'https://api.50network.com/china-firewall/check/ip/'.($type ? 'icmp/' : ($port ? 'tcp_port/' : 'tcp_ack/')).$ip.($port ? '/'.$port : '');
+
         $checkName = $type ? 'ICMP' : 'TCP';
-        $request   = (new Client(['timeout' => 15]))->get($url);
-        $result    = json_decode($request->getBody(), true);
+        $request = (new Client(['timeout' => 15]))->get($url);
+        $result = json_decode($request->getBody(), true);
 
-        if ($request->getStatusCode() == 200) {
-            if ( ! $result) {
-                Log::warning(
-                    "【" . $checkName . "阻断检测】检测" . $ip . "时,接口返回异常访问链接:" . $url
-                );
+        if ($request->getStatusCode() === 200) {
+            if (!$result) {
+                Log::warning("【".$checkName."阻断检测】检测".$ip."时,接口返回异常访问链接:".$url);
 
                 return false;
             }
 
-            if ( ! $result['success']) {
+            if (!$result['success']) {
                 if ($result['error'] === "execute timeout (3s)") {
                     sleep(10);
 
                     return self::networkCheck($ip, $type, $port);
                 }
 
-                Log::warning(
-                    "【" . $checkName . "阻断检测】检测" . $ip . ($port ?: '') . "时,返回" . var_export(
-                        $result,
-                        true
-                    )
-                );
+                Log::warning("【".$checkName."阻断检测】检测".$ip.$port."时,返回".var_export($result, true));
 
                 return false;
             }
@@ -54,11 +47,11 @@ class NetworkDetection
                 return "通讯正常"; // 正常
             }
 
-            if ($result['firewall-enable'] && ! $result['firewall-disable']) {
+            if ($result['firewall-enable'] && !$result['firewall-disable']) {
                 return "海外阻断"; // 国外访问异常
             }
 
-            if ( ! $result['firewall-enable'] && $result['firewall-disable']) {
+            if (!$result['firewall-enable'] && $result['firewall-disable']) {
                 return "国内阻断"; // 被墙
             }
 
@@ -77,26 +70,23 @@ class NetworkDetection
      */
     public static function ping(string $ip)
     {
-        $url     = 'https://api.oioweb.cn/api/hostping.php?host=' . $ip;//https://api.iiwl.cc/api/ping.php?host=
+        $url = 'https://api.oioweb.cn/api/hostping.php?host='.$ip; // https://api.iiwl.cc/api/ping.php?host=
         $request = (new Client(['timeout' => 15]))->get($url);
         $message = json_decode($request->getBody(), true);
 
         // 发送成功
-        if ($request->getStatusCode() == 200) {
+        if ($request->getStatusCode() === 200) {
             if ($message && $message['code']) {
                 return $message['data'];
             }
             // 发送失败
-            Log::warning(
-                "【PING】检测" . $ip . "时,返回" . var_export($message, true)
-            );
+            Log::warning("【PING】检测".$ip."时,返回".var_export($message, true));
 
             return false;
         }
-        Log::warning("【PING】检测" . $ip . "时,接口返回异常访问链接:" . $url);
+        Log::warning("【PING】检测".$ip."时,接口返回异常访问链接:".$url);
 
         // 发送错误
         return false;
     }
-
-}
+}

+ 10 - 34
app/Components/PushNotification.php

@@ -8,7 +8,6 @@ use Log;
 
 class PushNotification
 {
-
     public static function send($title, $content)
     {
         switch (sysConfig('is_notification')) {
@@ -32,33 +31,22 @@ class PushNotification
     private static function ServerChan(string $title, string $content)
     {
         // TODO:一天仅可发送不超过500条
-        $request = (new Client(['timeout' => 15]))->get(
-            'https://sc.ftqq.com/' . sysConfig(
-                'server_chan_key'
-            ) . '.send?text=' . $title . '&desp=' . urlencode($content)
-        );
+        $request = (new Client(['timeout' => 15]))->get('https://sc.ftqq.com/'.sysConfig('server_chan_key').'.send?text='.$title.'&desp='.urlencode($content));
         $message = json_decode($request->getBody(), true);
         // 发送成功
-        if ($request->getStatusCode() == 200) {
-            if ( ! $message['errno']) {
+        if ($request->getStatusCode() === 200) {
+            if (!$message['errno']) {
                 Helpers::addNotificationLog($title, $content, 2);
 
                 return $message;
             }
             // 发送失败
-            Helpers::addNotificationLog(
-                $title,
-                $content,
-                2,
-                'admin',
-                -1,
-                $message ? $message['errmsg'] : '未知'
-            );
+            Helpers::addNotificationLog($title, $content, 2, 'admin', -1, $message ? $message['errmsg'] : '未知');
 
             return false;
         }
         // 发送错误
-        Log::error('ServerChan消息推送异常:' . var_export($request, true));
+        Log::error('ServerChan消息推送异常:'.var_export($request, true));
 
         return false;
     }
@@ -73,36 +61,24 @@ class PushNotification
      */
     private static function Bark(string $title, string $content)
     {
-        $request = (new Client(['timeout' => 15]))->get(
-            'https://api.day.app/' . sysConfig(
-                'bark_key'
-            ) . '/' . $title . '/' . $content
-        );
+        $request = (new Client(['timeout' => 15]))->get('https://api.day.app/'.sysConfig('bark_key').'/'.$title.'/'.$content);
         $message = json_decode($request->getBody(), true);
 
-        if ($request->getStatusCode() == 200) {
+        if ($request->getStatusCode() === 200) {
             // 发送成功
-            if ($message['code'] == 200) {
+            if ($message['code'] === 200) {
                 Helpers::addNotificationLog($title, $content, 3);
 
                 return $message;
             }
             // 发送失败
-            Helpers::addNotificationLog(
-                $title,
-                $content,
-                3,
-                'admin',
-                -1,
-                $message
-            );
+            Helpers::addNotificationLog($title, $content, 3, 'admin', -1, $message);
 
             return false;
         }
         // 发送错误
-        Log::error('Bark消息推送异常:' . var_export($request, true));
+        Log::error('Bark消息推送异常:'.var_export($request, true));
 
         return false;
     }
-
 }

+ 6 - 10
app/Components/QQInfo.php

@@ -6,16 +6,15 @@ use GuzzleHttp\Client;
 
 class QQInfo
 {
-
     public static function getName(string $qq): string
     {
         //向接口发起请求获取json数据
-        $url     = 'https://r.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?get_nick=1&uins=' . $qq;
+        $url = 'https://r.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?get_nick=1&uins='.$qq;
         $request = (new Client(['timeout' => 15]))->get($url);
         $message = mb_convert_encoding($request->getBody(), "UTF-8", "GBK");
 
         // 接口是否异常
-        if ($request->getStatusCode() == 200 && str_contains($message, $qq)) {
+        if ($request->getStatusCode() === 200 && str_contains($message, $qq)) {
             //对获取的json数据进行截取并解析成数组
             $message = json_decode(substr($message, 17, -1), true);
 
@@ -28,13 +27,12 @@ class QQInfo
     public static function getName2(string $qq): string
     {
         //向接口发起请求获取json数据
-        $url     = 'https://api.toubiec.cn/qq?qq=' . $qq . '&size=100';
+        $url = 'https://api.toubiec.cn/qq?qq='.$qq.'&size=100';
         $request = (new Client(['timeout' => 15]))->get($url);
         $message = json_decode($request->getBody(), true);
 
         // 接口是否异常
-        if ($message && $message['code'] == 200
-            && $request->getStatusCode() == 200) {
+        if ($message && $message['code'] == 200 && $request->getStatusCode() === 200) {
             return $message['name'];
         }
 
@@ -44,17 +42,15 @@ class QQInfo
     public static function getName3(string $qq): string
     {
         //向接口发起请求获取json数据
-        $url     = 'https://api.unipay.qq.com/v1/r/1450000186/wechat_query?cmd=1&pf=mds_storeopen_qb-__mds_qqclub_tab_-html5&pfkey=pfkey&from_h5=1&from_https=1&openid=openid&openkey=openkey&session_id=hy_gameid&session_type=st_dummy&qq_appid=&offerId=1450000186&sandbox=&provide_uin=' . $qq;
+        $url = 'https://api.unipay.qq.com/v1/r/1450000186/wechat_query?cmd=1&pf=mds_storeopen_qb-__mds_qqclub_tab_-html5&pfkey=pfkey&from_h5=1&from_https=1&openid=openid&openkey=openkey&session_id=hy_gameid&session_type=st_dummy&qq_appid=&offerId=1450000186&sandbox=&provide_uin='.$qq;
         $request = (new Client(['timeout' => 15]))->get($url);
         $message = json_decode($request->getBody(), true);
 
         // 接口是否异常
-        if ($message && $message['ret'] == 0
-            && $request->getStatusCode() == 200) {
+        if ($message && $message['ret'] == 0 && $request->getStatusCode() === 200) {
             return urldecode($message['nick']);
         }
 
         return $qq;
     }
-
 }

+ 16 - 59
app/Console/Commands/AutoClearLog.php

@@ -19,7 +19,6 @@ use Log;
 
 class AutoClearLog extends Command
 {
-
     protected $signature = 'autoClearLog';
     protected $description = '自动清除日志';
 
@@ -32,12 +31,10 @@ class AutoClearLog extends Command
             $this->clearLog();
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     // 清除日志
@@ -45,82 +42,42 @@ class AutoClearLog extends Command
     {
         try {
             // 清除节点负载信息日志
-            NodeHeartBeat::where('log_time', '<=', strtotime("-30 minutes"))
-                         ->delete();
+            NodeHeartBeat::where('log_time', '<=', strtotime("-30 minutes"))->delete();
 
             // 清除节点在线用户数日志
-            NodeOnlineLog::where('log_time', '<=', strtotime("-1 hour"))
-                         ->delete();
+            NodeOnlineLog::where('log_time', '<=', strtotime("-1 hour"))->delete();
 
             // 清除用户流量日志
-            UserDataFlowLog::where('log_time', '<=', strtotime("-3 days"))
-                           ->delete();
+            UserDataFlowLog::where('log_time', '<=', strtotime("-3 days"))->delete();
 
             // 清除用户每时各流量数据日志
-            UserHourlyDataFlow::where(
-                'created_at',
-                '<=',
-                date('Y-m-d H:i:s', strtotime('-3 days'))
-            )->delete();
+            UserHourlyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
 
             // 清除用户各节点 / 节点总计的每天流量数据日志
             UserDailyDataFlow::where('node_id', '<>', 0)
-                             ->where(
-                                 'created_at',
-                                 '<=',
-                                 date('Y-m-d H:i:s', strtotime('-1 month'))
-                             )
-                             ->orWhere(
-                                 'created_at',
-                                 '<=',
-                                 date(
-                                     'Y-m-d H:i:s',
-                                     strtotime('-3 month')
-                                 )
-                             )
-                             ->delete();
+                ->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-1 month')))
+                ->orWhere('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))
+                ->delete();
 
             // 清除节点每小时流量数据日志
-            NodeHourlyDataFlow::where(
-                'created_at',
-                '<=',
-                date('Y-m-d H:i:s', strtotime('-3 days'))
-            )->delete();
+            NodeHourlyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
 
             // 清除节点每天流量数据日志
-            NodeDailyDataFlow::where(
-                'created_at',
-                '<=',
-                date('Y-m-d H:i:s', strtotime('-2 month'))
-            )->delete();
+            NodeDailyDataFlow::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-2 month')))->delete();
 
             // 清除用户封禁日志
-            UserBanedLog::where(
-                'created_at',
-                '<=',
-                date('Y-m-d H:i:s', strtotime("-3 month"))
-            )->delete();
+            UserBanedLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
 
             // 清除用户连接IP
-            NodeOnlineUserIp::where('created_at', '<=', strtotime("-1 month"))
-                            ->delete();
+            NodeOnlineUserIp::where('created_at', '<=', strtotime("-1 month"))->delete();
 
             // 清除用户登陆日志
-            UserLoginLog::where(
-                'created_at',
-                '<=',
-                date('Y-m-d H:i:s', strtotime("-3 month"))
-            )->delete();
+            UserLoginLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
 
             // 清除用户订阅记录
-            UserSubscribeLog::where(
-                'request_time',
-                '<=',
-                date('Y-m-d H:i:s', strtotime("-1 month"))
-            )->delete();
+            UserSubscribeLog::where('request_time', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))->delete();
         } catch (Exception $e) {
-            Log::error('【清理日志】错误: ' . $e->getMessage());
+            Log::error('【清理日志】错误: '.$e->getMessage());
         }
     }
-
 }

+ 40 - 80
app/Console/Commands/AutoJob.php

@@ -20,7 +20,6 @@ use Log;
 
 class AutoJob extends Command
 {
-
     protected $signature = 'autoJob';
     protected $description = '自动化任务';
 
@@ -56,16 +55,13 @@ class AutoJob extends Command
 
         // 检查维护模式
         if (sysConfig('maintenance_mode')) {
-            Config::whereIn('name', ['maintenance_mode', 'maintenance_time'])
-                  ->update(['value' => null]);
+            Config::whereIn('name', ['maintenance_mode', 'maintenance_time'])->update(['value' => null]);
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     // 关闭超时未支付本地订单
@@ -86,15 +82,13 @@ class AutoJob extends Command
 
         // 优惠券到期 / 用尽的 自动置无效
         Coupon::whereStatus(0)
-              ->where('end_time', '<=', time())
-              ->orWhereIn('type', [1, 2])
-              ->whereUsableTimes(0)
-              ->update(['status' => 2]);
+            ->where('end_time', '<=', time())
+            ->orWhereIn('type', [1, 2])
+            ->whereUsableTimes(0)
+            ->update(['status' => 2]);
 
         // 邀请码到期自动置无效
-        Invite::whereStatus(0)
-              ->where('dateline', '<=', date('Y-m-d H:i:s'))
-              ->update(['status' => 2]);
+        Invite::whereStatus(0)->where('dateline', '<=', date('Y-m-d H:i:s'))->update(['status' => 2]);
     }
 
     // 封禁访问异常的订阅链接
@@ -103,31 +97,20 @@ class AutoJob extends Command
         if (sysConfig('is_subscribe_ban')) {
             $subscribe_ban_times = sysConfig('subscribe_ban_times');
             foreach (User::activeUser()->with('subscribe')->get() as $user) {
-                if ( ! $user->subscribe || $user->subscribe->status === 0) { // 无订阅链接 或 已封
+                if (!$user->subscribe || $user->subscribe->status === 0) { // 无订阅链接 或 已封
                     continue;
                 }
                 // 24小时内不同IP的请求次数
                 $request_times = $user->subscribeLogs()
-                                      ->where(
-                                          'request_time',
-                                          '>=',
-                                          date(
-                                              "Y-m-d H:i:s",
-                                              strtotime("-1 days")
-                                          )
-                                      )
-                                      ->distinct()
-                                      ->count('request_ip');
+                    ->where('request_time', '>=', date("Y-m-d H:i:s", strtotime("-1 days")))
+                    ->distinct()
+                    ->count('request_ip');
                 if ($request_times >= $subscribe_ban_times) {
-                    $user->subscribe->update(
-                        [
-                            'status'   => 0,
-                            'ban_time' => strtotime(
-                                "+" . sysConfig('traffic_ban_time') . " minutes"
-                            ),
-                            'ban_desc' => '存在异常,自动封禁',
-                        ]
-                    );
+                    $user->subscribe->update([
+                        'status'   => 0,
+                        'ban_time' => strtotime("+".sysConfig('traffic_ban_time')." minutes"),
+                        'ban_desc' => '存在异常,自动封禁',
+                    ]);
 
                     // 记录封禁日志
                     $this->addUserBanLog($user->id, 0, '【完全封禁订阅】-订阅24小时内请求异常');
@@ -143,14 +126,11 @@ class AutoJob extends Command
      * @param  int  $time  封禁时长,单位分钟
      * @param  string  $description  封禁理由
      */
-    private function addUserBanLog(
-        int $userId,
-        int $time,
-        string $description
-    ): void {
-        $log              = new UserBanedLog();
-        $log->user_id     = $userId;
-        $log->time        = $time;
+    private function addUserBanLog(int $userId, int $time, string $description): void
+    {
+        $log = new UserBanedLog();
+        $log->user_id = $userId;
+        $log->time = $time;
         $log->description = $description;
         $log->save();
     }
@@ -162,7 +142,7 @@ class AutoJob extends Command
         $userList = User::activeUser()->whereBanTime(null);
         if (sysConfig('is_traffic_ban')) {
             $trafficBanValue = sysConfig('traffic_ban_value');
-            $trafficBanTime  = sysConfig('traffic_ban_time');
+            $trafficBanTime = sysConfig('traffic_ban_time');
             foreach ($userList->get() as $user) {
                 // 对管理员豁免
                 if ($user->is_admin) {
@@ -170,32 +150,21 @@ class AutoJob extends Command
                 }
 
                 // 多往前取5分钟,防止数据统计任务执行时间过长导致没有数据
-                $totalTraffic = UserHourlyDataFlow::userRecentUsed($user->id)
-                                                  ->sum('total');
+                $totalTraffic = UserHourlyDataFlow::userRecentUsed($user->id)->sum('total');
                 if ($totalTraffic >= $trafficBanValue * GB) {
-                    $user->update(
-                        [
-                            'enable'   => 0,
-                            'ban_time' => strtotime(
-                                "+" . $trafficBanTime . " minutes"
-                            ),
-                        ]
-                    );
+                    $user->update([
+                        'enable'   => 0,
+                        'ban_time' => strtotime("+".$trafficBanTime." minutes"),
+                    ]);
 
                     // 写入日志
-                    $this->addUserBanLog(
-                        $user->id,
-                        $trafficBanTime,
-                        '【临时封禁代理】-1小时内流量异常'
-                    );
+                    $this->addUserBanLog($user->id, $trafficBanTime, '【临时封禁代理】-1小时内流量异常');
                 }
             }
         }
 
         // 禁用流量超限用户
-        foreach (
-            $userList->whereRaw("u + d >= transfer_enable")->get() as $user
-        ) {
+        foreach ($userList->whereRaw("u + d >= transfer_enable")->get() as $user) {
             $user->update(['enable' => 0]);
 
             // 写入日志
@@ -207,10 +176,7 @@ class AutoJob extends Command
     private function unblockUsers(): void
     {
         // 解封被临时封禁的账号
-        $userList = User::whereEnable(0)
-                        ->where('status', '>=', 0)
-                        ->whereNotNull('ban_time')
-                        ->get();
+        $userList = User::whereEnable(0)->where('status', '>=', 0)->whereNotNull('ban_time')->get();
         foreach ($userList as $user) {
             if ($user->ban_time < time()) {
                 $user->update(['enable' => 1, 'ban_time' => null]);
@@ -222,11 +188,11 @@ class AutoJob extends Command
 
         // 可用流量大于已用流量也解封(比如:邀请返利自动加了流量)
         $userList = User::whereEnable(0)
-                        ->where('status', '>=', 0)
-                        ->whereBanTime(null)
-                        ->where('expired_at', '>=', date('Y-m-d'))
-                        ->whereRaw("u + d < transfer_enable")
-                        ->get();
+            ->where('status', '>=', 0)
+            ->whereBanTime(null)
+            ->where('expired_at', '>=', date('Y-m-d'))
+            ->whereRaw("u + d < transfer_enable")
+            ->get();
         foreach ($userList as $user) {
             $user->update(['enable' => 1]);
 
@@ -255,15 +221,13 @@ class AutoJob extends Command
     {
         if (sysConfig('is_node_offline')) {
             $offlineCheckTimes = sysConfig('offline_check_times');
-            $onlineNode        = NodeHeartBeat::recently()->distinct()->pluck(
-                'node_id'
-            )->toArray();
+            $onlineNode = NodeHeartBeat::recently()->distinct()->pluck('node_id')->toArray();
             foreach (Node::whereIsRelay(0)->whereStatus(1)->get() as $node) {
                 // 10分钟内无节点负载信息则认为是后端炸了
-                $nodeTTL = ! in_array($node->id, $onlineNode);
+                $nodeTTL = !in_array($node->id, $onlineNode, true);
                 if ($nodeTTL && $offlineCheckTimes) {
                     // 已通知次数
-                    $cacheKey = 'offline_check_times' . $node->id;
+                    $cacheKey = 'offline_check_times'.$node->id;
                     if (Cache::has($cacheKey)) {
                         $times = Cache::get($cacheKey);
                     } else {
@@ -274,14 +238,10 @@ class AutoJob extends Command
 
                     if ($times < $offlineCheckTimes) {
                         Cache::increment($cacheKey);
-                        PushNotification::send(
-                            '节点异常警告',
-                            "节点**{$node->name}【{$node->ip}】**异常:**心跳异常,可能离线了**"
-                        );
+                        PushNotification::send('节点异常警告', "节点**{$node->name}【{$node->ip}】**异常:**心跳异常,可能离线了**");
                     }
                 }
             }
         }
     }
-
 }

+ 9 - 16
app/Console/Commands/AutoPingNode.php

@@ -10,7 +10,6 @@ use Log;
 
 class AutoPingNode extends Command
 {
-
     protected $signature = 'autoPingNode';
     protected $description = '节点定时Ping测速';
 
@@ -19,18 +18,13 @@ class AutoPingNode extends Command
         $jobStartTime = microtime(true);
 
         foreach (Node::whereIsRelay(0)->whereStatus(1)->get() as $node) {
-            $this->pingNode(
-                $node->id,
-                $node->is_ddns ? $node->server : $node->ip
-            );
+            $this->pingNode($node->id, $node->is_ddns ? $node->server : $node->ip);
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     // 节点Ping测速
@@ -39,16 +33,15 @@ class AutoPingNode extends Command
         $result = NetworkDetection::ping($ip);
 
         if ($result) {
-            $obj          = new NodePing();
+            $obj = new NodePing();
             $obj->node_id = $nodeId;
-            $obj->ct      = (int)$result['telecom']['time'];//电信
-            $obj->cu      = (int)$result['Unicom']['time'];// 联通
-            $obj->cm      = (int)$result['move']['time'];// 移动
-            $obj->hk      = (int)$result['HongKong']['time'];// 香港
+            $obj->ct = (int) $result['telecom']['time'];//电信
+            $obj->cu = (int) $result['Unicom']['time'];// 联通
+            $obj->cm = (int) $result['move']['time'];// 移动
+            $obj->hk = (int) $result['HongKong']['time'];// 香港
             $obj->save();
         } else {
-            Log::error("【" . $ip . "】Ping测速获取失败");
+            Log::error("【".$ip."】Ping测速获取失败");
         }
     }
-
 }

+ 6 - 22
app/Console/Commands/AutoReportNode.php

@@ -10,7 +10,6 @@ use Log;
 
 class AutoReportNode extends Command
 {
-
     protected $signature = 'autoReportNode';
     protected $description = '自动报告节点昨日使用情况';
 
@@ -24,25 +23,13 @@ class AutoReportNode extends Command
                 $msg = "|节点|上行流量|下行流量|合计|\r\n| :------ | :------ | :------ |\r\n";
                 foreach ($nodeList as $node) {
                     $log = NodeDailyDataFlow::whereNodeId($node->id)
-                                            ->whereDate(
-                                                'created_at',
-                                                date(
-                                                    "Y-m-d",
-                                                    strtotime('-1 days')
-                                                )
-                                            )
-                                            ->first();
+                        ->whereDate('created_at', date("Y-m-d", strtotime('-1 days')))
+                        ->first();
 
                     if ($log) {
-                        $msg .= '|' . $node->name . '|' . flowAutoShow(
-                                $log->u
-                            ) . '|' . flowAutoShow(
-                                    $log->d
-                                ) . '|' . $log->traffic . "\r\n";
+                        $msg .= '|'.$node->name.'|'.flowAutoShow($log->u).'|'.flowAutoShow($log->d).'|'.$log->traffic."\r\n";
                     } else {
-                        $msg .= '|' . $node->name . '|' . flowAutoShow(
-                                0
-                            ) . '|' . flowAutoShow(0) . "|0B\r\n";
+                        $msg .= '|'.$node->name.'|'.flowAutoShow(0).'|'.flowAutoShow(0)."|0B\r\n";
                     }
                 }
 
@@ -50,12 +37,9 @@ class AutoReportNode extends Command
             }
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
-
 }

+ 9 - 16
app/Console/Commands/AutoStatisticsNodeDailyTraffic.php

@@ -10,7 +10,6 @@ use Log;
 
 class AutoStatisticsNodeDailyTraffic extends Command
 {
-
     protected $signature = 'autoStatisticsNodeDailyTraffic';
     protected $description = '自动统计节点每日流量';
 
@@ -22,34 +21,28 @@ class AutoStatisticsNodeDailyTraffic extends Command
             $this->statisticsByNode($node->id);
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     private function statisticsByNode($node_id): void
     {
-        $query = UserDataFlowLog::whereNodeId($node_id)->whereBetween(
-            'log_time',
-            [strtotime(date('Y-m-d')), time()]
-        );
+        $query = UserDataFlowLog::whereNodeId($node_id)->whereBetween('log_time', [strtotime(date('Y-m-d')), time()]);
 
-        $u     = $query->sum('u');
-        $d     = $query->sum('d');
+        $u = $query->sum('u');
+        $d = $query->sum('d');
         $total = $u + $d;
 
         if ($total) { // 有数据才记录
-            $obj          = new NodeDailyDataFlow();
+            $obj = new NodeDailyDataFlow();
             $obj->node_id = $node_id;
-            $obj->u       = $u;
-            $obj->d       = $d;
-            $obj->total   = $total;
+            $obj->u = $u;
+            $obj->d = $d;
+            $obj->total = $total;
             $obj->traffic = flowAutoShow($total);
             $obj->save();
         }
     }
-
 }

+ 9 - 16
app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php

@@ -10,7 +10,6 @@ use Log;
 
 class AutoStatisticsNodeHourlyTraffic extends Command
 {
-
     protected $signature = 'autoStatisticsNodeHourlyTraffic';
     protected $description = '自动统计节点每小时流量';
 
@@ -22,34 +21,28 @@ class AutoStatisticsNodeHourlyTraffic extends Command
             $this->statisticsByNode($node->id);
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     private function statisticsByNode($node_id): void
     {
-        $query = UserDataFlowLog::whereNodeId($node_id)->whereBetween(
-            'log_time',
-            [strtotime("-1 hour"), time()]
-        );
+        $query = UserDataFlowLog::whereNodeId($node_id)->whereBetween('log_time', [strtotime("-1 hour"), time()]);
 
-        $u     = $query->sum('u');
-        $d     = $query->sum('d');
+        $u = $query->sum('u');
+        $d = $query->sum('d');
         $total = $u + $d;
 
         if ($total) { // 有数据才记录
-            $obj          = new NodeHourlyDataFlow();
+            $obj = new NodeHourlyDataFlow();
             $obj->node_id = $node_id;
-            $obj->u       = $u;
-            $obj->d       = $d;
-            $obj->total   = $total;
+            $obj->u = $u;
+            $obj->d = $d;
+            $obj->total = $total;
             $obj->traffic = flowAutoShow($total);
             $obj->save();
         }
     }
-
 }

+ 9 - 16
app/Console/Commands/AutoStatisticsUserDailyTraffic.php

@@ -11,7 +11,6 @@ use Log;
 
 class AutoStatisticsUserDailyTraffic extends Command
 {
-
     protected $signature = 'autoStatisticsUserDailyTraffic';
     protected $description = '自动统计用户每日流量';
 
@@ -29,39 +28,33 @@ class AutoStatisticsUserDailyTraffic extends Command
             }
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     private function statisticsByUser($user_id, $node_id = 0): void
     {
-        $query = UserDataFlowLog::whereUserId($user_id)->whereBetween(
-            'log_time',
-            [strtotime(date('Y-m-d')), time()]
-        );
+        $query = UserDataFlowLog::whereUserId($user_id)->whereBetween('log_time', [strtotime(date('Y-m-d')), time()]);
 
         if ($node_id) {
             $query->whereNodeId($node_id);
         }
 
-        $u     = $query->sum('u');
-        $d     = $query->sum('d');
+        $u = $query->sum('u');
+        $d = $query->sum('d');
         $total = $u + $d;
 
         if ($total) { // 有数据才记录
-            $obj          = new UserDailyDataFlow();
+            $obj = new UserDailyDataFlow();
             $obj->user_id = $user_id;
             $obj->node_id = $node_id;
-            $obj->u       = $u;
-            $obj->d       = $d;
-            $obj->total   = $total;
+            $obj->u = $u;
+            $obj->d = $d;
+            $obj->total = $total;
             $obj->traffic = flowAutoShow($total);
             $obj->save();
         }
     }
-
 }

+ 9 - 16
app/Console/Commands/AutoStatisticsUserHourlyTraffic.php

@@ -11,7 +11,6 @@ use Log;
 
 class AutoStatisticsUserHourlyTraffic extends Command
 {
-
     protected $signature = 'autoStatisticsUserHourlyTraffic';
     protected $description = '自动统计用户每小时流量';
 
@@ -29,39 +28,33 @@ class AutoStatisticsUserHourlyTraffic extends Command
             }
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     private function statisticsByNode($user_id, $node_id = 0): void
     {
-        $query = UserDataFlowLog::whereUserId($user_id)->whereBetween(
-            'log_time',
-            [strtotime("-1 hour"), time()]
-        );
+        $query = UserDataFlowLog::whereUserId($user_id)->whereBetween('log_time', [strtotime("-1 hour"), time()]);
 
         if ($node_id) {
             $query->whereNodeId($node_id);
         }
 
-        $u     = $query->sum('u');
-        $d     = $query->sum('d');
+        $u = $query->sum('u');
+        $d = $query->sum('d');
         $total = $u + $d;
 
         if ($total) { // 有数据才记录
-            $obj          = new UserHourlyDataFlow();
+            $obj = new UserHourlyDataFlow();
             $obj->user_id = $user_id;
             $obj->node_id = $node_id;
-            $obj->u       = $u;
-            $obj->d       = $d;
-            $obj->total   = $total;
+            $obj->u = $u;
+            $obj->d = $d;
+            $obj->total = $total;
             $obj->traffic = flowAutoShow($total);
             $obj->save();
         }
     }
-
 }

+ 40 - 88
app/Console/Commands/DailyJob.php

@@ -15,7 +15,6 @@ use Log;
 
 class DailyJob extends Command
 {
-
     protected $signature = 'dailyJob';
     protected $description = '每日任务';
 
@@ -34,72 +33,50 @@ class DailyJob extends Command
             $this->resetUserTraffic();
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     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'))->get();
         $isBanStatus = sysConfig('is_ban_status');
         foreach ($userList as $user) {
             if ($isBanStatus) {
-                $user->update(
-                    [
-                        'u'               => 0,
-                        'd'               => 0,
-                        'transfer_enable' => 0,
-                        'enable'          => 0,
-                        'reset_time'      => null,
-                        'ban_time'        => null,
-                        'status'          => -1,
-                    ]
-                );
+                $user->update([
+                    'u'               => 0,
+                    'd'               => 0,
+                    'transfer_enable' => 0,
+                    'enable'          => 0,
+                    'reset_time'      => null,
+                    'ban_time'        => null,
+                    'status'          => -1,
+                ]);
 
                 $this->addUserBanLog($user->id, 0, '【禁止登录,清空账户】-账号已过期');
 
                 // 废除其名下邀请码
-                Invite::whereInviterId($user->id)->whereStatus(0)->update(
-                    ['status' => 2]
-                );
+                Invite::whereInviterId($user->id)->whereStatus(0)->update(['status' => 2]);
 
                 // 写入用户流量变动记录
-                Helpers::addUserTrafficModifyLog(
-                    $user->id,
-                    0,
-                    $user->transfer_enable,
-                    0,
-                    '[定时任务]账号已过期(禁止登录,清空账户)'
-                );
+                Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(禁止登录,清空账户)');
             } else {
-                $user->update(
-                    [
-                        'u'               => 0,
-                        'd'               => 0,
-                        'transfer_enable' => 0,
-                        'enable'          => 0,
-                        'reset_time'      => null,
-                        'ban_time'        => null,
-                    ]
-                );
+                $user->update([
+                    'u'               => 0,
+                    'd'               => 0,
+                    'transfer_enable' => 0,
+                    'enable'          => 0,
+                    'reset_time'      => null,
+                    'ban_time'        => null,
+                ]);
 
                 $this->addUserBanLog($user->id, 0, '【封禁代理,清空账户】-账号已过期');
 
                 // 写入用户流量变动记录
-                Helpers::addUserTrafficModifyLog(
-                    $user->id,
-                    0,
-                    $user->transfer_enable,
-                    0,
-                    '[定时任务]账号已过期(封禁代理,清空账户)'
-                );
+                Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(封禁代理,清空账户)');
             }
         }
     }
@@ -110,17 +87,13 @@ class DailyJob extends Command
      * @param  int  $userId  用户ID
      * @param  int  $time  封禁时长,单位分钟
      * @param  string  $description  封禁理由
-     *
      * @return bool
      */
-    private function addUserBanLog(
-        int $userId,
-        int $time,
-        string $description
-    ): bool {
-        $log              = new UserBanedLog();
-        $log->user_id     = $userId;
-        $log->time        = $time;
+    private function addUserBanLog(int $userId, int $time, string $description): bool
+    {
+        $log = new UserBanedLog();
+        $log->user_id = $userId;
+        $log->time = $time;
         $log->description = $description;
 
         return $log->save();
@@ -129,18 +102,11 @@ class DailyJob extends Command
     // 关闭超过72小时未处理的工单
     private function closeTickets(): void
     {
-        $ticketList = Ticket::where(
-            'updated_at',
-            '<=',
-            date('Y-m-d', strtotime("-3 days"))
-        )->whereStatus(1)->get();
+        $ticketList = Ticket::where('updated_at', '<=', date('Y-m-d', strtotime("-3 days")))->whereStatus(1)->get();
         foreach ($ticketList as $ticket) {
             $ret = Ticket::whereId($ticket->id)->update(['status' => 2]);
             if ($ret) {
-                PushNotification::send(
-                    '工单关闭提醒',
-                    '工单:ID' . $ticket->id . '超过72小时未处理,系统已自动关闭'
-                );
+                PushNotification::send('工单关闭提醒', '工单:ID'.$ticket->id.'超过72小时未处理,系统已自动关闭');
             }
         }
     }
@@ -149,12 +115,12 @@ 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'))
-                        ->get();
+            ->where('expired_at', '>', date('Y-m-d'))
+            ->where('reset_time', '<=', date('Y-m-d'))
+            ->get();
         foreach ($userList as $user) {
             // 跳过 没有重置日期的账号
-            if ( ! $user->reset_time) {
+            if (!$user->reset_time) {
                 continue;
             }
 
@@ -162,7 +128,7 @@ class DailyJob extends Command
             $order = Order::userActivePlan($user->id)->first();
 
             // 无订单用户跳过
-            if ( ! $order) {
+            if (!$order) {
                 continue;
             }
 
@@ -171,29 +137,15 @@ class DailyJob extends Command
 
             $oldData = $user->transfer_enable;
             // 重置流量与重置日期 TODO 可用流量变动日志加入至UserObserver
-            $ret = $user->update(
-                (new OrderService($order))->resetTimeAndData($user->expired_at)
-            );
+            $ret = $user->update((new OrderService($order))->resetTimeAndData($user->expired_at));
             if ($ret) {
                 // 可用流量变动日志
-                Helpers::addUserTrafficModifyLog(
-                    $order->user_id,
-                    $order->id,
-                    $oldData,
-                    $user->transfer_enable,
-                    '【流量重置】重置可用流量'
-                );
-                Log::info(
-                    '用户[ID:' . $user->id . '  昵称: ' . $user->username . '  邮箱: ' . $user->email . '] 流量重置为 ' . flowAutoShow(
-                        $user->transfer_enable
-                    ) . '. 重置日期为 ' . ($user->reset_time ?: '【无】')
-                );
+                Helpers::addUserTrafficModifyLog($order->user_id, $order->id, $oldData, $user->transfer_enable,
+                    '【流量重置】重置可用流量');
+                Log::info('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置为 '.flowAutoShow($user->transfer_enable).'. 重置日期为 '.($user->reset_time ?: '【无】'));
             } else {
-                Log::error(
-                    '用户[ID:' . $user->id . '  昵称: ' . $user->username . '  邮箱: ' . $user->email . '] 流量重置失败'
-                );
+                Log::error('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置失败');
             }
         }
     }
-
 }

+ 26 - 58
app/Console/Commands/NodeBlockedDetection.php

@@ -14,7 +14,6 @@ use Mail;
 
 class NodeBlockedDetection extends Command
 {
-
     protected $signature = 'nodeBlockedDetection';
     protected $description = '节点阻断检测';
 
@@ -22,21 +21,16 @@ class NodeBlockedDetection extends Command
     {
         $jobStartTime = microtime(true);
         if (sysConfig('nodes_detection')) {
-            if ( ! Cache::has('LastCheckTime')) {
+            if (!Cache::has('LastCheckTime')) {
                 $this->checkNodes();
             } elseif (Cache::get('LastCheckTime') <= time()) {
                 $this->checkNodes();
             } else {
-                Log::info(
-                    '下次节点阻断检测时间:' . date(
-                        'Y-m-d H:i:s',
-                        Cache::get('LastCheckTime')
-                    )
-                );
+                Log::info('下次节点阻断检测时间:'.date('Y-m-d H:i:s', Cache::get('LastCheckTime')));
             }
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
         Log::info("---【{$this->description}】完成---,耗时 {$jobUsedTime} 秒");
@@ -46,60 +40,45 @@ class NodeBlockedDetection extends Command
     private function checkNodes(): void
     {
         $detectionCheckTimes = sysConfig('detection_check_times');
-        $sendText            = false;
-        $message             = "| 线路 | 协议 | 状态 |\r\n| ------ | ------ | ------ |\r\n";
-        $additionalMessage   = '';
-        foreach (
-            Node::whereIsRelay(0)->whereStatus(1)->where(
-                'detection_type',
-                '>',
-                0
-            )->get() as $node
-        ) {
+        $sendText = false;
+        $message = "| 线路 | 协议 | 状态 |\r\n| ------ | ------ | ------ |\r\n";
+        $additionalMessage = '';
+        foreach (Node::whereIsRelay(0)->whereStatus(1)->where('detection_type', '>', 0)->get() as $node) {
             $info = false;
-            if ($node->detection_type == 0) {
+            if ($node->detection_type === 0) {
                 continue;
             }
             // 使用DDNS的node先通过gethostbyname获取ipv4地址
             if ($node->is_ddns) {
                 $ip = gethostbyname($node->server);
-                if (strcmp($ip, $node->server) != 0) {
+                if (strcmp($ip, $node->server) !== 0) {
                     $node->ip = $ip;
                 } else {
-                    Log::warning(
-                        "【节点阻断检测】检测" . $node->server . "时,IP获取失败" . $ip . " | " . $node->server
-                    );
-                    $this->notifyMaster(
-                        "{$node->name}动态IP获取失败",
-                        "节点 {$node->name} : IP获取失败 "
-                    );
+                    Log::warning("【节点阻断检测】检测".$node->server."时,IP获取失败".$ip." | ".$node->server);
+                    $this->notifyMaster("{$node->name}动态IP获取失败", "节点 {$node->name} : IP获取失败 ");
                 }
             }
-            if ($node->detection_type != 1) {
+            if ($node->detection_type !== 1) {
                 $icmpCheck = NetworkDetection::networkCheck($node->ip, true);
-                if ($icmpCheck != false && $icmpCheck !== "通讯正常") {
-                    $message  .= "| " . $node->name . " | ICMP | " . $icmpCheck . " |\r\n";
+                if ($icmpCheck !== false && $icmpCheck !== "通讯正常") {
+                    $message .= "| ".$node->name." | ICMP | ".$icmpCheck." |\r\n";
                     $sendText = true;
-                    $info     = true;
+                    $info = true;
                 }
             }
-            if ($node->detection_type != 2) {
-                $tcpCheck = NetworkDetection::networkCheck(
-                    $node->ip,
-                    false,
-                    $node->single ? $node->port : null
-                );
-                if ($tcpCheck != false && $tcpCheck !== "通讯正常") {
-                    $message  .= "| " . $node->name . " | TCP | " . $tcpCheck . " |\r\n";
+            if ($node->detection_type !== 2) {
+                $tcpCheck = NetworkDetection::networkCheck($node->ip, false, $node->single ? $node->port : null);
+                if ($tcpCheck !== false && $tcpCheck !== "通讯正常") {
+                    $message .= "| ".$node->name." | TCP | ".$tcpCheck." |\r\n";
                     $sendText = true;
-                    $info     = true;
+                    $info = true;
                 }
             }
 
             // 节点检测次数
             if ($info && $detectionCheckTimes) {
                 // 已通知次数
-                $cacheKey = 'detection_check_times' . $node->id;
+                $cacheKey = 'detection_check_times'.$node->id;
                 if (Cache::has($cacheKey)) {
                     $times = Cache::get($cacheKey);
                 } else {
@@ -120,11 +99,8 @@ class NodeBlockedDetection extends Command
 
         //只有在出现阻断线路时,才会发出警报
         if ($sendText) {
-            $this->notifyMaster(
-                "节点阻断警告",
-                "阻断日志: \r\n\r\n" . $message . $additionalMessage
-            );
-            Log::info("阻断日志: \r\n" . $message . $additionalMessage);
+            $this->notifyMaster("节点阻断警告", "阻断日志: \r\n\r\n".$message.$additionalMessage);
+            Log::info("阻断日志: \r\n".$message.$additionalMessage);
         }
 
         // 随机生成下次检测时间
@@ -141,17 +117,9 @@ class NodeBlockedDetection extends Command
     private function notifyMaster(string $title, string $content): void
     {
         $result = PushNotification::send($title, $content);
-        if ( ! $result && sysConfig('webmaster_email')) {
-            $logId = Helpers::addNotificationLog(
-                $title,
-                $content,
-                1,
-                sysConfig('webmaster_email')
-            );
-            Mail::to(sysConfig('webmaster_email'))->send(
-                new nodeCrashWarning($logId)
-            );
+        if (!$result && sysConfig('webmaster_email')) {
+            $logId = Helpers::addNotificationLog($title, $content, 1, sysConfig('webmaster_email'));
+            Mail::to(sysConfig('webmaster_email'))->send(new nodeCrashWarning($logId));
         }
     }
-
 }

+ 12 - 29
app/Console/Commands/ServiceTimer.php

@@ -9,7 +9,6 @@ use Log;
 
 class ServiceTimer extends Command
 {
-
     protected $signature = 'serviceTimer';
     protected $description = '服务计时器';
 
@@ -20,47 +19,31 @@ class ServiceTimer extends Command
         // 扣减用户到期商品的流量
         $this->decGoodsTraffic();
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     // 扣减用户到期商品的流量
     private function decGoodsTraffic(): void
     {
         //获取失效的套餐
-        foreach (
-            Order::activePlan()->where(
-                'expired_at',
-                '<=',
-                date('Y-m-d H:i:s')
-            )->with('user')->get() as $order
-        ) {
+        foreach (Order::activePlan()->where('expired_at', '<=', date('Y-m-d H:i:s'))->with('user')->get() as $order) {
             // 清理全部流量,重置重置日期和等级 TODO 可用流量变动日志加入至UserObserver
             $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,
-                '[定时任务]用户所购商品到期,扣减商品对应的流量'
-            );
+            $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]);
         }
     }
-
 }

+ 10 - 28
app/Console/Commands/UserExpireAutoWarning.php

@@ -12,7 +12,6 @@ use Mail;
 
 class UserExpireAutoWarning extends Command
 {
-
     protected $signature = 'userExpireAutoWarning';
     protected $description = '用户临近到期自动发邮件提醒';
 
@@ -25,12 +24,10 @@ class UserExpireAutoWarning extends Command
             $this->userExpireWarning();
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     private function userExpireWarning(): void
@@ -45,34 +42,19 @@ class UserExpireAutoWarning extends Command
 
             // 计算剩余可用时间
             $lastCanUseDays = Helpers::daysToNow($user->expired_at);
-            if ($lastCanUseDays == 0) {
-                $title   = '账号过期提醒';
+            if ($lastCanUseDays === 0) {
+                $title = '账号过期提醒';
                 $content = '您的账号将于今天晚上【24:00】过期。';
 
-                $logId = Helpers::addNotificationLog(
-                    $title,
-                    $content,
-                    1,
-                    $user->email
-                );
-                Mail::to($user->email)->send(
-                    new userExpireWarningToday($logId)
-                );
+                $logId = Helpers::addNotificationLog($title, $content, 1, $user->email);
+                Mail::to($user->email)->send(new userExpireWarningToday($logId));
             } elseif ($lastCanUseDays > 0 && $lastCanUseDays <= $expireDays) {
-                $title   = '账号过期提醒';
-                $content = '您的账号还剩' . $lastCanUseDays . '天即将过期。';
+                $title = '账号过期提醒';
+                $content = '您的账号还剩'.$lastCanUseDays.'天即将过期。';
 
-                $logId = Helpers::addNotificationLog(
-                    $title,
-                    $content,
-                    1,
-                    $user->email
-                );
-                Mail::to($user->email)->send(
-                    new userExpireWarning($logId, $lastCanUseDays)
-                );
+                $logId = Helpers::addNotificationLog($title, $content, 1, $user->email);
+                Mail::to($user->email)->send(new userExpireWarning($logId, $lastCanUseDays));
             }
         }
     }
-
 }

+ 13 - 35
app/Console/Commands/UserTrafficAbnormalAutoWarning.php

@@ -9,7 +9,6 @@ use Log;
 
 class UserTrafficAbnormalAutoWarning extends Command
 {
-
     protected $signature = 'userTrafficAbnormalAutoWarning';
     protected $description = '用户流量异常警告';
 
@@ -20,12 +19,10 @@ class UserTrafficAbnormalAutoWarning extends Command
         // 用户流量异常警告
         $this->userTrafficAbnormalWarning();
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     // 用户流量异常警告
@@ -33,43 +30,24 @@ class UserTrafficAbnormalAutoWarning extends Command
     {
         // 1小时内流量异常用户(多往前取5分钟,防止数据统计任务执行时间过长导致没有数据)
         $userTotalTrafficLogs = UserHourlyDataFlow::whereNodeId(0)
-                                                  ->where('total', '>', MB * 50)
-                                                  ->where(
-                                                      'created_at',
-                                                      '>=',
-                                                      date(
-                                                          'Y-m-d H:i:s',
-                                                          time() - 3900
-                                                      )
-                                                  )
-                                                  ->groupBy('user_id')
-                                                  ->selectRaw(
-                                                      "user_id, sum(total) as totalTraffic"
-                                                  )
-                                                  ->get(
-                                                  ); // 只统计100M以上的记录,加快查询速度
-        $trafficBanValue      = sysConfig('traffic_ban_value');
+            ->where('total', '>', MB * 50)
+            ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
+            ->groupBy('user_id')
+            ->selectRaw("user_id, sum(total) as totalTraffic")
+            ->get(); // 只统计100M以上的记录,加快查询速度
+        $trafficBanValue = sysConfig('traffic_ban_value');
 
         foreach ($userTotalTrafficLogs->load('user') as $log) {
             // 推送通知管理员
             if ($log->totalTraffic > $trafficBanValue * GB) {
-                $user    = $log->user;
+                $user = $log->user;
                 $traffic = UserHourlyDataFlow::userRecentUsed($user->id)
-                                             ->selectRaw(
-                                                 "user_id, sum(`u`) as totalU, sum(`d`) as totalD, sum(total) as totalTraffic"
-                                             )
-                                             ->first();
+                    ->selectRaw("user_id, sum(`u`) as totalU, sum(`d`) as totalD, sum(total) as totalTraffic")
+                    ->first();
 
-                PushNotification::send(
-                    "流量异常用户提醒",
-                    "用户**{$user->email}(ID:{$user->id})**,最近1小时**上行流量:" . flowAutoShow(
-                        $traffic->totalU
-                    ) . ",下行流量:" . flowAutoShow(
-                        $traffic->totalD
-                    ) . ",共计:" . flowAutoShow($traffic->totalTraffic) . "**。"
-                );
+                PushNotification::send("流量异常用户提醒",
+                    "用户**{$user->email}(ID:{$user->id})**,最近1小时**上行流量:".flowAutoShow($traffic->totalU).",下行流量:".flowAutoShow($traffic->totalD).",共计:".flowAutoShow($traffic->totalTraffic)."**。");
             }
         }
     }
-
 }

+ 6 - 22
app/Console/Commands/UserTrafficAutoWarning.php

@@ -11,7 +11,6 @@ use Mail;
 
 class UserTrafficAutoWarning extends Command
 {
-
     protected $signature = 'userTrafficAutoWarning';
     protected $description = '用户流量超过警告阈值自动发邮件提醒';
 
@@ -24,42 +23,27 @@ class UserTrafficAutoWarning extends Command
             $this->userTrafficWarning();
         }
 
-        $jobEndTime  = microtime(true);
+        $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
 
-        Log::info(
-            '---【' . $this->description . '】完成---,耗时' . $jobUsedTime . '秒'
-        );
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
     // 用户流量超过警告阈值自动发邮件提醒
     private function userTrafficWarning(): void
     {
         $trafficWarningPercent = sysConfig('traffic_warning_percent');
-        foreach (
-            User::activeUser()->where('transfer_enable', '>', 0)->get() as $user
-        ) {
+        foreach (User::activeUser()->where('transfer_enable', '>', 0)->get() as $user) {
             // 用户名不是邮箱的跳过
             if (false === filter_var($user->email, FILTER_VALIDATE_EMAIL)) {
                 continue;
             }
 
-            $usedPercent = round(
-                               ($user->d + $user->u) / $user->transfer_enable,
-                               2
-                           ) * 100; // 已使用流量百分比
+            $usedPercent = round(($user->d + $user->u) / $user->transfer_enable, 2) * 100; // 已使用流量百分比
             if ($usedPercent >= $trafficWarningPercent) {
-                $logId = Helpers::addNotificationLog(
-                    "流量提醒",
-                    '流量已使用:' . $usedPercent . '%,请保持关注。',
-                    1,
-                    $user->email
-                );
-                Mail::to($user->email)->send(
-                    new userTrafficWarning($logId, $usedPercent)
-                );
+                $logId = Helpers::addNotificationLog("流量提醒", '流量已使用:'.$usedPercent.'%,请保持关注。', 1, $user->email);
+                Mail::to($user->email)->send(new userTrafficWarning($logId, $usedPercent));
             }
         }
     }
-
 }

+ 39 - 90
app/Console/Commands/fixDailyTrafficLogError.php

@@ -10,7 +10,6 @@ use Log;
 
 class fixDailyTrafficLogError extends Command
 {
-
     protected $signature = 'fixDailyTrafficLogError';
     protected $description = '修复原版本的每日流量计算错误';
 
@@ -22,81 +21,45 @@ class fixDailyTrafficLogError extends Command
         $this->end = date('Y-m-d 23:59:59', strtotime("-1 days"));
         $nodeArray = UserDataFlowLog::distinct()->pluck('node_id')->toArray();
 
-        Log::info(
-            '----------------------------【修复原版本的每日流量计算错误】开始----------------------------'
-        );
-        Log::info(
-            '----------------------------【节点流量日志修正】开始----------------------------'
-        );
+        Log::info('----------------------------【修复原版本的每日流量计算错误】开始----------------------------');
+        Log::info('----------------------------【节点流量日志修正】开始----------------------------');
         foreach (NodeDailyDataFlow::all() as $log) {
-            NodeDailyDataFlow::whereId($log->id)->update(
-                [
-                    'created_at' => date(
-                        'Y-m-d H:i:s',
-                        strtotime("$log->created_at -1 days")
-                    ),
-                ]
-            );
+            NodeDailyDataFlow::whereId($log->id)->update([
+                'created_at' => date('Y-m-d H:i:s', strtotime("$log->created_at -1 days")),
+            ]);
         }
 
-        Log::info(
-            '----------------------------【添加节点流量日志】开始----------------------------'
-        );
+        Log::info('----------------------------【添加节点流量日志】开始----------------------------');
         foreach ($nodeArray as $nodeId) {
             $query = UserDataFlowLog::whereNodeId($nodeId)
-                                    ->whereBetween(
-                                        'log_time',
-                                        [
-                                            strtotime(
-                                                date(
-                                                    'Y-m-d',
-                                                    strtotime("-1 days")
-                                                )
-                                            ),
-                                            strtotime($this->end),
-                                        ]
-                                    );
+                ->whereBetween('log_time',
+                    [strtotime(date('Y-m-d', strtotime("-1 days"))), strtotime($this->end)]);
 
-            $u     = $query->sum('u');
-            $d     = $query->sum('d');
+            $u = $query->sum('u');
+            $d = $query->sum('d');
             $total = $u + $d;
 
             if ($total) { // 有数据才记录
-                $obj             = new NodeDailyDataFlow();
-                $obj->node_id    = $nodeId;
-                $obj->u          = $u;
-                $obj->d          = $d;
-                $obj->total      = $total;
-                $obj->traffic    = flowAutoShow($total);
+                $obj = new NodeDailyDataFlow();
+                $obj->node_id = $nodeId;
+                $obj->u = $u;
+                $obj->d = $d;
+                $obj->total = $total;
+                $obj->traffic = flowAutoShow($total);
                 $obj->created_at = $this->end;
                 $obj->save();
             }
         }
-        Log::info(
-            '----------------------------【添加节点流量日志】结束----------------------------'
-        );
-        Log::info(
-            '----------------------------【节点流量日志修正】结束----------------------------'
-        );
-        Log::info(
-            '----------------------------【用户流量日志修正】开始----------------------------'
-        );
+        Log::info('----------------------------【添加节点流量日志】结束----------------------------');
+        Log::info('----------------------------【节点流量日志修正】结束----------------------------');
+        Log::info('----------------------------【用户流量日志修正】开始----------------------------');
         foreach (UserDailyDataFlow::all() as $log) {
-            UserDailyDataFlow::whereId($log->id)->update(
-                [
-                    'created_at' => date(
-                        'Y-m-d H:i:s',
-                        strtotime("$log->created_at -1 days")
-                    ),
-                ]
-            );
+            UserDailyDataFlow::whereId($log->id)->update([
+                'created_at' => date('Y-m-d H:i:s', strtotime("$log->created_at -1 days")),
+            ]);
         }
-        Log::info(
-            '----------------------------【用户个人流量日志修正】开始----------------------------'
-        );
-        foreach (
-            UserDataFlowLog::distinct()->pluck('user_id')->toArray() as $userId
-        ) {
+        Log::info('----------------------------【用户个人流量日志修正】开始----------------------------');
+        foreach (UserDataFlowLog::distinct()->pluck('user_id')->toArray() as $userId) {
             // 统计一次所有节点的总和
             $this->statisticsByUser($userId);
             // 统计每个节点产生的流量
@@ -104,49 +67,35 @@ class fixDailyTrafficLogError extends Command
                 $this->statisticsByUser($userId, $nodeId);
             }
         }
-        Log::info(
-            '----------------------------【用户个人流量日志修正】结束----------------------------'
-        );
-        Log::info(
-            '----------------------------【用户流量日志修正】结束----------------------------'
-        );
-        Log::info(
-            '----------------------------【修复原版本的每日流量计算错误】结束----------------------------'
-        );
+        Log::info('----------------------------【用户个人流量日志修正】结束----------------------------');
+        Log::info('----------------------------【用户流量日志修正】结束----------------------------');
+        Log::info('----------------------------【修复原版本的每日流量计算错误】结束----------------------------');
     }
 
     private function statisticsByUser($user_id, $node_id = 0): void
     {
         $query = UserDataFlowLog::whereUserId($user_id)
-                                ->whereBetween(
-                                    'log_time',
-                                    [
-                                        strtotime(
-                                            date('Y-m-d', strtotime("-1 days"))
-                                        ),
-                                        strtotime($this->end),
-                                    ]
-                                );
+            ->whereBetween('log_time',
+                [strtotime(date('Y-m-d', strtotime("-1 days"))), strtotime($this->end)]);
 
         if ($node_id) {
             $query->whereNodeId($node_id);
         }
 
-        $u     = $query->sum('u');
-        $d     = $query->sum('d');
+        $u = $query->sum('u');
+        $d = $query->sum('d');
         $total = $u + $d;
 
         if ($total) { // 有数据才记录
-            $obj             = new UserDailyDataFlow();
-            $obj->user_id    = $user_id;
-            $obj->node_id    = $node_id;
-            $obj->u          = $u;
-            $obj->d          = $d;
-            $obj->total      = $total;
-            $obj->traffic    = flowAutoShow($total);
+            $obj = new UserDailyDataFlow();
+            $obj->user_id = $user_id;
+            $obj->node_id = $node_id;
+            $obj->u = $u;
+            $obj->d = $d;
+            $obj->total = $total;
+            $obj->traffic = flowAutoShow($total);
             $obj->created_at = $this->end;
             $obj->save();
         }
     }
-
-}
+}

+ 2 - 8
app/Console/Commands/updateCoupon.php

@@ -8,15 +8,12 @@ use Log;
 
 class updateCoupon extends Command
 {
-
     protected $signature = 'updateCoupon';
     protected $description = '修改原版Coupon至新版';
 
     public function handle(): void
     {
-        Log::info(
-            '----------------------------【优惠券转换】开始----------------------------'
-        );
+        Log::info('----------------------------【优惠券转换】开始----------------------------');
         $coupons = Coupon::withTrashed()->get();
         foreach ($coupons as $coupon) {
             if ($coupon->amount) {
@@ -32,9 +29,6 @@ class updateCoupon extends Command
             }
             $coupon->save();
         }
-        Log::info(
-            '----------------------------【优惠券转换】结束----------------------------'
-        );
+        Log::info('----------------------------【优惠券转换】结束----------------------------');
     }
-
 }

+ 6 - 20
app/Console/Commands/updateTextToJson.php

@@ -10,47 +10,33 @@ use Log;
 
 class updateTextToJson extends Command
 {
-
     protected $signature = 'updateTextToJson';
     protected $description = '转换原有数列至新数列';
 
     public function handle(): void
     {
-        Log::info(
-            '----------------------------【数据转换】开始----------------------------'
-        );
+        Log::info('----------------------------【数据转换】开始----------------------------');
         foreach (ReferralApply::all() as $referralApply) {
-            $referralApply->link_logs = $this->convertToJson(
-                $referralApply->getRawOriginal('link_logs')
-            );
+            $referralApply->link_logs = $this->convertToJson($referralApply->getRawOriginal('link_logs'));
             $referralApply->save();
         }
         Log::info('转换返利表完成');
         foreach (UserGroup::all() as $userGroup) {
-            $userGroup->nodes = $this->convertToJson(
-                $userGroup->getRawOriginal('nodes')
-            );
+            $userGroup->nodes = $this->convertToJson($userGroup->getRawOriginal('nodes'));
             $userGroup->save();
         }
         Log::info('转换用户分组表完成');
         foreach (RuleGroup::all() as $ruleGroup) {
-            $ruleGroup->rules = $this->convertToJson(
-                $ruleGroup->getRawOriginal('rules')
-            );
-            $ruleGroup->nodes = $this->convertToJson(
-                $ruleGroup->getRawOriginal('nodes')
-            );
+            $ruleGroup->rules = $this->convertToJson($ruleGroup->getRawOriginal('rules'));
+            $ruleGroup->nodes = $this->convertToJson($ruleGroup->getRawOriginal('nodes'));
             $ruleGroup->save();
         }
         Log::info('转换审核规则表完成');
-        Log::info(
-            '----------------------------【数据转换】结束----------------------------'
-        );
+        Log::info('----------------------------【数据转换】结束----------------------------');
     }
 
     private function convertToJson($string): array
     {
         return explode(',', $string);
     }
-
 }

+ 8 - 22
app/Console/Commands/updateTicket.php

@@ -9,40 +9,26 @@ use Log;
 
 class updateTicket extends Command
 {
-
     protected $signature = 'updateTicket';
     protected $description = '更新工单';
 
     public function handle(): void
     {
-        Log::info(
-            '----------------------------【更新工单】开始----------------------------'
-        );
+        Log::info('----------------------------【更新工单】开始----------------------------');
         // 获取管理员
         foreach (User::whereIsAdmin(1)->get() as $admin) {
-            Log::info(
-                '----------------------------【更新管理员' . $admin->id . '回复工单】开始----------------------------'
-            );
+            Log::info('----------------------------【更新管理员'.$admin->id.'回复工单】开始----------------------------');
             // 获取该管理回复过的工单, 更新工单
             foreach (TicketReply::whereUserId($admin->id)->get() as $reply) {
-                $ret = TicketReply::whereId($reply->id)->update(
-                    ['user_id' => 0, 'admin_id' => $admin->id]
-                );
+                $ret = TicketReply::whereId($reply->id)->update(['user_id' => 0, 'admin_id' => $admin->id]);
                 if ($ret) {
-                    Log::info(
-                        '--- 管理员:' . $admin->email . '回复子单ID:' . $reply->id . ' ---'
-                    );
+                    Log::info('--- 管理员:'.$admin->email.'回复子单ID:'.$reply->id.' ---');
                 } else {
-                    Log::error('更新回复子单ID:【' . $reply->id . '】 失败!');
+                    Log::error('更新回复子单ID:【'.$reply->id.'】 失败!');
                 }
             }
-            Log::info(
-                '----------------------------【更新管理员' . $admin->id . '回复工单】完成----------------------------'
-            );
+            Log::info('----------------------------【更新管理员'.$admin->id.'回复工单】完成----------------------------');
         }
-        Log::info(
-            '----------------------------【更新工单】结束----------------------------'
-        );
+        Log::info('----------------------------【更新工单】结束----------------------------');
     }
-
-}
+}

+ 7 - 21
app/Console/Commands/updateUserLevel.php

@@ -10,42 +10,28 @@ use Log;
 
 class updateUserLevel extends Command
 {
-
     protected $signature = 'updateUserLevel';
     protected $description = '更新用户等级';
 
     public function handle(): void
     {
-        Log::info(
-            '----------------------------【用户等级升级】开始----------------------------'
-        );
+        Log::info('----------------------------【用户等级升级】开始----------------------------');
         // 预设level 0
         User::where('level', '<>', 0)->update(['level' => 0]);
 
         // 获取商品列表,取新等级
-        $goodsLevel = Goods::type(2)
-                           ->where('level', '<>', 0)
-                           ->pluck('id')
-                           ->toArray();
+        $goodsLevel = Goods::type(2)->where('level', '<>', 0)->pluck('id')->toArray();
         // 取生效的套餐
-        $orderList = Order::active()->with('goods')->whereIn(
-            'goods_id',
-            $goodsLevel
-        )->get();
+        $orderList = Order::active()->with('goods')->whereIn('goods_id', $goodsLevel)->get();
         foreach ($orderList as $order) {
             $ret = $order->user->update(['level' => $order->goods->level]);
 
             if ($ret) {
-                Log::info(
-                    '用户: ' . $order->user_id . ', 按照订单' . $order->id . ' 等级为' . $order->goods->level
-                );
+                Log::info('用户: '.$order->user_id.', 按照订单'.$order->id.' 等级为'.$order->goods->level);
             } else {
-                Log::error('用户: ' . $order->user_id . ' 等级更新失败!');
+                Log::error('用户: '.$order->user_id.' 等级更新失败!');
             }
         }
-        Log::info(
-            '----------------------------【用户等级升级】结束----------------------------'
-        );
+        Log::info('----------------------------【用户等级升级】结束----------------------------');
     }
-
-}
+}

+ 7 - 17
app/Console/Commands/updateUserName.php

@@ -9,43 +9,33 @@ use Log;
 
 class updateUserName extends Command
 {
-
     protected $signature = 'updateUserName';
     protected $description = '升级用户昵称';
 
     public function handle(): void
     {
-        Log::info(
-            '----------------------------【升级用户昵称】开始----------------------------'
-        );
+        Log::info('----------------------------【升级用户昵称】开始----------------------------');
 
         $userList = User::all();
         foreach ($userList as $user) {
             $name = process($user->id);
             $user->update(['username' => $name]);
 
-            Log::info(
-                '---用户[ID:' . $user->id . ' - ' . $user->email . '] :' . $user->username . '---'
-            );
+            Log::info('---用户[ID:'.$user->id.' - '.$user->email.'] :'.$user->username.'---');
         }
 
         foreach ($userList as $user) {
-            if ($user->email == $user->username) {
+            if ($user->email === $user->username) {
                 $name = process($user->id);
 
                 $user->update(['username' => $name]);
 
-                Log::info(
-                    '---用户[ID:' . $user->id . ' - ' . $user->email . '] :' . $user->username . '---'
-                );
+                Log::info('---用户[ID:'.$user->id.' - '.$user->email.'] :'.$user->username.'---');
             }
         }
 
-        Log::info(
-            '----------------------------【升级用户昵称】结束----------------------------'
-        );
+        Log::info('----------------------------【升级用户昵称】结束----------------------------');
     }
-
 }
 
 function process($id)
@@ -67,11 +57,11 @@ function process($id)
             if (is_numeric($temp[1])) {
                 $name = QQInfo::getName3($temp[1]);
             } else {
-                echo $user->email . PHP_EOL;
+                echo $user->email.PHP_EOL;
             }
         }
     }
-    if ($name == false) {
+    if ($name === false) {
         $name = $user->email;
     }
 

+ 14 - 30
app/Console/Commands/upgradeUserResetTime.php

@@ -8,51 +8,39 @@ use Log;
 
 class upgradeUserResetTime extends Command
 {
-
     protected $signature = 'upgradeUserResetTime';
     protected $description = '升级用户重置日期';
 
     public function handle(): void
     {
-        Log::info(
-            '----------------------------【升级用户重置日期】开始----------------------------'
-        );
+        Log::info('----------------------------【升级用户重置日期】开始----------------------------');
 
         foreach (User::all() as $user) {
             $reset_time = null;
             if ($user->traffic_reset_day) {
-                $today         = date('d');// 今天 日期
-                $last_day      = date('t'); //本月最后一天
+                $today = date('d');// 今天 日期
+                $last_day = date('t'); //本月最后一天
                 $next_last_day = date('t', strtotime("+1 month"));//下个月最后一天
-                $resetDay      = $user->traffic_reset_day;// 用户原本的重置日期
+                $resetDay = $user->traffic_reset_day;// 用户原本的重置日期
                 // 案例:31 29,重置日 大于 本月最后一天
                 if ($resetDay > $last_day) {
                     //往后推一个月
-                    $resetDay   -= $last_day;
-                    $reset_time = date(
-                        'Y-m-' . $resetDay,
-                        strtotime("+1 month")
-                    );
+                    $resetDay -= $last_day;
+                    $reset_time = date('Y-m-'.$resetDay, strtotime("+1 month"));
                     //案例:20<30<31
                 } elseif ($resetDay < $last_day && $resetDay > $today) {
-                    $reset_time = date('Y-m-' . $resetDay);
+                    $reset_time = date('Y-m-'.$resetDay);
                     // 本日为重置日
-                } elseif ($resetDay == $today) {
+                } elseif ($resetDay === $today) {
                     $reset_time = date('Y-m-d', strtotime("+1 month"));
                     //本月已经重置过了
                 } elseif ($resetDay < $today) {
                     //类似第一种情况,向后推一月
                     if ($resetDay > $next_last_day) {
-                        $resetDay   -= $next_last_day;
-                        $reset_time = date(
-                            'Y-m-' . $resetDay,
-                            strtotime("+1 month")
-                        );
+                        $resetDay -= $next_last_day;
+                        $reset_time = date('Y-m-'.$resetDay, strtotime("+1 month"));
                     } else {
-                        $reset_time = date(
-                            'Y-m-' . $resetDay,
-                            strtotime("+1 month")
-                        );
+                        $reset_time = date('Y-m-'.$resetDay, strtotime("+1 month"));
                     }
                 }
                 // 用户账号有效期大于重置日期
@@ -62,14 +50,10 @@ class upgradeUserResetTime extends Command
                 $user->update(['reset_time' => $reset_time]);
             }
 
-            Log::info(
-                '---用户[ID:' . $user->id . ' - ' . $user->username . ' (' . $user->email . ')]的新重置日期为' . ($reset_time != null ? '【' . $reset_time . '】' : '【无】') . '---'
-            );
+            Log::info('---用户[ID:'.$user->id.' - '.$user->username.' ('.$user->email.')]的新重置日期为'.($reset_time !== null ? '【'.$reset_time.'】' :
+                    '【无】').'---');
         }
 
-        Log::info(
-            '----------------------------【升级用户重置日期】结束----------------------------'
-        );
+        Log::info('----------------------------【升级用户重置日期】结束----------------------------');
     }
-
 }

+ 1 - 2
app/Console/Kernel.php

@@ -88,9 +88,8 @@ class Kernel extends ConsoleKernel
      */
     protected function commands()
     {
-        $this->load(__DIR__ . '/Commands');
+        $this->load(__DIR__.'/Commands');
 
         require base_path('routes/console.php');
     }
-
 }

+ 31 - 88
app/Exceptions/Handler.php

@@ -4,8 +4,10 @@ namespace App\Exceptions;
 
 use App\Components\IP;
 use ErrorException;
+use Exception;
 use Illuminate\Auth\AuthenticationException;
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use Illuminate\Http\Request;
 use Illuminate\Session\TokenMismatchException;
 use Log;
 use ReflectionException;
@@ -36,20 +38,20 @@ class Handler extends ExceptionHandler
     /**
      * Report or log an exception.
      *
-     * @param  \Throwable  $exception
+     * @param  Throwable  $exception
      *
      * @return void
      *
-     * @throws \Exception|\Throwable
+     * @throws Exception|Throwable
      */
     public function report(Throwable $exception)
     {
         // 记录异常来源
-        Log::info('异常来源:' . get_class($exception));
+        Log::info('异常来源:'.get_class($exception));
 
         // 调试模式下记录错误详情
-        if (env('APP_DEBUG')) {
-            Log::debug('来自链接:' . url()->full());
+        if (config('app.debug')) {
+            Log::debug('来自链接:'.url()->full());
             Log::debug($exception);
         }
 
@@ -59,135 +61,76 @@ class Handler extends ExceptionHandler
     /**
      * Render an exception into an HTTP response.
      *
-     * @param  \Illuminate\Http\Request  $request
-     * @param  \Throwable  $exception
+     * @param  Request  $request
+     * @param  Throwable  $exception
      *
      * @return \Symfony\Component\HttpFoundation\Response
      *
-     * @throws \Throwable
+     * @throws Throwable
      */
     public function render($request, Throwable $exception)
     {
         // 调试模式下直接返回错误信息
-        if (env('APP_DEBUG')) {
+        if (config('app.debug')) {
             return parent::render($request, $exception);
         }
 
         // 捕获访问异常
         if ($exception instanceof NotFoundHttpException) {
-            Log::info(
-                "异常请求:" . $request->fullUrl() . ",IP:" . IP::getClientIp()
-            );
+            Log::info("异常请求:".$request->fullUrl().",IP:".IP::getClientIp());
 
             if ($request->ajax()) {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => trans('error.MissingPage'),
-                    ]
-                );
+                return Response::json(['status' => 'fail', 'message' => trans('error.MissingPage')]);
             }
 
-            return Response::view(
-                'auth.error',
-                ['message' => trans('error.MissingPage')],
-                404
-            );
+            return Response::view('auth.error', ['message' => trans('error.MissingPage')], 404);
         }
 
         // 捕获身份校验异常
         if ($exception instanceof AuthenticationException) {
             if ($request->ajax()) {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => trans('error.Unauthorized'),
-                    ]
-                );
+                return Response::json(['status' => 'fail', 'message' => trans('error.Unauthorized')]);
             }
 
-            return Response::view(
-                'auth.error',
-                ['message' => trans('error.Unauthorized')],
-                401
-            );
+            return Response::view('auth.error', ['message' => trans('error.Unauthorized')], 401);
         }
 
         // 捕获CSRF异常
         if ($exception instanceof TokenMismatchException) {
             if ($request->ajax()) {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => trans(
-                                         'error.RefreshPage'
-                                     ) . '<a href="/login" target="_blank">' . trans(
-                                         'error.Refresh'
-                                     ) . '</a>',
-                    ]
-                );
+                return Response::json([
+                    'status'  => 'fail',
+                    'message' => trans('error.RefreshPage').'<a href="/login" target="_blank">'.trans('error.Refresh').'</a>',
+                ]);
             }
 
-            return Response::view(
-                'auth.error',
-                [
-                    'message' => trans(
-                                     'error.RefreshPage'
-                                 ) . '<a href="/login" target="_blank">' . trans(
-                                     'error.Refresh'
-                                 ) . '</a>',
-                ],
-                419
-            );
+            return Response::view('auth.error',
+                ['message' => trans('error.RefreshPage').'<a href="/login" target="_blank">'.trans('error.Refresh').'</a>'], 419);
         }
 
         // 捕获反射异常
         if ($exception instanceof ReflectionException) {
             if ($request->ajax()) {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => trans('error.SystemError'),
-                    ]
-                );
+                return Response::json(['status' => 'fail', 'message' => trans('error.SystemError')]);
             }
 
-            return Response::view(
-                'auth.error',
-                ['message' => trans('error.SystemError')],
-                500
-            );
+            return Response::view('auth.error', ['message' => trans('error.SystemError')], 500);
         }
 
         // 捕获系统错误异常
         if ($exception instanceof ErrorException) {
             if ($request->ajax()) {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => trans('error.SystemError') . ', ' . trans(
-                                'error.Visit'
-                            ) . '<a href="/logs" target="_blank">' . trans(
-                                         'error.log'
-                                     ) . '</a>',
-                    ]
-                );
+                return Response::json([
+                    'status'  => 'fail',
+                    'message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="/logs" target="_blank">'.trans('error.log').'</a>',
+                ]);
             }
 
-            return Response::view(
-                'auth.error',
-                [
-                    'message' => trans('error.SystemError') . ', ' . trans(
-                            'error.Visit'
-                        ) . '<a href="/logs" target="_blank">' . trans(
-                                     'error.log'
-                                 ) . '</a>',
-                ],
-                500
-            );
+            return Response::view('auth.error',
+                ['message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="/logs" target="_blank">'.trans('error.log').'</a>'],
+                500);
         }
 
         return parent::render($request, $exception);
     }
-
 }

+ 31 - 58
app/Http/Controllers/Admin/AffiliateController.php

@@ -20,74 +20,56 @@ class AffiliateController extends Controller
 {
 
     // 提现申请列表
-    public function affiliateList(Request $request)
+    public function index(Request $request)
     {
-        $email  = $request->input('email');
+        $email = $request->input('email');
         $status = $request->input('status');
 
         $query = ReferralApply::with('user:id,email');
         if (isset($email)) {
-            $query->whereHas(
-                'user',
-                static function ($q) use ($email) {
-                    $q->where('email', 'like', '%' . $email . '%');
-                }
-            );
+            $query->whereHas('user', static function ($q) use ($email) {
+                $q->where('email', 'like', '%'.$email.'%');
+            });
         }
 
         if ($status) {
             $query->whereStatus($status);
         }
 
-        $view['applyList'] = $query->latest()->paginate(15)->appends(
-            $request->except('page')
-        );
+        $view['applyList'] = $query->latest()->paginate(15)->appends($request->except('page'));
 
-        return view('admin.affiliate.affiliateList', $view);
+        return view('admin.aff.index', $view);
     }
 
     // 提现申请详情
-    public function affiliateDetail(Request $request)
+    public function detail(Request $request, $id)
     {
-        $view['basic']       = ReferralApply::with('user:id,email')->find(
-            $request->input('id')
-        );
+        $view['basic'] = ReferralApply::with('user:id,email')->find($id);
         $view['commissions'] = [];
         if ($view['basic'] && $view['basic']->link_logs) {
-            $view['commissions'] = ReferralLog::with(
-                ['invitee:id,email', 'order.goods:id,name']
-            )
-                                              ->whereIn(
-                                                  'id',
-                                                  $view['basic']->link_logs
-                                              )
-                                              ->paginate(15)
-                                              ->appends(
-                                                  $request->except('page')
-                                              );
+            $view['commissions'] = ReferralLog::with(['invitee:id,email', 'order.goods:id,name'])
+                ->whereIn('id', $view['basic']->link_logs)
+                ->paginate(15)
+                ->appends($request->except('page'));
         }
 
-        return view('admin.affiliate.affiliateDetail', $view);
+        return view('admin.aff.detail', $view);
     }
 
     // 设置提现申请状态
-    public function setAffiliateStatus(Request $request): JsonResponse
+    public function setStatus(Request $request): JsonResponse
     {
-        $id     = $request->input('id');
-        $status = $request->input('status');
+        $id = $request->input('id');
+        $status = (int) $request->input('status');
 
         $ret = ReferralApply::whereId($id)->update(['status' => $status]);
         if ($ret) {
             // 审核申请的时候将关联的
             $referralApply = ReferralApply::findOrFail($id);
-            if ($referralApply && $status == 1) {
-                ReferralLog::whereIn('id', $referralApply->link_logs)->update(
-                    ['status' => 1]
-                );
-            } elseif ($referralApply && $status == 2) {
-                ReferralLog::whereIn('id', $referralApply->link_logs)->update(
-                    ['status' => 2]
-                );
+            if ($referralApply && $status === 1) {
+                ReferralLog::whereIn('id', $referralApply->link_logs)->update(['status' => 1]);
+            } elseif ($referralApply && $status === 2) {
+                ReferralLog::whereIn('id', $referralApply->link_logs)->update(['status' => 2]);
             }
         }
 
@@ -95,32 +77,24 @@ class AffiliateController extends Controller
     }
 
     // 用户返利流水记录
-    public function userRebateList(Request $request)
+    public function rebate(Request $request)
     {
         $invitee_email = $request->input('invitee_email');
         $inviter_email = $request->input('inviter_email');
-        $status        = $request->input('status');
+        $status = $request->input('status');
 
-        $query = ReferralLog::with(['invitee:id,email', 'inviter:id,email'])
-                            ->orderBy('status')
-                            ->latest();
+        $query = ReferralLog::with(['invitee:id,email', 'inviter:id,email'])->orderBy('status')->latest();
 
         if (isset($invitee_email)) {
-            $query->whereHas(
-                'invitee',
-                static function ($q) use ($invitee_email) {
-                    $q->where('email', 'like', '%' . $invitee_email . '%');
-                }
-            );
+            $query->whereHas('invitee', static function ($q) use ($invitee_email) {
+                $q->where('email', 'like', '%'.$invitee_email.'%');
+            });
         }
 
         if (isset($inviter_email)) {
-            $query->whereHas(
-                'inviter',
-                static function ($q) use ($inviter_email) {
-                    $q->where('email', 'like', '%' . $inviter_email . '%');
-                }
-            );
+            $query->whereHas('inviter', static function ($q) use ($inviter_email) {
+                $q->where('email', 'like', '%'.$inviter_email.'%');
+            });
         }
 
         if (isset($status)) {
@@ -129,7 +103,6 @@ class AffiliateController extends Controller
 
         $view['list'] = $query->paginate(15)->appends($request->except('page'));
 
-        return view('admin.affiliate.userRebateList', $view);
+        return view('admin.aff.rebate', $view);
     }
-
 }

+ 113 - 0
app/Http/Controllers/Admin/ArticleController.php

@@ -0,0 +1,113 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Admin\ArticleRequest;
+use App\Models\Article;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Log;
+use Redirect;
+use Response;
+use Session;
+
+class ArticleController extends Controller
+{
+
+    // 文章列表
+    public function index(Request $request)
+    {
+        $view['articles'] = Article::orderByDesc('sort')->paginate(15)->appends($request->except('page'));
+
+        return view('admin.article.index', $view);
+    }
+
+    // 添加文章页面
+    public function create()
+    {
+        return view('admin.article.create');
+    }
+
+    // 添加文章
+    public function store(ArticleRequest $request)
+    {
+        $data = $request->except('_method', '_token');
+        // LOGO
+        if ($request->input('type') != 4 && $request->hasFile('logo')) {
+            $data['logo'] = 'upload/'.$request->file('logo')->store('images');
+            if (!$data['logo']) {
+                Session::flash('errorMsg', 'LOGO不合法');
+
+                return Redirect::back()->withInput();
+            }
+        }
+
+        $id = Article::insertGetId($data);
+        if ($id) {
+            Session::flash('successMsg', '添加成功');
+        } else {
+            Session::flash('errorMsg', '添加失败');
+        }
+
+        return Redirect::to(route('admin.article.edit', $id));
+    }
+
+    // 文章页面
+    public function show($id)
+    {
+        $view['article'] = Article::find($id);
+
+        return view('admin.article.show', $view);
+    }
+
+    // 编辑文章页面
+    public function edit($id)
+    {
+        $view['article'] = Article::find($id);
+
+        return view('admin.article.edit', $view);
+    }
+
+    // 编辑文章
+    public function update(ArticleRequest $request, $id): RedirectResponse
+    {
+        $data = $request->except('_method', '_token');
+        $data['logo'] = $data['logo'] ?? null;
+        // LOGO
+        if ($request->input('type') != 4 && $request->hasFile('logo')) {
+            $data['logo'] = 'upload/'.$request->file('logo')->store('images');
+            if (!$data['logo']) {
+                Session::flash('errorMsg', 'LOGO不合法');
+
+                return Redirect::back()->withInput();
+            }
+        }
+
+        if (Article::find($id)->update($data)) {
+            Session::flash('successMsg', '编辑成功');
+        } else {
+            Session::flash('errorMsg', '编辑失败');
+        }
+
+        return Redirect::to(route('admin.article.edit', $id));
+    }
+
+    // 删除文章
+    public function destroy($id): JsonResponse
+    {
+        try {
+            Article::find($id)->delete();
+        } catch (Exception $e) {
+            Log::error('删除文章失败:'.$e->getMessage());
+
+            return Response::json(
+                ['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]
+            );
+        }
+
+        return Response::json(['status' => 'success', 'message' => '删除成功']);
+    }
+}

+ 88 - 0
app/Http/Controllers/Admin/CertController.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Http\Controllers\Controller;
+use App\Models\NodeCertificate;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class CertController extends Controller
+{
+    // 域名证书列表
+    public function index(Request $request)
+    {
+        $DvList = NodeCertificate::orderBy('id')->paginate(15)->appends($request->except('page'));
+        foreach ($DvList as $Dv) {
+            if ($Dv->pem) {
+                $DvInfo = openssl_x509_parse($Dv->pem);
+                if ($DvInfo) {
+                    $Dv->issuer = $DvInfo['issuer']['O'] ?? null;
+                    $Dv->from = date('Y-m-d', $DvInfo['validFrom_time_t']) ?: null;
+                    $Dv->to = date('Y-m-d', $DvInfo['validTo_time_t']) ?: null;
+                }
+            }
+        }
+        $view['list'] = $DvList;
+
+        return view('admin.node.cert.index', $view);
+    }
+
+    public function create()
+    {
+        return view('admin.node.cert.info');
+    }
+
+    // 添加域名证书
+    public function store(Request $request): JsonResponse
+    {
+        $cert = new NodeCertificate();
+        $cert->domain = $request->input('domain');
+        $cert->key = str_replace(["\r", "\n"], '', $request->input('key'));
+        $cert->pem = str_replace(["\r", "\n"], '', $request->input('pem'));
+        $cert->save();
+
+        if ($cert->id) {
+            return Response::json(['status' => 'success', 'message' => '生成成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '生成失败']);
+    }
+
+    // 编辑域名证书
+    public function edit($id)
+    {
+        $view['Dv'] = NodeCertificate::find($id);
+
+        return view('admin.node.cert.info', $view);
+    }
+
+    public function update(Request $request, $id): JsonResponse
+    {
+        $Dv = NodeCertificate::findOrFail($id);
+        if ($Dv->update(['domain' => $request->input('domain'), 'key' => $request->input('key'), 'pem' => $request->input('pem')])) {
+            return Response::json(['status' => 'success', 'message' => '修改成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '修改失败']);
+    }
+
+    // 删除域名证书
+    public function destroy($id): JsonResponse
+    {
+        try {
+            if (NodeCertificate::whereId($id)->delete()) {
+                return Response::json(['status' => 'success', 'message' => '操作成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除域名证书失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除域名证书失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '删除域名证书失败']);
+    }
+}

+ 106 - 0
app/Http/Controllers/Admin/Config/CountryController.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace App\Http\Controllers\Admin\Config;
+
+use App\Http\Controllers\Controller;
+use App\Models\Country;
+use App\Models\Node;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class CountryController extends Controller
+{
+
+    // 添加国家/地区
+    public function store(Request $request): JsonResponse
+    {
+        $code = $request->input('code');
+        $name = $request->input('name');
+
+        if (empty($code)) {
+            return Response::json(['status' => 'fail', 'message' => '国家/地区代码不能为空']);
+        }
+
+        if (empty($name)) {
+            return Response::json(['status' => 'fail', 'message' => '国家/地区名称不能为空']);
+        }
+
+        $exists = Country::find($code);
+        if ($exists) {
+            return Response::json(['status' => 'fail', 'message' => '该国家/地区名称已存在,请勿重复添加']);
+        }
+
+        $obj = new Country();
+        $obj->code = $code;
+        $obj->name = $name;
+
+        if ($obj->save()) {
+            return Response::json(['status' => 'success', 'message' => '提交成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+    }
+
+    // 编辑国家/地区
+    public function update(Request $request, $code): JsonResponse
+    {
+        $name = $request->input('name');
+
+        if (empty($name)) {
+            return Response::json(['status' => 'fail', 'message' => '国家/地区名称不能为空']);
+        }
+
+
+        $country = Country::find($code);
+        if (!$country) {
+            return Response::json(['status' => 'fail', 'message' => '国家/地区不存在']);
+        }
+
+        // 校验该国家/地区下是否存在关联节点
+        if (Node::whereCountryCode($country->code)->exists()) {
+            return Response::json(['status' => 'fail', 'message' => '该国家/地区下存在关联节点,请先取消关联']);
+        }
+
+        try {
+            $country->name = $name;
+            if ($country->save()) {
+                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('编辑国家/地区时失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '编辑失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+    }
+
+    // 删除国家/地区
+    public function destroy($code): ?JsonResponse
+    {
+        $country = Country::find($code);
+        if (!$country) {
+            return Response::json(['status' => 'fail', 'message' => '国家/地区不存在']);
+        }
+
+        // 校验该国家/地区下是否存在关联节点
+        if (Node::whereCountryCode($country->code)->exists()) {
+            return Response::json(['status' => 'fail', 'message' => '该国家/地区下存在关联节点,请先取消关联']);
+        }
+
+        try {
+            if ($country->delete()) {
+                return Response::json(['status' => 'success', 'message' => '操作成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除国家/地区失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+    }
+}

+ 68 - 0
app/Http/Controllers/Admin/Config/EmailFilterController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace App\Http\Controllers\Admin\Config;
+
+use App\Http\Controllers\Controller;
+use App\Models\EmailFilter;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+use Validator;
+
+class EmailFilterController extends Controller
+{
+    // 邮箱过滤列表
+    public function index()
+    {
+        $view['list'] = EmailFilter::orderByDesc('id')->paginate(15);
+
+        return view('admin.config.emailFilter', $view);
+    }
+
+    // 添加邮箱后缀
+    public function store(Request $request): JsonResponse
+    {
+        $validator = Validator::make($request->all(), [
+            'words' => 'required|unique:email_filter',
+        ]);
+
+        if ($validator->fails()) {
+            return Response::json(['status' => 'fail', 'message' => $validator->errors()->first()]);
+        }
+
+        try {
+            $obj = new EmailFilter();
+            $obj->type = $request->input('type');
+            $obj->words = strtolower($request->input('words'));
+
+            if ($obj->save()) {
+                return Response::json(['status' => 'success', 'message' => '添加成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('添加邮箱后缀时失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '添加失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+    }
+
+    // 删除邮箱后缀
+    public function destroy($id): JsonResponse
+    {
+        try {
+            $result = EmailFilter::whereId($id)->delete();
+            if ($result) {
+                return Response::json(['status' => 'success', 'message' => '删除成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除邮箱后缀失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+    }
+}

+ 54 - 0
app/Http/Controllers/Admin/Config/LabelController.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Http\Controllers\Admin\Config;
+
+use App\Http\Controllers\Controller;
+use App\Models\Label;
+use App\Models\NodeLabel;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class LabelController extends Controller
+{
+    // 添加标签
+    public function store(Request $request): JsonResponse
+    {
+        $label = new Label();
+        $label->name = $request->input('name');
+        $label->sort = $request->input('sort');
+
+        if ($label->save()) {
+            return Response::json(['status' => 'success', 'message' => '添加成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+    }
+
+    // 编辑标签
+    public function update(Request $request, $id): JsonResponse
+    {
+        if (Label::whereId($id)->update(['name' => $request->input('name'), 'sort' => $request->input('sort')])) {
+            return Response::json(['status' => 'success', 'message' => '编辑成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+    }
+
+    // 删除标签
+    public function destroy($id): ?JsonResponse
+    {
+        try {
+            Label::whereId($id)->delete();
+            NodeLabel::whereLabelId($id)->delete(); // 删除节点关联
+
+            return Response::json(['status' => 'success', 'message' => '删除成功']);
+        } catch (Exception $e) {
+            Log::error('删除标签失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+        }
+    }
+}

+ 94 - 0
app/Http/Controllers/Admin/Config/LevelController.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace App\Http\Controllers\Admin\Config;
+
+use App\Http\Controllers\Controller;
+use App\Models\Level;
+use App\Models\User;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+use Validator;
+
+class LevelController extends Controller
+{
+    // 添加等级
+    public function store(Request $request): JsonResponse
+    {
+        $validator = Validator::make($request->all(), [
+            'level'      => 'required|numeric|unique:level,level',
+            'level_name' => 'required',
+        ]);
+
+        if ($validator->fails()) {
+            return Response::json(['status' => 'fail', 'message' => $validator->errors()->first()]);
+        }
+
+        $obj = new Level();
+        $obj->level = $request->input('level');
+        $obj->name = $request->input('level_name');
+        $obj->save();
+
+        if ($obj->id) {
+            return Response::json(['status' => 'success', 'message' => '提交成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+    }
+
+    // 编辑等级
+    public function update(Request $request, $id): JsonResponse
+    {
+        $level = $request->input('level');
+
+        $validator = Validator::make($request->all(), [
+            'level'      => 'required|numeric',
+            'level_name' => 'required',
+        ]);
+
+        if ($validator->fails()) {
+            return Response::json(['status' => 'fail', 'message' => $validator->errors()->first()]);
+        }
+        // 校验该等级下是否存在关联账号
+        $levelCheck = Level::where('id', '<>', $id)->whereLevel($level)->exists();
+        if ($levelCheck) {
+            return Response::json(['status' => 'fail', 'message' => '该等级已存在!']);
+        }
+
+        // 校验该等级下是否存在关联账号
+        $userCount = User::whereLevel($level)->count();
+        if ($userCount) {
+            return Response::json(['status' => 'fail', 'message' => '该等级下存在关联账号,请先取消关联!']);
+        }
+
+        Level::whereId($id)->update(['level' => $level, 'name' => $request->input('level_name')]);
+
+        return Response::json(['status' => 'success', 'message' => '操作成功']);
+    }
+
+    // 删除等级
+    public function destroy($id): JsonResponse
+    {
+        $level = Level::find($id);
+
+        // 校验该等级下是否存在关联账号
+        $userCount = User::whereLevel($level->level)->count();
+        if ($userCount) {
+            return Response::json(['status' => 'fail', 'message' => '该等级下存在关联账号,请先取消关联']);
+        }
+
+        try {
+            if (Level::whereId($id)->delete()) {
+                return Response::json(['status' => 'success', 'message' => '删除成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除等级时报错:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+    }
+}

+ 79 - 0
app/Http/Controllers/Admin/Config/SsConfigController.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace App\Http\Controllers\Admin\Config;
+
+use App\Http\Controllers\Controller;
+use App\Models\SsConfig;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class SsConfigController extends Controller
+{
+    // 添加SS配置
+    public function store(Request $request): JsonResponse
+    {
+        $name = $request->input('name');
+        $type = $request->input('type', 1); // 类型:1-加密方式(method)、2-协议(protocol)、3-混淆(obfs)
+        $is_default = $request->input('is_default', 0);
+        $sort = $request->input('sort', 0);
+
+        if (empty($name)) {
+            return Response::json(['status' => 'fail', 'message' => '配置名称不能为空']);
+        }
+
+        // 校验是否已存在
+        $config = SsConfig::type($type)->whereName($name)->first();
+        if ($config) {
+            return Response::json(['status' => 'fail', 'message' => '配置已经存在,请勿重复添加']);
+        }
+
+        $ssConfig = new SsConfig();
+        $ssConfig->name = $name;
+        $ssConfig->type = $type;
+        $ssConfig->is_default = $is_default;
+        $ssConfig->sort = $sort;
+        $ssConfig->save();
+
+        return Response::json(['status' => 'success', 'message' => '添加成功']);
+    }
+
+    // 设置SS默认配置
+    public function update($id): JsonResponse
+    {
+        if (empty($id)) {
+            return Response::json(['status' => 'fail', 'message' => '非法请求']);
+        }
+
+        $config = SsConfig::find($id);
+        if (!$config) {
+            return Response::json(['status' => 'fail', 'message' => '配置不存在']);
+        }
+
+        // 去除该配置所属类型的默认值
+        SsConfig::default()->type($config->type)->update(['is_default' => 0]);
+
+        // 将该ID对应记录值置为默认值
+        SsConfig::whereId($id)->update(['is_default' => 1]);
+
+        return Response::json(['status' => 'success', 'message' => '操作成功']);
+    }
+
+    // 删除SS配置
+    public function destroy($id): JsonResponse
+    {
+        try {
+            if (SsConfig::whereId($id)->delete()) {
+                return Response::json(['status' => 'success', 'message' => '删除成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除SS配置时失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '删除失败']);
+    }
+}

+ 107 - 187
app/Http/Controllers/Admin/CouponController.php

@@ -3,8 +3,8 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Controllers\Controller;
+use App\Http\Requests\Admin\CouponRequest;
 use App\Models\Coupon;
-use DB;
 use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
@@ -14,7 +14,6 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 use Redirect;
 use Response;
 use Str;
-use Validator;
 
 /**
  * 优惠券控制器
@@ -25,18 +24,17 @@ use Validator;
  */
 class CouponController extends Controller
 {
-
     // 优惠券列表
-    public function couponList(Request $request)
+    public function index(Request $request)
     {
-        $sn     = $request->input('sn');
-        $type   = $request->input('type');
+        $sn = $request->input('sn');
+        $type = $request->input('type');
         $status = $request->input('status');
 
         $query = Coupon::query();
 
         if (isset($sn)) {
-            $query->where('sn', 'like', '%' . $sn . '%');
+            $query->where('sn', 'like', '%'.$sn.'%');
         }
 
         if (isset($type)) {
@@ -47,210 +45,132 @@ class CouponController extends Controller
             $query->whereStatus($status);
         }
 
-        $view['couponList'] = $query->latest()->paginate(15)->appends(
-            $request->except('page')
-        );
+        $view['couponList'] = $query->latest()->paginate(15)->appends($request->except('page'));
 
-        return view('admin.coupon.couponList', $view);
+        return view('admin.coupon.index', $view);
     }
 
-    // 添加优惠券
-    public function addCoupon(Request $request)
+    // 添加优惠券页面
+    public function create()
     {
-        if ($request->isMethod('POST')) {
-            Validator::make(
-                $request->all(),
-                [
-                    'name'         => 'required',
-                    'sn'           => 'unique:coupon',
-                    'type'         => 'required|integer|between:1,3',
-                    'usable_times' => 'integer|nullable',
-                    'num'          => 'required|integer|min:1',
-                    'value'        => 'required|numeric|min:0',
-                    'start_time'   => 'required|date|before_or_equal:end_time',
-                    'end_time'     => 'required|date|after_or_equal:start_time',
-                ],
-                [
-                    'name.required'              => '请填入卡券名称',
-                    'type.required'              => '请选择卡券类型',
-                    'type.integer'               => '卡券类型不合法,请重选',
-                    'type.between'               => '卡券类型不合法,请重选',
-                    'num.required'               => '请填写卡券数量',
-                    'num.integer'                => '卡券数量不合法',
-                    'num.min'                    => '卡券数量不合法,最小1',
-                    'value.required_unless'      => '请填入优惠值',
-                    'value.numeric'              => '优惠值金额不合法',
-                    'value.min'                  => '优惠值不合法,最小0',
-                    'start_time.required'        => '请填入有效期',
-                    'start_time.date'            => '有效期不合法',
-                    'start_time.before_or_equal' => '有效期不合法',
-                    'end_time.required'          => '请填入有效期',
-                    'end_time.date'              => '有效期不合法',
-                    'end_time.after_or_equal'    => '有效期不合法',
-                ]
-            );
-
-            $type = $request->input('type');
+        return view('admin.coupon.create');
+    }
 
-            // 优惠卷LOGO
-            $logo = '';
-            if ($request->hasFile('logo')) {
-                $logo = $this->uploadFile($request->file('logo'));
+    // 添加优惠券
+    public function store(CouponRequest $request)
+    {
+        // 优惠卷LOGO
+        $logo = null;
+        if ($request->hasFile('logo')) {
+            $logo = 'upload/'.$request->file('logo')->store('images');
 
-                if ( ! $logo) {
-                    return Redirect::back()->withInput()->withErrors('LOGO不合法');
-                }
+            if (!$logo) {
+                return Redirect::back()->withInput()->withErrors('LOGO不合法');
+            }
+        }
+        try {
+            $num = (int) $request->input('num');
+
+            for ($i = 0; $i < $num; $i++) {
+                $obj = new Coupon();
+                $obj->name = $request->input('name');
+                $obj->logo = $logo;
+                $obj->sn = $num === 1 && $request->input('sn') ? $request->input('sn') : Str::random(8);
+                $obj->type = $request->input('type');
+                $obj->usable_times = $request->input('usable_times');
+                $obj->value = $request->input('value');
+                $obj->rule = $request->input('rule');
+                $obj->start_time = strtotime($request->input('start_time'));
+                $obj->end_time = strtotime($request->input('end_time'));
+                $obj->status = 0;
+                $obj->save();
             }
 
-            try {
-                DB::beginTransaction();
-                $num = $request->input('num');
-                for ($i = 0; $i < $num; $i++) {
-                    $obj               = new Coupon();
-                    $obj->name         = $request->input('name');
-                    $obj->logo         = $logo;
-                    $obj->sn           = $num == 1 && $request->input(
-                        'sn'
-                    ) ? $request->input('sn') : Str::random(8);
-                    $obj->type         = $type;
-                    $obj->usable_times = $request->input('usable_times');
-                    $obj->value        = $request->input('value');
-                    $obj->rule         = $request->input('rule');
-                    $obj->start_time   = strtotime(
-                        $request->input('start_time')
-                    );
-                    $obj->end_time     = strtotime($request->input('end_time'));
-                    $obj->status       = 0;
-                    $obj->save();
-                }
-
-                DB::commit();
-
-                return Redirect::back()->with('successMsg', '生成成功');
-            } catch (Exception $e) {
-                DB::rollBack();
-
-                Log::error('生成优惠券失败:' . $e->getMessage());
+            return Redirect::to(route('admin.coupon.index'))->with('successMsg', '生成成功');
+        } catch (Exception $e) {
+            Log::error('生成优惠券失败:'.$e->getMessage());
 
-                return Redirect::back()->withInput()->withErrors(
-                    '生成失败:' . $e->getMessage()
-                );
-            }
-        } else {
-            return view('admin.coupon.addCoupon');
+            return Redirect::back()->withInput()->withInput()->withErrors('生成优惠券失败:'.$e->getMessage());
         }
     }
 
     // 删除优惠券
-    public function delCoupon(Request $request): JsonResponse
+    public function destroy($id): JsonResponse
     {
-        Coupon::find($request->input('id'))->delete();
+        try {
+            if (Coupon::find($id)->delete()) {
+                return Response::json(['status' => 'success', 'message' => '删除成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除优惠券失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'success', 'message' => '删除优惠券失败:'.$e->getMessage()]);
+        }
 
-        return Response::json(['status' => 'success', 'message' => '删除成功']);
+        return Response::json(['status' => 'fail', 'message' => '删除失败']);
     }
 
     // 导出卡券
     public function exportCoupon(): void
     {
-        $voucherList        = Coupon::type(1)->whereStatus(0)->get();
+        $voucherList = Coupon::type(1)->whereStatus(0)->get();
         $discountCouponList = Coupon::type(2)->whereStatus(0)->get();
-        $refillList         = Coupon::type(3)->whereStatus(0)->get();
-
-        $filename    = '卡券' . date('Ymd') . '.xlsx';
-        $spreadsheet = new Spreadsheet();
-        $spreadsheet->getProperties()
-                    ->setCreator('ProxyPanel')
-                    ->setLastModifiedBy('ProxyPanel')
-                    ->setTitle('邀请码')
-                    ->setSubject('邀请码')
-                    ->setDescription('')
-                    ->setKeywords('')
-                    ->setCategory('');
+        $refillList = Coupon::type(3)->whereStatus(0)->get();
+
+        try {
+            $filename = '卡券'.date('Ymd').'.xlsx';
+            $spreadsheet = new Spreadsheet();
+            $spreadsheet->getProperties()
+                ->setCreator('ProxyPanel')
+                ->setLastModifiedBy('ProxyPanel')
+                ->setTitle('邀请码')
+                ->setSubject('邀请码');
+
+            // 抵用券
+            $spreadsheet->setActiveSheetIndex(0);
+            $sheet = $spreadsheet->getActiveSheet();
+            $sheet->setTitle('抵用券');
+            $sheet->fromArray(['名称', '使用次数', '有效期', '券码', '金额(元)', '使用限制(元)'], null);
+            foreach ($voucherList as $k => $vo) {
+                $dateRange = date('Y-m-d', $vo->start_time).' ~ '.date('Y-m-d', $vo->end_time);
+                $sheet->fromArray([$vo->name, $vo->usable_times ?? '无限制', $dateRange, $vo->sn, $vo->value, $vo->rule], null,
+                    'A'.($k + 2));
+            }
 
-        // 抵用券
-        $spreadsheet->setActiveSheetIndex(0);
-        $sheet = $spreadsheet->getActiveSheet();
-        $sheet->setTitle('抵用券');
-        $sheet->fromArray(
-            ['名称', '使用次数', '有效期', '券码', '金额(元)', '使用限制(元)'],
-            null
-        );
-        foreach ($voucherList as $k => $vo) {
-            $dateRange = date('Y-m-d', $vo->start_time) . ' ~ ' . date(
-                    'Y-m-d',
-                    $vo->end_time
-                );
-            $sheet->fromArray(
-                [
-                    $vo->name,
-                    $vo->usable_times,
-                    $dateRange,
-                    $vo->sn,
-                    $vo->value,
-                    $vo->rule,
-                ],
-                null,
-                'A' . ($k + 2)
-            );
-        }
+            // 折扣券
+            $spreadsheet->createSheet(1);
+            $spreadsheet->setActiveSheetIndex(1);
+            $sheet = $spreadsheet->getActiveSheet();
+            $sheet->setTitle('折扣券');
+            $sheet->fromArray(['名称', '使用次数', '有效期', '券码', '折扣(折)', '使用限制(元)'], null);
+            foreach ($discountCouponList as $k => $vo) {
+                $dateRange = date('Y-m-d', $vo->start_time).' ~ '.date('Y-m-d', $vo->end_time);
+                $sheet->fromArray([$vo->name, $vo->usable_times ?? '无限制', $dateRange, $vo->sn, $vo->value, $vo->rule], null,
+                    'A'.($k + 2));
+            }
 
-        // 折扣券
-        $spreadsheet->createSheet(1);
-        $spreadsheet->setActiveSheetIndex(1);
-        $sheet = $spreadsheet->getActiveSheet();
-        $sheet->setTitle('折扣券');
-        $sheet->fromArray(
-            ['名称', '使用次数', '有效期', '券码', '折扣(折)', '使用限制(元)'],
-            null
-        );
-        foreach ($discountCouponList as $k => $vo) {
-            $dateRange = date('Y-m-d', $vo->start_time) . ' ~ ' . date(
-                    'Y-m-d',
-                    $vo->end_time
-                );
-            $sheet->fromArray(
-                [
-                    $vo->name,
-                    $vo->usable_times,
-                    $dateRange,
-                    $vo->sn,
-                    $vo->value,
-                    $vo->rule,
-                ],
-                null,
-                'A' . ($k + 2)
-            );
-        }
+            // 充值券
+            $spreadsheet->createSheet(2);
+            $spreadsheet->setActiveSheetIndex(2);
+            $sheet = $spreadsheet->getActiveSheet();
+            $sheet->setTitle('充值券');
+            $sheet->fromArray(['名称', '有效期', '券码', '金额(元)'], null);
+            foreach ($refillList as $k => $vo) {
+                $dateRange = date('Y-m-d', $vo->start_time).' ~ '.date('Y-m-d', $vo->end_time);
+                $sheet->fromArray([$vo->name, $dateRange, $vo->sn, $vo->value], null, 'A'.($k + 2));
+            }
 
-        // 充值券
-        $spreadsheet->createSheet(2);
-        $spreadsheet->setActiveSheetIndex(2);
-        $sheet = $spreadsheet->getActiveSheet();
-        $sheet->setTitle('充值券');
-        $sheet->fromArray(['名称', '有效期', '券码', '金额(元)'], null);
-        foreach ($refillList as $k => $vo) {
-            $dateRange = date('Y-m-d', $vo->start_time) . ' ~ ' . date(
-                    'Y-m-d',
-                    $vo->end_time
-                );
-            $sheet->fromArray(
-                [$vo->name, $dateRange, $vo->sn, $vo->value],
-                null,
-                'A' . ($k + 2)
-            );
+            // 指针切换回第一个sheet
+            $spreadsheet->setActiveSheetIndex(0);
+
+            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 输出07Excel文件
+            //header('Content-Type:application/vnd.ms-excel'); // 输出Excel03版本文件
+            header('Content-Disposition: attachment;filename="'.$filename.'"');
+            header('Cache-Control: max-age=0');
+            $writer = new Xlsx($spreadsheet);
+            $writer->save('php://output');
+        } catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
+            Log::error('导出优惠券时报错:'.$e->getMessage());
         }
-
-        // 指针切换回第一个sheet
-        $spreadsheet->setActiveSheetIndex(0);
-
-        header(
-            'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
-        ); // 输出07Excel文件
-        //header('Content-Type:application/vnd.ms-excel'); // 输出Excel03版本文件
-        header('Content-Disposition: attachment;filename="' . $filename . '"');
-        header('Cache-Control: max-age=0');
-        $writer = new Xlsx($spreadsheet);
-        $writer->save('php://output');
     }
-
 }

+ 0 - 75
app/Http/Controllers/Admin/EmailFilterController.php

@@ -1,75 +0,0 @@
-<?php
-
-namespace App\Http\Controllers\Admin;
-
-use App\Http\Controllers\Controller;
-use App\Models\EmailFilter;
-use Illuminate\Http\JsonResponse;
-use Illuminate\Http\Request;
-use Response;
-use Validator;
-
-/**
- * 邮箱后缀管理控制器
- *
- * Class EmailFilterController
- *
- * @package App\Http\Controllers\Controller
- */
-class EmailFilterController extends Controller
-{
-
-    // 邮箱过滤列表
-    public function filterList()
-    {
-        $view['list'] = EmailFilter::orderByDesc('id')->paginate(15);
-
-        return view('admin.config.emailFilter', $view);
-    }
-
-    // 添加邮箱后缀
-    public function addSuffix(Request $request): ?JsonResponse
-    {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'words' => 'required|unique:sensitive_words',
-            ],
-            [
-                'words.required' => '添加失败:请填写邮箱后缀',
-                'words.unique'   => '添加失败:邮箱后缀已存在',
-            ]
-        );
-
-        if ($validator->fails()) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'message' => $validator->getMessageBag()->first(),
-                ]
-            );
-        }
-
-        $obj        = new EmailFilter();
-        $obj->type  = $request->input('type');
-        $obj->words = strtolower($request->input('words'));
-        $obj->save();
-        if ($obj->id) {
-            return Response::json(['status' => 'success', 'message' => '添加成功']);
-        }
-
-        return Response::json(['status' => 'fail', 'message' => '添加失败']);
-    }
-
-    // 删除邮箱后缀
-    public function delSuffix(Request $request): ?JsonResponse
-    {
-        $result = EmailFilter::whereId($request->input('id'))->delete();
-        if ($result) {
-            return Response::json(['status' => 'success', 'message' => '删除成功']);
-        }
-
-        return Response::json(['status' => 'fail', 'message' => '删除失败']);
-    }
-
-}

+ 325 - 0
app/Http/Controllers/Admin/LogsController.php

@@ -0,0 +1,325 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Components\IP;
+use App\Http\Controllers\Controller;
+use App\Models\Node;
+use App\Models\NodeOnlineUserIp;
+use App\Models\NotificationLog;
+use App\Models\Order;
+use App\Models\PaymentCallback;
+use App\Models\User;
+use App\Models\UserBanedLog;
+use App\Models\UserCreditLog;
+use App\Models\UserDataFlowLog;
+use App\Models\UserDataModifyLog;
+use Illuminate\Http\Request;
+use Redirect;
+
+class LogsController extends Controller
+{
+    // 订单列表
+    public function orderList(Request $request)
+    {
+        $email = $request->input('email');
+        $order_sn = $request->input('order_sn');
+        $is_coupon = $request->input('is_coupon');
+        $is_expire = $request->input('is_expire');
+        $pay_way = $request->input('pay_way');
+        $status = $request->input('status');
+        $range_time = $request->input('range_time');
+        $sort = $request->input('sort'); // 0-按创建时间降序、1-按创建时间升序
+        $order_id = $request->input('id');
+
+        $query = Order::with(['user:id,email', 'goods:id,name', 'coupon:id,name,sn']);
+
+        if (isset($email)) {
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
+        }
+        if (isset($order_sn)) {
+            $query->where('order_sn', 'like', '%'.$order_sn.'%');
+        }
+
+        if (isset($is_coupon)) {
+            if ($is_coupon) {
+                $query->where('coupon_id', '<>', 0);
+            } else {
+                $query->whereCouponId(0);
+            }
+        }
+
+        if (isset($is_expire)) {
+            $query->whereIsExpire($is_expire);
+        }
+
+        if (isset($pay_way)) {
+            $query->wherePayWay($pay_way);
+        }
+
+        if (isset($status)) {
+            $query->whereStatus($status);
+        }
+
+        if (isset($range_time) && $range_time !== ',') {
+            $range_time = explode(',', $range_time);
+            $query->where('created_at', '>=', $range_time[0])->where('created_at', '<=', $range_time[1]);
+        }
+
+        if (isset($order_id)) {
+            $query->whereId($order_id);
+        }
+
+        if ($sort) {
+            $query->orderBy('id');
+        } else {
+            $query->orderByDesc('id');
+        }
+
+        $view['orderList'] = $query->paginate(15)->appends($request->except('page'));
+
+        return view('admin.logs.order', $view);
+    }
+
+    // 流量日志
+    public function trafficLog(Request $request)
+    {
+        $port = $request->input('port');
+        $user_id = $request->input('user_id');
+        $email = $request->input('email');
+        $nodeId = $request->input('nodeId');
+        $startTime = $request->input('startTime');
+        $endTime = $request->input('endTime');
+
+        $query = UserDataFlowLog::with(['user', 'node']);
+
+        if (isset($port)) {
+            $query->whereHas('user', static function ($q) use ($port) { $q->wherePort($port); });
+        }
+
+        if (isset($user_id)) {
+            $query->whereUserId($user_id);
+        }
+
+        if (isset($email)) {
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
+        }
+
+        if (isset($nodeId)) {
+            $query->whereNodeId($nodeId);
+        }
+
+        if (isset($startTime)) {
+            $query->where('log_time', '>=', strtotime($startTime));
+        }
+
+        if (isset($endTime)) {
+            $query->where('log_time', '<=', strtotime($endTime));
+        }
+
+        // 已使用流量
+        $view['totalTraffic'] = flowAutoShow($query->sum('u') + $query->sum('d'));
+
+        $list = $query->latest('log_time')->paginate(20)->appends($request->except('page'));
+        foreach ($list as $vo) {
+            $vo->u = flowAutoShow($vo->u);
+            $vo->d = flowAutoShow($vo->d);
+            $vo->log_time = date('Y-m-d H:i:s', $vo->log_time);
+        }
+
+        $view['list'] = $list;
+        $view['nodeList'] = Node::whereStatus(1)->orderByDesc('sort')->latest()->get();
+
+        return view('admin.logs.traffic', $view);
+    }
+
+    // 邮件发送日志列表
+    public function notificationLog(Request $request)
+    {
+        $email = $request->input('email');
+        $type = $request->input('type');
+
+        $query = NotificationLog::query();
+
+        if (isset($email)) {
+            $query->where('address', 'like', '%'.$email.'%');
+        }
+
+        if (isset($type)) {
+            $query->whereType($type);
+        }
+
+        $view['list'] = $query->latest()->paginate(15)->appends($request->except('page'));
+
+        return view('admin.logs.notification', $view);
+    }
+
+    // 在线IP监控(实时)
+    public function onlineIPMonitor(Request $request, $id = null)
+    {
+        $ip = $request->input('ip');
+        $email = $request->input('email');
+        $port = $request->input('port');
+        $nodeId = $request->input('nodeId');
+
+        $query = NodeOnlineUserIp::with(['node:id,name', 'user:id,email'])->where('created_at', '>=', strtotime("-2 minutes"));
+
+        if (isset($ip)) {
+            $query->whereIp($ip);
+        }
+
+        if (isset($email)) {
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
+        }
+
+        if (isset($port)) {
+            $query->whereHas('user', static function ($q) use ($port) { $q->wherePort($port); });
+        }
+
+        if (isset($nodeId)) {
+            $query->whereHas('node', static function ($q) use ($nodeId) { $q->whereId($nodeId); });
+        }
+
+        if (isset($id)) {
+            $query->whereHas('user', static function ($q) use ($id) { $q->whereId($id); });
+        }
+
+        $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);
+        }
+
+        $view['list'] = $onlineIPLogs;
+        $view['nodeList'] = Node::whereStatus(1)->orderByDesc('sort')->latest()->get();
+
+        return view('admin.logs.onlineIPMonitor', $view);
+    }
+
+    // 用户余额变动记录
+    public function userCreditLogList(Request $request)
+    {
+        $email = $request->input('email');
+
+        $query = UserCreditLog::with('user:id,email')->latest();
+
+        if (isset($email)) {
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
+        }
+
+        $view['list'] = $query->paginate(15)->appends($request->except('page'));
+
+        return view('admin.logs.userCreditHistory', $view);
+    }
+
+    // 用户封禁记录
+    public function userBanLogList(Request $request)
+    {
+        $email = $request->input('email');
+
+        $query = UserBanedLog::with('user:id,email,t')->latest();
+
+        if (isset($email)) {
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
+        }
+
+        $view['list'] = $query->paginate(15)->appends($request->except('page'));
+
+        return view('admin.logs.userBanHistory', $view);
+    }
+
+    // 用户流量变动记录
+    public function userTrafficLogList(Request $request)
+    {
+        $email = $request->input('email');
+
+        $query = UserDataModifyLog::with(['user:id,email', 'order.goods:id,name']);
+
+        if (isset($email)) {
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
+        }
+
+        $view['list'] = $query->latest()->paginate(15)->appends($request->except('page'));
+
+        return view('admin.logs.userTraffic', $view);
+    }
+
+    // 用户在线IP记录
+    public function userOnlineIPList(Request $request)
+    {
+        $email = $request->input('email');
+        $port = $request->input('port');
+        $wechat = $request->input('wechat');
+        $qq = $request->input('qq');
+
+        $query = User::activeUser();
+
+        if (isset($email)) {
+            $query->where('email', 'like', '%'.$email.'%');
+        }
+
+        if (isset($wechat)) {
+            $query->where('wechat', 'like', '%'.$wechat.'%');
+        }
+
+        if (isset($qq)) {
+            $query->where('qq', 'like', '%'.$qq.'%');
+        }
+
+        if (isset($port)) {
+            $query->wherePort($port);
+        }
+
+        $userList = $query->paginate(15)->appends($request->except('page'));
+
+        $nodeOnlineIPs = NodeOnlineUserIp::with('node:id,name')->where('created_at', '>=', strtotime("-10 minutes"))->latest()->distinct();
+        // Todo 优化查询
+        foreach ($userList as $user) {
+            // 最近5条在线IP记录,如果后端设置为60秒上报一次,则为10分钟内的在线IP
+            $user->onlineIPList = $nodeOnlineIPs->wherePort($user->port)->limit(5)->get();
+        }
+
+        $view['userList'] = $userList;
+
+        return view('admin.logs.userOnlineIP', $view);
+    }
+
+    // 用户流量监控
+    public function userTrafficMonitor($id)
+    {
+        if (empty($id)) {
+            return Redirect::back();
+        }
+
+        $user = User::find($id);
+        if (empty($user)) {
+            return Redirect::back();
+        }
+
+        $view['email'] = $user->email;
+        $view = array_merge($view, $this->dataFlowChart($user->id));
+
+        return view('admin.logs.userMonitor', $view);
+    }
+
+    // 回调日志
+    public function callbackList(Request $request)
+    {
+        $status = $request->input('status', 0);
+
+        $query = PaymentCallback::query();
+
+        if (isset($status)) {
+            $query->whereStatus($status);
+        }
+
+        $view['list'] = $query->latest()->paginate(10)->appends($request->except('page'));
+
+        return view('admin.logs.callback', $view);
+    }
+}

+ 20 - 35
app/Http/Controllers/Admin/MarketingController.php

@@ -22,7 +22,6 @@ use RuntimeException;
  */
 class MarketingController extends Controller
 {
-
     // 邮件群发消息列表
     public function emailList(Request $request)
     {
@@ -58,28 +57,23 @@ class MarketingController extends Controller
     // 添加推送消息
     public function addPushMarketing(Request $request): ?JsonResponse
     {
-        $title   = $request->input('title');
+        $title = $request->input('title');
         $content = $request->input('content');
 
-        if ( ! sysConfig('is_push_bear')) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '推送失败:请先启用并配置PushBear']
-            );
+        if (!sysConfig('is_push_bear')) {
+            return Response::json(['status' => 'fail', 'message' => '推送失败:请先启用并配置PushBear']);
         }
 
         try {
             DB::beginTransaction();
 
-            $response = (new Client())->get(
-                'https://pushbear.ftqq.com/sub',
-                [
-                    'query' => [
-                        'sendkey' => sysConfig('push_bear_send_key'),
-                        'text'    => $title,
-                        'desp'    => $content,
-                    ],
-                ]
-            );
+            $response = (new Client())->get('https://pushbear.ftqq.com/sub', [
+                'query' => [
+                    'sendkey' => sysConfig('push_bear_send_key'),
+                    'text'    => $title,
+                    'desp'    => $content,
+                ],
+            ]);
 
             $result = json_decode($response->getBody(), true);
             if ($result->code) { // 失败
@@ -94,33 +88,24 @@ class MarketingController extends Controller
 
             return Response::json(['status' => 'success', 'message' => '推送成功']);
         } catch (Exception $e) {
-            Log::error('PushBear消息推送失败:' . $e->getMessage());
+            Log::error('PushBear消息推送失败:'.$e->getMessage());
 
             DB::rollBack();
 
-            return Response::json(
-                ['status' => 'fail', 'message' => '推送失败:' . $e->getMessage()]
-            );
+            return Response::json(['status' => 'fail', 'message' => '推送失败:'.$e->getMessage()]);
         }
     }
 
-    private function addMarketing(
-        $type = 1,
-        $title = '',
-        $content = '',
-        $status = 1,
-        $error = '',
-        $receiver = ''
-    ): bool {
-        $marketing           = new Marketing();
-        $marketing->type     = $type;
+    private function addMarketing($type = 1, $title = '', $content = '', $status = 1, $error = '', $receiver = ''): bool
+    {
+        $marketing = new Marketing();
+        $marketing->type = $type;
         $marketing->receiver = $receiver;
-        $marketing->title    = $title;
-        $marketing->content  = $content;
-        $marketing->error    = $error;
-        $marketing->status   = $status;
+        $marketing->title = $title;
+        $marketing->content = $content;
+        $marketing->error = $error;
+        $marketing->status = $status;
 
         return $marketing->save();
     }
-
 }

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

@@ -0,0 +1,295 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Components\NetworkDetection;
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Admin\NodeRequest;
+use App\Jobs\VNet\reloadNode;
+use App\Models\Country;
+use App\Models\Label;
+use App\Models\Level;
+use App\Models\Node;
+use App\Models\NodeAuth;
+use App\Models\NodeCertificate;
+use App\Models\NodePing;
+use App\Services\NodeService;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Redirect;
+use Response;
+use Session;
+use Str;
+
+class NodeController extends Controller
+{
+    // 节点列表
+    public function index(Request $request)
+    {
+        $status = $request->input('status');
+
+        $query = Node::with(['onlineLogs', 'dailyDataFlows']);
+
+        if (isset($status)) {
+            $query->whereStatus($status);
+        }
+
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->paginate(15)->appends($request->except('page'));
+        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;
+
+            // 已产生流量
+            $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);
+        }
+
+        $view['nodeList'] = $nodeList;
+
+        return view('admin.node.index', $view);
+    }
+
+    // 添加节点页面
+    public function create()
+    {
+        return view('admin.node.info', [
+            'countryList' => Country::orderBy('code')->get(),
+            'levelList'   => Level::orderBy('level')->get(),
+            'labelList'   => Label::orderByDesc('sort')->orderBy('id')->get(),
+            'dvList'      => NodeCertificate::orderBy('id')->get(),
+        ]);
+    }
+
+    // 添加节点
+    public function store(NodeRequest $request): JsonResponse
+    {
+        // TODO:判断是否已存在绑定了相同域名的节点,提示是否要强制替换,或者不提示之前强制将其他节点的绑定域名置为空,然后发起域名绑定请求,或者请求进入队列
+        try {
+            $node = Node::create($request->except('_token', 'labels'));
+
+            if ($node) {
+                // 生成节点标签
+                if ($request->exists('labels')) {
+                    (new NodeService())->makeLabels($node->id, $request->input('labels'));
+                }
+
+                return Response::json(['status' => 'success', 'message' => '添加成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('添加节点信息异常:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '添加线路失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '添加线路失败']);
+    }
+
+    // 编辑节点页面
+    public function edit($id)
+    {
+        return view('admin.node.info', [
+            'node'        => Node::with('labels')->find($id),
+            'countryList' => Country::orderBy('code')->get(),
+            'levelList'   => Level::orderBy('level')->get(),
+            'labelList'   => Label::orderByDesc('sort')->orderBy('id')->get(),
+            'dvList'      => NodeCertificate::orderBy('id')->get(),
+        ]);
+    }
+
+    // 编辑节点
+    public function update(NodeRequest $request, $id): JsonResponse
+    {
+        $node = Node::find($id);
+
+        try {
+            // 生成节点标签
+            if ($request->exists('labels')) {
+                (new NodeService())->makeLabels($node->id, $request->input('labels'));
+            }
+
+            // TODO:更新节点绑定的域名DNS(将节点IP更新到域名DNS 的A记录)
+            if ($node->update($request->except('_token', 'labels'))) {
+                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('编辑节点信息异常:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '编辑失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+    }
+
+    // 删除节点
+    public function destroy($id): JsonResponse
+    {
+        $node = Node::findOrFail($id);
+
+        try {
+            if ($node->delete()) {
+                return Response::json(['status' => 'success', 'message' => '删除成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('删除线路失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '删除线路失败:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '删除线路失败']);
+    }
+
+    // 节点信息验证
+    public function checkNode($id): JsonResponse
+    {
+        $node = Node::find($id);
+        // 使用DDNS的node先获取ipv4地址
+        if ($node->is_ddns) {
+            $ip = gethostbyname($node->server);
+            if (strcmp($ip, $node->server) !== 0) {
+                $node->ip = $ip;
+            } else {
+                return Response::json(['status' => 'fail', 'title' => 'IP获取错误', 'message' => $node->name.'IP获取失败',]);
+            }
+        }
+        $data[0] = NetworkDetection::networkCheck($node->ip, true); //ICMP
+        $data[1] = NetworkDetection::networkCheck($node->ip, false, $node->single ? $node->port : null); //TCP
+
+        return Response::json(['status' => 'success', 'title' => '['.$node->name.']阻断信息', 'message' => $data,]);
+    }
+
+    // 刷新节点地理位置
+    public function refreshGeo($id): JsonResponse
+    {
+        if ((new NodeService())->getNodeGeo($id)) {
+            return Response::json(['status' => 'success', 'message' => '获取地理位置更新成功!']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '获取地理位置更新失败!']);
+    }
+
+    // 重载节点
+    public function reload($id): JsonResponse
+    {
+        if (reloadNode::dispatchNow(Node::whereId($id)->get())) {
+            return Response::json(['status' => 'success', 'message' => '重载成功!']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '重载失败!']);
+    }
+
+    // 节点流量监控
+    public function nodeMonitor($id)
+    {
+        $node = Node::find($id);
+        if (!$node) {
+            Session::flash('errorMsg', '节点不存在,请重试');
+
+            return Redirect::back();
+        }
+
+        $view['nodeName'] = $node->name;
+        $view['nodeServer'] = $node->server;
+        $view = array_merge($view, $this->DataFlowChart($node->id, 1));
+
+        return view('admin.node.monitor', $view);
+    }
+
+    // Ping节点延迟
+    public function pingNode($id): JsonResponse
+    {
+        $node = Node::findOrFail($id);
+
+        $result = NetworkDetection::ping($node->is_ddns ? $node->server : $node->ip);
+
+        if ($result) {
+            return Response::json([
+                'status'  => 'success',
+                'message' => [
+                    $result['telecom']['time'] ?: '无',//电信
+                    $result['Unicom']['time'] ?: '无',// 联通
+                    $result['move']['time'] ?: '无',// 移动
+                    $result['HongKong']['time'] ?: '无'// 香港
+                ],
+            ]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => 'Ping访问失败']);
+    }
+
+    // Ping节点延迟日志
+    public function pingLog(Request $request)
+    {
+        $node_id = $request->input('nodeId');
+        $query = NodePing::query();
+        if (isset($node_id)) {
+            $query->whereNodeId($node_id);
+        }
+
+        $view['nodeList'] = Node::orderBy('id')->get();
+        $view['pingLogs'] = $query->latest()->paginate(15)->appends($request->except('page'));
+
+        return view('admin.node.ping', $view);
+    }
+
+    // 节点授权列表
+    public function authList(Request $request)
+    {
+        $view['list'] = NodeAuth::orderBy('node_id')->paginate(15)->appends($request->except('page'));
+
+        return view('admin.node.auth', $view);
+    }
+
+    // 添加节点授权
+    public function addAuth(): JsonResponse
+    {
+        $nodeArray = Node::whereStatus(1)->orderBy('id')->pluck('id')->toArray();
+        $authArray = NodeAuth::orderBy('node_id')->pluck('node_id')->toArray();
+
+        $arrayDifferent = array_diff($nodeArray, $authArray);
+
+        if (empty($arrayDifferent)) {
+            return Response::json(['status' => 'success', 'message' => '没有需要生成授权的节点']);
+        }
+
+        foreach ($arrayDifferent as $nodeId) {
+            $obj = new NodeAuth();
+            $obj->node_id = $nodeId;
+            $obj->key = Str::random();
+            $obj->secret = Str::random(8);
+            $obj->save();
+        }
+
+        return Response::json(['status' => 'success', 'message' => '生成成功']);
+    }
+
+    // 删除节点授权
+    public function delAuth($id): JsonResponse
+    {
+        try {
+            NodeAuth::whereId($id)->delete();
+        } catch (Exception $e) {
+            return Response::json(['status' => 'fail', 'message' => '错误:'.var_export($e, true)]);
+        }
+
+        return Response::json(['status' => 'success', 'message' => '操作成功']);
+    }
+
+    // 重置节点授权
+    public function refreshAuth($id): JsonResponse
+    {
+        $ret = NodeAuth::find($id)->update(['key' => Str::random(), 'secret' => Str::random(8)]);
+        if ($ret) {
+            return Response::json(['status' => 'success', 'message' => '操作成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '操作失败']);
+    }
+}

+ 22 - 48
app/Http/Controllers/Admin/RuleController.php

@@ -15,20 +15,17 @@ use Validator;
 
 class RuleController extends Controller
 {
-
     // 审计规则列表
     public function index(Request $request)
     {
-        $type  = $request->input('type');
+        $type = $request->input('type');
         $query = Rule::query();
 
         if ($type) {
             $query->whereType($type);
         }
 
-        $view['rules'] = $query->paginate(15)->appends(
-            $request->except('page')
-        );
+        $view['rules'] = $query->paginate(15)->appends($request->except('page'));
 
         return view('admin.rule.index', $view);
     }
@@ -36,28 +33,23 @@ class RuleController extends Controller
     // 添加审计规则
     public function store(Request $request): JsonResponse
     {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'type'    => 'required|between:1,4',
-                'name'    => 'required',
-                'pattern' => 'required',
-            ]
-        );
+        $validator = Validator::make($request->all(), [
+            'type'    => 'required|between:1,4',
+            'name'    => 'required',
+            'pattern' => 'required',
+        ]);
 
         if ($validator->fails()) {
-            return Response::json(
-                ['status' => 'fail', 'message' => $validator->errors()->all()]
-            );
+            return Response::json(['status' => 'fail', 'message' => $validator->errors()->all()]);
         }
 
-        $obj          = new Rule();
-        $obj->type    = $request->input('type');
-        $obj->name    = $request->input('name');
-        $obj->pattern = $request->input('pattern');
-        $obj->save();
+        $rule = new Rule();
+        $rule->type = $request->input('type');
+        $rule->name = $request->input('name');
+        $rule->pattern = $request->input('pattern');
+        $rule->save();
 
-        if ($obj->id) {
+        if ($rule->id) {
             return Response::json(['status' => 'success', 'message' => '提交成功']);
         }
 
@@ -67,13 +59,7 @@ class RuleController extends Controller
     // 编辑审计规则
     public function update(Request $request, $id): JsonResponse
     {
-        $ret = Rule::whereId($id)->update(
-            [
-                'name'    => $request->input('rule_name'),
-                'pattern' => $request->input('rule_pattern'),
-            ]
-        );
-        if ($ret) {
+        if (Rule::find($id)->update(['name' => $request->input('rule_name'), 'pattern' => $request->input('rule_pattern')])) {
             return Response::json(['status' => 'success', 'message' => '操作成功']);
         }
 
@@ -94,9 +80,7 @@ class RuleController extends Controller
                 }
             }
         } catch (Exception $e) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '操作失败, ' . $e->getMessage()]
-            );
+            return Response::json(['status' => 'fail', 'message' => '操作失败, '.$e->getMessage()]);
         }
 
         return Response::json(['status' => 'success', 'message' => '操作成功']);
@@ -105,22 +89,17 @@ class RuleController extends Controller
     // 用户触发审计规则日志
     public function ruleLogList(Request $request)
     {
-        $uid    = $request->input('uid');
-        $email  = $request->input('email');
+        $uid = $request->input('uid');
+        $email = $request->input('email');
         $nodeId = $request->input('node_id');
         $ruleId = $request->input('rule_id');
-        $query  = RuleLog::query();
+        $query = RuleLog::query();
 
         if ($uid) {
             $query->whereUserId($uid);
         }
         if (isset($email)) {
-            $query->whereHas(
-                'user',
-                static function ($q) use ($email) {
-                    $q->where('email', 'like', '%' . $email . '%');
-                }
-            );
+            $query->whereHas('user', static function ($q) use ($email) { $q->where('email', 'like', '%'.$email.'%'); });
         }
         if ($nodeId) {
             $query->whereNodeId($nodeId);
@@ -131,9 +110,7 @@ class RuleController extends Controller
 
         $view['nodeList'] = Node::all();
         $view['ruleList'] = Rule::all();
-        $view['ruleLogs'] = $query->latest()->paginate(15)->appends(
-            $request->except('page')
-        );
+        $view['ruleLogs'] = $query->latest()->paginate(15)->appends($request->except('page'));
 
         return view('admin.rule.log', $view);
     }
@@ -144,9 +121,7 @@ class RuleController extends Controller
         try {
             $ret = RuleLog::query()->delete();
         } catch (Exception $e) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '清理失败, ' . $e->getMessage()]
-            );
+            return Response::json(['status' => 'fail', 'message' => '清理失败, '.$e->getMessage()]);
         }
         $result = RuleLog::doesntExist();
         if ($ret || $result) {
@@ -155,5 +130,4 @@ class RuleController extends Controller
 
         return Response::json(['status' => 'fail', 'message' => '清理失败']);
     }
-
 }

+ 32 - 48
app/Http/Controllers/Admin/RuleGroupController.php

@@ -17,13 +17,10 @@ use Validator;
 
 class RuleGroupController extends Controller
 {
-
     // 审计规则分组列表
     public function index(Request $request)
     {
-        $view['ruleGroupList'] = RuleGroup::paginate(15)->appends(
-            $request->except('page')
-        );
+        $view['ruleGroupList'] = RuleGroup::paginate(15)->appends($request->except('page'));
 
         return view('admin.rule.group.index', $view);
     }
@@ -39,24 +36,19 @@ class RuleGroupController extends Controller
     // 添加审计规则分组
     public function store(Request $request): RedirectResponse
     {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'name'  => 'required',
-                'type'  => 'required|boolean',
-                'rules' => 'required',
-            ]
-        );
+        $validator = Validator::make($request->all(), [
+            'name'  => 'required',
+            'type'  => 'required|boolean',
+            'rules' => 'required',
+        ]);
 
         if ($validator->fails()) {
-            return Redirect::back()->withInput()->withErrors(
-                $validator->errors()
-            );
+            return Redirect::back()->withInput()->withErrors($validator->errors());
         }
 
-        $obj        = new RuleGroup();
-        $obj->name  = $request->input('name');
-        $obj->type  = (int)$request->input('type');
+        $obj = new RuleGroup();
+        $obj->name = $request->input('name');
+        $obj->type = (int) $request->input('type');
         $obj->rules = $request->input('rules');
         $obj->save();
 
@@ -70,8 +62,8 @@ class RuleGroupController extends Controller
     // 编辑审计规则分组页面
     public function edit($id)
     {
-        $view['ruleGroup'] = RuleGroup::findOrFail($id);
-        $view['ruleList']  = Rule::all();
+        $view['ruleGroup'] = RuleGroup::find($id);
+        $view['ruleList'] = Rule::all();
 
         return view('admin.rule.group.info', $view);
     }
@@ -79,27 +71,21 @@ class RuleGroupController extends Controller
     // 编辑审计规则分组
     public function update(Request $request, $id): RedirectResponse
     {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'name' => 'required',
-                'type' => 'required|boolean',
-            ]
-        );
+        $validator = Validator::make($request->all(), [
+            'name' => 'required',
+            'type' => 'required|boolean',
+        ]);
         if ($validator->fails()) {
-            return Redirect::back()->withInput()->withErrors(
-                $validator->errors()
-            );
+            return Redirect::back()->withInput()->withErrors($validator->errors());
         }
-        $name      = $request->input('name');
-        $type      = (int)$request->input('type');
-        $rules     = $request->input('rules');
-        $ruleGroup = RuleGroup::findOrFail($id);
 
-        $ruleGroup->name  = $name;
-        $ruleGroup->type  = $type;
-        $ruleGroup->rules = $rules;
-        if ($ruleGroup->save()) {
+        $ret = RuleGroup::find($id)->update([
+            'name'  => $request->input('name'),
+            'type'  => $request->input('type'),
+            'rules' => $request->input('rules'),
+        ]);
+
+        if ($ret) {
             return Redirect::back()->with('successMsg', '操作成功');
         }
 
@@ -113,9 +99,7 @@ class RuleGroupController extends Controller
             RuleGroup::whereId($id)->delete();
             RuleGroupNode::whereRuleGroupId($id)->delete();
         } catch (Exception $e) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '删除失败,' . $e->getMessage()]
-            );
+            return Response::json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
         }
 
         return Response::json(['status' => 'success', 'message' => '清理成功']);
@@ -125,14 +109,15 @@ class RuleGroupController extends Controller
     public function assignNode($id)
     {
         $view['ruleGroup'] = RuleGroup::find($id);
-        $view['nodeList']  = Node::all();
+        $view['nodeList'] = Node::all();
 
         return view('admin.rule.group.assign', $view);
     }
 
+    // 规则分组关联节点
     public function assign(Request $request, $id)
     {
-        $nodes     = $request->input('nodes');
+        $nodes = $request->input('nodes');
         $ruleGroup = RuleGroup::findOrFail($id);
 
         try {
@@ -142,18 +127,18 @@ class RuleGroupController extends Controller
             RuleGroupNode::whereRuleGroupId($id)->delete();
             if ($nodes) {
                 $ruleGroup->nodes = $nodes;
-                if ( ! $ruleGroup->save()) {
+                if (!$ruleGroup->save()) {
                     return Redirect::back()->withErrors("更新错误!");
                 }
 
                 foreach ($nodes as $nodeId) {
-                    $obj                = new RuleGroupNode();
+                    $obj = new RuleGroupNode();
                     $obj->rule_group_id = $id;
-                    $obj->node_id       = $nodeId;
+                    $obj->node_id = $nodeId;
                     $obj->save();
                 }
             } else {
-                RuleGroup::whereId($id)->update(['nodes' => null]);
+                RuleGroup::find($id)->update(['nodes' => null]);
             }
         } catch (Exception $e) {
             return Redirect::back()->withInput()->withErrors($e->getMessage());
@@ -161,5 +146,4 @@ class RuleGroupController extends Controller
 
         return Redirect::back()->with('successMsg', '操作成功');
     }
-
 }

+ 44 - 107
app/Http/Controllers/Admin/ShopController.php

@@ -3,9 +3,10 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Controllers\Controller;
+use App\Http\Requests\Admin\ShopStoreRequest;
+use App\Http\Requests\Admin\ShopUpdateRequest;
 use App\Models\Goods;
 use App\Models\Level;
-use DB;
 use Exception;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
@@ -14,7 +15,6 @@ use Log;
 use Redirect;
 use Response;
 use Session;
-use Validator;
 
 /**
  * 商店控制器
@@ -25,11 +25,10 @@ use Validator;
  */
 class ShopController extends Controller
 {
-
     // 商品列表
     public function index(Request $request)
     {
-        $type   = $request->input('type');
+        $type = $request->input('type');
         $status = $request->input('status');
 
         $query = Goods::query();
@@ -42,9 +41,7 @@ class ShopController extends Controller
             $query->whereStatus($status);
         }
 
-        $view['goodsList'] = $query->orderByDesc('status')
-                                   ->paginate(10)
-                                   ->appends($request->except('page'));
+        $view['goodsList'] = $query->orderByDesc('status')->paginate(10)->appends($request->except('page'));
 
         return view('admin.shop.index', $view);
     }
@@ -52,140 +49,77 @@ class ShopController extends Controller
     // 添加商品页面
     public function create()
     {
-        $view['goods']     = null;
         $view['levelList'] = Level::orderBy('level')->get();
 
         return view('admin.shop.info', $view);
     }
 
     // 添加商品
-    public function store(Request $request): RedirectResponse
+    public function store(ShopStoreRequest $request): RedirectResponse
     {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'name'    => 'required',
-                'traffic' => 'required|integer|min:1|max:10240000|nullable',
-                'price'   => 'required|numeric|min:0',
-                'type'    => 'required',
-                'renew'   => 'required_unless:type,2|min:0',
-                'days'    => 'required|integer',
-            ],
-            [
-                'traffic.min' => '内含流量不能低于1MB',
-                'traffic.max' => '内含流量不能超过10TB',
-            ]
-        );
-
-        if ($validator->fails()) {
-            return Redirect::back()->withInput()->withErrors(
-                $validator->errors()
-            );
-        }
-
         // 商品LOGO
-        $logo = null;
         if ($request->hasFile('logo')) {
-            $logo = $this->uploadFile($request->file('logo'));
+            $logo = 'upload/'.$request->file('logo')->store('images');
 
-            if ( ! $logo) {
+            if (!$logo) {
                 return Redirect::back()->withInput()->withErrors('LOGO不合法');
             }
         }
 
         try {
-            DB::beginTransaction();
-
-            $obj              = new Goods();
-            $obj->name        = $request->input('name');
-            $obj->logo        = $logo ?: null;
-            $obj->traffic     = $request->input('traffic');
-            $obj->type        = $request->input('type');
-            $obj->price       = round($request->input('price'), 2);
-            $obj->level       = $request->input('level');
-            $obj->renew       = round($request->input('renew'), 2);
-            $obj->period      = $request->input('period');
-            $obj->info        = $request->input('info');
-            $obj->description = $request->input('description');
-            $obj->days        = $request->input('days');
-            $obj->invite_num  = $request->input('invite_num');
-            $obj->limit_num   = $request->input('limit_num');
-            $obj->color       = $request->input('color');
-            $obj->sort        = $request->input('sort');
-            $obj->is_hot      = $request->input('is_hot') ? 1 : 0;
-            $obj->status      = $request->input('status') ? 1 : 0;
-            $obj->save();
-
-            DB::commit();
-
-            return Redirect::back()->with('successMsg', '添加成功');
+            $data = $request->except('_token', 'logo');
+            $data['logo'] = $logo ?? null;
+            $data['is_hot'] = $request->input('is_hot') ? 1 : 0;
+            $data['status'] = $request->input('status') ? 1 : 0;
+
+            $good = Goods::create($data);
+
+            if ($good) {
+                return Redirect::to(route('admin.goods.edit', $good->id))->with('successMsg', '添加成功');
+            }
         } catch (Exception $e) {
-            DB::rollBack();
-            Log::error('添加商品信息异常:' . $e->getMessage());
+            Log::error('添加商品信息异常:'.$e->getMessage());
 
-            return Redirect::back()->withInput()->withErrors('添加失败');
+            return Redirect::back()->withInput()->withErrors('添加商品信息失败:'.$e->getMessage());
         }
+
+        return Redirect::back()->withInput()->withErrors('添加商品信息失败');
     }
 
     // 编辑商品页面
     public function edit($id)
     {
-        $view['goods']     = Goods::find($id);
+        $view['goods'] = Goods::find($id);
         $view['levelList'] = Level::orderBy('level')->get();
 
         return view('admin.shop.info', $view);
     }
 
     // 编辑商品
-    public function update(Request $request, $id)
+    public function update(ShopUpdateRequest $request, $id)
     {
-        $goods = Goods::find($id);
-        if ( ! $goods) {
-            Session::flash('errorMsg', '商品不存在');
-
-            return Redirect::back();
-        }
-
+        $goods = Goods::findOrFail($id);
+        $data = $request->except('_token', '_method', 'logo');
         // 商品LOGO
         if ($request->hasFile('logo')) {
-            $logo = $this->uploadFile($request->file('logo'));
-
-            if ( ! $logo) {
-                Session::flash('errorMsg', 'LOGO不合法');
+            $logo = 'upload/'.$request->file('logo')->store('images');
 
-                return Redirect::back()->withInput();
+            if (!$logo) {
+                return Redirect::back()->withInput()->withErrors('LOGO不合法');
             }
-            Goods::whereId($id)->update(['logo' => $logo]);
+            $data['logo'] = $logo;
         }
 
         try {
-            DB::beginTransaction();
-
-            $data = [
-                'name'        => $request->input('name'),
-                'price'       => round($request->input('price'), 2) * 100,
-                'level'       => $request->input('level'),
-                'renew'       => round($request->input('renew'), 2) * 100,
-                'period'      => $request->input('period'),
-                'info'        => $request->input('info'),
-                'description' => $request->input('description'),
-                'invite_num'  => $request->input('invite_num'),
-                'limit_num'   => $request->input('limit_num'),
-                'color'       => $request->input('color'),
-                'sort'        => $request->input('sort'),
-                'is_hot'      => $request->input('is_hot') ? 1 : 0,
-                'status'      => $request->input('status') ? 1 : 0,
-            ];
-
-            Goods::whereId($id)->update($data);
-
-            Session::flash('successMsg', '编辑成功');
-
-            DB::commit();
-        } catch (Exception $e) {
-            Session::flash('errorMsg', '编辑失败');
+            $data['is_hot'] = $request->input('is_hot') ? 1 : 0;
+            $data['status'] = $request->input('status') ? 1 : 0;
 
-            DB::rollBack();
+            if ($goods->update($data)) {
+                Session::flash('successMsg', '编辑成功');
+            }
+        } catch (Exception $e) {
+            Log::error('编辑商品信息失败:'.$e->getMessage());
+            Session::flash('errorMsg', '编辑商品信息失败:'.$e->getMessage());
         }
 
         return Redirect::back();
@@ -195,12 +129,15 @@ class ShopController extends Controller
     public function destroy($id): JsonResponse
     {
         try {
-            Goods::find($id)->delete();
+            if (Goods::find($id)->delete()) {
+                return Response::json(['status' => 'success', 'message' => '删除成功']);
+            }
         } catch (Exception $e) {
-            Session::flash('errorMsg', '编辑失败' . $e);
+            Log::error('编辑商品失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '编辑商品失败:'.$e->getMessage()]);
         }
 
-        return Response::json(['status' => 'success', 'message' => '删除成功']);
+        return Response::json(['status' => 'fail', 'message' => '删除失败']);
     }
-
 }

+ 16 - 32
app/Http/Controllers/Admin/SubscribeController.php

@@ -18,13 +18,12 @@ use Response;
  */
 class SubscribeController extends Controller
 {
-
     // 订阅码列表
-    public function subscribeList(Request $request)
+    public function index(Request $request)
     {
         $user_id = $request->input('user_id');
-        $email   = $request->input('email');
-        $status  = $request->input('status');
+        $email = $request->input('email');
+        $status = $request->input('status');
 
         $query = UserSubscribe::with(['user:id,email']);
 
@@ -33,63 +32,48 @@ class SubscribeController extends Controller
         }
 
         if (isset($email)) {
-            $query->whereHas(
-                'user',
-                static function ($q) use ($email) {
-                    $q->where('email', 'like', '%' . $email . '%');
-                }
-            );
+            $query->whereHas('user', static function ($q) use ($email) {
+                $q->where('email', 'like', '%'.$email.'%');
+            });
         }
 
         if (isset($status)) {
             $query->whereStatus($status);
         }
 
-        $view['subscribeList'] = $query->latest()->paginate(20)->appends(
-            $request->except('page')
-        );
+        $view['subscribeList'] = $query->latest()->paginate(20)->appends($request->except('page'));
 
-        return view('admin.subscribe.subscribeList', $view);
+        return view('admin.subscribe.index', $view);
     }
 
     //订阅记录
-    public function subscribeLog(Request $request)
+    public function subscribeLog(Request $request, $id)
     {
-        $id    = $request->input('id');
         $query = UserSubscribeLog::with('user:email');
 
         if (isset($id)) {
             $query->whereUserSubscribeId($id);
         }
 
-        $view['subscribeLog'] = $query->latest()->paginate(20)->appends(
-            $request->except('page')
-        );
+        $view['subscribeLog'] = $query->latest()->paginate(20)->appends($request->except('page'));
 
-        return view('admin.subscribe.subscribeLog', $view);
+        return view('admin.subscribe.log', $view);
     }
 
     // 设置用户的订阅的状态
-    public function setSubscribeStatus(Request $request): JsonResponse
+    public function setSubscribeStatus(Request $request, $id): JsonResponse
     {
-        $id     = $request->input('id');
-        $status = $request->input('status', 0);
-
         if (empty($id)) {
             return Response::json(['status' => 'fail', 'message' => '操作异常']);
         }
+        $subscribe = UserSubscribe::find($id);
 
-        if ($status) {
-            UserSubscribe::find($id)->update(
-                ['status' => 1, 'ban_time' => null, 'ban_desc' => '']
-            );
+        if ($subscribe->status) {
+            $subscribe->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '后台手动封禁']);
         } else {
-            UserSubscribe::find($id)->update(
-                ['status' => 0, 'ban_time' => time(), 'ban_desc' => '后台手动封禁']
-            );
+            $subscribe->update(['status' => 1, 'ban_time' => null, 'ban_desc' => '']);
         }
 
         return Response::json(['status' => 'success', 'message' => '操作成功']);
     }
-
 }

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

@@ -0,0 +1,198 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Components\PushNotification;
+use App\Http\Controllers\Controller;
+use App\Models\Config;
+use App\Models\Label;
+use DB;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Redirect;
+use Response;
+use Session;
+
+class SystemController extends Controller
+{
+    // 设置系统扩展信息,例如客服、统计代码
+    public function setExtend(Request $request): ?RedirectResponse
+    {
+        $websiteAnalytics = $request->input('website_analytics');
+        $websiteCustomerService = $request->input('website_customer_service');
+
+        try {
+            DB::beginTransaction();
+
+            // 首页LOGO
+            if ($request->hasFile('website_home_logo')) {
+                $ret = 'upload/'.$request->file('website_home_logo')->store('images');
+                if (!$ret) {
+                    Session::flash('errorMsg', 'LOGO不合法');
+
+                    return Redirect::back();
+                }
+                Config::find('website_home_logo')->update(['value' => $ret]);
+            }
+
+            // 站内LOGO
+            if ($request->hasFile('website_logo')) {
+                $ret = 'upload/'.$request->file('website_logo')->store('images');
+                if (!$ret) {
+                    Session::flash('errorMsg', 'LOGO不合法');
+
+                    return Redirect::back();
+                }
+                Config::find('website_logo')->update(['value' => $ret]);
+            }
+
+            Config::find('website_analytics')->update(['value' => $websiteAnalytics]);
+            Config::find('website_customer_service')->update(['value' => $websiteCustomerService]);
+
+            Session::flash('successMsg', '更新成功');
+
+            DB::commit();
+
+            return Redirect::back();
+        } catch (Exception $e) {
+            DB::rollBack();
+
+            Session::flash('errorMsg', '更新失败');
+
+            return Redirect::back();
+        }
+    }
+
+    // 系统设置
+    public function index()
+    {
+        $view = Config::pluck('value', 'name')->toArray();
+        $view['labelList'] = Label::orderByDesc('sort')->orderBy('id')->get();
+
+        return view('admin.config.system', $view);
+    }
+
+    // 设置某个配置项
+    public function setConfig(Request $request): JsonResponse
+    {
+        $name = $request->input('name');
+        $value = $request->input('value');
+
+        if (!$name) {
+            return Response::json(['status' => 'fail', 'message' => '设置失败:请求参数异常']);
+        }
+
+        // 屏蔽异常配置
+        if (!in_array($name, Config::pluck('name')->toArray(), true)) {
+            return Response::json(['status' => 'fail', 'message' => '设置失败:配置不存在']);
+        }
+
+        // 如果开启用户邮件重置密码,则先设置网站名称和网址
+        if ($value !== '0' && in_array($name, ['is_reset_password', 'is_activate_account', 'expire_warning', 'traffic_warning',], true)) {
+            $config = Config::find('website_name');
+            if (!$config->value) {
+                return Response::json(['status' => 'fail', 'message' => '设置失败:启用该配置需要先设置【网站名称】']);
+            }
+
+            $config = Config::find('website_url');
+            if (!$config->value) {
+                return Response::json(['status' => 'fail', 'message' => '设置失败:启用该配置需要先设置【网站地址】']);
+            }
+        }
+
+        // 支付设置判断
+        if ($value !== null && in_array($name, ['is_AliPay', 'is_QQPay', 'is_WeChatPay', 'is_otherPay',], true)) {
+            switch ($value) {
+                case 'f2fpay':
+                    if (!sysConfig('f2fpay_app_id') || !sysConfig('f2fpay_private_key') || !sysConfig('f2fpay_public_key')) {
+                        return Response::json(['status' => 'fail', 'message' => '请先设置【支付宝F2F】必要参数',]);
+                    }
+                    break;
+                case 'codepay':
+                    if (!sysConfig('codepay_url') || !sysConfig('codepay_id') || !sysConfig('codepay_key')) {
+                        return Response::json(['status' => 'fail', 'message' => '请先设置【码支付】必要参数']);
+                    }
+                    break;
+                case 'epay':
+                    if (!sysConfig('epay_url') || !sysConfig('epay_mch_id') || !sysConfig('epay_key')) {
+                        return Response::json(['status' => 'fail', 'message' => '请先设置【易支付】必要参数']);
+                    }
+                    break;
+                case 'payjs':
+                    if (!sysConfig('payjs_mch_id') || !sysConfig('payjs_key')) {
+                        return Response::json(['status' => 'fail', 'message' => '请先设置【PayJs】必要参数']);
+                    }
+                    break;
+                case 'bitpayx':
+                    if (!sysConfig('bitpay_secret')) {
+                        return Response::json(['status' => 'fail', 'message' => '请先设置【麻瓜宝】必要参数']);
+                    }
+                    break;
+                case 'paypal':
+                    if (!sysConfig('paypal_username') || !sysConfig('paypal_password') || !sysConfig('paypal_secret')) {
+                        return Response::json(['status' => 'fail', 'message' => '请先设置【PayPal】必要参数',]);
+                    }
+                    break;
+                default:
+                    return Response::json(['status' => 'fail', 'message' => '未知支付渠道']);
+            }
+        }
+
+        // 演示环境禁止修改特定配置项
+        if (config('app.demo')) {
+            $denyConfig = [
+                'website_url',
+                'min_rand_traffic',
+                'max_rand_traffic',
+                'push_bear_send_key',
+                'push_bear_qrcode',
+                'is_forbid_china',
+                'website_security_code',
+            ];
+
+            if (in_array($name, $denyConfig, true)) {
+                return Response::json(['status' => 'fail', 'message' => '演示环境禁止修改该配置']);
+            }
+        }
+
+        // 如果是返利比例,则需要除100
+        if ($name === 'referral_percent') {
+            $value = (int) $value / 100;
+        }
+
+        // 更新配置
+        Config::find($name)->update(['value' => $value]);
+
+        return Response::json(['status' => 'success', 'message' => '操作成功']);
+    }
+
+    // 推送通知测试
+    public function sendTestNotification(): JsonResponse
+    {
+        if (sysConfig('is_notification')) {
+            $result = PushNotification::send('这是测试的标题', 'ProxyPanel测试内容');
+            if ($result === false) {
+                return Response::json(['status' => 'fail', 'message' => '发送失败,请重新尝试!']);
+            }
+            switch (sysConfig('is_notification')) {
+                case 'serverChan':
+                    if (!$result['errno']) {
+                        return Response::json(['status' => 'success', 'message' => '发送成功,请查看手机是否收到推送消息',]);
+                    }
+
+                    return Response::json(['status' => 'fail', 'message' => $result ? $result['errmsg'] : '未知',]);
+                case 'bark':
+                    if ($result['code'] == 200) {
+                        return Response::json(['status' => 'success', 'message' => '发送成功,请查看手机是否收到推送消息',]);
+                    }
+
+                    return Response::json(['status' => 'fail', 'message' => $result['message']]);
+                default:
+            }
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '请先选择【日志通知】渠道']);
+    }
+}

+ 64 - 106
app/Http/Controllers/Admin/TicketController.php

@@ -11,7 +11,6 @@ use App\Models\Ticket;
 use App\Models\TicketReply;
 use App\Models\User;
 use Auth;
-use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Mail;
 use Response;
@@ -27,168 +26,127 @@ class TicketController extends Controller
 {
 
     // 工单列表
-    public function ticketList(Request $request)
+    public function index(Request $request)
     {
         $email = $request->input('email');
 
         $query = Ticket::whereIn('admin_id', [0, Auth::id()]);
 
         if (isset($email)) {
-            $query->whereHas(
-                'user',
-                static function ($q) use ($email) {
-                    $q->where('email', 'like', '%' . $email . '%');
-                }
-            );
+            $query->whereHas('user', static function ($q) use ($email) {
+                $q->where('email', 'like', '%'.$email.'%');
+            });
         }
 
-        $view['ticketList'] = $query->latest()->paginate(10)->appends(
-            $request->except('page')
-        );
+        $view['ticketList'] = $query->latest()->paginate(10)->appends($request->except('page'));
 
-        return view('admin.ticket.ticketList', $view);
+        return view('admin.ticket.index', $view);
     }
 
     // 创建工单
-    public function createTicket(Request $request): ?JsonResponse
+    public function store(Request $request)
     {
-        $id      = $request->input('id');
-        $email   = $request->input('email');
-        $title   = $request->input('title');
+        $id = $request->input('id');
+        $email = $request->input('email');
+        $title = $request->input('title');
         $content = $request->input('content');
 
         $user = User::find($id) ?: User::whereEmail($email)->first();
 
-        if ( ! $user) {
+        if (!$user) {
             return Response::json(['status' => 'fail', 'message' => '用户不存在']);
         }
 
-        if ($user == Auth::user()) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '不能对自己发起工单']
-            );
+        if ($user === Auth::user()) {
+            return Response::json(['status' => 'fail', 'message' => '不能对自己发起工单']);
         }
 
         if (empty($title) || empty($content)) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '请输入标题和内容']
-            );
+            return Response::json(['status' => 'fail', 'message' => '请输入标题和内容']);
         }
 
-        $obj           = new Ticket();
-        $obj->user_id  = $user->id;
+        $obj = new Ticket();
+        $obj->user_id = $user->id;
         $obj->admin_id = Auth::id();
-        $obj->title    = $title;
-        $obj->content  = $content;
-        $obj->status   = 0;
+        $obj->title = $title;
+        $obj->content = $content;
+        $obj->status = 0;
         $obj->save();
 
         if ($obj->id) {
-            return Response::json(
-                ['status' => 'success', 'message' => '工单创建成功']
-            );
+            return Response::json(['status' => 'success', 'message' => '工单创建成功']);
         }
 
         return Response::json(['status' => 'fail', 'message' => '工单创建失败']);
     }
 
+    // 回复
+    public function edit($id)
+    {
+        $view['ticket'] = Ticket::find($id);
+        $view['replyList'] = TicketReply::whereTicketId($id)->oldest()->get();
+
+        return view('admin.ticket.reply', $view);
+    }
+
     // 回复工单
-    public function replyTicket(Request $request)
+    public function update(Request $request, $id)
     {
-        $id = $request->input('id');
+        $content = substr(str_replace(["atob", "eval"], "", clean($request->input('content'))), 0, 300);
 
-        if ($request->isMethod('POST')) {
-            $content = clean($request->input('content'));
-            $content = str_replace(["atob", "eval"], "", $content);
-            $content = substr($content, 0, 300);
-
-            $obj            = new TicketReply();
-            $obj->ticket_id = $id;
-            $obj->admin_id  = Auth::id();
-            $obj->content   = $content;
-            $obj->save();
-
-            if ($obj->id) {
-                // 将工单置为已回复
-                $ticket = Ticket::with('user')->whereId($id)->firstOrFail();
-                Ticket::whereId($id)->update(['status' => 1]);
-
-                $title   = "工单回复提醒";
-                $content = "标题:" . $ticket->title . "<br>管理员回复:" . $content;
-
-                // 发通知邮件
-                if ( ! Auth::getUser()->is_admin) {
-                    if (sysConfig('webmaster_email')) {
-                        $logId = Helpers::addNotificationLog(
-                            $title,
-                            $content,
-                            1,
-                            sysConfig(
-                                'webmaster_email'
-                            )
-                        );
-                        Mail::to(sysConfig('webmaster_email'))->send(
-                            new replyTicket($logId, $title, $content)
-                        );
-                    }
-                    // 推送通知管理员
-                    PushNotification::send($title, $content);
-                } else {
-                    $logId = Helpers::addNotificationLog(
-                        $title,
-                        $content,
-                        1,
-                        $ticket->user->email
-                    );
-                    Mail::to($ticket->user->email)->send(
-                        new replyTicket($logId, $title, $content)
-                    );
-                }
+        $obj = new TicketReply();
+        $obj->ticket_id = $id;
+        $obj->admin_id = Auth::id();
+        $obj->content = $content;
+        $obj->save();
 
-                return Response::json(
-                    ['status' => 'success', 'message' => '回复成功']
-                );
+        if ($obj->id) {
+            // 将工单置为已回复
+            $ticket = Ticket::with('user')->find($id);
+            Ticket::whereId($id)->update(['status' => 1]);
+
+            $title = "工单回复提醒";
+            $content = "标题:".$ticket->title."<br>管理员回复:".$content;
+
+            // 发通知邮件
+            if (!Auth::getUser()->is_admin) {
+                if (sysConfig('webmaster_email')) {
+                    $logId = Helpers::addNotificationLog($title, $content, 1, sysConfig('webmaster_email'));
+                    Mail::to(sysConfig('webmaster_email'))->send(new replyTicket($logId, $title, $content));
+                }
+                // 推送通知管理员
+                PushNotification::send($title, $content);
+            } else {
+                $logId = Helpers::addNotificationLog($title, $content, 1, $ticket->user->email);
+                Mail::to($ticket->user->email)->send(new replyTicket($logId, $title, $content));
             }
 
-            return Response::json(['status' => 'fail', 'message' => '回复失败']);
+            return Response::json(['status' => 'success', 'message' => '回复成功']);
         }
 
-        $view['ticket']    = Ticket::find($id);
-        $view['replyList'] = TicketReply::whereTicketId($id)->oldest()->get();
-
-        return view('admin.ticket.replyTicket', $view);
+        return Response::json(['status' => 'fail', 'message' => '回复失败']);
     }
 
     // 关闭工单
-    public function closeTicket(Request $request): JsonResponse
+    public function destroy($id)
     {
-        $id = $request->input('id');
-
         $ticket = Ticket::with('user')->whereId($id)->first();
-        if ( ! $ticket) {
+        if (!$ticket) {
             return Response::json(['status' => 'fail', 'message' => '关闭失败']);
         }
 
         $ret = Ticket::whereId($id)->update(['status' => 2]);
-        if ( ! $ret) {
+        if (!$ret) {
             return Response::json(['status' => 'fail', 'message' => '关闭失败']);
         }
 
-        $title   = "工单关闭提醒";
-        $content = "工单【" . $ticket->title . "】已关闭";
+        $title = "工单关闭提醒";
+        $content = "工单【".$ticket->title."】已关闭";
 
         // 发邮件通知用户
-        $logId = Helpers::addNotificationLog(
-            $title,
-            $content,
-            1,
-            $ticket->user->email
-        );
-        Mail::to($ticket->user->email)->send(
-            new closeTicket($logId, $title, $content)
-        );
+        $logId = Helpers::addNotificationLog($title, $content, 1, $ticket->user->email);
+        Mail::to($ticket->user->email)->send(new closeTicket($logId, $title, $content));
 
         return Response::json(['status' => 'success', 'message' => '关闭成功']);
     }
-
 }

+ 44 - 79
app/Http/Controllers/Admin/ToolsController.php

@@ -2,13 +2,11 @@
 
 namespace App\Http\Controllers\Admin;
 
-use App\Components\Helpers;
 use App\Components\IP;
 use App\Http\Controllers\Controller;
 use App\Models\User;
 use DB;
 use Exception;
-use Hash;
 use Illuminate\Http\Request;
 use Redirect;
 use Response;
@@ -16,7 +14,6 @@ use Session;
 
 class ToolsController extends Controller
 {
-
     // SS(R)链接反解析
     public function decompile(Request $request)
     {
@@ -24,15 +21,13 @@ class ToolsController extends Controller
             $content = $request->input('content');
 
             if (empty($content)) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '请在左侧填入要反解析的SS(R)链接']
-                );
+                return Response::json(['status' => 'fail', 'message' => '请在左侧填入要反解析的SS(R)链接']);
             }
 
             // 反解析处理
             $content = str_replace("\n", ",", $content);
             $content = explode(',', $content);
-            $txt     = '';
+            $txt = '';
             foreach ($content as $item) {
                 // 判断是SS还是SSR链接
                 $str = '';
@@ -42,15 +37,13 @@ class ToolsController extends Controller
                     $str = mb_substr($item, 5);
                 }
 
-                $txt .= "\r\n" . base64url_decode($str);
+                $txt .= "\r\n".base64url_decode($str);
             }
 
             // 生成转换好的JSON文件
             file_put_contents(public_path('downloads/decompile.json'), $txt);
 
-            return Response::json(
-                ['status' => 'success', 'data' => $txt, 'message' => '反解析成功']
-            );
+            return Response::json(['status' => 'success', 'data' => $txt, 'message' => '反解析成功']);
         }
 
         return view('admin.tools.decompile');
@@ -60,29 +53,22 @@ class ToolsController extends Controller
     public function convert(Request $request)
     {
         if ($request->isMethod('POST')) {
-            $method          = $request->input('method');
+            $method = $request->input('method');
             $transfer_enable = $request->input('transfer_enable');
-            $protocol        = $request->input('protocol');
-            $protocol_param  = $request->input('protocol_param');
-            $obfs            = $request->input('obfs');
-            $obfs_param      = $request->input('obfs_param');
-            $content         = $request->input('content');
+            $protocol = $request->input('protocol');
+            $protocol_param = $request->input('protocol_param');
+            $obfs = $request->input('obfs');
+            $obfs_param = $request->input('obfs_param');
+            $content = $request->input('content');
 
             if (empty($content)) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '请在左侧填入要转换的内容']
-                );
+                return Response::json(['status' => 'fail', 'message' => '请在左侧填入要转换的内容']);
             }
 
             // 校验格式
             $content = json_decode($content, true);
             if (empty($content->port_password)) {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => '转换失败:配置信息里缺少【port_password】字段,或者该字段为空',
-                    ]
-                );
+                return Response::json(['status' => 'fail', 'message' => '转换失败:配置信息里缺少【port_password】字段,或者该字段为空']);
             }
 
             // 转换成SSR格式JSON
@@ -99,8 +85,8 @@ class ToolsController extends Controller
                     'port'            => $port,
                     'protocol'        => $protocol,
                     'protocol_param'  => empty($protocol_param) ? "" : $protocol_param,
-                    'transfer_enable' => toGB($transfer_enable),
-                    'user'            => date('Ymd') . '_IMPORT_' . $port,
+                    'transfer_enable' => $transfer_enable,
+                    'user'            => date('Ymd').'_IMPORT_'.$port,
                 ];
             }
 
@@ -109,16 +95,9 @@ class ToolsController extends Controller
             // 生成转换好的JSON文件
             file_put_contents(public_path('downloads/convert.json'), $json);
 
-            return Response::json(
-                ['status' => 'success', 'data' => $json, 'message' => '转换成功']
-            );
+            return Response::json(['status' => 'success', 'data' => $json, 'message' => '转换成功']);
         }
 
-        // 加密方式、协议、混淆
-        $view['methodList']   = Helpers::methodList();
-        $view['protocolList'] = Helpers::protocolList();
-        $view['obfsList']     = Helpers::obfsList();
-
         return view('admin.tools.convert', $view);
     }
 
@@ -136,7 +115,7 @@ class ToolsController extends Controller
             $filePath = public_path('downloads/decompile.json');
         }
 
-        if ( ! file_exists($filePath)) {
+        if (!file_exists($filePath)) {
             exit('文件不存在,请检查目录权限');
         }
 
@@ -147,7 +126,7 @@ class ToolsController extends Controller
     public function import(Request $request)
     {
         if ($request->isMethod('POST')) {
-            if ( ! $request->hasFile('uploadFile')) {
+            if (!$request->hasFile('uploadFile')) {
                 Session::flash('errorMsg', '请选择要上传的文件');
 
                 return Redirect::back();
@@ -156,28 +135,26 @@ class ToolsController extends Controller
             $file = $request->file('uploadFile');
 
             // 只能上传JSON文件
-            if ($file->getClientMimeType(
-                ) !== 'application/json' || $file->getClientOriginalExtension(
-                ) !== 'json') {
+            if ($file->getClientMimeType() !== 'application/json' || $file->getClientOriginalExtension() !== 'json') {
                 Session::flash('errorMsg', '只允许上传JSON文件');
 
                 return Redirect::back();
             }
 
-            if ( ! $file->isValid()) {
+            if (!$file->isValid()) {
                 Session::flash('errorMsg', '产生未知错误,请重新上传');
 
                 return Redirect::back();
             }
 
             $save_path = realpath(storage_path('uploads'));
-            $new_name  = md5($file->getClientOriginalExtension()) . '.json';
+            $new_name = md5($file->getClientOriginalExtension()).'.json';
             $file->move($save_path, $new_name);
 
             // 读取文件内容
-            $data = file_get_contents($save_path . '/' . $new_name);
+            $data = file_get_contents($save_path.'/'.$new_name);
             $data = json_decode($data, true);
-            if ( ! $data) {
+            if (!$data) {
                 Session::flash('errorMsg', '内容格式解析异常,请上传符合SSR(R)配置规范的JSON文件');
 
                 return Redirect::back();
@@ -186,21 +163,21 @@ class ToolsController extends Controller
             try {
                 DB::beginTransaction();
                 foreach ($data as $user) {
-                    $obj                  = new User();
-                    $obj->username        = $user->user;
-                    $obj->email           = $user->user;
-                    $obj->password        = Hash::make('123456');
-                    $obj->port            = $user->port;
-                    $obj->passwd          = $user->passwd;
-                    $obj->vmess_id        = $user->uuid;
+                    $obj = new User();
+                    $obj->username = $user->user;
+                    $obj->email = $user->user;
+                    $obj->password = '123456';
+                    $obj->port = $user->port;
+                    $obj->passwd = $user->passwd;
+                    $obj->vmess_id = $user->uuid;
                     $obj->transfer_enable = $user->transfer_enable;
-                    $obj->method          = $user->method;
-                    $obj->protocol        = $user->protocol;
-                    $obj->obfs            = $user->obfs;
-                    $obj->expired_at      = '2099-01-01';
-                    $obj->reg_ip          = IP::getClientIp();
-                    $obj->created_at      = date('Y-m-d H:i:s');
-                    $obj->updated_at      = date('Y-m-d H:i:s');
+                    $obj->method = $user->method;
+                    $obj->protocol = $user->protocol;
+                    $obj->obfs = $user->obfs;
+                    $obj->expired_at = '2099-01-01';
+                    $obj->reg_ip = IP::getClientIp();
+                    $obj->created_at = date('Y-m-d H:i:s');
+                    $obj->updated_at = date('Y-m-d H:i:s');
                     $obj->save();
                 }
 
@@ -225,8 +202,8 @@ class ToolsController extends Controller
     public function analysis()
     {
         $file = storage_path('app/ssserver.log');
-        if ( ! file_exists($file)) {
-            Session::flash('analysisErrorMsg', $file . ' 不存在,请先创建文件');
+        if (!file_exists($file)) {
+            Session::flash('analysisErrorMsg', $file.' 不存在,请先创建文件');
 
             return view('admin.tools.analysis');
         }
@@ -242,24 +219,13 @@ class ToolsController extends Controller
                 }
 
                 preg_match('/TCP request (\w+\.){2}\w+/', $log, $tcp_matches);
-                if ( ! empty($tcp_matches)) {
-                    $url[] = str_replace(
-                        'TCP request ',
-                        '[TCP] ',
-                        $tcp_matches[0]
-                    );
+                if (!empty($tcp_matches)) {
+                    $url[] = str_replace('TCP request ', '[TCP] ', $tcp_matches[0]);
                 } else {
-                    preg_match(
-                        '/UDP data to (25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)/',
-                        $log,
-                        $udp_matches
-                    );
-                    if ( ! empty($udp_matches)) {
-                        $url[] = str_replace(
-                            'UDP data to ',
-                            '[UDP] ',
-                            $udp_matches[0]
-                        );
+                    preg_match('/UDP data to (25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)/',
+                        $log, $udp_matches);
+                    if (!empty($udp_matches)) {
+                        $url[] = str_replace('UDP data to ', '[UDP] ', $udp_matches[0]);
                     }
                 }
             }
@@ -269,5 +235,4 @@ class ToolsController extends Controller
 
         return view('admin.tools.analysis', $view);
     }
-
 }

+ 378 - 0
app/Http/Controllers/Admin/UserController.php

@@ -0,0 +1,378 @@
+<?php
+
+namespace App\Http\Controllers\Admin;
+
+use App\Components\Helpers;
+use App\Components\IP;
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Admin\UserStoreRequest;
+use App\Http\Requests\Admin\UserUpdateRequest;
+use App\Models\Level;
+use App\Models\Node;
+use App\Models\User;
+use App\Models\UserGroup;
+use App\Models\UserHourlyDataFlow;
+use App\Services\UserService;
+use Auth;
+use DB;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Redirect;
+use Response;
+use Session;
+use Str;
+
+class UserController extends Controller
+{
+    // 用户列表
+    public function index(Request $request)
+    {
+        $id = $request->input('id');
+        $email = $request->input('email');
+        $wechat = $request->input('wechat');
+        $qq = $request->input('qq');
+        $port = $request->input('port');
+        $status = $request->input('status');
+        $enable = $request->input('enable');
+        $online = $request->input('online');
+        $flowAbnormal = $request->input('flowAbnormal');
+        $expireWarning = $request->input('expireWarning');
+        $largeTraffic = $request->input('largeTraffic');
+
+        $query = User::with('subscribe');
+        if (isset($id)) {
+            $query->whereId($id);
+        }
+
+        if (isset($email)) {
+            $query->where('email', 'like', '%'.$email.'%');
+        }
+
+        if (isset($wechat)) {
+            $query->where('wechat', 'like', '%'.$wechat.'%');
+        }
+
+        if (isset($qq)) {
+            $query->where('qq', 'like', '%'.$qq.'%');
+        }
+
+        if (isset($port)) {
+            $query->wherePort($port);
+        }
+
+        if (isset($status)) {
+            $query->whereStatus($status);
+        }
+
+        if (isset($enable)) {
+            $query->whereEnable($enable);
+        }
+
+        // 流量超过100G的
+        if ($largeTraffic) {
+            $query->whereIn('status', [0, 1])->whereRaw('(u + d) >= 107374182400');
+        }
+
+        // 临近过期提醒
+        if ($expireWarning) {
+            $query->whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime("+".sysConfig('expire_days')." days"))]);
+        }
+
+        // 当前在线
+        if ($online) {
+            $query->where('t', '>=', strtotime("-10 minutes"));
+        }
+
+        // 不活跃用户
+        if ($request->input('unActive')) {
+            $query->whereBetween('t', [1, strtotime("-".sysConfig('expire_days')." days"),])->whereEnable(1);
+        }
+
+        // 1小时内流量异常用户
+        if ($flowAbnormal) {
+            $query->whereIn('id', $this->trafficAbnormal());
+        }
+
+        $userList = $query->orderByDesc('id')->paginate(15)->appends($request->except('page'));
+        foreach ($userList as $user) {
+            $user->used_flow = flowAutoShow($user->u + $user->d);
+            if ($user->expired_at < date('Y-m-d')) {
+                $user->expireWarning = -1; // 已过期
+            } elseif ($user->expired_at == date('Y-m-d')) {
+                $user->expireWarning = 0; // 今天过期
+            } elseif ($user->expired_at > date('Y-m-d') && $user->expired_at <= date('Y-m-d', strtotime("+30 days"))) {
+                $user->expireWarning = 1; // 最近一个月过期
+            } else {
+                $user->expireWarning = 2; // 大于一个月过期
+            }
+
+            // 流量异常警告
+            $totalTraffic = UserHourlyDataFlow::userRecentUsed($user->id)->sum('total');
+            $user->trafficWarning = $totalTraffic > (sysConfig('traffic_ban_value') * GB) ? 1 : 0;
+
+            // 订阅地址
+            $user->link = (sysConfig('subscribe_domain') ?: sysConfig('website_url')).'/s/'.$user->subscribe->code;
+        }
+
+        $view['userList'] = $userList;
+
+        return view('admin.user.index', $view);
+    }
+
+    // 1小时内流量异常用户
+    private function trafficAbnormal(): array
+    {
+        $userTotalTrafficList = UserHourlyDataFlow::whereNodeId(0)
+            ->where('total', '>', MB * 50)
+            ->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))
+            ->groupBy('user_id')
+            ->selectRaw("user_id, sum(total) as totalTraffic")->pluck('totalTraffic', 'user_id')
+            ->toArray(); // 只统计50M以上的记录,加快速度
+        foreach ($userTotalTrafficList as $user) {
+            if ($user->totalTraffic > sysConfig('traffic_ban_value') * GB) {
+                $result[] = $user->user_id;
+            }
+        }
+
+        return $result ?? [];
+    }
+
+    // 添加账号页面
+    public function create()
+    {
+        // 生成一个可用端口
+        $view['methodList'] = Helpers::methodList();
+        $view['protocolList'] = Helpers::protocolList();
+        $view['obfsList'] = Helpers::obfsList();
+        $view['levelList'] = Level::orderBy('level')->get();
+        $view['groupList'] = UserGroup::orderBy('id')->get();
+
+        return view('admin.user.info', $view);
+    }
+
+    // 添加账号
+    public function store(UserStoreRequest $request): JsonResponse
+    {
+        try {
+            $data = $request->except('_token', 'uuid');
+            $data['password'] = $data['password'] ?? Str::random();
+            $data['port'] = $data['port'] ?? Helpers::getPort();
+            $data['passwd'] = $data['passwd'] ?? Str::random();
+            $data['vmess_id'] = $request->input('uuid') ?? Str::uuid();
+            $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', 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;
+            $user = User::create($data);
+
+            if ($user) {
+                // 写入用户流量变动记录
+                Helpers::addUserTrafficModifyLog($user->id, 0, 0, $data['transfer_enable'], '后台手动添加用户');
+
+                return Response::json(['status' => 'success', 'message' => '添加成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('添加用户错误:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => $e->getMessage()]);
+        }
+
+
+        return Response::json(['status' => 'fail', 'message' => '添加失败']);
+    }
+
+    // 编辑账号页面
+    public function edit($id)
+    {
+        $user = User::find($id);
+
+        $view['user'] = $user->load('inviter:id,email');
+        $view['methodList'] = Helpers::methodList();
+        $view['protocolList'] = Helpers::protocolList();
+        $view['obfsList'] = Helpers::obfsList();
+        $view['levelList'] = Level::orderBy('level')->get();
+        $view['groupList'] = UserGroup::orderBy('id')->get();
+
+        return view('admin.user.info', $view);
+    }
+
+    // 编辑账号
+    public function update(UserUpdateRequest $request, $id)
+    {
+        $user = User::find($id);
+
+        try {
+            $data = $request->except('_token', 'password', 'uuid', 'password', 'is_admin');
+            $data['passwd'] = $request->input('passwd') ?? Str::random();
+            $data['vmess_id'] = $request->input('uuid') ?? Str::uuid();
+            $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['remark'] = str_replace(["atob", "eval"], "", $data['remark']);
+
+            // 只有admin才有权限操作管理员属性
+            if (Auth::getUser()->is_admin === 1) {
+                $data['is_admin'] = (int) $request->input('is_admin');
+            }
+
+            // 非演示环境才可以修改管理员密码
+            $password = $request->input('password');
+            if (!empty($password) && !(env('APP_DEMO') && $id === 1)) {
+                $data['password'] = $password;
+            }
+
+            // 写入用户流量变动记录
+            if ($user->transfer_enable !== $data['transfer_enable']) {
+                Helpers::addUserTrafficModifyLog($id, 0, $user->transfer_enable, $data['transfer_enable'], '后台手动编辑用户');
+            }
+
+            if ($user->update($data)) {
+                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('编辑用户信息异常:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '编辑用户信息错误:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+    }
+
+    // 删除用户
+    public function destroy($id)
+    {
+        if ($id <= 1) {
+            return Response::json(['status' => 'fail', 'message' => '系统管理员不可删除']);
+        }
+
+        try {
+            DB::beginTransaction();
+
+            User::find($id)->delete();
+
+            DB::commit();
+
+            return Response::json(['status' => 'success', 'message' => '删除成功']);
+        } catch (Exception $e) {
+            Log::error('删除用户信息异常:'.$e->getMessage());
+            DB::rollBack();
+
+            return Response::json(['status' => 'fail', 'message' => '删除失败']);
+        }
+    }
+
+    // 批量生成账号
+    public function batchAddUsers(Request $request)
+    {
+        try {
+            DB::beginTransaction();
+
+            for ($i = 0; $i < $request->input('amount', 1); $i++) {
+                $uid = Helpers::addUser(Str::random(8).'@auto.generate', Str::random(), 1024 * GB, 365);
+
+                if ($uid) {
+                    // 写入用户流量变动记录
+                    Helpers::addUserTrafficModifyLog($uid, 0, 0, 1024 * GB, '后台批量生成用户');
+                }
+            }
+
+            DB::commit();
+
+            return Response::json(['status' => 'success', 'message' => '批量生成账号成功']);
+        } catch (Exception $e) {
+            DB::rollBack();
+
+            return Response::json(['status' => 'fail', 'message' => '批量生成账号失败:'.$e->getMessage()]);
+        }
+    }
+
+    // 转换成某个用户的身份
+    public function switchToUser(Request $request): JsonResponse
+    {
+        $id = $request->input('user_id');
+
+        $user = User::find($id);
+        if (!$user) {
+            return Response::json(['status' => 'fail', 'message' => "用户不存在"]);
+        }
+
+        // 存储当前管理员ID,并将当前登录信息改成要切换的用户的身份信息
+        Session::put('admin', Auth::id());
+        Auth::login($user);
+
+        return Response::json(['status' => 'success', 'message' => "身份切换成功"]);
+    }
+
+    // 重置用户流量
+    public function resetTraffic(Request $request): JsonResponse
+    {
+        try {
+            User::find($request->input('id'))->update(['u' => 0, 'd' => 0]);
+        } catch (Exception $e) {
+            Log::error('流量重置失败:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '流量重置失败']);
+        }
+
+        return Response::json(['status' => 'success', 'message' => '流量重置成功']);
+    }
+
+    // 操作用户余额
+    public function handleUserCredit(Request $request): JsonResponse
+    {
+        $userId = $request->input('user_id');
+        $amount = $request->input('amount');
+
+        if (empty($userId) || empty($amount)) {
+            return Response::json(['status' => 'fail', 'message' => '充值异常']);
+        }
+        $user = User::find($userId);
+
+        // 加减余额
+        if ((new UserService($user))->updateCredit($amount)) {
+            Helpers::addUserCreditLog($userId, 0, $user->credit, $user->credit + $amount, $amount, '后台手动充值');  // 写入余额变动日志
+
+            return Response::json(['status' => 'success', 'message' => '充值成功']);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '充值失败']);
+    }
+
+    // 导出配置信息
+    public function export(Request $request, $id)
+    {
+        if (empty($id)) {
+            return Redirect::back();
+        }
+
+        $user = User::find($id);
+        if (empty($user)) {
+            return Redirect::back();
+        }
+
+        $view['nodeList'] = Node::whereStatus(1)->orderByDesc('sort')->orderBy('id')->paginate(15)->appends($request->except('page'));
+        $view['user'] = $user;
+
+        return view('admin.user.export', $view);
+    }
+
+    public function exportProxyConfig(Request $request, $id): JsonResponse
+    {
+        $node = Node::find($id);
+        if ($node->type === 1) {
+            if ($node->compatible) {
+                $proxyType = 'SS';
+            } else {
+                $proxyType = 'SSR';
+            }
+        } else {
+            $proxyType = 'V2Ray';
+        }
+
+        $data = $this->getUserNodeInfo($id, $node->id, $request->input('type') !== 'text' ? 0 : 1);
+
+        return Response::json(['status' => 'success', 'data' => $data, 'title' => $proxyType]);
+    }
+}

+ 11 - 30
app/Http/Controllers/Admin/UserGroupController.php

@@ -16,12 +16,9 @@ use Validator;
 
 class UserGroupController extends Controller
 {
-
     public function index(Request $request)
     {
-        $view['list'] = UserGroup::paginate(15)->appends(
-            $request->except('page')
-        );
+        $view['list'] = UserGroup::paginate(15)->appends($request->except('page'));
 
         return view('admin.user.group.index', $view);
     }
@@ -37,27 +34,16 @@ class UserGroupController extends Controller
     // 添加用户分组
     public function store(Request $request): RedirectResponse
     {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'name'  => 'required',
-                'nodes' => 'required',
-            ]
-        );
+        $validator = Validator::make($request->all(), ['name' => 'required', 'nodes' => 'required',]);
 
         if ($validator->fails()) {
-            return Redirect::back()->withInput()->withErrors(
-                $validator->errors()
-            );
+            return Redirect::back()->withInput()->withErrors($validator->errors());
         }
 
-        $obj        = new UserGroup();
-        $obj->name  = $request->input('name');
-        $obj->nodes = $request->input('nodes');
-        $obj->save();
+        $userGroup = UserGroup::create(['name' => $request->input('name'), 'nodes' => $request->input('nodes')]);
 
-        if ($obj->id) {
-            return Redirect::back()->with('successMsg', '操作成功');
+        if ($userGroup) {
+            return Redirect::to(route('admin.user.group.edit', $userGroup->id))->with('successMsg', '操作成功');
         }
 
         return Redirect::back()->withInput()->withErrors('操作失败');
@@ -67,7 +53,7 @@ class UserGroupController extends Controller
     public function edit($id)
     {
         $view['userGroup'] = UserGroup::findOrFail($id);
-        $view['nodeList']  = Node::whereStatus(1)->get();
+        $view['nodeList'] = Node::whereStatus(1)->get();
 
         return view('admin.user.group.info', $view);
     }
@@ -75,8 +61,8 @@ class UserGroupController extends Controller
     // 编辑用户分组
     public function update(Request $request, $id)
     {
-        $userGroup        = UserGroup::findOrFail($id);
-        $userGroup->name  = $request->input('name');
+        $userGroup = UserGroup::findOrFail($id);
+        $userGroup->name = $request->input('name');
         $userGroup->nodes = $request->input('nodes');
         if ($userGroup->save()) {
             return Redirect::back()->with('successMsg', '操作成功');
@@ -90,20 +76,15 @@ class UserGroupController extends Controller
     {
         // 校验该分组下是否存在关联账号
         if (User::whereGroupId($id)->count()) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '该分组下存在关联账号,请先取消关联!']
-            );
+            return Response::json(['status' => 'fail', 'message' => '该分组下存在关联账号,请先取消关联!']);
         }
 
         try {
             UserGroup::whereId($id)->delete();
         } catch (Exception $e) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '删除失败,' . $e->getMessage()]
-            );
+            return Response::json(['status' => 'fail', 'message' => '删除失败,'.$e->getMessage()]);
         }
 
         return Response::json(['status' => 'success', 'message' => '清理成功']);
     }
-
 }

File diff suppressed because it is too large
+ 41 - 1383
app/Http/Controllers/AdminController.php


+ 34 - 57
app/Http/Controllers/Api/WebApi/BaseController.php

@@ -23,19 +23,19 @@ class BaseController
     // 上报节点心跳信息
     public function setNodeStatus(Request $request, $id): JsonResponse
     {
-        $cpu  = (int)$request->input('cpu') / 100;
-        $mem  = (int)$request->input('mem') / 100;
-        $disk = (int)$request->input('disk') / 100;
+        $cpu = (int) $request->input('cpu') / 100;
+        $mem = (int) $request->input('mem') / 100;
+        $disk = (int) $request->input('disk') / 100;
 
         if (is_null($request->input('uptime'))) {
             return $this->returnData('上报节点心跳信息失败,请检查字段');
         }
 
-        $obj          = new NodeHeartBeat();
+        $obj = new NodeHeartBeat();
         $obj->node_id = $id;
-        $obj->uptime  = (int)$request->input('uptime');
+        $obj->uptime = (int) $request->input('uptime');
         //$obj->load = $request->input('load');
-        $obj->load     = implode(' ', [$cpu, $mem, $disk]);
+        $obj->load = implode(' ', [$cpu, $mem, $disk]);
         $obj->log_time = time();
         $obj->save();
 
@@ -47,15 +47,9 @@ class BaseController
     }
 
     // 返回数据
-    public function returnData(
-        $message,
-        $status = 'fail',
-        $code = 400,
-        $data = [],
-        $addition = []
-    ): JsonResponse {
+    public function returnData($message, $status = 'fail', $code = 400, $data = [], $addition = []): JsonResponse
+    {
         $etag = Helpers::abortIfNotModified($data);
-
         $data = [
             'status'  => $status,
             'code'    => $code,
@@ -73,38 +67,35 @@ class BaseController
     // 上报节点在线人数
     public function setNodeOnline(Request $request, $id): JsonResponse
     {
-        $inputArray  = $request->all();
+        $inputArray = $request->all();
         $onlineCount = 0;
         foreach ($inputArray as $input) {
-            if ( ! array_key_exists('ip', $input) || ! array_key_exists(
-                    'uid',
-                    $input
-                )) {
+            if (!array_key_exists('ip', $input) || !array_key_exists('uid', $input)) {
                 return $this->returnData('上报节点在线情况失败,请检查字段');
             }
 
-            if ( ! isset($input['ip'], $input['uid'])) {
+            if (!isset($input['ip'], $input['uid'])) {
                 return $this->returnData('上报节点在线情况失败,请检查字段');
             }
 
-            $obj             = new NodeOnlineUserIp();
-            $obj->node_id    = $id;
-            $obj->user_id    = $input['uid'];
-            $obj->ip         = $input['ip'];
-            $obj->port       = User::find($input['uid'])->port;
+            $obj = new NodeOnlineUserIp();
+            $obj->node_id = $id;
+            $obj->user_id = $input['uid'];
+            $obj->ip = $input['ip'];
+            $obj->port = User::find($input['uid'])->port;
             $obj->created_at = time();
             $obj->save();
 
-            if ( ! $obj->id) {
+            if (!$obj->id) {
                 return $this->returnData('上报节点在线情况失败,请检查字段');
             }
             $onlineCount++;
         }
 
-        $obj              = new NodeOnlineLog();
-        $obj->node_id     = $id;
+        $obj = new NodeOnlineLog();
+        $obj->node_id = $id;
         $obj->online_user = $onlineCount;
-        $obj->log_time    = time();
+        $obj->log_time = time();
         $obj->save();
 
         if ($obj->id) {
@@ -118,23 +109,23 @@ class BaseController
     public function setUserTraffic(Request $request, $id): JsonResponse
     {
         foreach ($request->all() as $input) {
-            if ( ! array_key_exists('uid', $input)) {
+            if (!array_key_exists('uid', $input)) {
                 return $this->returnData('上报用户流量日志失败,请检查字段');
             }
 
             $rate = Node::find($id)->traffic_rate;
 
-            $log           = new UserDataFlowLog();
-            $log->user_id  = (int)$input['uid'];
-            $log->u        = (int)$input['upload'] * $rate;
-            $log->d        = (int)$input['download'] * $rate;
-            $log->node_id  = $id;
-            $log->rate     = $rate;
-            $log->traffic  = flowAutoShow($log->u + $log->d);
+            $log = new UserDataFlowLog();
+            $log->user_id = (int) $input['uid'];
+            $log->u = (int) $input['upload'] * $rate;
+            $log->d = (int) $input['download'] * $rate;
+            $log->node_id = $id;
+            $log->rate = $rate;
+            $log->traffic = flowAutoShow($log->u + $log->d);
             $log->log_time = time();
             $log->save();
 
-            if ( ! $log->id) {
+            if (!$log->id) {
                 return $this->returnData('上报用户流量日志失败,请检查字段');
             }
             $user = User::find($log->user_id);
@@ -153,7 +144,7 @@ class BaseController
     public function getNodeRule($id): JsonResponse
     {
         $nodeRule = RuleGroupNode::whereNodeId($id)->first();
-        $data     = [];
+        $data = [];
         //节点未设置任何审计规则
         if ($nodeRule) {
             $ruleGroup = RuleGroup::find($nodeRule->rule_group_id);
@@ -169,36 +160,23 @@ class BaseController
                     }
                 }
 
-                return $this->returnData(
-                    '获取节点审计规则成功',
-                    'success',
-                    200,
-                    [
-                        'mode'  => $ruleGroup->type ? 'reject' : 'allow',
-                        'rules' => $data,
-                    ]
-                );
+                return $this->returnData('获取节点审计规则成功', 'success', 200, ['mode' => $ruleGroup->type ? 'reject' : 'allow', 'rules' => $data]);
             }
         }
 
         //放行
-        return $this->returnData(
-            '获取节点审计规则成功',
-            'success',
-            200,
-            ['mode' => 'all', 'rules' => $data]
-        );
+        return $this->returnData('获取节点审计规则成功', 'success', 200, ['mode' => 'all', 'rules' => $data]);
     }
 
     // 上报用户触发的审计规则记录
     public function addRuleLog(Request $request, $id): JsonResponse
     {
         if ($request->has(['uid', 'rule_id', 'reason'])) {
-            $obj          = new RuleLog();
+            $obj = new RuleLog();
             $obj->user_id = $request->input('uid');
             $obj->node_id = $id;
             $obj->rule_id = $request->input('rule_id');
-            $obj->reason  = $request->input('reason');
+            $obj->reason = $request->input('reason');
             $obj->save();
 
             if ($obj->id) {
@@ -208,5 +186,4 @@ class BaseController
 
         return $this->returnData('上报用户触发审计规则记录失败');
     }
-
 }

+ 13 - 26
app/Http/Controllers/Api/WebApi/TrojanController.php

@@ -7,35 +7,29 @@ use Illuminate\Http\JsonResponse;
 
 class TrojanController extends BaseController
 {
-
     // 获取节点信息
     public function getNodeInfo($id): JsonResponse
     {
         $node = Node::find($id);
 
-        return $this->returnData(
-            '获取节点信息成功',
-            'success',
-            200,
-            [
-                'id'           => $node->id,
-                'is_udp'       => $node->is_udp ? true : false,
-                'speed_limit'  => $node->speed_limit,
-                'client_limit' => $node->client_limit,
-                'push_port'    => $node->push_port,
-                'redirect_url' => sysConfig('redirect_url'),
-                'trojan_port'  => $node->port,
-                'secret'       => $node->auth->secret,
-                'license'      => sysConfig('trojan_license'),
-            ]
-        );
+        return $this->returnData('获取节点信息成功', 'success', 200, [
+            'id'           => $node->id,
+            'is_udp'       => $node->is_udp ? true : false,
+            'speed_limit'  => $node->speed_limit,
+            'client_limit' => $node->client_limit,
+            'push_port'    => $node->push_port,
+            'redirect_url' => sysConfig('redirect_url'),
+            'trojan_port'  => $node->port,
+            'secret'       => $node->auth->secret,
+            'license'      => sysConfig('trojan_license'),
+        ]);
     }
 
     // 获取节点可用的用户列表
     public function getUserList($id): JsonResponse
     {
         $users = Node::find($id)->node_access_users;
-        $data  = [];
+        $data = [];
 
         foreach ($users as $user) {
             $data[] = [
@@ -45,13 +39,6 @@ class TrojanController extends BaseController
             ];
         }
 
-        return $this->returnData(
-            '获取用户列表成功',
-            'success',
-            200,
-            $data,
-            ['updateTime' => time()]
-        );
+        return $this->returnData('获取用户列表成功', 'success', 200, $data, ['updateTime' => time()]);
     }
-
 }

+ 12 - 28
app/Http/Controllers/Api/WebApi/V2RayController.php

@@ -9,18 +9,13 @@ use Illuminate\Http\Request;
 
 class V2RayController extends BaseController
 {
-
     // 获取节点信息
     public function getNodeInfo($id): JsonResponse
     {
-        $node   = Node::find($id);
+        $node = Node::find($id);
         $nodeDv = NodeCertificate::whereDomain($node->v2_host)->first();
 
-        return $this->returnData(
-            '获取节点信息成功',
-            'success',
-            200,
-            [
+        return $this->returnData('获取节点信息成功', 'success', 200, [
                 'id'              => $node->id,
                 'is_udp'          => $node->is_udp ? true : false,
                 'speed_limit'     => $node->speed_limit,
@@ -28,8 +23,8 @@ class V2RayController extends BaseController
                 'push_port'       => $node->push_port,
                 'redirect_url'    => sysConfig('redirect_url'),
                 'secret'          => $node->auth->secret,
-                'key'             => $nodeDv ? $nodeDv->key : '',
-                'pem'             => $nodeDv ? $nodeDv->pem : '',
+                'key'             => $nodeDv->key ?? '',
+                'pem'             => $nodeDv->pem ?? '',
                 'v2_license'      => sysConfig('v2ray_license'),
                 'v2_alter_id'     => $node->v2_alter_id,
                 'v2_port'         => $node->v2_port,
@@ -39,9 +34,7 @@ class V2RayController extends BaseController
                 'v2_host'         => $node->v2_host,
                 'v2_path'         => $node->v2_path,
                 'v2_tls'          => $node->v2_tls ? true : false,
-                'v2_tls_provider' => $node->tls_provider ?: sysConfig(
-                    'v2ray_tls_provider'
-                ),
+                'v2_tls_provider' => $node->tls_provider ?: sysConfig('v2ray_tls_provider'),
             ]
         );
     }
@@ -50,7 +43,7 @@ class V2RayController extends BaseController
     public function getUserList($id): JsonResponse
     {
         $users = Node::find($id)->node_access_users;
-        $data  = [];
+        $data = [];
 
         foreach ($users as $user) {
             $data[] = [
@@ -60,13 +53,7 @@ class V2RayController extends BaseController
             ];
         }
 
-        return $this->returnData(
-            '获取用户列表成功',
-            'success',
-            200,
-            $data,
-            ['updateTime' => time()]
-        );
+        return $this->returnData('获取用户列表成功', 'success', 200, $data, ['updateTime' => time()]);
     }
 
     // 上报节点伪装域名证书信息
@@ -77,16 +64,14 @@ class V2RayController extends BaseController
 
         if ($request->has(['key', 'pem'])) {
             $node = Node::find($id);
-            $Dv   = NodeCertificate::whereDomain($node->v2_host)->first();
+            $Dv = NodeCertificate::whereDomain($node->v2_host)->first();
             if ($Dv) {
-                $ret = NodeCertificate::whereId($Dv->id)->update(
-                    ['key' => $key, 'pem' => $pem]
-                );
+                $ret = NodeCertificate::whereId($Dv->id)->update(['key' => $key, 'pem' => $pem]);
             } else {
-                $ret         = new NodeCertificate();
+                $ret = new NodeCertificate();
                 $ret->domain = $node->server;
-                $ret->key    = $request->input('key');
-                $ret->pem    = $request->input('pem');
+                $ret->key = $request->input('key');
+                $ret->pem = $request->input('pem');
                 $ret->save();
             }
 
@@ -97,5 +82,4 @@ class V2RayController extends BaseController
 
         return $this->returnData('上报节点伪装域名证书失败,请检查字段');
     }
-
 }

+ 7 - 18
app/Http/Controllers/Api/WebApi/VNetController.php

@@ -13,22 +13,18 @@ class VNetController extends BaseController
     {
         $node = Node::find($id);
 
-        return $this->returnData(
-            '获取节点信息成功',
-            'success',
-            200,
-            [
+        return $this->returnData('获取节点信息成功', 'success', 200, [
                 'id'           => $node->id,
                 'method'       => $node->method,
                 'protocol'     => $node->protocol,
                 'obfs'         => $node->obfs,
-                'obfs_param'   => $node->obfs_param ?: '',
+                'obfs_param'   => $node->obfs_param ?? '',
                 'is_udp'       => $node->is_udp,
                 'speed_limit'  => $node->speed_limit,
                 'client_limit' => $node->client_limit,
                 'single'       => $node->single,
-                'port'         => (string)$node->port,
-                'passwd'       => $node->passwd ?: '',
+                'port'         => (string) $node->port,
+                'passwd'       => $node->passwd ?? '',
                 'push_port'    => $node->push_port,
                 'secret'       => $node->auth->secret,
                 'redirect_url' => sysConfig('redirect_url'),
@@ -39,9 +35,9 @@ class VNetController extends BaseController
     // 获取节点可用的用户列表
     public function getUserList($id): JsonResponse
     {
-        $node  = Node::find($id);
+        $node = Node::find($id);
         $users = $node->node_access_users;
-        $data  = [];
+        $data = [];
 
         foreach ($users as $user) {
             $data[] = [
@@ -58,16 +54,9 @@ class VNetController extends BaseController
         }
 
         if ($data) {
-            return $this->returnData(
-                '获取用户列表成功',
-                'success',
-                200,
-                $data,
-                ['updateTime' => time()]
-            );
+            return $this->returnData('获取用户列表成功', 'success', 200, $data, ['updateTime' => time()]);
         }
 
         return $this->returnData('获取用户列表失败');
     }
-
 }

File diff suppressed because it is too large
+ 200 - 435
app/Http/Controllers/AuthController.php


+ 70 - 215
app/Http/Controllers/Controller.php

@@ -15,36 +15,16 @@ use Exception;
 use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
 use Illuminate\Foundation\Bus\DispatchesJobs;
 use Illuminate\Foundation\Validation\ValidatesRequests;
-use Illuminate\Http\UploadedFile;
 use Illuminate\Routing\Controller as BaseController;
 use RuntimeException;
 use Str;
 
 class Controller extends BaseController
 {
-
     use AuthorizesRequests;
     use DispatchesJobs;
     use ValidatesRequests;
 
-    // 生成随机密码
-    public function makePasswd(): string
-    {
-        return Str::random();
-    }
-
-    // 生成UUID
-    public function makeUUID()
-    {
-        return Str::uuid();
-    }
-
-    // 生成网站安全码
-    public function makeSecurityCode(): string
-    {
-        return strtolower(Str::random(8));
-    }
-
     // 类似Linux中的tail命令
     public function tail($file, $n, $base = 5)
     {
@@ -55,7 +35,7 @@ class Controller extends BaseController
 
         $fp = fopen($file, 'rb+');
         assert($n > 0);
-        $pos   = $n + 1;
+        $pos = $n + 1;
         $lines = [];
         while (count($lines) <= $n) {
             try {
@@ -65,7 +45,7 @@ class Controller extends BaseController
             }
 
             $pos *= $base;
-            while ( ! feof($fp)) {
+            while (!feof($fp)) {
                 array_unshift($lines, fgets($fp));
             }
         }
@@ -83,13 +63,13 @@ class Controller extends BaseController
     public function countLine($file): int
     {
         $fp = fopen($file, 'rb');
-        $i  = 0;
-        while ( ! feof($fp)) {
+        $i = 0;
+        while (!feof($fp)) {
             //每次读取2M
             if ($data = fread($fp, 1024 * 1024 * 2)) {
                 //计算读取到的行数
                 $num = substr_count($data, "\n");
-                $i   += $num;
+                $i += $num;
             }
         }
 
@@ -108,63 +88,30 @@ class Controller extends BaseController
     public function base64ImageSaver($base64_image_content): ?string
     {
         // 匹配出图片的格式
-        if (preg_match(
-            '/^(data:\s*image\/(\w+);base64,)/',
-            $base64_image_content,
-            $result
-        )) {
+        if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)) {
             $type = $result[2];
 
             $directory = date('Ymd');
-            $path      = '/assets/images/qrcode/' . $directory . '/';
+            $path = '/assets/images/qrcode/'.$directory.'/';
             // 检查是否有该文件夹,如果没有就创建,并给予最高权限
-            if ( ! file_exists(public_path($path))
-                 && ! mkdir(
-                    $concurrentDirectory = public_path($path),
-                    0755,
-                    true
-                )
-                 && ! is_dir($concurrentDirectory)) {
-                throw new RuntimeException(
-                    sprintf(
-                        'Directory "%s" was not created',
-                        $concurrentDirectory
-                    )
-                );
+            if (!file_exists(public_path($path))
+                && !mkdir($concurrentDirectory = public_path($path), 0755, true)
+                && !is_dir($concurrentDirectory)) {
+                throw new RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
             }
 
-            $fileName = Str::random(18) . ".{$type}";
-            if (file_put_contents(
-                public_path($path . $fileName),
-                base64_decode(
-                    str_replace($result[1], '', $base64_image_content)
-                )
-            )) {
-                chmod(public_path($path . $fileName), 0744);
+            $fileName = Str::random(18).".{$type}";
+            if (file_put_contents(public_path($path.$fileName),
+                base64_decode(str_replace($result[1], '', $base64_image_content)))) {
+                chmod(public_path($path.$fileName), 0744);
 
-                return $path . $fileName;
+                return $path.$fileName;
             }
         }
 
         return '';
     }
 
-    // 上传文件处理
-    public function uploadFile(UploadedFile $file): string
-    {
-        $fileType = $file->getClientOriginalExtension();
-
-        // 验证文件合法性
-        if ( ! in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])) {
-            return false;
-        }
-
-        $name = date('YmdHis') . random_int(1000, 2000) . '.' . $fileType;
-        $move = $file->move(base_path() . '/public/upload/image/', $name);
-
-        return $move ? '/upload/image/' . $name : '';
-    }
-
     /**
      * 节点信息
      *
@@ -174,95 +121,61 @@ class Controller extends BaseController
      *
      * @return string
      */
-    public function getUserNodeInfo(
-        int $uid,
-        int $nodeId,
-        int $infoType
-    ): string {
-        $user   = User::find($uid);
-        $node   = Node::find($nodeId);
+    public function getUserNodeInfo(int $uid, int $nodeId, int $infoType): string
+    {
+        $user = User::find($uid);
+        $node = Node::find($nodeId);
         $scheme = null;
-        $group  = sysConfig('website_name');// 分组名称
-        $host   = $node->is_relay ? $node->relay_server : ($node->server ?: $node->ip);
-        $data   = null;
+        $group = sysConfig('website_name');// 分组名称
+        $host = $node->is_relay ? $node->relay_server : ($node->server ?: $node->ip);
+        $data = null;
         switch ($node->type) {
             case 2:
                 // 生成v2ray scheme
                 if ($infoType !== 1) {
                     // 生成v2ray scheme
-                    $data = $this->v2raySubUrl(
-                        $node->name,
-                        $host,
-                        $node->v2_port,
-                        $user->vmess_id,
-                        $node->v2_alter_id,
-                        $node->v2_net,
-                        $node->v2_type,
-                        $node->v2_host,
-                        $node->v2_path,
-                        $node->v2_tls ? "tls" : ""
-                    );
+                    $data = $this->v2raySubUrl($node->name, $host, $node->v2_port, $user->vmess_id, $node->v2_alter_id,
+                        $node->v2_net, $node->v2_type, $node->v2_host, $node->v2_path, $node->v2_tls ? "tls" : "");
                 } else {
-                    $data = "服务器:" . $host . PHP_EOL . "IPv6:" . ($node->ipv6 ?: "") . PHP_EOL . "端口:" . $node->v2_port . PHP_EOL . "加密方式:" . $node->v2_method . PHP_EOL . "用户ID:" . $user->vmess_id . PHP_EOL . "额外ID:" . $node->v2_alter_id . PHP_EOL . "传输协议:" . $node->v2_net . PHP_EOL . "伪装类型:" . $node->v2_type . PHP_EOL . "伪装域名:" . ($node->v2_host ?: "") . PHP_EOL . "路径:" . ($node->v2_path ?: "") . PHP_EOL . "TLS:" . ($node->v2_tls ? "tls" : "") . PHP_EOL;
+                    $data = "服务器:".$host.PHP_EOL."IPv6:".($node->ipv6 ?: "").PHP_EOL."端口:".$node->v2_port.PHP_EOL."加密方式:".$node->v2_method.PHP_EOL."用户ID:".$user->vmess_id.PHP_EOL."额外ID:".$node->v2_alter_id.PHP_EOL."传输协议:".$node->v2_net.PHP_EOL."伪装类型:".$node->v2_type.PHP_EOL."伪装域名:".($node->v2_host ?: "").PHP_EOL."路径:".($node->v2_path ?: "").PHP_EOL."TLS:".($node->v2_tls ? "tls" : "").PHP_EOL;
                 }
                 break;
             case 3:
                 if ($infoType !== 1) {
-                    $data = $this->trojanSubUrl(
-                        $user->passwd,
-                        $host,
-                        $node->port,
-                        $node->name
-                    );
+                    $data = $this->trojanSubUrl($user->passwd, $host, $node->port, $node->name);
                 } else {
-                    $data = "备注:" . $node->name . PHP_EOL . "服务器:" . $host . PHP_EOL . "密码:" . $user->passwd . PHP_EOL . "端口:" . $node->port . PHP_EOL;
+                    $data = "备注:".$node->name.PHP_EOL."服务器:".$host.PHP_EOL."密码:".$user->passwd.PHP_EOL."端口:".$node->port.PHP_EOL;
                 }
                 break;
             case 1:
             case 4:
                 $protocol = $node->protocol;
-                $method   = $node->method;
-                $obfs     = $node->obfs;
+                $method = $node->method;
+                $obfs = $node->obfs;
                 if ($node->single) {
                     //单端口使用中转的端口
-                    $port           = $node->is_relay ? $node->relay_port : $node->port;
-                    $passwd         = $node->passwd;
-                    $protocol_param = $user->port . ':' . $user->passwd;
+                    $port = $node->is_relay ? $node->relay_port : $node->port;
+                    $passwd = $node->passwd;
+                    $protocol_param = $user->port.':'.$user->passwd;
                 } else {
-                    $port           = $user->port;
-                    $passwd         = $user->passwd;
+                    $port = $user->port;
+                    $passwd = $user->passwd;
                     $protocol_param = $node->protocol_param;
                     if ($node->type === 1) {
                         $protocol = $user->protocol;
-                        $method   = $user->method;
-                        $obfs     = $user->obfs;
+                        $method = $user->method;
+                        $obfs = $user->obfs;
                     }
                 }
 
                 if ($infoType !== 1) {
                     // 生成ss/ssr scheme
-                    $data = $node->compatible ? $this->ssSubUrl(
-                        $host,
-                        $port,
-                        $method,
-                        $passwd,
-                        $group
-                    ) : $this->ssrSubUrl(
-                        $host,
-                        $port,
-                        $protocol,
-                        $method,
-                        $obfs,
-                        $passwd,
-                        $node->obfs_param,
-                        $protocol_param,
-                        $node->name,
-                        $group,
-                        $node->is_udp
-                    );
+                    $data = $node->compatible ? $this->ssSubUrl($host, $port, $method, $passwd,
+                        $group) : $this->ssrSubUrl($host, $port, $protocol, $method, $obfs, $passwd, $node->obfs_param,
+                        $protocol_param, $node->name, $group, $node->is_udp);
                 } else {
                     // 生成文本配置信息
-                    $data = "服务器:" . $host . PHP_EOL . "IPv6:" . $node->ipv6 . PHP_EOL . "服务器端口:" . $port . PHP_EOL . "密码:" . $passwd . PHP_EOL . "加密:" . $method . PHP_EOL . ($node->compatible ? '' : "协议:" . $protocol . PHP_EOL . "协议参数:" . $protocol_param . PHP_EOL . "混淆:" . $obfs . PHP_EOL . "混淆参数:" . $node->obfs_param . PHP_EOL);
+                    $data = "服务器:".$host.PHP_EOL."IPv6:".$node->ipv6.PHP_EOL."服务器端口:".$port.PHP_EOL."密码:".$passwd.PHP_EOL."加密:".$method.PHP_EOL.($node->compatible ? '' : "协议:".$protocol.PHP_EOL."协议参数:".$protocol_param.PHP_EOL."混淆:".$obfs.PHP_EOL."混淆参数:".$node->obfs_param.PHP_EOL);
                 }
                 break;
             default:
@@ -271,78 +184,36 @@ class Controller extends BaseController
         return $data;
     }
 
-    public function v2raySubUrl(
-        $name,
-        $host,
-        $port,
-        $uuid,
-        $alter_id,
-        $net,
-        $type,
-        $domain,
-        $path,
-        $tls
-    ): string {
-        return 'vmess://' . base64url_encode(
-                json_encode(
-                    [
-                        "v"    => "2",
-                        "ps"   => $name,
-                        "add"  => $host,
-                        "port" => $port,
-                        "id"   => $uuid,
-                        "aid"  => $alter_id,
-                        "net"  => $net,
-                        "type" => $type,
-                        "host" => $domain,
-                        "path" => $path,
-                        "tls"  => $tls ? "tls" : "",
-                    ],
-                    JSON_PRETTY_PRINT
-                )
-            );
+    public function v2raySubUrl($name, $host, $port, $uuid, $alter_id, $net, $type, $domain, $path, $tls): string
+    {
+        return 'vmess://'.base64url_encode(json_encode([
+                "v"    => "2",
+                "ps"   => $name,
+                "add"  => $host,
+                "port" => $port,
+                "id"   => $uuid,
+                "aid"  => $alter_id,
+                "net"  => $net,
+                "type" => $type,
+                "host" => $domain,
+                "path" => $path,
+                "tls"  => $tls ? "tls" : "",
+            ], JSON_PRETTY_PRINT));
     }
 
     public function trojanSubUrl($password, $domain, $port, $remark): string
     {
-        return 'trojan://' . urlencode(
-                $password
-            ) . '@' . $domain . ':' . $port . '#' . urlencode($remark);
+        return 'trojan://'.urlencode($password).'@'.$domain.':'.$port.'#'.urlencode($remark);
     }
 
     public function ssSubUrl($host, $port, $method, $passwd, $group): string
     {
-        return 'ss://' . base64url_encode(
-                $method . ':' . $passwd . '@' . $host . ':' . $port
-            ) . '#' . $group;
+        return 'ss://'.base64url_encode($method.':'.$passwd.'@'.$host.':'.$port).'#'.$group;
     }
 
-    public function ssrSubUrl(
-        $host,
-        $port,
-        $protocol,
-        $method,
-        $obfs,
-        $passwd,
-        $obfs_param,
-        $protocol_param,
-        $name,
-        $group,
-        $is_udp
-    ): string {
-        return 'ssr://' . base64url_encode(
-                $host . ':' . $port . ':' . $protocol . ':' . $method . ':' . $obfs . ':' . base64url_encode(
-                    $passwd
-                ) . '/?obfsparam=' . base64url_encode(
-                    $obfs_param
-                ) . '&protoparam=' . base64url_encode(
-                    $protocol_param
-                ) . '&remarks=' . base64url_encode(
-                    $name
-                ) . '&group=' . base64url_encode(
-                    $group
-                ) . '&udpport=' . $is_udp . '&uot=0'
-            );
+    public function ssrSubUrl($host, $port, $protocol, $method, $obfs, $passwd, $obfs_param, $protocol_param, $name, $group, $is_udp): string
+    {
+        return 'ssr://'.base64url_encode($host.':'.$port.':'.$protocol.':'.$method.':'.$obfs.':'.base64url_encode($passwd).'/?obfsparam='.base64url_encode($obfs_param).'&protoparam='.base64url_encode($protocol_param).'&remarks='.base64url_encode($name).'&group='.base64url_encode($group).'&udpport='.$is_udp.'&uot=0');
     }
 
     // 流量使用图表
@@ -350,25 +221,16 @@ class Controller extends BaseController
     {
         if ($is_node) {
             $currentFlow = UserDataFlowLog::whereNodeId($id);
-            $hourlyFlow  = NodeHourlyDataFlow::whereNodeId($id);
-            $dailyFlow   = NodeDailyDataFlow::whereNodeId($id);
+            $hourlyFlow = NodeHourlyDataFlow::whereNodeId($id);
+            $dailyFlow = NodeDailyDataFlow::whereNodeId($id);
         } else {
             $currentFlow = UserDataFlowLog::whereUserId($id);
-            $hourlyFlow  = UserHourlyDataFlow::userHourly($id);
-            $dailyFlow   = UserDailyDataFlow::userDaily($id);
+            $hourlyFlow = UserHourlyDataFlow::userHourly($id);
+            $dailyFlow = UserDailyDataFlow::userDaily($id);
         }
-        $currentFlow = $currentFlow->where(
-            'log_time',
-            '>=',
-            strtotime(date('Y-m-d H:00'))
-        )->sum(DB::raw('u + d'));
-        $hourlyFlow  = $hourlyFlow->whereDate('created_at', date('Y-m-d'))
-                                  ->pluck('total', 'created_at')
-                                  ->toArray();
-        $dailyFlow   = $dailyFlow->whereMonth('created_at', date('n'))->pluck(
-            'total',
-            'created_at'
-        )->toArray();
+        $currentFlow = $currentFlow->where('log_time', '>=', strtotime(date('Y-m-d H:00')))->sum(DB::raw('u + d'));
+        $hourlyFlow = $hourlyFlow->whereDate('created_at', date('Y-m-d'))->pluck('total', 'created_at')->toArray();
+        $dailyFlow = $dailyFlow->whereMonth('created_at', date('n'))->pluck('total', 'created_at')->toArray();
 
         // 节点一天内的流量
         $hourlyData = array_fill(0, date('G') + 1, 0);
@@ -380,15 +242,9 @@ class Controller extends BaseController
         // 节点一个月内的流量
         $dailyData = array_fill(0, date('j'), 0);
         foreach ($dailyFlow as $date => $dataFlow) {
-            $dailyData[date('j', strtotime($date)) - 1] = round(
-                $dataFlow / GB,
-                3
-            );
+            $dailyData[date('j', strtotime($date)) - 1] = round($dataFlow / GB, 3);
         }
-        $dailyData[date('j', strtotime(now())) - 1] = round(
-            (array_sum($hourlyFlow) + $currentFlow) / GB,
-            3
-        );
+        $dailyData[date('j', strtotime(now())) - 1] = round((array_sum($hourlyFlow) + $currentFlow) / GB, 3);
 
         return [
             'trafficDaily'  => json_encode($dailyData),
@@ -397,5 +253,4 @@ class Controller extends BaseController
             'dayHours'      => json_encode(range(0, date("G") + 1, 1))// 本日小时
         ];
     }
-
 }

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

@@ -10,18 +10,17 @@ use Str;
 
 abstract class AbstractPayment
 {
-
     abstract public function purchase(Request $request): JsonResponse;
 
     abstract public function notify(Request $request): void;
 
     protected function creatNewPayment($uid, $oid, $amount): Payment
     {
-        $payment           = new Payment();
+        $payment = new Payment();
         $payment->trade_no = Str::random(8);
-        $payment->user_id  = $uid;
+        $payment->user_id = $uid;
         $payment->order_id = $oid;
-        $payment->amount   = $amount;
+        $payment->amount = $amount;
         $payment->save();
 
         return $payment;
@@ -34,15 +33,12 @@ abstract class AbstractPayment
      *
      * @return int
      */
-    protected function addPamentCallback(
-        string $trade_no,
-        string $out_trade_no,
-        int $amount
-    ): int {
-        $log               = new PaymentCallback();
-        $log->trade_no     = $trade_no;
+    protected function addPamentCallback(string $trade_no, string $out_trade_no, int $amount): int
+    {
+        $log = new PaymentCallback();
+        $log->trade_no = $trade_no;
         $log->out_trade_no = $out_trade_no;
-        $log->amount       = $amount;
+        $log->amount = $amount;
 
         return $log->save();
     }
@@ -50,10 +46,7 @@ abstract class AbstractPayment
     // MD5验签
     protected function verify($data, $key, $signature, $filter = true): bool
     {
-        return hash_equals(
-            $this->aliStyleSign($data, $key, $filter),
-            $signature
-        );
+        return hash_equals($this->aliStyleSign($data, $key, $filter), $signature);
     }
 
     /**
@@ -65,11 +58,8 @@ abstract class AbstractPayment
      *
      * @return string md5加密后的数据
      */
-    protected function aliStyleSign(
-        array $data,
-        string $key,
-        $filter = true
-    ): string {
+    protected function aliStyleSign(array $data, string $key, $filter = true): string
+    {
         // 剃离sign,sign_type,空值
         unset($data['sign'], $data['sign_type']);
         if ($filter) {
@@ -80,7 +70,6 @@ abstract class AbstractPayment
         ksort($data, SORT_STRING);
         reset($data);
 
-        return md5(urldecode(http_build_query($data)) . $key);
+        return md5(urldecode(http_build_query($data)).$key);
     }
-
 }

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

@@ -11,30 +11,19 @@ use Response;
 
 class BitpayX extends AbstractPayment
 {
-
     public function purchase($request): JsonResponse
     {
-        $payment = $this->creatNewPayment(
-            Auth::id(),
-            $request->input('id'),
-            $request->input('amount')
-        );
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
-        $data   = [
+        $data = [
             'merchant_order_id' => $payment->trade_no,
             'price_amount'      => $payment->amount,
             'price_currency'    => 'CNY',
-            'title'             => '支付单号:' . $payment->trade_no,
-            'description'       => sysConfig('subject_name') ?: sysConfig(
-                'website_name'
-            ),
-            'callback_url'      => (sysConfig(
-                    'website_callback_url'
-                ) ?: sysConfig(
-                    'website_url'
-                )) . '/callback/notify?method=bitpayx',
-            'success_url'       => sysConfig('website_url') . '/invoices',
-            'cancel_url'        => sysConfig('website_url') . '/invoices',
+            'title'             => '支付单号:'.$payment->trade_no,
+            'description'       => sysConfig('subject_name') ?: sysConfig('website_name'),
+            'callback_url'      => (sysConfig('website_callback_url') ?: sysConfig('website_url')).'/callback/notify?method=bitpayx',
+            'success_url'       => sysConfig('website_url').'/invoices',
+            'cancel_url'        => sysConfig('website_url').'/invoices',
             'token'             => $this->sign($payment->trade_no),
         ];
         $result = $this->sendRequest($data);
@@ -43,20 +32,12 @@ class BitpayX extends AbstractPayment
             $result['payment_url'] .= '&lang=zh';
             $payment->update(['url' => $result['payment_url']]);
 
-            return Response::json(
-                [
-                    'status'  => 'success',
-                    'url'     => $result['payment_url'],
-                    'message' => '创建订单成功!',
-                ]
-            );
+            return Response::json(['status' => 'success', 'url' => $result['payment_url'], 'message' => '创建订单成功!']);
         }
 
-        Log::error('创建订单错误:' . var_export($result, true));
+        Log::error('创建订单错误:'.var_export($result, true));
 
-        return Response::json(
-            ['status' => 'fail', 'message' => '创建订单失败!' . $result['error']]
-        );
+        return Response::json(['status' => 'fail', 'message' => '创建订单失败!'.$result['error']]);
     }
 
     private function sign($tradeNo): string
@@ -72,26 +53,22 @@ class BitpayX extends AbstractPayment
 
     private function sendRequest($data, $type = 'createOrder')
     {
-        $client = new Client(
-            [
-                'base_uri' => 'https://api.mugglepay.com/v1/',
-                'timeout'  => 15,
-                'headers'  => [
-                    'token'        => sysConfig('bitpay_secret'),
-                    'content-type' => 'application/json',
-                ],
-            ]
-        );
+        $client = new Client([
+            'base_uri' => 'https://api.mugglepay.com/v1/',
+            'timeout'  => 15,
+            'headers'  => [
+                'token'        => sysConfig('bitpay_secret'),
+                'content-type' => 'application/json',
+            ],
+        ]);
 
         if ($type === 'query') {
-            $request = $client->get(
-                'orders/merchant_order_id/status?id=' . $data['merchant_order_id']
-            );
+            $request = $client->get('orders/merchant_order_id/status?id='.$data['merchant_order_id']);
         } else {// Create Order
             $request = $client->post('orders', ['body' => json_encode($data)]);
         }
         if ($request->getStatusCode() !== 200) {
-            Log::error('BitPayX请求支付错误:' . var_export($request, true));
+            Log::error('BitPayX请求支付错误:'.var_export($request, true));
         }
 
         return json_decode($request->getBody(), true);
@@ -101,10 +78,7 @@ class BitpayX extends AbstractPayment
     public function notify($request): void
     {
         $tradeNo = $request->input(['merchant_order_id']);
-        if ($request->input(['status']) === 'PAID' && hash_equals(
-                $this->sign($tradeNo),
-                $request->input(['token'])
-            )) {
+        if ($request->input(['status']) === 'PAID' && hash_equals($this->sign($tradeNo), $request->input(['token']))) {
             $payment = Payment::whereTradeNo($tradeNo)->first();
             if ($payment) {
                 $ret = $payment->order->update(['status' => 2]);
@@ -115,5 +89,4 @@ class BitpayX extends AbstractPayment
         }
         exit(json_encode(['status' => 400]));
     }
-
 }

+ 8 - 24
app/Http/Controllers/Gateway/CodePay.php

@@ -9,48 +9,33 @@ use Response;
 
 class CodePay extends AbstractPayment
 {
-
     public function purchase($request): JsonResponse
     {
-        $payment = $this->creatNewPayment(
-            Auth::id(),
-            $request->input('id'),
-            $request->input('amount')
-        );
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
-        $data         = [
+        $data = [
             'id'         => sysConfig('codepay_id'),
             'pay_id'     => $payment->trade_no,
-            'type'       => $request->input('type'),
-            //1支付宝支付 2QQ钱包 3微信支付
+            'type'       => $request->input('type'),            //1支付宝支付 2QQ钱包 3微信支付
             'price'      => $payment->amount,
             'page'       => 1,
             'outTime'    => 900,
-            'notify_url' => (sysConfig('website_callback_url') ?: sysConfig(
-                    'website_url'
-                )) . '/callback/notify?method=codepay',
-            'return_url' => sysConfig('website_url') . '/invoices',
+            'notify_url' => (sysConfig('website_callback_url') ?: sysConfig('website_url')).'/callback/notify?method=codepay',
+            'return_url' => sysConfig('website_url').'/invoices',
         ];
         $data['sign'] = $this->aliStyleSign($data, sysConfig('codepay_key'));
 
-        $url = sysConfig('codepay_url') . http_build_query($data);
+        $url = sysConfig('codepay_url').http_build_query($data);
         $payment->update(['url' => $url]);
 
-        return Response::json(
-            ['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']
-        );
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
     }
 
     public function notify($request): void
     {
         $trade_no = $request->input('pay_id');
         if ($trade_no && $request->input('pay_no')
-            && $this->verify(
-                $request->except('method'),
-                sysConfig('codepay_key'),
-                $request->input('sign'),
-                false
-            )) {
+            && $this->verify($request->except('method'), sysConfig('codepay_key'), $request->input('sign'), false)) {
             $payment = Payment::whereTradeNo($trade_no)->first();
             if ($payment) {
                 $ret = $payment->order->update(['status' => 2]);
@@ -61,5 +46,4 @@ class CodePay extends AbstractPayment
         }
         exit('fail');
     }
-
 }

+ 19 - 46
app/Http/Controllers/Gateway/EPay.php

@@ -11,14 +11,9 @@ use Response;
 
 class EPay extends AbstractPayment
 {
-
     public function purchase(Request $request): JsonResponse
     {
-        $payment = $this->creatNewPayment(
-            Auth::id(),
-            $request->input('id'),
-            $request->input('amount')
-        );
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
         switch ($request->input('type')) {
             case 2:
@@ -33,40 +28,29 @@ class EPay extends AbstractPayment
                 break;
         }
 
-        $data         = [
+        $data = [
             'pid'          => sysConfig('epay_mch_id'),
             'type'         => $type,
-            'notify_url'   => (sysConfig('website_callback_url') ?: sysConfig(
-                    'website_url'
-                )) . '/callback/notify?method=epay',
-            'return_url'   => sysConfig('website_url') . '/invoices',
+            'notify_url'   => (sysConfig('website_callback_url') ?: sysConfig('website_url')).'/callback/notify?method=epay',
+            'return_url'   => sysConfig('website_url').'/invoices',
             'out_trade_no' => $payment->trade_no,
-            'name'         => sysConfig('subject_name') ?: sysConfig(
-                'website_name'
-            ),
+            '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);
+        $url = sysConfig('epay_url').'submit.php?'.http_build_query($data);
         $payment->update(['url' => $url]);
 
-        return Response::json(
-            ['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']
-        );
+        return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
     }
 
     public function notify(Request $request): void
     {
         if ($request->input('trade_status') === 'TRADE_SUCCESS'
-            && $this->verify(
-                $request->except('method'),
-                sysConfig('epay_key'),
-                $request->input('sign')
-            )) {
-            $payment = Payment::whereTradeNo($request->input('out_trade_no'))
-                              ->first();
+            && $this->verify($request->except('method'), sysConfig('epay_key'), $request->input('sign'))) {
+            $payment = Payment::whereTradeNo($request->input('out_trade_no'))->first();
             if ($payment) {
                 $ret = $payment->order->update(['status' => 2]);
                 if ($ret) {
@@ -79,28 +63,17 @@ class EPay extends AbstractPayment
 
     public function queryInfo(): JsonResponse
     {
-        $request = (new Client())->get(
-            sysConfig('epay_url') . 'api.php',
-            [
-                'query' => [
-                    'act' => 'query',
-                    'pid' => sysConfig('epay_mch_id'),
-                    'key' => sysConfig('epay_key'),
-                ],
-            ]
-        );
-        if ($request->getStatusCode() == 200) {
-            return Response::json(
-                [
-                    'status' => 'success',
-                    'data'   => json_decode($request->getBody(), true),
-                ]
-            );
+        $request = (new Client())->get(sysConfig('epay_url').'api.php', [
+            'query' => [
+                'act' => 'query',
+                'pid' => sysConfig('epay_mch_id'),
+                'key' => sysConfig('epay_key'),
+            ],
+        ]);
+        if ($request->getStatusCode() === 200) {
+            return Response::json(['status' => 'success', 'data' => json_decode($request->getBody(), true)]);
         }
 
-        return Response::json(
-            ['status' => 'fail', 'message' => '获取失败!请检查配置信息']
-        );
+        return Response::json(['status' => 'fail', 'message' => '获取失败!请检查配置信息']);
     }
-
 }

+ 18 - 44
app/Http/Controllers/Gateway/F2Fpay.php

@@ -2,7 +2,6 @@
 
 namespace App\Http\Controllers\Gateway;
 
-use App\Components\IP;
 use App\Models\Payment;
 use Auth;
 use Exception;
@@ -15,8 +14,7 @@ use Response;
 
 class F2Fpay extends AbstractPayment
 {
-
-    private static $aliConfig;
+    private static array $aliConfig;
 
     public function __construct()
     {
@@ -27,59 +25,40 @@ class F2Fpay extends AbstractPayment
             'ali_public_key'  => sysConfig('f2fpay_public_key'),
             'rsa_private_key' => sysConfig('f2fpay_private_key'),
             'limit_pay'       => [],
-            'notify_url'      => (sysConfig(
-                    'website_callback_url'
-                ) ?: sysConfig(
-                    'website_url'
-                )) . '/callback/notify?method=f2fpay',
-            'return_url'      => sysConfig('website_url') . '/invoices',
+            'notify_url'      => (sysConfig('website_callback_url') ?: sysConfig('website_url')).'/callback/notify?method=f2fpay',
+            'return_url'      => sysConfig('website_url').'/invoices',
             'fee_type'        => 'CNY',
         ];
     }
 
     public function purchase($request): JsonResponse
     {
-        $payment = $this->creatNewPayment(
-            Auth::id(),
-            $request->input('id'),
-            $request->input('amount')
-        );
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
         $data = [
             'body'        => '',
-            'subject'     => sysConfig('subject_name') ?: sysConfig(
-                'website_name'
-            ),
+            'subject'     => sysConfig('subject_name') ?: sysConfig('website_name'),
             'trade_no'    => $payment->trade_no,
             'time_expire' => time() + 900, // 必须 15分钟 内付款
             'amount'      => $payment->amount,
         ];
 
         try {
-            $result = (new Client(Client::ALIPAY, self::$aliConfig))->pay(
-                Client::ALI_CHANNEL_QR,
-                $data
-            );
+            $result = (new Client(Client::ALIPAY, self::$aliConfig))->pay(Client::ALI_CHANNEL_QR, $data);
         } catch (InvalidArgumentException $e) {
-            Log::error("【支付宝当面付】输入信息错误: " . $e->getMessage());
+            Log::error("【支付宝当面付】输入信息错误: ".$e->getMessage());
             exit;
         } catch (ClassNotFoundException $e) {
-            Log::error("【支付宝当面付】未知类型: " . $e->getMessage());
+            Log::error("【支付宝当面付】未知类型: ".$e->getMessage());
             exit;
         } catch (Exception $e) {
-            Log::error("【支付宝当面付】错误: " . $e->getMessage());
+            Log::error("【支付宝当面付】错误: ".$e->getMessage());
             exit;
         }
 
         $payment->update(['qr_code' => 1, 'url' => $result['qr_code']]);
 
-        return Response::json(
-            [
-                'status'  => 'success',
-                'data'    => $payment->trade_no,
-                'message' => '创建订单成功!',
-            ]
-        );
+        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
     }
 
     public function notify($request): void
@@ -90,26 +69,22 @@ class F2Fpay extends AbstractPayment
         ];
 
         try {
-            $result = (new Client(
-                Client::ALIPAY, self::$aliConfig
-            ))->tradeQuery($data);
-            Log::info("【支付宝当面付】回调验证查询:" . var_export($result, true));
+            $result = (new Client(Client::ALIPAY, self::$aliConfig))->tradeQuery($data);
+            Log::info("【支付宝当面付】回调验证查询:".var_export($result, true));
         } catch (InvalidArgumentException $e) {
-            Log::error("【支付宝当面付】回调信息错误: " . $e->getMessage());
+            Log::error("【支付宝当面付】回调信息错误: ".$e->getMessage());
             exit;
         } catch (ClassNotFoundException $e) {
-            Log::error("【支付宝当面付】未知类型: " . $e->getMessage());
+            Log::error("【支付宝当面付】未知类型: ".$e->getMessage());
             exit;
         } catch (Exception $e) {
-            Log::error("【支付宝当面付】错误: " . $e->getMessage());
+            Log::error("【支付宝当面付】错误: ".$e->getMessage());
             exit;
         }
 
         if ($result['code'] == 10000 && $result['msg'] === "Success") {
             if ($_POST['trade_status'] === 'TRADE_FINISHED' || $_POST['trade_status'] === 'TRADE_SUCCESS') {
-                $payment = Payment::whereTradeNo(
-                    $request->input('out_trade_no')
-                )->first();
+                $payment = Payment::whereTradeNo($request->input('out_trade_no'))->first();
                 if ($payment) {
                     $ret = $payment->order->update(['status' => 2]);
                     if ($ret) {
@@ -117,14 +92,13 @@ class F2Fpay extends AbstractPayment
                     }
                 }
             } else {
-                Log::info('支付宝当面付-POST:交易失败[' . IP::getClientIp() . ']');
+                Log::info('支付宝当面付-POST:交易失败');
             }
         } else {
-            Log::info('支付宝当面付-POST:验证失败[' . IP::getClientIp() . ']');
+            Log::info('支付宝当面付-POST:验证失败');
         }
 
         // 返回验证结果
         exit('fail');
     }
-
 }

+ 3 - 14
app/Http/Controllers/Gateway/Local.php

@@ -11,24 +11,16 @@ use Response;
 
 class Local extends AbstractPayment
 {
-
     public function purchase($request): JsonResponse
     {
         $order = Order::find($request->input('id'));
         $goods = Goods::find($request->input('goods_id'));
-        $user  = $order->user;
+        $user = $order->user;
 
         if ($user && $goods) {
             $user->update(['credit' => $user->credit - $order->amount]);
             // 记录余额操作日志
-            Helpers::addUserCreditLog(
-                $user->id,
-                $order->id,
-                $user->credit + $order->amount,
-                $user->credit,
-                -1 * $order->amount,
-                '购买商品' . $goods->name
-            );
+            Helpers::addUserCreditLog($user->id, $order->id, $user->credit + $order->amount, $user->credit, -1 * $order->amount, '购买商品'.$goods->name);
         }
 
         $order->update(['status' => 2]);
@@ -36,8 +28,5 @@ class Local extends AbstractPayment
         return Response::json(['status' => 'success', 'message' => '购买完成!']);
     }
 
-    public function notify($request): void
-    {
-    }
-
+    public function notify($request): void { }
 }

+ 9 - 29
app/Http/Controllers/Gateway/PayJs.php

@@ -10,8 +10,7 @@ use Xhat\Payjs\Payjs as Pay;
 
 class PayJs extends AbstractPayment
 {
-
-    private static $config;
+    private static array $config;
 
     public function __construct()
     {
@@ -23,38 +22,20 @@ class PayJs extends AbstractPayment
 
     public function purchase($request): JsonResponse
     {
-        $payment = $this->creatNewPayment(
-            Auth::id(),
-            $request->input('id'),
-            $request->input('amount')
-        );
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
-        $result = (new Pay($this::$config))->cashier(
-            [
-                'body'         => sysConfig('subject_name') ?: sysConfig(
-                    'website_name'
-                ),
-                'total_fee'    => $payment->amount * 100,
-                'out_trade_no' => $payment->trade_no,
-                'notify_url'   => (sysConfig(
-                        'website_callback_url'
-                    ) ?: sysConfig(
-                        'website_url'
-                    )) . '/callback/notify?method=payjs',
-            ]
-        );
+        $result = (new Pay($this::$config))->cashier([
+            'body'         => sysConfig('subject_name') ?: sysConfig('website_name'),
+            'total_fee'    => $payment->amount * 100,
+            'out_trade_no' => $payment->trade_no,
+            'notify_url'   => (sysConfig('website_callback_url') ?: sysConfig('website_url')).'/callback/notify?method=payjs',
+        ]);
 
         // 获取收款二维码内容
         $payment->update(['qr_code' => 1, 'url' => $result]);
 
         //$this->addPamentCallback($payment->trade_no, null, $payment->amount * 100);
-        return Response::json(
-            [
-                'status'  => 'success',
-                'data'    => $payment->trade_no,
-                'message' => '创建订单成功!',
-            ]
-        );
+        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
     }
 
     public function notify($request): void
@@ -72,5 +53,4 @@ class PayJs extends AbstractPayment
         }
         exit('fail');
     }
-
 }

+ 27 - 72
app/Http/Controllers/Gateway/PayPal.php

@@ -15,14 +15,13 @@ use Srmklive\PayPal\Services\ExpressCheckout;
 
 class PayPal extends AbstractPayment
 {
-
-    protected $provider;
+    protected ExpressCheckout $provider;
     protected $exChange;
 
     public function __construct()
     {
         $this->provider = new ExpressCheckout();
-        $config         = [
+        $config = [
             'mode' => 'live',
             'live' => [
                 'username'    => sysConfig('paypal_username'),
@@ -35,22 +34,15 @@ class PayPal extends AbstractPayment
             'payment_action' => 'Sale',
             'currency'       => 'USD',
             'billing_type'   => 'MerchantInitiatedBilling',
-            'notify_url'     => (sysConfig('website_callback_url') ?: sysConfig(
-                    'website_url'
-                )) . '/callback/notify?method=paypal',
+            'notify_url'     => (sysConfig('website_callback_url') ?: sysConfig('website_url')).'/callback/notify?method=paypal',
             'locale'         => 'zh_CN',
             'validate_ssl'   => true,
         ];
         $this->provider->setApiCredentials($config);
         $this->exChange = 7;
-        $client         = new Client(['timeout' => 15]);
-        $exChangeRate   = json_decode(
-            $client->get(
-                'http://api.k780.com/?app=finance.rate&scur=USD&tcur=CNY&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4'
-            )
-                   ->getBody(),
-            true
-        );
+        $client = new Client(['timeout' => 15]);
+        $exChangeRate = json_decode($client->get('http://api.k780.com/?app=finance.rate&scur=USD&tcur=CNY&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4')
+            ->getBody(), true);
 
         if ($exChangeRate && $exChangeRate['success']) {
             $this->exChange = $exChangeRate['result']['rate'];
@@ -59,34 +51,22 @@ class PayPal extends AbstractPayment
 
     public function purchase($request): JsonResponse
     {
-        $payment = $this->creatNewPayment(
-            Auth::id(),
-            $request->input('id'),
-            $request->input('amount')
-        );
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
 
         $data = $this->getCheckoutData($payment->trade_no, $payment->amount);
 
         try {
             $response = $this->provider->setExpressCheckout($data);
-            if ( ! $response['paypal_link']) {
-                Log::error('Paypal处理错误:' . var_export($response, true));
+            if (!$response['paypal_link']) {
+                Log::error('Paypal处理错误:'.var_export($response, true));
 
-                return Response::json(
-                    ['status' => 'fail', 'message' => '创建订单失败,请使用其他方式或通知管理员!']
-                );
+                return Response::json(['status' => 'fail', 'message' => '创建订单失败,请使用其他方式或通知管理员!']);
             }
             $payment->update(['url' => $response['paypal_link']]);
 
-            return Response::json(
-                [
-                    'status'  => 'success',
-                    'url'     => $response['paypal_link'],
-                    'message' => '创建订单成功!',
-                ]
-            );
+            return Response::json(['status' => 'success', 'url' => $response['paypal_link'], 'message' => '创建订单成功!']);
         } catch (Exception $e) {
-            Log::error("【PayPal】错误: " . $e->getMessage());
+            Log::error("【PayPal】错误: ".$e->getMessage());
             exit;
         }
     }
@@ -99,63 +79,39 @@ class PayPal extends AbstractPayment
             'invoice_id'          => $trade_no,
             'items'               => [
                 [
-                    'name'  => sysConfig('subject_name') ?: sysConfig(
-                        'website_name'
-                    ),
+                    'name'  => sysConfig('subject_name') ?: sysConfig('website_name'),
                     'price' => $amount,
-                    'desc'  => 'Description for' . (sysConfig(
-                            'subject_name'
-                        ) ?: sysConfig('website_name')),
+                    'desc'  => 'Description for'.(sysConfig('subject_name') ?: sysConfig('website_name')),
                     'qty'   => 1,
                 ],
             ],
             'invoice_description' => $trade_no,
-            'return_url'          => sysConfig(
-                                         'website_url'
-                                     ) . '/callback/checkout',
-            'cancel_url'          => sysConfig('website_url') . '/invoices',
+            'return_url'          => sysConfig('website_url').'/callback/checkout',
+            'cancel_url'          => sysConfig('website_url').'/invoices',
             'total'               => $amount,
         ];
     }
 
     public function getCheckout(Request $request)
     {
-        $token   = $request->get('token');
+        $token = $request->get('token');
         $PayerID = $request->get('PayerID');
 
         // Verify Express Checkout Token
         $response = $this->provider->getExpressCheckoutDetails($token);
 
-        if (in_array(
-            strtoupper($response['ACK']),
-            ['SUCCESS', 'SUCCESSWITHWARNING']
-        )) {
-            $payment = Payment::whereTradeNo($response['INVNUM'])->firstOrFail(
-            );
-            $data    = $this->getCheckoutData(
-                $payment->trade_no,
-                $payment->amount
-            );
+        if (in_array(strtoupper($response['ACK']), ['SUCCESS', 'SUCCESSWITHWARNING'])) {
+            $payment = Payment::whereTradeNo($response['INVNUM'])->firstOrFail();
+            $data = $this->getCheckoutData($payment->trade_no, $payment->amount);
             // Perform transaction on PayPal
-            $payment_status = $this->provider->doExpressCheckoutPayment(
-                $data,
-                $token,
-                $PayerID
-            );
-            $status         = $payment_status['PAYMENTINFO_0_PAYMENTSTATUS'];
-
-            if ( ! strcasecmp($status, 'Completed') || ! strcasecmp(
-                    $status,
-                    'Processed'
-                )) {
-                Log::info(
-                    "Order $payment->order_id has been paid successfully!"
-                );
+            $payment_status = $this->provider->doExpressCheckoutPayment($data, $token, $PayerID);
+            $status = $payment_status['PAYMENTINFO_0_PAYMENTSTATUS'];
+
+            if (!strcasecmp($status, 'Completed') || !strcasecmp($status, 'Processed')) {
+                Log::info("Order $payment->order_id has been paid successfully!");
                 $payment->order->update(['status' => 1]);
             } else {
-                Log::error(
-                    "Error processing PayPal payment for Order $payment->id!"
-                );
+                Log::error("Error processing PayPal payment for Order $payment->id!");
             }
         }
 
@@ -172,7 +128,7 @@ class PayPal extends AbstractPayment
         }
         $post = $request->all();
 
-        $response = (string)$this->provider->verifyIPN($post);
+        $response = (string) $this->provider->verifyIPN($post);
 
         if ($response === 'VERIFIED' && $request['invoice']) {
             $payment = Payment::whereTradeNo($request['invoice'])->first();
@@ -185,5 +141,4 @@ class PayPal extends AbstractPayment
         }
         exit("fail");
     }
-
 }

+ 0 - 650
app/Http/Controllers/NodeController.php

@@ -1,650 +0,0 @@
-<?php
-
-namespace App\Http\Controllers;
-
-use App\Components\Helpers;
-use App\Components\NetworkDetection;
-use App\Jobs\VNet\reloadNode;
-use App\Models\Country;
-use App\Models\Label;
-use App\Models\Level;
-use App\Models\Node;
-use App\Models\NodeAuth;
-use App\Models\NodeCertificate;
-use App\Models\NodePing;
-use App\Services\NodeService;
-use DB;
-use Exception;
-use Illuminate\Http\JsonResponse;
-use Illuminate\Http\Request;
-use Log;
-use Redirect;
-use Response;
-use Session;
-use Str;
-use Validator;
-
-class NodeController extends Controller
-{
-
-    // 节点列表
-    public function nodeList(Request $request)
-    {
-        $status = $request->input('status');
-
-        $query = Node::with(['onlineLogs', 'dailyDataFlows']);
-
-        if (isset($status)) {
-            $query->whereStatus($status);
-        }
-
-        $nodeList = $query->orderByDesc('sort')
-                          ->orderBy('id')
-                          ->paginate(15)
-                          ->appends($request->except('page'));
-        foreach ($nodeList as $node) {
-            // 在线人数
-            $online_log         = $node->onlineLogs()
-                                       ->where(
-                                           'log_time',
-                                           '>=',
-                                           strtotime("-5 minutes")
-                                       )
-                                       ->latest('log_time')
-                                       ->first();
-            $node->online_users = empty($online_log) ? 0 : $online_log->online_user;
-
-            // 已产生流量
-            $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
-            );
-        }
-
-        $view['nodeList'] = $nodeList;
-
-        return view('admin.node.nodeList', $view);
-    }
-
-    public function checkNode($id): JsonResponse
-    {
-        $node = Node::find($id);
-        // 使用DDNS的node先获取ipv4地址
-        if ($node->is_ddns) {
-            $ip = gethostbyname($node->server);
-            if (strcmp($ip, $node->server) != 0) {
-                $node->ip = $ip;
-            } else {
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'title'   => 'IP获取错误',
-                        'message' => $node->name . 'IP获取失败',
-                    ]
-                );
-            }
-        }
-        $data[0] = NetworkDetection::networkCheck($node->ip, true); //ICMP
-        $data[1] = NetworkDetection::networkCheck(
-            $node->ip,
-            false,
-            $node->single ? $node->port : null
-        ); //TCP
-
-        return Response::json(
-            [
-                'status'  => 'success',
-                'title'   => '[' . $node->name . ']阻断信息',
-                'message' => $data,
-            ]
-        );
-    }
-
-    // 添加节点
-    public function addNode(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $validator = $this->nodeValidation($request);
-            if ($validator) {
-                return $validator;
-            }
-
-            // TODO:判断是否已存在绑定了相同域名的节点,提示是否要强制替换,或者不提示之前强制将其他节点的绑定域名置为空,然后发起域名绑定请求,或者请求进入队列
-            try {
-                DB::beginTransaction();
-
-                $node                 = new Node();
-                $node->type           = $request->input('type');
-                $node->name           = $request->input('name');
-                $node->country_code   = $request->input('country_code');
-                $node->server         = $request->input('server');
-                $node->ip             = $request->input('ip');
-                $node->ipv6           = $request->input('ipv6');
-                $node->relay_server   = $request->input('relay_server');
-                $node->relay_port     = $request->input('relay_port');
-                $node->level          = $request->input('level');
-                $node->speed_limit    = (int)$request->input(
-                        'speed_limit'
-                    ) * Mbps;
-                $node->client_limit   = $request->input('client_limit');
-                $node->description    = $request->input('description');
-                $node->method         = $request->input('method');
-                $node->protocol       = $request->input('protocol');
-                $node->protocol_param = $request->input('protocol_param');
-                $node->obfs           = $request->input('obfs');
-                $node->obfs_param     = $request->input('obfs_param');
-                $node->traffic_rate   = $request->input('traffic_rate');
-                $node->is_subscribe   = (int)$request->input('is_subscribe');
-                $node->is_ddns        = (int)$request->input('is_ddns');
-                $node->is_relay       = (int)$request->input('is_relay');
-                $node->is_udp         = (int)$request->input('is_udp');
-                $node->push_port      = $request->input('push_port');
-                $node->detection_type = $request->input('detection_type');
-                $node->compatible     = (int)$request->input('compatible');
-                $node->single         = (int)$request->input('single');
-                $node->port           = $request->input('port');
-                $node->passwd         = $request->input('passwd');
-                $node->sort           = $request->input('sort');
-                $node->status         = (int)$request->input('status');
-                $node->v2_alter_id    = $request->input('v2_alter_id');
-                $node->v2_port        = $request->input('v2_port');
-                $node->v2_method      = $request->input('v2_method');
-                $node->v2_net         = $request->input('v2_net');
-                $node->v2_type        = $request->input('v2_type');
-                $node->v2_host        = $request->input('v2_host') ?: '';
-                $node->v2_path        = $request->input('v2_path');
-                $node->v2_tls         = (int)$request->input('v2_tls');
-                $node->tls_provider   = $request->input('tls_provider');
-                $node->save();
-
-                DB::commit();
-                // 生成节点标签
-                (new NodeService())->makeLabels(
-                    $node->id,
-                    $request->input('labels')
-                );
-
-                return Response::json(
-                    ['status' => 'success', 'message' => '添加成功']
-                );
-            } catch (Exception $e) {
-                DB::rollBack();
-                Log::error('添加节点信息异常:' . $e->getMessage());
-
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => '添加失败:' . $e->getMessage(),
-                    ]
-                );
-            }
-        } else {
-            $view['methodList']   = Helpers::methodList();
-            $view['protocolList'] = Helpers::protocolList();
-            $view['obfsList']     = Helpers::obfsList();
-            $view['countryList']  = Country::orderBy('code')->get();
-            $view['levelList']    = Level::orderBy('level')->get();
-            $view['labelList']    = Label::orderByDesc('sort')
-                                         ->orderBy('id')
-                                         ->get();
-            $view['dvList']       = NodeCertificate::orderBy('id')->get();
-
-            return view('admin.node.nodeInfo', $view);
-        }
-    }
-
-    // 节点信息验证
-    private function nodeValidation(Request $request)
-    {
-        if ($request->input('server')) {
-            $domain       = $request->input('server');
-            $domain       = explode('.', $domain);
-            $domainSuffix = end($domain); // 取得域名后缀
-
-            if ( ! in_array($domainSuffix, config('domains'), true)) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '绑定域名不合法']
-                );
-            }
-        }
-
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'type'           => 'required|between:1,3',
-                'name'           => 'required',
-                'country_code'   => 'required',
-                'server'         => 'required_if:is_ddns,1',
-                'push_port'      => 'numeric|between:0,65535',
-                'traffic_rate'   => 'required|numeric|min:0',
-                'level'          => 'required|numeric|between:0,255',
-                'speed_limit'    => 'required|numeric|min:0',
-                'client_limit'   => 'required|numeric|min:0',
-                'port'           => 'nullable|numeric|between:0,65535',
-                'ip'             => 'ipv4',
-                'ipv6'           => 'nullable|ipv6',
-                'relay_server'   => 'required_if:is_relay,1',
-                'relay_port'     => 'required_if:is_relay,1|numeric|between:0,65535',
-                'method'         => 'required_if:type,1',
-                'protocol'       => 'required_if:type,1',
-                'obfs'           => 'required_if:type,1',
-                'is_subscribe'   => 'boolean',
-                'is_ddns'        => 'boolean',
-                'is_relay'       => 'boolean',
-                'is_udp'         => 'boolean',
-                'detection_type' => 'between:0,3',
-                'compatible'     => 'boolean',
-                'single'         => 'boolean',
-                'sort'           => 'required|numeric|between:0,255',
-                'status'         => 'boolean',
-                '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_tls'         => 'boolean',
-            ],
-            [
-                'server.required_unless' => '开启DDNS, 域名不能为空',
-            ]
-        );
-
-        if ($validator->fails()) {
-            return Response::json(
-                ['status' => 'fail', 'message' => $validator->errors()->all()]
-            );
-        }
-
-        return false;
-    }
-
-    // 刷新节点地理位置
-    public function refreshGeo(Request $request): JsonResponse
-    {
-        if ((new NodeService())->getNodeGeo($request->input('id', 0))) {
-            return Response::json(
-                ['status' => 'success', 'message' => '获取地理位置更新成功!']
-            );
-        }
-
-        return Response::json(['status' => 'fail', 'message' => '获取地理位置更新失败!']);
-    }
-
-    // 重载节点
-    public function reload($id): JsonResponse
-    {
-        if (reloadNode::dispatchNow(Node::whereId($id)->get())) {
-            return Response::json(
-                ['status' => 'success', 'message' => '重载成功!']
-            );
-        }
-
-        return Response::json(['status' => 'fail', 'message' => '重载失败!']);
-    }
-
-    // 编辑节点
-    public function editNode(Request $request)
-    {
-        $id = $request->input('id');
-
-        if ($request->isMethod('POST')) {
-            $validator = $this->nodeValidation($request);
-            if ($validator) {
-                return $validator;
-            }
-
-            $node = Node::find($id);
-
-            try {
-                DB::beginTransaction();
-                // 生成节点标签
-                (new NodeService())->makeLabels(
-                    $node->id,
-                    $request->input('labels')
-                );
-
-                $node->update(
-                    [
-                        'type'           => $request->input('type'),
-                        'name'           => $request->input('name'),
-                        'country_code'   => $request->input('country_code'),
-                        'server'         => $request->input('server'),
-                        'ip'             => $request->input('ip'),
-                        'ipv6'           => $request->input('ipv6'),
-                        'relay_server'   => $request->input('relay_server'),
-                        'relay_port'     => $request->input('relay_port'),
-                        'level'          => $request->input('level'),
-                        'speed_limit'    => (int)$request->input(
-                                'speed_limit'
-                            ) * Mbps,
-                        'client_limit'   => $request->input('client_limit'),
-                        'description'    => $request->input('description'),
-                        'method'         => $request->input('method'),
-                        'protocol'       => $request->input('protocol'),
-                        'protocol_param' => $request->input('protocol_param'),
-                        'obfs'           => $request->input('obfs'),
-                        'obfs_param'     => $request->input('obfs_param'),
-                        'traffic_rate'   => $request->input('traffic_rate'),
-                        'is_subscribe'   => (int)$request->input(
-                            'is_subscribe'
-                        ),
-                        'is_ddns'        => (int)$request->input('is_ddns'),
-                        'is_relay'       => (int)$request->input('is_relay'),
-                        'is_udp'         => (int)$request->input('is_udp'),
-                        'push_port'      => $request->input('push_port'),
-                        'detection_type' => $request->input('detection_type'),
-                        'compatible'     => (int)$request->input('compatible'),
-                        'single'         => (int)$request->input('single'),
-                        'port'           => $request->input('port'),
-                        'passwd'         => $request->input('passwd'),
-                        'sort'           => $request->input('sort'),
-                        'status'         => (int)$request->input('status'),
-                        'v2_alter_id'    => $request->input('v2_alter_id'),
-                        'v2_port'        => $request->input('v2_port'),
-                        'v2_method'      => $request->input('v2_method'),
-                        'v2_net'         => $request->input('v2_net'),
-                        'v2_type'        => $request->input('v2_type'),
-                        'v2_host'        => $request->input('v2_host') ?: '',
-                        'v2_path'        => $request->input('v2_path'),
-                        'v2_tls'         => (int)$request->input('v2_tls'),
-                        'tls_provider'   => $request->input('tls_provider'),
-                    ]
-                );
-                // TODO:更新节点绑定的域名DNS(将节点IP更新到域名DNS 的A记录)
-
-                DB::commit();
-
-                return Response::json(
-                    ['status' => 'success', 'message' => '编辑成功']
-                );
-            } catch (Exception $e) {
-                DB::rollBack();
-                Log::error('编辑节点信息异常:' . $e->getMessage());
-
-                return Response::json(
-                    [
-                        'status'  => 'fail',
-                        'message' => '编辑失败:' . $e->getMessage(),
-                    ]
-                );
-            }
-        }
-
-        $view['node']         = Node::with('labels')->find($id);
-        $view['methodList']   = Helpers::methodList();
-        $view['protocolList'] = Helpers::protocolList();
-        $view['obfsList']     = Helpers::obfsList();
-        $view['countryList']  = Country::orderBy('code')->get();
-        $view['levelList']    = Level::orderBy('level')->get();
-        $view['labelList']    = Label::orderByDesc('sort')->orderBy('id')->get(
-        );
-        $view['dvList']       = NodeCertificate::orderBy('id')->get();
-
-        return view('admin.node.nodeInfo', $view);
-    }
-
-    // 删除节点
-    public function delNode(Request $request): ?JsonResponse
-    {
-        $id = $request->input('id');
-
-        $node = Node::find($id);
-        if ( ! $node) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '节点不存在,请重试']
-            );
-        }
-
-        try {
-            DB::beginTransaction();
-            $node->delete();
-            DB::commit();
-
-            return Response::json(['status' => 'success', 'message' => '删除成功']);
-        } catch (Exception $e) {
-            DB::rollBack();
-            Log::error('删除节点信息异常:' . $e->getMessage());
-
-            return Response::json(
-                ['status' => 'fail', 'message' => '删除失败:' . $e->getMessage()]
-            );
-        }
-    }
-
-    // 节点流量监控
-    public function nodeMonitor(Request $request)
-    {
-        $node = Node::find($request->input('id'));
-        if ( ! $node) {
-            Session::flash('errorMsg', '节点不存在,请重试');
-
-            return Redirect::back();
-        }
-
-        $view['nodeName']   = $node->name;
-        $view['nodeServer'] = $node->server;
-        $view               = array_merge(
-            $view,
-            $this->DataFlowChart($node->id, 1)
-        );
-
-        return view('admin.node.nodeMonitor', $view);
-    }
-
-    // Ping节点延迟
-    public function pingNode($id): ?JsonResponse
-    {
-        $node = Node::find($id);
-        if ( ! $node) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '节点不存在,请重试']
-            );
-        }
-
-        $result = NetworkDetection::ping(
-            $node->is_ddns ? $node->server : $node->ip
-        );
-
-        if ($result) {
-            return Response::json(
-                [
-                    'status'  => 'success',
-                    'message' => [
-                        $result['telecom']['time'] ?: '无',//电信
-                        $result['Unicom']['time'] ?: '无',// 联通
-                        $result['move']['time'] ?: '无',// 移动
-                        $result['HongKong']['time'] ?: '无'// 香港
-                    ],
-                ]
-            );
-        }
-
-        return Response::json(['status' => 'fail', 'message' => 'Ping访问失败']);
-    }
-
-    // Ping节点延迟日志
-    public function pingLog(Request $request)
-    {
-        $node_id = $request->input('nodeId');
-        $query   = NodePing::query();
-        if (isset($node_id)) {
-            $query->whereNodeId($node_id);
-        }
-
-        $view['nodeList'] = Node::orderBy('id')->get();
-        $view['pingLogs'] = $query->latest()->paginate(15)->appends(
-            $request->except('page')
-        );
-
-        return view('admin.logs.nodePingLog', $view);
-    }
-
-    // 节点授权列表
-    public function authList(Request $request)
-    {
-        $view['list'] = NodeAuth::orderBy('node_id')->paginate(15)->appends(
-            $request->except('page')
-        );
-
-        return view('admin.node.authList', $view);
-    }
-
-    // 添加节点授权
-    public function addAuth(): JsonResponse
-    {
-        $nodeArray = Node::whereStatus(1)->orderBy('id')->pluck('id')->toArray(
-        );
-        $authArray = NodeAuth::orderBy('id')->pluck('node_id')->toArray();
-
-        if ($nodeArray == $authArray) {
-            return Response::json(
-                ['status' => 'success', 'message' => '没有需要生成授权的节点']
-            );
-        }
-
-        foreach (array_diff($nodeArray, $authArray) as $nodeId) {
-            $obj          = new NodeAuth();
-            $obj->node_id = $nodeId;
-            $obj->key     = Str::random();
-            $obj->secret  = Str::random(8);
-            $obj->save();
-        }
-
-        return Response::json(['status' => 'success', 'message' => '生成成功']);
-    }
-
-    // 删除节点授权
-    public function delAuth(Request $request): JsonResponse
-    {
-        try {
-            NodeAuth::whereId($request->input('id'))->delete();
-        } catch (Exception $e) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '错误:' . var_export($e, true)]
-            );
-        }
-
-        return Response::json(['status' => 'success', 'message' => '操作成功']);
-    }
-
-    // 重置节点授权
-    public function refreshAuth(Request $request): ?JsonResponse
-    {
-        $ret = NodeAuth::whereId($request->input('id'))->update(
-            [
-                'key'    => Str::random(),
-                'secret' => Str::random(8),
-            ]
-        );
-        if ($ret) {
-            return Response::json(['status' => 'success', 'message' => '操作成功']);
-        }
-
-        return Response::json(['status' => 'fail', 'message' => '操作失败']);
-    }
-
-    // 域名证书列表
-    public function certificateList(Request $request)
-    {
-        $DvList = NodeCertificate::orderBy('id')->paginate(15)->appends(
-            $request->except('page')
-        );
-        foreach ($DvList as $Dv) {
-            if ($Dv->key && $Dv->pem) {
-                $DvInfo     = openssl_x509_parse($Dv->pem);
-                $Dv->issuer = $DvInfo['issuer']['O'];
-                $Dv->from   = $DvInfo['validFrom_time_t'] ? date(
-                    'Y-m-d',
-                    $DvInfo['validFrom_time_t']
-                ) : null;
-                $Dv->to     = $DvInfo['validTo'] ? date(
-                    'Y-m-d',
-                    $DvInfo['validTo_time_t']
-                ) : null;
-            }
-        }
-        $view['list'] = $DvList;
-
-        return view('admin.node.certificateList', $view);
-    }
-
-    // 添加域名证书
-    public function addCertificate(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $obj         = new NodeCertificate();
-            $obj->domain = $request->input('domain');
-            $obj->key    = str_replace(
-                ["\r", "\n"],
-                '',
-                $request->input('key')
-            );
-            $obj->pem    = str_replace(
-                ["\r", "\n"],
-                '',
-                $request->input('pem')
-            );
-            $obj->save();
-
-            if ($obj->id) {
-                return Response::json(
-                    ['status' => 'success', 'message' => '生成成功']
-                );
-            }
-
-            return Response::json(['status' => 'fail', 'message' => '生成失败']);
-        }
-
-        return view('admin.node.certificateInfo');
-    }
-
-    // 编辑域名证书
-    public function editCertificate(Request $request)
-    {
-        $Dv = NodeCertificate::find($request->input('id'));
-        if ($request->isMethod('POST')) {
-            if ($Dv) {
-                $ret = NodeCertificate::whereId($Dv->id)->update(
-                    [
-                        'domain' => $request->input('domain'),
-                        'key'    => $request->input('key'),
-                        'pem'    => $request->input('pem'),
-                    ]
-                );
-                if ($ret) {
-                    return Response::json(
-                        ['status' => 'success', 'message' => '修改成功']
-                    );
-                }
-            }
-
-            return Response::json(['status' => 'fail', 'message' => '修改失败']);
-        }
-
-        $view['Dv'] = $Dv;
-
-        return view('admin.node.certificateInfo', $view);
-    }
-
-    // 删除域名证书
-    public function delCertificate(Request $request): JsonResponse
-    {
-        try {
-            NodeCertificate::whereId($request->input('id'))->delete();
-        } catch (Exception $e) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '错误:' . var_export($e, true)]
-            );
-        }
-
-        return Response::json(['status' => 'success', 'message' => '操作成功']);
-    }
-
-}

+ 53 - 125
app/Http/Controllers/PaymentController.php

@@ -30,19 +30,13 @@ use Response;
  */
 class PaymentController extends Controller
 {
-
-    private static $method;
+    private static string $method;
 
     public static function notify(Request $request): int
     {
         self::$method = $request->input('method');
 
-        Log::info(
-            self::$method . "回调接口[POST]:" . self::$method . var_export(
-                $request->all(),
-                true
-            )
-        );
+        Log::info(self::$method."回调接口[POST]:".self::$method.var_export($request->all(), true));
         self::getClient()->notify($request);
 
         return 0;
@@ -66,7 +60,7 @@ class PaymentController extends Controller
             case 'epay':
                 return new EPay();
             default:
-                Log::error("未知支付:" . self::$method);
+                Log::error("未知支付:".self::$method);
 
                 return false;
         }
@@ -76,16 +70,12 @@ class PaymentController extends Controller
     {
         $payment = Payment::whereTradeNo($request->input('trade_no'))->first();
         if ($payment) {
-            if ($payment->status == 1) {
-                return Response::json(
-                    ['status' => 'success', 'message' => '支付成功']
-                );
+            if ($payment->status === 1) {
+                return Response::json(['status' => 'success', 'message' => '支付成功']);
             }
 
-            if ($payment->status == -1) {
-                return Response::json(
-                    ['status' => 'error', 'message' => '订单超时未支付,已自动关闭']
-                );
+            if ($payment->status === -1) {
+                return Response::json(['status' => 'error', 'message' => '订单超时未支付,已自动关闭']);
             }
 
             return Response::json(['status' => 'fail', 'message' => '等待支付']);
@@ -97,28 +87,24 @@ class PaymentController extends Controller
     // 创建支付订单
     public function purchase(Request $request)
     {
-        $goods_id     = $request->input('goods_id');
-        $coupon_sn    = $request->input('coupon_sn');
+        $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;
+        $credit = $request->input('amount');
+        $pay_type = $request->input('pay_type');
+        $amount = 0;
 
         $goods = Goods::find($goods_id);
         // 充值余额
         if ($credit) {
-            if ( ! is_numeric($credit) || $credit <= 0) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '充值余额不合规']
-                );
+            if (!is_numeric($credit) || $credit <= 0) {
+                return Response::json(['status' => 'fail', 'message' => '充值余额不合规']);
             }
             $amount = $credit;
             // 购买服务
         } elseif ($goods_id && self::$method) {
-            if ( ! $goods || ! $goods->status) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '订单创建失败:商品已下架']
-                );
+            if (!$goods || !$goods->status) {
+                return Response::json(['status' => 'fail', 'message' => '订单创建失败:商品已下架']);
             }
             $amount = $goods->price;
 
@@ -126,103 +112,73 @@ class PaymentController extends Controller
             $activePlan = Order::userActivePlan()->doesntExist();
 
             // 无生效套餐,禁止购买加油包
-            if ($goods->type == 1 && $activePlan) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '购买加油包前,请先购买套餐']
-                );
+            if ($goods->type === 1 && $activePlan) {
+                return Response::json(['status' => 'fail', 'message' => '购买加油包前,请先购买套餐']);
             }
 
             //非余额付款下,检查在线支付是否开启
             if (self::$method !== 'credit') {
                 // 判断是否开启在线支付
-                if ( ! sysConfig('is_onlinePay')) {
-                    return Response::json(
-                        ['status' => 'fail', 'message' => '订单创建失败:系统并未开启在线支付功能']
-                    );
+                if (!sysConfig('is_onlinePay')) {
+                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:系统并未开启在线支付功能']);
                 }
 
                 // 判断是否存在同个商品的未支付订单
                 if (Order::uid()->whereStatus(0)->exists()) {
-                    return Response::json(
-                        [
-                            'status'  => 'fail',
-                            'message' => '订单创建失败:尚有未支付的订单,请先去支付',
-                        ]
-                    );
+                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:尚有未支付的订单,请先去支付']);
                 }
             } elseif (Auth::getUser()->credit < $amount) { // 验证账号余额是否充足
-                return Response::json(
-                    ['status' => 'fail', 'message' => '您的余额不足,请先充值']
-                );
+                return Response::json(['status' => 'fail', 'message' => '您的余额不足,请先充值']);
             }
 
             // 单个商品限购
             if ($goods->limit_num) {
-                $count = Order::uid()->where('status', '>=', 0)->whereGoodsId(
-                    $goods_id
-                )->count();
+                $count = Order::uid()->where('status', '>=', 0)->whereGoodsId($goods_id)->count();
                 if ($count >= $goods->limit_num) {
-                    return Response::json(
-                        [
-                            'status'  => 'fail',
-                            'message' => '此商品限购' . $goods->limit_num . '次,您已购买' . $count . '次',
-                        ]
-                    );
+                    return Response::json(['status' => 'fail', 'message' => '此商品限购'.$goods->limit_num.'次,您已购买'.$count.'次']);
                 }
             }
 
             // 使用优惠券 TODO 代码整合至 CouponService
             if ($coupon_sn) {
-                $coupon = Coupon::whereStatus(0)
-                                ->whereIn('type', [1, 2])
-                                ->whereSn($coupon_sn)
-                                ->first();
-                if ( ! $coupon) {
-                    return Response::json(
-                        ['status' => 'fail', 'message' => '订单创建失败:优惠券不存在']
-                    );
+                $coupon = Coupon::whereStatus(0)->whereIn('type', [1, 2])->whereSn($coupon_sn)->first();
+                if (!$coupon) {
+                    return Response::json(['status' => 'fail', 'message' => '订单创建失败:优惠券不存在']);
                 }
 
                 // 计算实际应支付总价
-                $amount = $coupon->type == 2 ? $goods->price * $coupon->value / 100 : $goods->price - $coupon->value;
-                $amount = $amount > 0 ? round(
-                    $amount,
-                    2
-                ) : 0; // 四舍五入保留2位小数,避免无法正常创建订单
+                $amount = $coupon->type === 2 ? $goods->price * $coupon->value / 100 : $goods->price - $coupon->value;
+                $amount = $amount > 0 ? round($amount, 2) : 0; // 四舍五入保留2位小数,避免无法正常创建订单
             }
 
             // 价格异常判断
             if ($amount < 0) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '订单创建失败:订单总价异常']
-                );
+                return Response::json(['status' => 'fail', 'message' => '订单创建失败:订单总价异常']);
             }
 
-            if ($amount == 0 && self::$method !== 'credit') {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '订单创建失败:订单总价为0,无需使用在线支付']
-                );
+            if ($amount === 0 && self::$method !== 'credit') {
+                return Response::json(['status' => 'fail', 'message' => '订单创建失败:订单总价为0,无需使用在线支付']);
             }
         }
 
-        $orderSn = date('ymdHis') . random_int(100000, 999999);
+        $orderSn = date('ymdHis').random_int(100000, 999999);
 
         // 生成订单
-        $order                = new Order();
-        $order->order_sn      = $orderSn;
-        $order->user_id       = Auth::id();
-        $order->goods_id      = $credit ? 0 : $goods_id;
-        $order->coupon_id     = ! empty($coupon) ? $coupon->id : 0;
+        $order = new Order();
+        $order->order_sn = $orderSn;
+        $order->user_id = Auth::id();
+        $order->goods_id = $credit ? 0 : $goods_id;
+        $order->coupon_id = $coupon->id ?? 0;
         $order->origin_amount = $credit ?: $goods->price;
-        $order->amount        = $amount;
-        $order->is_expire     = 0;
-        $order->pay_type      = $pay_type;
-        $order->pay_way       = self::$method;
-        $order->status        = 0;
+        $order->amount = $amount;
+        $order->is_expire = 0;
+        $order->pay_type = $pay_type;
+        $order->pay_way = self::$method;
+        $order->status = 0;
         $order->save();
 
         // 使用优惠券,减少可使用次数
-        if ( ! empty($coupon)) {
+        if (!empty($coupon)) {
             if ($coupon->usable_times > 0) {
                 Coupon::whereId($coupon->id)->decrement('usable_times', 1);
             }
@@ -230,9 +186,7 @@ class PaymentController extends Controller
             Helpers::addCouponLog('订单支付使用', $coupon->id, $goods_id, $order->id);
         }
 
-        $request->merge(
-            ['id' => $order->id, 'type' => $pay_type, 'amount' => $amount]
-        );
+        $request->merge(['id' => $order->id, 'type' => $pay_type, 'amount' => $amount]);
 
         // 生成支付单
         return self::getClient()->purchase($request);
@@ -242,10 +196,8 @@ class PaymentController extends Controller
     {
         $order = Order::find($request->input('id'));
         if ($order) {
-            if ( ! $order->update(['status' => -1])) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '关闭订单失败']
-                );
+            if (!$order->update(['status' => -1])) {
+                return Response::json(['status' => 'fail', 'message' => '关闭订单失败']);
             }
         } else {
             return Response::json(['status' => 'fail', 'message' => '未找到订单']);
@@ -257,38 +209,14 @@ class PaymentController extends Controller
     // 支付单详情
     public function detail($trade_no)
     {
-        $payment               = Payment::uid()
-                                        ->with(['order', 'order.goods'])
-                                        ->whereTradeNo(
-                                            $trade_no
-                                        )
-                                        ->firstOrFail();
-        $view['payment']       = $payment;
-        $goods                 = $payment->order->goods;
-        $view['name']          = $goods ? $goods->name : '余额充值';
-        $view['days']          = $goods ? $goods->days : 0;
-        $view['pay_type']      = $payment->order->pay_type_label ?: 0;
+        $payment = Payment::uid()->with(['order', 'order.goods'])->whereTradeNo($trade_no)->firstOrFail();
+        $view['payment'] = $payment;
+        $goods = $payment->order->goods;
+        $view['name'] = $goods->name ?? '余额充值';
+        $view['days'] = $goods->days ?? 0;
+        $view['pay_type'] = $payment->order->pay_type_label ?: 0;
         $view['pay_type_icon'] = $payment->order->pay_type_icon;
 
         return view('user.payment', $view);
     }
-
-    // 回调日志
-    public function callbackList(Request $request)
-    {
-        $status = $request->input('status', 0);
-
-        $query = PaymentCallback::query();
-
-        if (isset($status)) {
-            $query->whereStatus($status);
-        }
-
-        $view['list'] = $query->latest()->paginate(10)->appends(
-            $request->except('page')
-        );
-
-        return view('admin.logs.callbackList', $view);
-    }
-
 }

+ 24 - 73
app/Http/Controllers/User/AffiliateController.php

@@ -16,47 +16,18 @@ class AffiliateController extends Controller
     // 推广返利
     public function referral()
     {
-        if (ReferralLog::uid()->doesntExist() && Order::uid()
-                                                      ->whereStatus(2)
-                                                      ->doesntExist()) {
-            return Response::view(
-                'auth.error',
-                ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返 回</a>'],
-                402
-            );
+        if (ReferralLog::uid()->doesntExist() && Order::uid()->whereStatus(2)->doesntExist()) {
+            return Response::view('auth.error', ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返 回</a>'], 402);
         }
-        $view['referral_traffic']  = flowAutoShow(
-            sysConfig('referral_traffic') * MB
-        );
-        $view['referral_percent']  = sysConfig('referral_percent');
-        $view['referral_money']    = sysConfig('referral_money');
-        $view['totalAmount']       = ReferralLog::uid()->sum(
-                'commission'
-            ) / 100;
-        $view['canAmount']         = ReferralLog::uid()->whereStatus(0)->sum(
-                'commission'
-            ) / 100;
-        $view['aff_link']          = sysConfig(
-                                         'website_url'
-                                     ) . '/register?aff=' . Auth::id();
-        $view['referralLogList']   = ReferralLog::uid()
-                                                ->with('invitee:id,email')
-                                                ->latest()
-                                                ->paginate(
-                                                    10,
-                                                    ['*'],
-                                                    'log_page'
-                                                );
-        $view['referralApplyList'] = ReferralApply::uid()->latest()->paginate(
-            10,
-            ['*'],
-            'apply_page'
-        );
-        $view['referralUserList']  = Auth::getUser()
-                                         ->invitees()
-                                         ->select(['email', 'created_at'])
-                                         ->latest()
-                                         ->paginate(10, ['*'], 'user_page');
+        $view['referral_traffic'] = flowAutoShow(sysConfig('referral_traffic') * MB);
+        $view['referral_percent'] = sysConfig('referral_percent');
+        $view['referral_money'] = sysConfig('referral_money');
+        $view['totalAmount'] = ReferralLog::uid()->sum('commission') / 100;
+        $view['canAmount'] = ReferralLog::uid()->whereStatus(0)->sum('commission') / 100;
+        $view['aff_link'] = sysConfig('website_url').'/register?aff='.Auth::id();
+        $view['referralLogList'] = ReferralLog::uid()->with('invitee:id,email')->latest()->paginate(10, ['*'], 'log_page');
+        $view['referralApplyList'] = ReferralApply::uid()->latest()->paginate(10, ['*'], 'apply_page');
+        $view['referralUserList'] = Auth::getUser()->invitees()->select(['email', 'created_at'])->latest()->paginate(10, ['*'], 'user_page');
 
         return view('user.referral', $view);
     }
@@ -66,53 +37,33 @@ class AffiliateController extends Controller
     {
         // 判断账户是否过期
         if (Auth::getUser()->expired_at < date('Y-m-d')) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '申请失败:账号已过期,请先购买服务吧']
-            );
+            return Response::json(['status' => 'fail', 'message' => '申请失败:账号已过期,请先购买服务吧']);
         }
 
         // 判断是否已存在申请
-        $referralApply = ReferralApply::uid()->whereIn('status', [0, 1])->first(
-        );
+        $referralApply = ReferralApply::uid()->whereIn('status', [0, 1])->first();
         if ($referralApply) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '申请失败:已存在申请,请等待之前的申请处理完']
-            );
+            return Response::json(['status' => 'fail', 'message' => '申请失败:已存在申请,请等待之前的申请处理完']);
         }
 
         // 校验可以提现金额是否超过系统设置的阀值
         $commission = ReferralLog::uid()->whereStatus(0)->sum('commission');
         $commission /= 100;
         if ($commission < sysConfig('referral_money')) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'message' => '申请失败:满' . sysConfig(
-                            'referral_money'
-                        ) . '元才可以提现,继续努力吧',
-                ]
-            );
+            return Response::json(['status' => 'fail', 'message' => '申请失败:满'.sysConfig('referral_money').'元才可以提现,继续努力吧',]);
         }
 
-        $ref            = new ReferralApply();
-        $ref->user_id   = Auth::id();
-        $ref->before    = $commission;
-        $ref->after     = 0;
-        $ref->amount    = $commission;
-        $ref->link_logs = ReferralLog::uid()
-                                     ->whereStatus(0)
-                                     ->pluck('id')
-                                     ->toArray();
-        $ref->status    = 0;
+        $ref = new ReferralApply();
+        $ref->user_id = Auth::id();
+        $ref->before = $commission;
+        $ref->after = 0;
+        $ref->amount = $commission;
+        $ref->link_logs = ReferralLog::uid()->whereStatus(0)->pluck('id')->toArray();
+        $ref->status = 0;
         if ($ref->save()) {
-            return Response::json(
-                ['status' => 'success', 'message' => '申请成功,请等待管理员审核']
-            );
+            return Response::json(['status' => 'success', 'message' => '申请成功,请等待管理员审核']);
         }
 
-        return Response::json(
-            ['status' => 'fail', 'message' => '申请失败,返利单建立失败,请稍后尝试或通知管理员']
-        );
+        return Response::json(['status' => 'fail', 'message' => '申请失败,返利单建立失败,请稍后尝试或通知管理员']);
     }
-
 }

+ 25 - 78
app/Http/Controllers/User/SubscribeController.php

@@ -13,8 +13,7 @@ use Response;
 
 class SubscribeController extends Controller
 {
-
-    private $subType;
+    private int $subType;
 
     // 通过订阅码获取订阅信息
     public function getSubscribeByCode(Request $request, $code)
@@ -26,35 +25,28 @@ class SubscribeController extends Controller
 
         // 检查订阅码是否有效
         $subscribe = UserSubscribe::whereCode($code)->first();
-        if ( ! $subscribe) {
+        if (!$subscribe) {
             exit($this->infoGenerator('使用的订阅链接错误!请重新从官网获取!'));
         }
 
-        if ($subscribe->status != 1) {
+        if ($subscribe->status !== 1) {
             exit($this->infoGenerator('您的订阅链接已被封禁,请前往官网查询原因!'));
         }
 
         // 检查用户是否有效
         $user = $subscribe->user;
-        if ( ! $user) {
+        if (!$user) {
             exit($this->infoGenerator('错误订阅链接,账号不存在!请前往官网重新获取订阅链接'));
         }
 
-        if ($user->status == -1) {
+        if ($user->status === -1) {
             exit($this->infoGenerator('您的账号已经被禁止使用,请重新注册'));
         }
 
-        if ($user->enable != 1) {
+        if ($user->enable !== 1) {
             $unusedTransfer = $user->transfer_enable - $user->u - $user->d;
             if ($user->ban_time) {
-                exit(
-                $this->infoGenerator(
-                    '您的账号处于封禁状态,请在' . date(
-                        'Y-m-d H:i:s',
-                        $user->ban_time
-                    ) . '之后再更新!'
-                )
-                );
+                exit($this->infoGenerator('您的账号处于封禁状态,请在'.date('Y-m-d H:i:s', $user->ban_time).'之后再更新!'));
             }
 
             if ($unusedTransfer <= 0) {
@@ -72,11 +64,7 @@ class SubscribeController extends Controller
         $subscribe->increment('times', 1);
 
         // 记录每次请求
-        $this->subscribeLog(
-            $subscribe->id,
-            IP::getClientIp(),
-            $request->headers
-        );
+        $this->subscribeLog($subscribe->id, IP::getClientIp(), $request->headers);
 
         // 获取这个账号可用节点
         $query = $user->whereIsSubscribe(1)->userAccessNodes();
@@ -87,8 +75,7 @@ class SubscribeController extends Controller
             $query = $query->whereType($this->subType);
         }
 
-        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get()->toArray(
-        );
+        $nodeList = $query->orderByDesc('sort')->orderBy('id')->get()->toArray();
         if (empty($nodeList)) {
             exit($this->infoGenerator('无可用节点'));
         }
@@ -102,31 +89,17 @@ class SubscribeController extends Controller
 
         // 展示到期时间和剩余流量
         if (sysConfig('is_custom_subscribe')) {
-            $scheme .= $this->infoGenerator(
-                    '到期时间: ' . ($user->expired_at < date(
-                        'Y-m-d'
-                    ) ? '过期' : $user->expired_at)
-                ) . $this->infoGenerator(
-                    '剩余流量: ' . flowAutoShow(
-                        $user->transfer_enable - $user->u - $user->d
-                    )
-                );
+            $scheme .= $this->infoGenerator('到期时间: '.($user->expired_at < date('Y-m-d') ? '过期' : $user->expired_at)).$this->infoGenerator('剩余流量: '.flowAutoShow($user->transfer_enable - $user->u - $user->d));
         }
 
         // 控制客户端最多获取节点数
         foreach ($nodeList as $key => $node) {
             // 控制显示的节点数
-            if (sysConfig('subscribe_max') && $key >= sysConfig(
-                    'subscribe_max'
-                )) {
+            if (sysConfig('subscribe_max') && $key >= sysConfig('subscribe_max')) {
                 break;
             }
 
-            $scheme .= $this->getUserNodeInfo(
-                    $user->id,
-                    $node['id'],
-                    0
-                ) . PHP_EOL;
+            $scheme .= $this->getUserNodeInfo($user->id, $node['id'], 0).PHP_EOL;
         }
 
         $headers = [
@@ -137,9 +110,7 @@ class SubscribeController extends Controller
 
         // 适配Quantumult的自定义订阅头
         if (sysConfig('is_custom_subscribe')) {
-            $headers['Subscription-Userinfo'] = 'upload=' . $user->u . '; download=' . $user->d . '; total=' . $user->transfer_enable . '; expire=' . strtotime(
-                    $user->expired_at
-                );
+            $headers['Subscription-Userinfo'] = 'upload='.$user->u.'; download='.$user->d.'; total='.$user->transfer_enable.'; expire='.strtotime($user->expired_at);
         }
 
         return Response::make(base64url_encode($scheme), 200, $headers);
@@ -151,57 +122,33 @@ class SubscribeController extends Controller
         $result = null;
         switch ($this->subType) {
             case 2:
-                $result = 'vmess://' . base64url_encode(
-                        json_encode(
-                            [
-                                "v"    => "2",
-                                "ps"   => $text,
-                                "add"  => "0.0.0.0",
-                                "port" => 0,
-                                "id"   => 0,
-                                "aid"  => 0,
-                                "net"  => "tcp",
-                                "type" => "none",
-                                "host" => "",
-                                "path" => "/",
-                                'tls'  => "tls",
-                            ],
-                            JSON_PRETTY_PRINT
-                        )
-                    );
+                $result = 'vmess://'.base64url_encode(json_encode([
+                        "v"   => "2", "ps" => $text, "add" => "0.0.0.0", "port" => 0, "id" => 0,
+                        "aid" => 0, "net" => "tcp", "type" => "none", "host" => "", "path" => "/",
+                        'tls' => "tls",
+                    ], JSON_PRETTY_PRINT));
                 break;
             case 3:
-                $result = 'trojan://0@0.0.0.0:0?peer=0.0.0.0#' . rawurlencode(
-                        $text
-                    );
+                $result = 'trojan://0@0.0.0.0:0?peer=0.0.0.0#'.rawurlencode($text);
                 break;
             case 1:
             case 4:
             default:
-                $result = 'ssr://' . base64url_encode(
-                        '0.0.0.0:0:origin:none:plain:' . base64url_encode(
-                            '0000'
-                        ) . '/?obfsparam=&protoparam=&remarks=' . base64url_encode(
-                            $text
-                        ) . '&group=' . base64url_encode(
-                            sysConfig('website_name')
-                        ) . '&udpport=0&uot=0'
-                    );
+                $result = 'ssr://'.base64url_encode('0.0.0.0:0:origin:none:plain:'.base64url_encode('0000').'/?obfsparam=&protoparam=&remarks='.base64url_encode($text).'&group='.base64url_encode(sysConfig('website_name')).'&udpport=0&uot=0');
                 break;
         }
 
-        return $result . PHP_EOL;
+        return $result.PHP_EOL;
     }
 
     // 写入订阅访问日志
     private function subscribeLog($subscribeId, $ip, $headers): void
     {
-        $log                    = new UserSubscribeLog();
+        $log = new UserSubscribeLog();
         $log->user_subscribe_id = $subscribeId;
-        $log->request_ip        = $ip;
-        $log->request_time      = date('Y-m-d H:i:s');
-        $log->request_header    = $headers;
+        $log->request_ip = $ip;
+        $log->request_time = date('Y-m-d H:i:s');
+        $log->request_header = $headers;
         $log->save();
     }
-
 }

+ 152 - 394
app/Http/Controllers/UserController.php

@@ -16,7 +16,6 @@ use App\Models\NodePing;
 use App\Models\Order;
 use App\Models\Ticket;
 use App\Models\TicketReply;
-use App\Models\User;
 use App\Models\UserHourlyDataFlow;
 use App\Models\UserLoginLog;
 use App\Models\UserSubscribe;
@@ -46,52 +45,27 @@ use Validator;
  */
 class UserController extends Controller
 {
-
     public function index()
     {
-        $user                   = Auth::getUser();
-        $totalTransfer          = $user->transfer_enable;
-        $usedTransfer           = $user->u + $user->d;
-        $unusedTransfer         = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;
-        $expireTime             = $user->expired_at;
-        $view['remainDays']     = $expireTime < date(
-            'Y-m-d'
-        ) ? -1 : Helpers::daysToNow($expireTime);
-        $view['resetDays']      = $user->reset_time ? Helpers::daysToNow(
-            $user->reset_time
-        ) : 0;
+        $user = Auth::getUser();
+        $totalTransfer = $user->transfer_enable;
+        $usedTransfer = $user->u + $user->d;
+        $unusedTransfer = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;
+        $expireTime = $user->expired_at;
+        $view['remainDays'] = $expireTime < date('Y-m-d') ? -1 : Helpers::daysToNow($expireTime);
+        $view['resetDays'] = $user->reset_time ? Helpers::daysToNow($user->reset_time) : 0;
         $view['unusedTransfer'] = $unusedTransfer;
-        $view['expireTime']     = $expireTime;
-        $view['banedTime']      = $user->ban_time ? date(
-            'Y-m-d H:i:s',
-            $user->ban_time
-        ) : 0;
-        $view['unusedPercent']  = $totalTransfer > 0 ? round(
-            $unusedTransfer / $totalTransfer,
-            2
-        ) : 0;
-        $view['noticeList']     = Article::type(2)->latest()->Paginate(1); // 公告
+        $view['expireTime'] = $expireTime;
+        $view['banedTime'] = $user->ban_time ? date('Y-m-d H:i:s', $user->ban_time) : 0;
+        $view['unusedPercent'] = $totalTransfer > 0 ? round($unusedTransfer / $totalTransfer, 2) : 0;
+        $view['noticeList'] = Article::type(2)->latest()->Paginate(1); // 公告
         //流量异常判断
-        $hourlyTraffic            = UserHourlyDataFlow::userRecentUsed(
-            $user->id
-        )->sum(
-            'total'
-        );
-        $view['isTrafficWarning'] = $hourlyTraffic >= (sysConfig(
-                                                           'traffic_ban_value'
-                                                       ) * GB) ?: 0;
+        $hourlyTraffic = UserHourlyDataFlow::userRecentUsed($user->id)->sum('total');
+        $view['isTrafficWarning'] = $hourlyTraffic >= (sysConfig('traffic_ban_value') * GB) ?: 0;
         //付费用户判断
-        $view['not_paying_user'] = Order::uid()->active()->where(
-            'origin_amount',
-            '>',
-            0
-        )->doesntExist();
-        $view['userLoginLog']    = UserLoginLog::whereUserId($user->id)->latest(
-        )->first(); // 近期登录日志
-        $view                    = array_merge(
-            $view,
-            $this->dataFlowChart($user->id)
-        );
+        $view['not_paying_user'] = Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist();
+        $view['userLoginLog'] = UserLoginLog::whereUserId($user->id)->latest()->first(); // 近期登录日志
+        $view = array_merge($view, $this->dataFlowChart($user->id));
 
         return view('user.index', $view);
     }
@@ -101,51 +75,29 @@ class UserController extends Controller
     {
         $user = Auth::getUser();
         // 系统开启登录加积分功能才可以签到
-        if ( ! sysConfig('is_checkin')) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '系统未开启签到功能']
-            );
+        if (!sysConfig('is_checkin')) {
+            return Response::json(['status' => 'fail', 'message' => '系统未开启签到功能']);
         }
 
         // 已签到过,验证是否有效
-        if (Cache::has('userCheckIn_' . $user->id)) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '已经签到过了,明天再来吧']
-            );
+        if (Cache::has('userCheckIn_'.$user->id)) {
+            return Response::json(['status' => 'fail', 'message' => '已经签到过了,明天再来吧']);
         }
 
-        $traffic = random_int(
-                       (int)sysConfig('min_rand_traffic'),
-                       (int)sysConfig('max_rand_traffic')
-                   ) * MB;
+        $traffic = random_int((int) sysConfig('min_rand_traffic'), (int) sysConfig('max_rand_traffic')) * MB;
 
-        if ( ! (new UserService())->incrementData($traffic)) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '签到失败,系统异常']
-            );
+        if (!(new UserService())->incrementData($traffic)) {
+            return Response::json(['status' => 'fail', 'message' => '签到失败,系统异常']);
         }
 
         // 写入用户流量变动记录
-        Helpers::addUserTrafficModifyLog(
-            $user->id,
-            0,
-            $user->transfer_enable,
-            $user->transfer_enable + $traffic,
-            '[签到]'
-        );
+        Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, $user->transfer_enable + $traffic, '[签到]');
 
         // 多久后可以再签到
-        $ttl = sysConfig('traffic_limit_time') ? sysConfig(
-                                                     'traffic_limit_time'
-                                                 ) * Minute : Day;
-        Cache::put('userCheckIn_' . $user->id, '1', $ttl);
-
-        return Response::json(
-            [
-                'status'  => 'success',
-                'message' => '签到成功,系统送您 ' . flowAutoShow($traffic) . '流量',
-            ]
-        );
+        $ttl = sysConfig('traffic_limit_time') ? sysConfig('traffic_limit_time') * Minute : Day;
+        Cache::put('userCheckIn_'.$user->id, '1', $ttl);
+
+        return Response::json(['status' => 'success', 'message' => '签到成功,系统送您 '.flowAutoShow($traffic).'流量']);
     }
 
     // 节点列表
@@ -157,45 +109,33 @@ class UserController extends Controller
 
             $node = Node::find($request->input('id'));
             // 生成节点信息
-            if ($node->type == 1) {
+            if ($node->type === 1) {
                 $proxyType = $node->compatible ? 'SS' : 'SSR';
             } else {
                 $proxyType = 'V2Ray';
             }
-            $data = $this->getUserNodeInfo(
-                $user->id,
-                $node->id,
-                $infoType !== 'text' ? 0 : 1
-            );
-
-            return Response::json(
-                ['status' => 'success', 'data' => $data, 'title' => $proxyType]
-            );
+            $data = $this->getUserNodeInfo($user->id, $node->id, $infoType !== 'text' ? 0 : 1);
+
+            return Response::json(['status' => 'success', 'data' => $data, 'title' => $proxyType]);
         }
 
         // 获取当前用户可用节点
-        $nodeList = $user->userAccessNodes()
-                         ->with(['labels', 'level_table'])
-                         ->get();
+        $nodeList = $user->userAccessNodes()->with(['labels', 'level_table'])->get();
 
         $view['nodesGeo'] = $nodeList->pluck('name', 'geo')->toArray();
-        $onlineNode       = NodeHeartBeat::recently()->distinct()->pluck(
-            'node_id'
-        )->toArray();
-        $pingNodeLogs     = NodePing::whereMonth('created_at', date('m'))->get(
-            ['node_id', 'ct', 'cu', 'cm', 'hk']
-        );
+        $onlineNode = NodeHeartBeat::recently()->distinct()->pluck('node_id')->toArray();
+        $pingNodeLogs = NodePing::whereMonth('created_at', date('m'))->get(['node_id', 'ct', 'cu', 'cm', 'hk']);
         foreach ($nodeList as $node) {
-            $data     = $pingNodeLogs->where('node_id', $node->id);
+            $data = $pingNodeLogs->where('node_id', $node->id);
             $node->ct = round($data->pluck('ct')->filter()->avg(), 2);
             $node->cu = round($data->pluck('cu')->filter()->avg(), 2);
             $node->cm = round($data->pluck('cm')->filter()->avg(), 2);
             $node->hk = round($data->pluck('hk')->filter()->avg(), 2);
 
             // 节点在线状态
-            $node->offline = ! in_array($node->id, $onlineNode);
+            $node->offline = !in_array($node->id, $onlineNode, true);
         }
-        $view['nodeList'] = $nodeList ?: [];
+        $view['nodeList'] = $nodeList ?? [];
 
         return view('user.nodeList', $view);
     }
@@ -215,66 +155,48 @@ class UserController extends Controller
         if ($request->isMethod('POST')) {
             $old_password = $request->input('old_password');
             $new_password = $request->input('new_password');
-            $username     = $request->input('username');
-            $wechat       = $request->input('wechat');
-            $qq           = $request->input('qq');
-            $passwd       = $request->input('passwd');
+            $username = $request->input('username');
+            $wechat = $request->input('wechat');
+            $qq = $request->input('qq');
+            $passwd = $request->input('passwd');
 
             // 修改密码
             if ($old_password && $new_password) {
-                if ( ! Hash::check($old_password, $user->password)) {
-                    return Redirect::to('profile#tab_1')->withErrors(
-                        '旧密码错误,请重新输入'
-                    );
+                if (!Hash::check($old_password, $user->password)) {
+                    return Redirect::to('profile#tab_1')->withErrors('旧密码错误,请重新输入');
                 }
 
                 if (Hash::check($new_password, $user->password)) {
-                    return Redirect::to('profile#tab_1')->withErrors(
-                        '新密码不可与旧密码一样,请重新输入'
-                    );
+                    return Redirect::to('profile#tab_1')->withErrors('新密码不可与旧密码一样,请重新输入');
                 }
 
                 // 演示环境禁止改管理员密码
-                if ($user->id === 1 && env('APP_DEMO')) {
-                    return Redirect::to('profile#tab_1')->withErrors(
-                        '演示环境禁止修改管理员密码'
-                    );
+                if ($user->id === 1 && config('app.demo')) {
+                    return Redirect::to('profile#tab_1')->withErrors('演示环境禁止修改管理员密码');
                 }
 
-                if ( ! $user->update(
-                    ['password' => Hash::make($new_password)]
-                )) {
+                if (!$user->update(['password' => $new_password])) {
                     return Redirect::to('profile#tab_1')->withErrors('修改失败');
                 }
 
-                return Redirect::to('profile#tab_1')->with(
-                    'successMsg',
-                    '修改成功'
-                );
+                return Redirect::to('profile#tab_1')->with('successMsg', '修改成功');
                 // 修改代理密码
             }
 
             if ($passwd) {
-                if ( ! $user->update(['passwd' => $passwd])) {
+                if (!$user->update(['passwd' => $passwd])) {
                     return Redirect::to('profile#tab_3')->withErrors('修改失败');
                 }
 
-                return Redirect::to('profile#tab_3')->with(
-                    'successMsg',
-                    '修改成功'
-                );
+                return Redirect::to('profile#tab_3')->with('successMsg', '修改成功');
             }
 
             // 修改联系方式
             if (empty($username)) {
-                return Redirect::to('profile#tab_2')->withErrors(
-                    '修改失败,昵称不能为空值'
-                );
+                return Redirect::to('profile#tab_2')->withErrors('修改失败,昵称不能为空值');
             }
 
-            if ( ! $user->update(
-                ['username' => $username, 'wechat' => $wechat, 'qq' => $qq]
-            )) {
+            if (!$user->update(['username' => $username, 'wechat' => $wechat, 'qq' => $qq])) {
                 return Redirect::to('profile#tab_2')->withErrors('修改失败');
             }
 
@@ -289,23 +211,19 @@ class UserController extends Controller
     {
         $user = Auth::getUser();
         // 余额充值商品,只取10个
-        $view['chargeGoodsList'] = Goods::type(3)->whereStatus(1)->orderBy(
-            'price'
-        )->limit(10)->get();
-        $view['goodsList']       = Goods::whereStatus(1)
-                                        ->where('type', '<=', '2')
-                                        ->orderByDesc('type')
-                                        ->orderByDesc('sort')
-                                        ->paginate(10)
-                                        ->appends($request->except('page'));
-        $renewOrder              = Order::userActivePlan($user->id)->first();
-        $renewPrice              = $renewOrder ? $renewOrder->goods : 0;
-        $view['renewTraffic']    = $renewPrice ? $renewPrice->renew : 0;
+        $view['chargeGoodsList'] = Goods::type(3)->whereStatus(1)->orderBy('price')->limit(10)->get();
+        $view['goodsList'] = Goods::whereStatus(1)
+            ->where('type', '<=', '2')
+            ->orderByDesc('type')
+            ->orderByDesc('sort')
+            ->paginate(10)
+            ->appends($request->except('page'));
+        $renewOrder = Order::userActivePlan($user->id)->first();
+        $renewPrice = $renewOrder->goods ?? 0;
+        $view['renewTraffic'] = $renewPrice->renew ?? 0;
         // 有重置日时按照重置日为标准,否者就以过期日为标准
-        $dataPlusDays         = $user->reset_time ?: $user->expired_at;
-        $view['dataPlusDays'] = $dataPlusDays > date(
-            'Y-m-d'
-        ) ? Helpers::daysToNow($dataPlusDays) : 0;
+        $dataPlusDays = $user->reset_time ?? $user->expired_at;
+        $view['dataPlusDays'] = $dataPlusDays > date('Y-m-d') ? Helpers::daysToNow($dataPlusDays) : 0;
 
         return view('user.services', $view);
     }
@@ -313,13 +231,11 @@ class UserController extends Controller
     //重置流量
     public function resetUserTraffic(): ?JsonResponse
     {
-        $user      = Auth::getUser();
-        $order     = Order::userActivePlan()->first();
+        $user = Auth::getUser();
+        $order = Order::userActivePlan()->first();
         $renewCost = $order->goods->renew;
         if ($user->credit < $renewCost) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '余额不足,请充值余额']
-            );
+            return Response::json(['status' => 'fail', 'message' => '余额不足,请充值余额']);
         }
 
         $user->update(['u' => 0, 'd' => 0]);
@@ -328,14 +244,7 @@ class UserController extends Controller
         (new UserService($user))->updateCredit(-$renewCost);
 
         // 记录余额操作日志
-        Helpers::addUserCreditLog(
-            $user->id,
-            '',
-            $user->credit,
-            $user->credit - $renewCost,
-            -1 * $renewCost,
-            '用户自行重置流量'
-        );
+        Helpers::addUserCreditLog($user->id, '', $user->credit, $user->credit - $renewCost, -1 * $renewCost, '用户自行重置流量');
 
         return Response::json(['status' => 'success', 'message' => '重置成功']);
     }
@@ -343,9 +252,7 @@ class UserController extends Controller
     // 工单
     public function ticketList(Request $request)
     {
-        $view['ticketList'] = Ticket::uid()->latest()->paginate(10)->appends(
-            $request->except('page')
-        );
+        $view['ticketList'] = Ticket::uid()->latest()->paginate(10)->appends($request->except('page'));
 
         return view('user.ticketList', $view);
     }
@@ -353,11 +260,11 @@ class UserController extends Controller
     // 订单
     public function invoices(Request $request)
     {
-        $view['orderList']   = Order::uid()
-                                    ->with(['goods', 'payment'])
-                                    ->orderByDesc('id')
-                                    ->paginate(10)
-                                    ->appends($request->except('page'));
+        $view['orderList'] = Order::uid()
+            ->with(['goods', 'payment'])
+            ->orderByDesc('id')
+            ->paginate(10)
+            ->appends($request->except('page'));
         $view['prepaidPlan'] = Order::userPrepay()->exists();
 
         return view('user.invoices', $view);
@@ -365,15 +272,13 @@ class UserController extends Controller
 
     public function closePlan(): JsonResponse
     {
-        $activePlan            = Order::userActivePlan()->first();
+        $activePlan = Order::userActivePlan()->first();
         $activePlan->is_expire = 1;
 
         if ($activePlan->save()) {
             // 关闭先前套餐后,新套餐自动运行
             if (Order::userActivePlan()->exists()) {
-                return Response::json(
-                    ['status' => 'success', 'message' => '激活成功']
-                );
+                return Response::json(['status' => 'success', 'message' => '激活成功']);
             }
 
             return Response::json(['status' => 'success', 'message' => '关闭']);
@@ -385,10 +290,7 @@ class UserController extends Controller
     // 订单明细
     public function invoiceDetail($sn)
     {
-        $view['order'] = Order::uid()
-                              ->with(['goods', 'coupon', 'payment'])
-                              ->whereOrderSn($sn)
-                              ->firstOrFail();
+        $view['order'] = Order::uid()->with(['goods', 'coupon', 'payment'])->whereOrderSn($sn)->firstOrFail();
 
         return view('user.invoiceDetail', $view);
     }
@@ -396,41 +298,30 @@ class UserController extends Controller
     // 添加工单
     public function createTicket(Request $request): ?JsonResponse
     {
-        $user    = Auth::getUser();
-        $title   = $request->input('title');
+        $user = Auth::getUser();
+        $title = $request->input('title');
         $content = clean($request->input('content'));
         $content = str_replace(["atob", "eval"], "", $content);
 
         if (empty($title) || empty($content)) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '请输入标题和内容']
-            );
+            return Response::json(['status' => 'fail', 'message' => '请输入标题和内容']);
         }
 
-        $obj          = new Ticket();
+        $obj = new Ticket();
         $obj->user_id = $user->id;
-        $obj->title   = $title;
+        $obj->title = $title;
         $obj->content = $content;
-        $obj->status  = 0;
+        $obj->status = 0;
         $obj->save();
 
         if ($obj->id) {
             $emailTitle = "新工单提醒";
-            $content    = "标题:【" . $title . "】<br>用户:" . $user->email . "<br>内容:" . $content;
+            $content = "标题:【".$title."】<br>用户:".$user->email."<br>内容:".$content;
 
             // 发邮件通知管理员
             if (sysConfig('webmaster_email')) {
-                $logId = Helpers::addNotificationLog(
-                    $emailTitle,
-                    $content,
-                    1,
-                    sysConfig(
-                        'webmaster_email'
-                    )
-                );
-                Mail::to(sysConfig('webmaster_email'))->send(
-                    new newTicket($logId, $emailTitle, $content)
-                );
+                $logId = Helpers::addNotificationLog($emailTitle, $content, 1, sysConfig('webmaster_email'));
+                Mail::to(sysConfig('webmaster_email'))->send(new newTicket($logId, $emailTitle, $content));
             }
 
             PushNotification::send($emailTitle, $content);
@@ -454,21 +345,17 @@ class UserController extends Controller
             $content = substr($content, 0, 300);
 
             if (empty($content)) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '回复内容不能为空']
-                );
+                return Response::json(['status' => 'fail', 'message' => '回复内容不能为空']);
             }
 
             if ($ticket->status == 2) {
-                return Response::json(
-                    ['status' => 'fail', 'message' => '错误:该工单已关闭']
-                );
+                return Response::json(['status' => 'fail', 'message' => '错误:该工单已关闭']);
             }
 
-            $obj            = new TicketReply();
+            $obj = new TicketReply();
             $obj->ticket_id = $id;
-            $obj->user_id   = Auth::id();
-            $obj->content   = $content;
+            $obj->user_id = Auth::id();
+            $obj->content = $content;
             $obj->save();
 
             if ($obj->id) {
@@ -476,39 +363,25 @@ class UserController extends Controller
                 $ticket->status = 0;
                 $ticket->save();
 
-                $title   = "工单回复提醒";
-                $content = "标题:【" . $ticket->title . "】<br>用户回复:" . $content;
+                $title = "工单回复提醒";
+                $content = "标题:【".$ticket->title."】<br>用户回复:".$content;
 
                 // 发邮件通知管理员
                 if (sysConfig('webmaster_email')) {
-                    $logId = Helpers::addNotificationLog(
-                        $title,
-                        $content,
-                        1,
-                        sysConfig(
-                            'webmaster_email'
-                        )
-                    );
-                    Mail::to(sysConfig('webmaster_email'))->send(
-                        new replyTicket($logId, $title, $content)
-                    );
+                    $logId = Helpers::addNotificationLog($title, $content, 1, sysConfig('webmaster_email'));
+                    Mail::to(sysConfig('webmaster_email'))->send(new replyTicket($logId, $title, $content));
                 }
 
                 PushNotification::send($title, $content);
 
-                return Response::json(
-                    ['status' => 'success', 'message' => '回复成功']
-                );
+                return Response::json(['status' => 'success', 'message' => '回复成功']);
             }
 
             return Response::json(['status' => 'fail', 'message' => '回复失败']);
         }
 
-        $view['ticket']    = $ticket;
-        $view['replyList'] = TicketReply::whereTicketId($id)
-                                        ->with('user')
-                                        ->oldest()
-                                        ->get();
+        $view['ticket'] = $ticket;
+        $view['replyList'] = TicketReply::whereTicketId($id)->with('user')->oldest()->get();
 
         return view('user.replyTicket', $view);
     }
@@ -520,7 +393,7 @@ class UserController extends Controller
 
         $ret = Ticket::uid()->whereId($id)->update(['status' => 2]);
         if ($ret) {
-            PushNotification::send('工单关闭提醒', '工单:ID' . $id . '用户已手动关闭');
+            PushNotification::send('工单关闭提醒', '工单:ID'.$id.'用户已手动关闭');
 
             return Response::json(['status' => 'success', 'message' => '关闭成功']);
         }
@@ -531,22 +404,14 @@ class UserController extends Controller
     // 邀请码
     public function invite()
     {
-        if (Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist(
-        )) {
-            return Response::view(
-                'auth.error',
-                ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返 回</a>'],
-                402
-            );
+        if (Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist()) {
+            return Response::view('auth.error',
+                ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返 回</a>'], 402);
         }
 
-        $view['num']              = Auth::getUser()->invite_num; // 还可以生成的邀请码数量
-        $view['inviteList']       = Invite::uid()
-                                          ->with(['invitee', 'inviter'])
-                                          ->paginate(10); // 邀请码列表
-        $view['referral_traffic'] = flowAutoShow(
-            sysConfig('referral_traffic') * MB
-        );
+        $view['num'] = Auth::getUser()->invite_num; // 还可以生成的邀请码数量
+        $view['inviteList'] = Invite::uid()->with(['invitee', 'inviter'])->paginate(10); // 邀请码列表
+        $view['referral_traffic'] = flowAutoShow(sysConfig('referral_traffic') * MB);
         $view['referral_percent'] = sysConfig('referral_percent');
 
         return view('user.invite', $view);
@@ -557,29 +422,18 @@ class UserController extends Controller
     {
         $user = Auth::getUser();
         if ($user->invite_num <= 0) {
-            return Response::json(
-                ['status' => 'fail', 'message' => '生成失败:已无邀请码生成名额']
-            );
+            return Response::json(['status' => 'fail', 'message' => '生成失败:已无邀请码生成名额']);
         }
 
-        $obj             = new Invite();
+        $obj = new Invite();
         $obj->inviter_id = $user->id;
         $obj->invitee_id = 0;
-        $obj->code       = strtoupper(
-            mb_substr(md5(microtime() . Str::random()), 8, 12)
-        );
-        $obj->status     = 0;
-        $obj->dateline   = date(
-            'Y-m-d H:i:s',
-            strtotime(
-                "+" . sysConfig(
-                    'user_invite_days'
-                ) . " days"
-            )
-        );
+        $obj->code = strtoupper(mb_substr(md5(microtime().Str::random()), 8, 12));
+        $obj->status = 0;
+        $obj->dateline = date('Y-m-d H:i:s', strtotime("+".sysConfig('user_invite_days')." days"));
         $obj->save();
 
-        User::uid()->decrement('invite_num', 1);
+        $user->decrement('invite_num', 1);
 
         return Response::json(['status' => 'success', 'message' => '生成成功']);
     }
@@ -587,69 +441,39 @@ class UserController extends Controller
     // 使用优惠券
     public function redeemCoupon(Request $request): JsonResponse
     {
-        $coupon_sn  = $request->input('coupon_sn');
+        $coupon_sn = $request->input('coupon_sn');
         $good_price = $request->input('price');
 
         if (empty($coupon_sn)) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'title'   => '使用失败',
-                    'message' => '请输入您的优惠劵!',
-                ]
-            );
+            return Response::json(['status' => 'fail', 'title' => '使用失败', 'message' => '请输入您的优惠劵!']);
         }
 
         $coupon = Coupon::whereSn($coupon_sn)->whereIn('type', [1, 2])->first();
-        if ( ! $coupon) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'title'   => '优惠券不存在',
-                    'message' => '请确认优惠券是否输入正确!',
-                ]
-            );
+        if (!$coupon) {
+            return Response::json(['status' => 'fail', 'title' => '优惠券不存在', 'message' => '请确认优惠券是否输入正确!']);
         }
 
         if ($coupon->status == 1) {
-            return Response::json(
-                ['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已被使用!']
-            );
+            return Response::json(['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已被使用!']);
         }
 
         if ($coupon->status == 2) {
-            return Response::json(
-                ['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已失效!']
-            );
+            return Response::json(['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已失效!']);
         }
 
         if ($coupon->end_time < time()) {
             $coupon->status = 2;
             $coupon->save();
 
-            return Response::json(
-                ['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已失效!']
-            );
+            return Response::json(['status' => 'fail', 'title' => '抱歉', 'message' => '优惠券已失效!']);
         }
 
         if ($coupon->start_time > time()) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'title'   => '优惠券尚未生效',
-                    'message' => '请等待活动正式开启',
-                ]
-            );
+            return Response::json(['status' => 'fail', 'title' => '优惠券尚未生效', 'message' => '请等待活动正式开启']);
         }
 
         if ($good_price < $coupon->rule) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'title'   => '使用条件未满足',
-                    'message' => '请购买价格更高的套餐',
-                ]
-            );
+            return Response::json(['status' => 'fail', 'title' => '使用条件未满足', 'message' => '请购买价格更高的套餐']);
         }
 
         $data = [
@@ -658,26 +482,22 @@ class UserController extends Controller
             'value' => $coupon->value,
         ];
 
-        return Response::json(
-            ['status' => 'success', 'data' => $data, 'message' => '优惠券有效']
-        );
+        return Response::json(['status' => 'success', 'data' => $data, 'message' => '优惠券有效']);
     }
 
     // 购买服务
     public function buy($goods_id)
     {
-        $user  = Auth::getUser();
+        $user = Auth::getUser();
         $goods = Goods::whereId($goods_id)->whereStatus(1)->first();
         if (empty($goods)) {
             return Redirect::to('services');
         }
         // 有重置日时按照重置日为标准,否者就以过期日为标准
-        $dataPlusDays         = $user->reset_time ?: $user->expired_at;
-        $view['dataPlusDays'] = $dataPlusDays > date(
-            'Y-m-d'
-        ) ? Helpers::daysToNow($dataPlusDays) : 0;
-        $view['activePlan']   = Order::userActivePlan()->exists();
-        $view['goods']        = $goods;
+        $dataPlusDays = $user->reset_time ?? $user->expired_at;
+        $view['dataPlusDays'] = $dataPlusDays > date('Y-m-d') ? Helpers::daysToNow($dataPlusDays) : 0;
+        $view['activePlan'] = Order::userActivePlan()->exists();
+        $view['goods'] = $goods;
 
         return view('user.buy', $view);
     }
@@ -701,55 +521,20 @@ class UserController extends Controller
         $view['sub'] = $data;
 
         //付费用户判断
-        $view['not_paying_user'] = Order::uid()->active()->where(
-            'origin_amount',
-            '>',
-            0
-        )->doesntExist();
+        $view['not_paying_user'] = Order::uid()->active()->where('origin_amount', '>', 0)->doesntExist();
         //客户端安装
-        $view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url=' . sysConfig(
-                'website_url'
-            ) . '/clients/Shadowrocket.plist';
-        $view['Quantumult_install']   = 'itms-services://?action=download-manifest&url=' . sysConfig(
-                'website_url'
-            ) . '/clients/Quantumult.plist';
+        $view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url='.sysConfig('website_url').'/clients/Shadowrocket.plist';
+        $view['Quantumult_install'] = 'itms-services://?action=download-manifest&url='.sysConfig('website_url').'/clients/Quantumult.plist';
         // 订阅连接
-        $subscribe                       = UserSubscribe::whereUserId(
-            Auth::id()
-        )
-                                                        ->firstOrFail();
-        $view['subscribe_status']        = $subscribe->status;
-        $subscribe_link                  = (sysConfig(
-                'subscribe_domain'
-            ) ?: sysConfig(
-                'website_url'
-            )) . '/s/' . $subscribe->code;
-        $view['link']                    = $subscribe_link;
-        $view['subscribe_link']          = 'sub://' . base64url_encode(
-                $subscribe_link
-            );
-        $view['Shadowrocket_link']       = 'shadowrocket://add/sub://' . base64url_encode(
-                $subscribe_link
-            ) . '?remarks=' . (sysConfig('website_name') . '-' . sysConfig(
-                    'website_url'
-                ));
-        $view['Shadowrocket_linkQrcode'] = 'sub://' . base64url_encode(
-                $subscribe_link
-            ) . '#' . base64url_encode(sysConfig('website_name'));
-        $view['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'
-                                           );
-        $view['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'
-                                           );
+        $subscribe = UserSubscribe::whereUserId(Auth::id())->firstOrFail();
+        $view['subscribe_status'] = $subscribe->status;
+        $subscribe_link = (sysConfig('subscribe_domain') ?: sysConfig('website_url')).'/s/'.$subscribe->code;
+        $view['link'] = $subscribe_link;
+        $view['subscribe_link'] = 'sub://'.base64url_encode($subscribe_link);
+        $view['Shadowrocket_link'] = 'shadowrocket://add/sub://'.base64url_encode($subscribe_link).'?remarks='.(sysConfig('website_name').'-'.sysConfig('website_url'));
+        $view['Shadowrocket_linkQrcode'] = 'sub://'.base64url_encode($subscribe_link).'#'.base64url_encode(sysConfig('website_name'));
+        $view['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');
+        $view['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');
 
         return view('user.help', $view);
     }
@@ -761,9 +546,7 @@ class UserController extends Controller
             DB::beginTransaction();
 
             // 更换订阅码
-            Auth::getUser()->subscribe->update(
-                ['code' => Helpers::makeSubscribeCode()]
-            );
+            Auth::getUser()->subscribe->update(['code' => Helpers::makeSubscribeCode()]);
 
             // 更换连接密码
             Auth::getUser()->update(['passwd' => Str::random()]);
@@ -774,18 +557,16 @@ class UserController extends Controller
         } catch (Exception $e) {
             DB::rollBack();
 
-            Log::error("更换订阅地址异常:" . $e->getMessage());
+            Log::error("更换订阅地址异常:".$e->getMessage());
 
-            return Response::json(
-                ['status' => 'fail', 'message' => '更换失败' . $e->getMessage()]
-            );
+            return Response::json(['status' => 'fail', 'message' => '更换失败'.$e->getMessage()]);
         }
     }
 
     // 转换成管理员的身份
     public function switchToAdmin(): JsonResponse
     {
-        if ( ! Session::has('admin')) {
+        if (!Session::has('admin')) {
             return Response::json(['status' => 'fail', 'message' => '非法请求']);
         }
 
@@ -793,9 +574,7 @@ class UserController extends Controller
         $user = Auth::loginUsingId(Session::get('admin'));
         Session::forget('admin');
         if ($user) {
-            return Response::json(
-                ['status' => 'success', 'message' => "身份切换成功"]
-            );
+            return Response::json(['status' => 'success', 'message' => "身份切换成功"]);
         }
 
         return Response::json(['status' => 'fail', 'message' => '身份切换失败']);
@@ -804,28 +583,14 @@ class UserController extends Controller
     // Todo 卡券余额合并至CouponService
     public function charge(Request $request): ?JsonResponse
     {
-        $validator = Validator::make(
-            $request->all(),
-            [
-                'coupon_sn' => [
-                    'required',
-                    Rule::exists('coupon', 'sn')->where(
-                        static function ($query) {
-                            $query->whereType(3)->whereStatus(0);
-                        }
-                    ),
-                ],
+        $validator = Validator::make($request->all(), [
+            'coupon_sn' => [
+                'required', Rule::exists('coupon', 'sn')->where(static function ($query) { $query->whereType(3)->whereStatus(0); }),
             ],
-            ['coupon_sn.required' => '券码不能为空', 'coupon_sn.exists' => '该券不可用']
-        );
+        ], ['coupon_sn.required' => '券码不能为空', 'coupon_sn.exists' => '该券不可用']);
 
         if ($validator->fails()) {
-            return Response::json(
-                [
-                    'status'  => 'fail',
-                    'message' => $validator->getMessageBag()->first(),
-                ]
-            );
+            return Response::json(['status' => 'fail', 'message' => $validator->getMessageBag()->first()]);
         }
 
         $coupon = Coupon::whereSn($request->input('coupon_sn'))->firstOrFail();
@@ -834,14 +599,8 @@ class UserController extends Controller
             DB::beginTransaction();
             // 写入日志
             $user = Auth::getUser();
-            Helpers::addUserCreditLog(
-                $user->id,
-                0,
-                $user->credit,
-                $user->credit + $coupon->value,
-                $coupon->value,
-                '用户手动充值 - [充值券:' . $request->input('coupon_sn') . ']'
-            );
+            Helpers::addUserCreditLog($user->id, 0, $user->credit, $user->credit + $coupon->value, $coupon->value,
+                '用户手动充值 - [充值券:'.$request->input('coupon_sn').']');
 
             // 余额充值
             (new UserService($user))->updateCredit($coupon->value);
@@ -856,11 +615,10 @@ class UserController extends Controller
 
             return Response::json(['status' => 'success', 'message' => '充值成功']);
         } catch (Exception $e) {
-            Log::error('卡劵充值错误:' . $e->getMessage());
+            Log::error('卡劵充值错误:'.$e->getMessage());
             DB::rollBack();
 
             return Response::json(['status' => 'fail', 'message' => '充值失败']);
         }
     }
-
 }

+ 0 - 2
app/Http/Kernel.php

@@ -36,7 +36,6 @@ use Illuminate\View\Middleware\ShareErrorsFromSession;
 
 class Kernel extends HttpKernel
 {
-
     /**
      * The application's global HTTP middleware stack.
      *
@@ -105,5 +104,4 @@ class Kernel extends HttpKernel
         'affiliate'        => Affiliate::class,
 
     ];
-
 }

+ 0 - 2
app/Http/Middleware/Affiliate.php

@@ -8,7 +8,6 @@ use Illuminate\Http\Request;
 
 class Affiliate
 {
-
     /**
      * 返利识别
      *
@@ -26,5 +25,4 @@ class Affiliate
 
         return $next($request);
     }
-
 }

+ 4 - 6
app/Http/Middleware/Authenticate.php

@@ -3,23 +3,21 @@
 namespace App\Http\Middleware;
 
 use Illuminate\Auth\Middleware\Authenticate as Middleware;
+use Illuminate\Http\Request;
 
 class Authenticate extends Middleware
 {
-
     /**
-     * Get the path the user should be redirected to when they are not
-     * authenticated.
+     * Get the path the user should be redirected to when they are not authenticated.
      *
-     * @param  \Illuminate\Http\Request  $request
+     * @param  Request  $request
      *
      * @return string|null
      */
     protected function redirectTo($request)
     {
-        if ( ! $request->expectsJson()) {
+        if (!$request->expectsJson()) {
             return route('login');
         }
     }
-
 }

+ 0 - 2
app/Http/Middleware/CheckForMaintenanceMode.php

@@ -6,7 +6,6 @@ use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
 
 class CheckForMaintenanceMode extends Middleware
 {
-
     /**
      * The URIs that should be reachable while maintenance mode is enabled.
      *
@@ -14,5 +13,4 @@ class CheckForMaintenanceMode extends Middleware
      */
     protected $except = [//
     ];
-
 }

+ 0 - 2
app/Http/Middleware/EncryptCookies.php

@@ -6,7 +6,6 @@ use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
 
 class EncryptCookies extends Middleware
 {
-
     /**
      * The names of the cookies that should not be encrypted.
      *
@@ -14,5 +13,4 @@ class EncryptCookies extends Middleware
      */
     protected $except = [//
     ];
-
 }

+ 2 - 4
app/Http/Middleware/RedirectIfAuthenticated.php

@@ -9,12 +9,11 @@ use Illuminate\Http\Request;
 
 class RedirectIfAuthenticated
 {
-
     /**
      * Handle an incoming request.
      *
-     * @param  \Illuminate\Http\Request  $request
-     * @param  \Closure  $next
+     * @param  Request  $request
+     * @param  Closure  $next
      * @param  string|null  $guard
      *
      * @return mixed
@@ -27,5 +26,4 @@ class RedirectIfAuthenticated
 
         return $next($request);
     }
-
 }

+ 0 - 2
app/Http/Middleware/SetLocale.php

@@ -8,7 +8,6 @@ use Session;
 
 class SetLocale
 {
-
     /**
      * 变更语言
      *
@@ -30,5 +29,4 @@ class SetLocale
 
         return $next($request);
     }
-
 }

+ 0 - 2
app/Http/Middleware/TrimStrings.php

@@ -6,7 +6,6 @@ use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
 
 class TrimStrings extends Middleware
 {
-
     /**
      * The names of the attributes that should not be trimmed.
      *
@@ -16,5 +15,4 @@ class TrimStrings extends Middleware
         'password',
         'password_confirmation',
     ];
-
 }

+ 0 - 2
app/Http/Middleware/TrustHosts.php

@@ -6,7 +6,6 @@ use Illuminate\Http\Middleware\TrustHosts as Middleware;
 
 class TrustHosts extends Middleware
 {
-
     /**
      * Get the host patterns that should be trusted.
      *
@@ -18,5 +17,4 @@ class TrustHosts extends Middleware
             $this->allSubdomainsOfApplicationUrl(),
         ];
     }
-
 }

+ 0 - 2
app/Http/Middleware/TrustProxies.php

@@ -7,7 +7,6 @@ use Illuminate\Http\Request;
 
 class TrustProxies extends Middleware
 {
-
     /**
      * The trusted proxies for this application.
      *
@@ -21,5 +20,4 @@ class TrustProxies extends Middleware
      * @var int
      */
     protected $headers = Request::HEADER_X_FORWARDED_ALL;
-
 }

+ 0 - 2
app/Http/Middleware/VerifyCsrfToken.php

@@ -6,7 +6,6 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
 
 class VerifyCsrfToken extends Middleware
 {
-
     /**
      * The URIs that should be excluded from CSRF verification.
      *
@@ -15,5 +14,4 @@ class VerifyCsrfToken extends Middleware
     protected $except = [
         "callback/notify",
     ];
-
 }

+ 7 - 11
app/Http/Middleware/WebApi.php

@@ -10,7 +10,6 @@ use Response;
 
 class WebApi
 {
-
     /**
      * Handle an incoming request.
      *
@@ -21,25 +20,25 @@ class WebApi
      */
     public function handle($request, Closure $next)
     {
-        $id   = $request->id;
-        $key  = $request->header('key');
+        $id = $request->id;
+        $key = $request->header('key');
         $time = $request->header('timestamp');
 
-        if ( ! isset($key)) {// 未提供 key
+        if (!isset($key)) {// 未提供 key
             return $this->returnData('Your key is null!');
         }
 
-        if ( ! isset($id)) {// 未提供 node
+        if (!isset($id)) {// 未提供 node
             return $this->returnData('Your Node Id is null!');
         }
 
         $node = Node::find($id);
-        if ( ! $node) {// node不存在
+        if (!$node) {// node不存在
             return $this->returnData('Unknown Node!');
         }
 
         $nodeAuth = NodeAuth::whereNodeId($id)->first();
-        if ( ! $nodeAuth || $key !== $nodeAuth->key) {// key不存在/不匹配
+        if (!$nodeAuth || $key !== $nodeAuth->key) {// key不存在/不匹配
             return $this->returnData('Token is invalid!');
         }
 
@@ -53,9 +52,6 @@ class WebApi
     // 返回数据
     public function returnData($message): JsonResponse
     {
-        return Response::json(
-            ['status' => 'fail', 'code' => 404, 'message' => $message]
-        );
+        return Response::json(['status' => 'fail', 'code' => 404, 'message' => $message]);
     }
-
 }

+ 1 - 3
app/Http/Middleware/isAdmin.php

@@ -9,7 +9,6 @@ use Redirect;
 
 class isAdmin
 {
-
     /**
      * 校验是否为管理员身份
      *
@@ -20,11 +19,10 @@ class isAdmin
      */
     public function handle(Request $request, Closure $next)
     {
-        if ( ! Auth::getUser()->is_admin) {
+        if (!Auth::getUser()->is_admin) {
             return Redirect::to('/');
         }
 
         return $next($request);
     }
-
 }

+ 0 - 2
app/Http/Middleware/isAdminlogin.php

@@ -8,7 +8,6 @@ use Redirect;
 
 class isAdminLogin
 {
-
     /**
      * Handle an incoming request.
      *
@@ -25,5 +24,4 @@ class isAdminLogin
 
         return $next($request);
     }
-
 }

+ 15 - 53
app/Http/Middleware/isForbidden.php

@@ -24,82 +24,44 @@ class isForbidden
     {
         // 拒绝机器人访问
         if (sysConfig('is_forbid_robot') && Agent::isRobot()) {
-            Log::info("识别到机器人访问(" . IP::getClientIp() . ")");
+            Log::info("识别到机器人访问(".IP::getClientIp().")");
 
-            return Response::view(
-                'auth.error',
-                ['message' => trans('error.ForbiddenRobot')],
-                403
-            );
+            return Response::view('auth.error', ['message' => trans('error.ForbiddenRobot')], 403);
         }
 
         // 拒绝通过订阅链接域名访问网站,防止网站被探测
         if (false !== strpos(sysConfig('subscribe_domain'), $request->getHost())
-            && ! str_contains(
-                sysConfig('subscribe_domain'),
-                sysConfig('website_url')
-            )) {
-            Log::info("识别到通过订阅链接访问,强制跳转至百度(" . IP::getClientIp() . ")");
+            && !str_contains(sysConfig('subscribe_domain'), sysConfig('website_url'))) {
+            Log::info("识别到通过订阅链接访问,强制跳转至百度(".IP::getClientIp().")");
 
             return redirect('https://www.baidu.com');
         }
 
-        $ip         = IP::getClientIP();
+        $ip = IP::getClientIP();
         $ipLocation = IP::getIPInfo($ip);
 
         // 拒绝无IP请求
-        if ( ! $ipLocation || empty(array_filter($ipLocation))) {
-            return Response::view(
-                'auth.error',
-                ['message' => trans('error.ForbiddenAccess')],
-                403
-            );
+        if (!$ipLocation || empty(array_filter($ipLocation))) {
+            return Response::view('auth.error', ['message' => trans('error.ForbiddenAccess')], 403);
         }
 
-        if ( ! in_array($ipLocation['country'], ['本机地址', '局域网'])) {
+        if (!in_array($ipLocation['country'], ['本机地址', '局域网'])) {
             // 拒绝大陆IP访问
-            if (sysConfig('is_forbid_china') &&
-                in_array($ipLocation['country'], ['China', '中国']) &&
-                ! in_array(
-                    $ipLocation['province'],
-                    ['香港', '澳门', '台湾', '台湾省']
-                )) {
-                Log::info('识别到大陆IP,拒绝访问:' . $ip);
+            if (sysConfig('is_forbid_china') && in_array($ipLocation['country'], ['China', '中国'])
+                && !in_array($ipLocation['province'], ['香港', '澳门', '台湾', '台湾省'])) {
+                Log::info('识别到大陆IP,拒绝访问:'.$ip);
 
-                return Response::view(
-                    'auth.error',
-                    [
-                        'message' => trans(
-                            'error.ForbiddenChina'
-                        ),
-                    ],
-                    403
-                );
+                return Response::view('auth.error', ['message' => trans('error.ForbiddenChina')], 403);
             }
 
             // 拒绝非大陆IP访问
-            if (sysConfig('is_forbid_oversea')
-                && ! in_array(
-                    $ipLocation['country'],
-                    ['China', '中国', 'Taiwan', 'Hong Kong', 'Macao']
-                )) {
-                Log::info(
-                    '识别到海外IP,拒绝访问:' . $ip . ' - ' . $ipLocation['country']
-                );
+            if (sysConfig('is_forbid_oversea') && !in_array($ipLocation['country'], ['China', '中国', 'Taiwan', 'Hong Kong', 'Macao'])) {
+                Log::info('识别到海外IP,拒绝访问:'.$ip.' - '.$ipLocation['country']);
 
-                return Response::view(
-                    'auth.error',
-                    [
-                        'message' => trans(
-                            'error.ForbiddenOversea'
-                        ),
-                    ],
-                    403
-                );
+                return Response::view('auth.error', ['message' => trans('error.ForbiddenOversea')], 403);
             }
         }
 
         return $next($request);
     }
-
 }

+ 0 - 2
app/Http/Middleware/isLogin.php

@@ -8,7 +8,6 @@ use Redirect;
 
 class isLogin
 {
-
     /**
      * 校验是否已登录
      *
@@ -25,5 +24,4 @@ class isLogin
 
         return $next($request);
     }
-
 }

+ 4 - 9
app/Http/Middleware/isMaintenance.php

@@ -7,7 +7,6 @@ use Illuminate\Http\Request;
 
 class isMaintenance
 {
-
     /**
      * 校验是否开启维护模式
      *
@@ -19,16 +18,12 @@ class isMaintenance
     public function handle(Request $request, Closure $next)
     {
         if (sysConfig('maintenance_mode')) {
-            return response()->view(
-                'auth.maintenance',
-                [
-                    'message' => sysConfig('maintenance_content'),
-                    'time'    => sysConfig('maintenance_time') ?: '0',
-                ]
-            );
+            return response()->view('auth.maintenance', [
+                'message' => sysConfig('maintenance_content'),
+                'time'    => sysConfig('maintenance_time') ?: '0',
+            ]);
         }
 
         return $next($request);
     }
-
 }

+ 9 - 11
app/Http/Middleware/isSecurity.php

@@ -10,7 +10,6 @@ use Response;
 
 class isSecurity
 {
-
     /**
      * 是否需要安全码才访问(仅用于登录页)
      *
@@ -21,23 +20,23 @@ class isSecurity
      */
     public function handle($request, Closure $next)
     {
-        $ip                  = IP::getClientIP();
-        $code                = $request->securityCode;
-        $cacheKey            = 'SecurityLogin_' . ip2long($ip);
+        $ip = IP::getClientIP();
+        $code = $request->securityCode;
+        $cacheKey = 'SecurityLogin_'.ip2long($ip);
         $websiteSecurityCode = sysConfig('website_security_code');
 
-        if ($websiteSecurityCode && ! Cache::has($cacheKey)) {
+        if ($websiteSecurityCode && !Cache::has($cacheKey)) {
             if ($code != $websiteSecurityCode) {
-                Log::info("拒绝非安全入口访问(" . $ip . ")");
+                Log::info("拒绝非安全入口访问(".$ip.")");
 
                 return Response::view(
                     'auth.error',
                     [
-                        'message' => trans('error.SecurityError') . ', 
-                        ' . trans(
+                        'message' => trans('error.SecurityError').',
+                        '.trans(
                                 'error.Visit'
-                            ) . '<a href="/login?securityCode=" target="_self">' .
-                                     trans('error.SecurityEnter') . '</a>',
+                            ).'<a href="/login?securityCode=" target="_self">'.
+                            trans('error.SecurityEnter').'</a>',
                     ],
                     403
                 );
@@ -48,5 +47,4 @@ class isSecurity
 
         return $next($request);
     }
-
 }

+ 20 - 0
app/Http/Requests/Admin/ArticleRequest.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ArticleRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'title'   => 'required',
+            'type'    => 'required|numeric',
+            'summary' => 'nullable',
+            'logo'    => 'nullable|exclude_if:type,4|image',
+            'content' => 'required',
+            'sort'    => 'required_if:type,1|numeric',
+        ];
+    }
+}

+ 22 - 0
app/Http/Requests/Admin/CouponRequest.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class CouponRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'name'         => 'required',
+            'sn'           => 'unique:coupon',
+            'type'         => 'required|integer|between:1,3',
+            'usable_times' => 'integer|nullable',
+            'num'          => 'required|integer|min:1',
+            'value'        => 'required|numeric|min:0',
+            'start_time'   => 'required|date|before_or_equal:end_time',
+            'end_time'     => 'required|date|after_or_equal:start_time',
+        ];
+    }
+}

+ 53 - 0
app/Http/Requests/Admin/NodeRequest.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class NodeRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'type'           => 'required|between:1,3',
+            'name'           => 'required',
+            'country_code'   => 'required',
+            'server'         => 'required_if:is_ddns,1|nullable|ends_with:'.implode(",", config('domains')),
+            'push_port'      => 'numeric|between:0,65535',
+            'traffic_rate'   => 'required|numeric|min:0',
+            'level'          => 'required|numeric|between:0,255',
+            'speed_limit'    => 'required|numeric|min:0',
+            'client_limit'   => 'required|numeric|min:0',
+            'port'           => 'nullable|numeric|between:0,65535',
+            'ip'             => 'ipv4',
+            'ipv6'           => 'nullable|ipv6',
+            'relay_server'   => 'required_if:is_relay,1',
+            'relay_port'     => 'required_if:is_relay,1|numeric|between:0,65535',
+            'method'         => 'required_if:type,1',
+            'protocol'       => 'required_if:type,1',
+            'obfs'           => 'required_if:type,1',
+            'is_subscribe'   => 'boolean',
+            'is_ddns'        => 'boolean',
+            'is_relay'       => 'boolean',
+            'is_udp'         => 'boolean',
+            'detection_type' => 'between:0,3',
+            'compatible'     => 'boolean',
+            'single'         => 'boolean',
+            'sort'           => 'required|numeric|between:0,255',
+            'status'         => 'boolean',
+            '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_tls'         => 'boolean',
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'server.required_if' => '开启DDNS, 域名不能为空',
+        ];
+    }
+}

+ 20 - 0
app/Http/Requests/Admin/ShopStoreRequest.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ShopStoreRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'name'    => 'required',
+            'traffic' => 'required|integer|min:1|max:10240000|nullable',
+            'price'   => 'required|numeric|min:0',
+            'type'    => 'required',
+            'renew'   => 'required_unless:type,2|min:0',
+            'days'    => 'required|integer',
+        ];
+    }
+}

+ 17 - 0
app/Http/Requests/Admin/ShopUpdateRequest.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ShopUpdateRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'name'    => 'required',
+            'price'   => 'required|numeric|min:0',
+            'renew'   => 'required_unless:type,2|min:0',
+        ];
+    }
+}

+ 16 - 0
app/Http/Requests/Admin/UserStoreRequest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class UserStoreRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'username' => 'required',
+            'email'    => 'required|unique:user,email,'.$this->user,
+        ];
+    }
+}

+ 33 - 0
app/Http/Requests/Admin/UserUpdateRequest.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Http\Requests\Admin;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class UserUpdateRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'username'        => 'required',
+            'email'           => 'required|unique:user,email,'.$this->user,
+            'port'            => 'required|numeric|exclude_if:port,0|gt:0|unique:user,port,'.$this->user,
+            'passwd'          => 'required|string',
+            'uuid'            => 'required|uuid',
+            'transfer_enable' => 'required|numeric',
+            'enable'          => 'required|boolean',
+            'method'          => 'required|string',
+            'protocol'        => 'required|string',
+            'obfs'            => 'required|string',
+            'speed_limit'     => 'required|numeric',
+            'expired_at'      => 'required|date_format:Y-m-d',
+            'remark'          => 'nullable|string',
+            'level'           => 'required|numeric',
+            'group_id'        => 'numeric',
+            'is_admin'        => 'boolean|exclude_unless:id,1|gte:1',
+            'reset_time'      => 'nullable|date_format:Y-m-d',
+            'invite_num'      => 'numeric',
+            'status'          => 'required|boolean',
+        ];
+    }
+}

+ 8 - 15
app/Jobs/VNet/addUser.php

@@ -12,19 +12,18 @@ use Illuminate\Queue\SerializesModels;
 
 class addUser implements ShouldQueue
 {
-
     use Dispatchable;
     use InteractsWithQueue;
     use Queueable;
     use SerializesModels;
 
-    private $data;
+    private array $data;
     private $nodes;
 
     public function __construct($userIds, $nodes)
     {
         $this->nodes = $nodes;
-        $data        = [];
+        $data = [];
         foreach (User::findMany($userIds) as $user) {
             $data[] = [
                 'uid'         => $user->id,
@@ -41,24 +40,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
-            );
+            $this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
         }
     }
 
     private function send($host, $secret): void
     {
-        $client = new Client(
-            [
-                'base_uri' => $host,
-                'timeout'  => 15,
-                'headers'  => ['secret' => $secret],
-            ]
-        );
+        $client = new Client([
+            'base_uri' => $host,
+            'timeout'  => 15,
+            'headers'  => ['secret' => $secret],
+        ]);
 
         $client->post('api/v2/user/add/list', ['json' => $this->data]);
     }
-
 }

+ 8 - 15
app/Jobs/VNet/delUser.php

@@ -11,7 +11,6 @@ use Illuminate\Queue\SerializesModels;
 
 class delUser implements ShouldQueue
 {
-
     use Dispatchable;
     use InteractsWithQueue;
     use Queueable;
@@ -23,34 +22,28 @@ class delUser implements ShouldQueue
     public function __construct($userIds, $nodes)
     {
         $this->userIds = $userIds;
-        $this->nodes   = $nodes;
+        $this->nodes = $nodes;
     }
 
     public function handle(): void
     {
         foreach ($this->nodes as $node) {
-            $this->send(
-                ($node->server ?: $node->ip) . ':' . $node->push_port,
-                $node->auth->secret
-            );
+            $this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
         }
     }
 
     private function send($host, $secret): void
     {
-        $client = new Client(
-            [
-                'base_uri' => $host,
-                'timeout'  => 15,
-                'headers'  => ['secret' => $secret],
-            ]
-        );
+        $client = new Client([
+            'base_uri' => $host,
+            'timeout'  => 15,
+            'headers'  => ['secret' => $secret],
+        ]);
 
         if (is_array($this->userIds)) {
             $client->post('api/v2/user/del/list', ['json' => $this->userIds]);
         } else {
-            $client->post('api/user/del/' . $this->userIds);
+            $client->post('api/user/del/'.$this->userIds);
         }
     }
-
 }

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

@@ -12,48 +12,41 @@ use Illuminate\Queue\SerializesModels;
 
 class editUser implements ShouldQueue
 {
-
     use Dispatchable;
     use InteractsWithQueue;
     use Queueable;
     use SerializesModels;
 
-    private $data;
+    private array $data;
     private $nodes;
 
     public function __construct(User $user, $nodes)
     {
         $this->nodes = $nodes;
-        $this->data  = [
+        $this->data = [
             'uid'         => $user->id,
-            'port'        => (int)$user->port,
+            'port'        => (int) $user->port,
             'passwd'      => $user->passwd,
             'speed_limit' => $user->speed_limit,
-            'enable'      => (int)$user->enable,
+            'enable'      => (int) $user->enable,
         ];
     }
 
     public function handle(): void
     {
         foreach ($this->nodes as $node) {
-            $this->send(
-                ($node->server ?: $node->ip) . ':' . $node->push_port,
-                $node->auth->secret
-            );
+            $this->send(($node->server ?: $node->ip).':'.$node->push_port, $node->auth->secret);
         }
     }
 
     private function send($host, $secret): void
     {
-        $client = new Client(
-            [
-                'base_uri' => $host,
-                'timeout'  => 15,
-                'headers'  => ['secret' => $secret],
-            ]
-        );
+        $client = new Client([
+            'base_uri' => $host,
+            'timeout'  => 15,
+            'headers'  => ['secret' => $secret],
+        ]);
 
         $client->post('api/user/edit', ['json' => $this->data]);
     }
-
 }

Some files were not shown because too many files changed in this diff