Browse Source

优化 自动任务

1. 使用chunk分段处理大规模数据处理;
2. 优化部分任务的查询逻辑;
3. 提取各任务时间戳至,config/tasks.php,允许机场主自定义各任务;
兔姬桑 4 years ago
parent
commit
396fbbad56
43 changed files with 619 additions and 653 deletions
  1. 1 1
      app/Components/Helpers.php
  2. 19 19
      app/Console/Commands/AutoClearLogs.php
  3. 97 87
      app/Console/Commands/AutoJob.php
  4. 0 48
      app/Console/Commands/AutoStatisticsNodeDailyTraffic.php
  5. 0 48
      app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php
  6. 0 60
      app/Console/Commands/AutoStatisticsUserDailyTraffic.php
  7. 0 60
      app/Console/Commands/AutoStatisticsUserHourlyTraffic.php
  8. 82 88
      app/Console/Commands/DailyJob.php
  9. 3 3
      app/Console/Commands/DailyNodeReport.php
  10. 43 0
      app/Console/Commands/NodeDailyTrafficStatistics.php
  11. 43 0
      app/Console/Commands/NodeHourlyTrafficStatistics.php
  12. 9 14
      app/Console/Commands/NodeStatusDetection.php
  13. 22 21
      app/Console/Commands/ServiceTimer.php
  14. 52 0
      app/Console/Commands/UserDailyTrafficStatistics.php
  15. 0 41
      app/Console/Commands/UserExpireAutoWarning.php
  16. 43 0
      app/Console/Commands/UserExpireWarning.php
  17. 69 0
      app/Console/Commands/UserHourlyTrafficMonitoring.php
  18. 0 58
      app/Console/Commands/UserTrafficAbnormalAutoWarning.php
  19. 0 46
      app/Console/Commands/UserTrafficAutoWarning.php
  20. 46 0
      app/Console/Commands/UserTrafficWarning.php
  21. 25 28
      app/Console/Kernel.php
  22. 3 8
      app/Http/Controllers/Admin/NodeController.php
  23. 3 3
      app/Http/Controllers/Admin/UserController.php
  24. 2 2
      app/Http/Controllers/AdminController.php
  25. 1 1
      app/Http/Controllers/UserController.php
  26. 1 1
      app/Models/NodeHeartbeat.php
  27. 1 1
      app/Models/Order.php
  28. 1 0
      app/Models/ReferralApply.php
  29. 6 1
      app/Models/User.php
  30. 1 0
      app/Models/UserDailyDataFlow.php
  31. 1 0
      app/Models/UserHourlyDataFlow.php
  32. 1 1
      app/Models/VerifyCode.php
  33. 2 1
      app/Notifications/Verification.php
  34. 4 4
      app/Services/OrderService.php
  35. 0 1
      config/common.php
  36. 29 0
      config/tasks.php
  37. 1 1
      database/factories/UserFactory.php
  38. 2 1
      resources/lang/en/notification.php
  39. 1 0
      resources/lang/zh-CN/notification.php
  40. 2 2
      resources/views/admin/config/system.blade.php
  41. 1 1
      resources/views/admin/logs/order.blade.php
  42. 1 1
      resources/views/admin/user/index.blade.php
  43. 1 1
      resources/views/user/payment.blade.php

+ 1 - 1
app/Components/Helpers.php

@@ -80,7 +80,7 @@ class Helpers
             'protocol'        => self::getDefaultProtocol(),
             'obfs'            => self::getDefaultObfs(),
             'transfer_enable' => $transfer_enable,
-            'expired_at'      => date('Y-m-d', strtotime('+'.$date.' days')),
+            'expired_at'      => date('Y-m-d', strtotime($date.' days')),
             'user_group_id'   => null,
             'reg_ip'          => IP::getClientIp(),
             'inviter_id'      => $inviter_id,

+ 19 - 19
app/Console/Commands/AutoClearLog.php → app/Console/Commands/AutoClearLogs.php

@@ -20,12 +20,12 @@ use Exception;
 use Illuminate\Console\Command;
 use Log;
 
-class AutoClearLog extends Command
+class AutoClearLogs extends Command
 {
-    protected $signature = 'autoClearLog';
+    protected $signature = 'autoClearLogs';
     protected $description = '自动清除日志';
 
-    public function handle(): void
+    public function handle()
     {
         $jobStartTime = microtime(true);
 
@@ -41,53 +41,53 @@ class AutoClearLog extends Command
     }
 
     // 清除日志
-    private function clearLog(): void
+    private function clearLog()
     {
         try {
             // 清除节点每天流量数据日志
-            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(config('tasks.clean.node_daily_logs'))))->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(config('tasks.clean.node_hourly_logs'))))->delete();
 
             // 清理通知日志
-            NotificationLog::where('updated_at', '<=', date('Y-m-d H:i:s', strtotime('-1 month')))->delete();
+            NotificationLog::where('updated_at', '<=', date('Y-m-d H:i:s', strtotime(config('tasks.clean.notification_logs'))))->delete();
 
             // 清除节点负载信息日志
-            NodeHeartbeat::where('log_time', '<=', strtotime('-30 minutes'))->delete();
+            NodeHeartbeat::where('log_time', '<=', strtotime(config('tasks.clean.node_heartbeats')))->delete();
 
             // 清除节点在线用户数日志
-            NodeOnlineLog::where('log_time', '<=', strtotime('-1 hour'))->delete();
+            NodeOnlineLog::where('log_time', '<=', strtotime(config('tasks.clean.node_online_logs')))->delete();
 
             // 清理在线支付日志
-            Payment::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-1 year')))->delete();
+            Payment::where('created_at', '<=', date('Y-m-d H:i:s', strtotime(config('tasks.clean.payments'))))->delete();
 
             // 清理审计触发日志
-            RuleLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();
+            RuleLog::where('created_at', '<=', date('Y-m-d H:i:s', strtotime(config('tasks.clean.rule_logs'))))->delete();
 
             // 清除用户连接IP
-            NodeOnlineIp::where('created_at', '<=', strtotime('-1 week'))->delete();
+            NodeOnlineIp::where('created_at', '<=', strtotime(config('tasks.clean.node_online_ips')))->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(config('tasks.clean.user_baned_logs'))))->delete();
 
             // 清除用户各节点 / 节点总计的每天流量数据日志
             UserDailyDataFlow::where('node_id', '<>')
-                ->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')))
+                ->where('created_at', '<=', date('Y-m-d H:i:s', strtotime(config('tasks.clean.user_daily_logs_nodes'))))
+                ->orWhere('created_at', '<=', date('Y-m-d H:i:s', strtotime(config('tasks.clean.user_daily_logs_total'))))
                 ->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(config('tasks.clean.user_hourly_logs'))))->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(config('tasks.clean.login_logs'))))->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(config('tasks.clean.subscribe_logs'))))->delete();
 
             // 清除用户流量日志
-            UserDataFlowLog::where('log_time', '<=', strtotime('-3 days'))->delete();
+            UserDataFlowLog::where('log_time', '<=', strtotime(config('tasks.clean.traffic_logs')))->delete();
         } catch (Exception $e) {
             Log::error('【清理日志】错误: '.$e->getMessage());
         }

+ 97 - 87
app/Console/Commands/AutoJob.php

@@ -10,6 +10,7 @@ use App\Models\Order;
 use App\Models\User;
 use App\Models\VerifyCode;
 use Illuminate\Console\Command;
+use Illuminate\Database\Eloquent\Builder;
 use Log;
 
 class AutoJob extends Command
@@ -20,32 +21,25 @@ class AutoJob extends Command
     /*
      * 警告:除非熟悉业务流程,否则不推荐更改以下执行顺序,随意变更以下顺序可能导致系统异常
      */
-    public function handle(): void
+    public function handle()
     {
         $jobStartTime = microtime(true);
 
-        // 关闭超时未支付本地订单
-        Order::query()->recentUnPay()->update(['status' => -1]);
+        Order::recentUnPay()->update(['status' => -1]); // 关闭超时未支付本地订单
+        $this->expireCode(); //过期验证码、优惠券、邀请码无效化
 
-        //过期验证码、优惠券、邀请码无效化
-        $this->expireCode();
-
-        // 封禁访问异常的订阅链接
-        $this->blockSubscribe();
-
-        // 封禁账号
-        $this->blockUsers();
+        if (sysConfig('is_subscribe_ban')) {
+            $this->blockSubscribe(); // 封禁访问异常的订阅链接
+        }
 
-        // 解封被封禁账号
-        $this->unblockUsers();
+        $this->blockUsers(); // 封禁账号
+        $this->unblockUsers(); // 解封被封禁的账号
 
-        // 端口回收与分配
         if (sysConfig('auto_release_port')) {
-            $this->dispatchPort();
+            $this->dispatchPort(); // 端口回收与再分配
         }
 
-        // 检查维护模式
-        if (sysConfig('maintenance_mode') && sysConfig('maintenance_time') && sysConfig('maintenance_time') <= date('c')) {
+        if (sysConfig('maintenance_mode') && sysConfig('maintenance_time') && sysConfig('maintenance_time') <= date('c')) {// 检查维护模式
             Config::whereIn('name', ['maintenance_mode', 'maintenance_content', 'maintenance_time'])->update(['value' => null]);
         }
 
@@ -55,115 +49,131 @@ class AutoJob extends Command
         Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
-    // 注册验证码自动置无效 & 优惠券无效化
-    private function expireCode(): void
+    private function expireCode()// 注册验证码自动置无效 & 优惠券无效化
     {
         // 注册验证码自动置无效
         VerifyCode::recentUnused()->update(['status' => 2]);
 
         // 优惠券到期 / 用尽的 自动置无效
-        Coupon::withTrashed()->whereStatus(0)->where('end_time', '<=', time())->orWhereIn('type', [1, 2])->whereUsableTimes(0)->update(['status' => 2]);
+        Coupon::withTrashed()
+            ->whereStatus(0)
+            ->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]);
     }
 
-    // 封禁访问异常的订阅链接
-    private function blockSubscribe(): void
+    private function blockSubscribe()// 封禁访问异常的订阅链接
     {
-        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) { // 无订阅链接 或 已封
-                    continue;
-                }
-                // 24小时内不同IP的请求次数
-                $request_times = $user->subscribeLogs()
-                    ->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' => '存在异常,自动封禁',
-                    ]);
-
-                    // 记录封禁日志
-                    Helpers::addUserBanLog($user->id, 0, '【完全封禁订阅】-订阅24小时内请求异常');
+        $subscribe_ban_times = sysConfig('subscribe_ban_times');
+        User::activeUser()
+            ->with(['subscribe', 'subscribeLogs'])
+            ->whereHas('subscribe', function (Builder $query) {
+                $query->where('status', '==', 0); // 获取有订阅且未被封禁用户
+            })
+            ->chunk(config('tasks.chunk'), function ($users) use ($subscribe_ban_times) {
+                foreach ($users as $user) {
+                    // 24小时内不同IP的请求次数
+                    $request_times = $user->subscribeLogs()
+                        ->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' => '存在异常,自动封禁',
+                        ]);
+
+                        Helpers::addUserBanLog($user->id, 0, '【完全封禁订阅】-订阅24小时内请求异常'); // 记录封禁日志
+                    }
                 }
-            }
-        }
+            });
     }
 
-    // 封禁账号
-    private function blockUsers(): void
+    private function blockUsers()// 封禁账号
     {
         // 禁用流量超限用户
-        foreach (User::activeUser()->whereRaw('u + d >= transfer_enable')->get() as $user) {
-            $user->update(['enable' => 0]);
+        User::activeUser()
+            ->whereRaw('u + d >= transfer_enable')
+            ->chunk(config('tasks.chunk'), function ($users) {
+                foreach ($users as $user) {
+                    $user->update(['enable' => 0]);
 
-            // 写入日志
-            Helpers::addUserBanLog($user->id, 0, '【封禁代理】-流量已用完');
-        }
+                    Helpers::addUserBanLog($user->id, 0, '【封禁代理】-流量已用完'); // 写入日志
+                }
+            });
 
         // 封禁1小时内流量异常账号
         if (sysConfig('is_traffic_ban')) {
             $trafficBanTime = sysConfig('traffic_ban_time');
-            foreach (User::activeUser()->whereBanTime(null)->get() as $user) {
-                // 多往前取5分钟,防止数据统计任务执行时间过长导致没有数据
-                if ($user->isTrafficWarning()) {
-                    $user->update([
-                        'enable'   => 0,
-                        'ban_time' => strtotime('+'.$trafficBanTime.' minutes'),
-                    ]);
-
-                    // 写入日志
-                    Helpers::addUserBanLog($user->id, $trafficBanTime, '【临时封禁代理】-1小时内流量异常');
-                }
-            }
+            User::activeUser()
+                ->whereBanTime(null)
+                ->chunk(config('tasks.chunk'), function ($users) use ($trafficBanTime) {
+                    foreach ($users as $user) {
+                        // 多往前取5分钟,防止数据统计任务执行时间过长导致没有数据
+                        if ($user->isTrafficWarning()) {
+                            $user->update([
+                                'enable'   => 0,
+                                'ban_time' => strtotime($trafficBanTime.' minutes'),
+                            ]);
+
+                            Helpers::addUserBanLog($user->id, $trafficBanTime, '【临时封禁代理】-1小时内流量异常'); // 写入日志
+                        }
+                    }
+                });
         }
     }
 
-    // 解封被临时封禁的账号
-    private function unblockUsers(): void
+    private function unblockUsers()// 解封被临时封禁的账号
     {
         // 解封被临时封禁的账号
-        $userList = User::whereEnable(0)->where('status', '>=', 0)->whereNotNull('ban_time')->where('ban_time', '<', time())->get();
-        foreach ($userList as $user) {
-            $user->update(['enable' => 1, 'ban_time' => null]);
-
-            // 写入操作日志
-            Helpers::addUserBanLog($user->id, 0, '【自动解封】-临时封禁到期');
-        }
+        User::bannedUser()
+            ->whereNotNull('ban_time')
+            ->where('ban_time', '<', time())
+            ->chunk(config('tasks.chunk'), function ($users) {
+                foreach ($users as $user) {
+                    $user->update(['enable' => 1, 'ban_time' => null]);
+
+                    Helpers::addUserBanLog($user->id, 0, '【自动解封】-临时封禁到期'); // 写入操作日志
+                }
+            });
 
         // 可用流量大于已用流量也解封(比如:邀请返利自动加了流量)
-        $userList = User::whereEnable(0)
-            ->where('status', '>=', 0)
+        User::bannedUser()
             ->whereBanTime(null)
             ->where('expired_at', '>=', date('Y-m-d'))
             ->whereRaw('u + d < transfer_enable')
-            ->get();
-        foreach ($userList as $user) {
-            $user->update(['enable' => 1]);
+            ->chunk(config('tasks.chunk'), function ($users) {
+                foreach ($users as $user) {
+                    $user->update(['enable' => 1]);
 
-            // 写入操作日志
-            Helpers::addUserBanLog($user->id, 0, '【自动解封】-有流量解封');
-        }
+                    Helpers::addUserBanLog($user->id, 0, '【自动解封】-有流量解封'); // 写入操作日志
+                }
+            });
     }
 
     // 端口回收与分配
-    private function dispatchPort(): void
+    private function dispatchPort()
     {
         // 自动分配端口
-        User::activeUser()->wherePort(0)->get()->each(function ($user) {
-            $user->update(['port' => Helpers::getPort()]);
-        });
+        User::activeUser()
+            ->wherePort(0)
+            ->chunk(config('tasks.chunk'), function ($users) {
+                foreach ($users as $user) {
+                    $user->update(['port' => Helpers::getPort()]);
+                }
+            });
 
-        // 被封禁 / 过期一个月 的账号自动释放端口
+        // 被封禁 / 过期xx天 的账号自动释放端口
         User::where('port', '<>', 0)
             ->whereStatus(-1)
-            ->orWhere('expired_at', '<=', date('Y-m-d', strtotime('-1 months')))
+            ->orWhere('expired_at', '<=', date('Y-m-d', strtotime('-'.config('tasks.release_port').' days')))
             ->update(['port' => 0]);
     }
 }

+ 0 - 48
app/Console/Commands/AutoStatisticsNodeDailyTraffic.php

@@ -1,48 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\Node;
-use App\Models\NodeDailyDataFlow;
-use App\Models\UserDataFlowLog;
-use Illuminate\Console\Command;
-use Log;
-
-class AutoStatisticsNodeDailyTraffic extends Command
-{
-    protected $signature = 'autoStatisticsNodeDailyTraffic';
-    protected $description = '自动统计节点每日流量';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        foreach (Node::whereStatus(1)->orderBy('id')->get() as $node) {
-            $this->statisticsByNode($node->id);
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        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()]);
-
-        $u = $query->sum('u');
-        $d = $query->sum('d');
-        $total = $u + $d;
-
-        if ($total) { // 有数据才记录
-            $obj = new NodeDailyDataFlow();
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = flowAutoShow($total);
-            $obj->save();
-        }
-    }
-}

+ 0 - 48
app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php

@@ -1,48 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\Node;
-use App\Models\NodeHourlyDataFlow;
-use App\Models\UserDataFlowLog;
-use Illuminate\Console\Command;
-use Log;
-
-class AutoStatisticsNodeHourlyTraffic extends Command
-{
-    protected $signature = 'autoStatisticsNodeHourlyTraffic';
-    protected $description = '自动统计节点每小时流量';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        foreach (Node::whereStatus(1)->orderBy('id')->get() as $node) {
-            $this->statisticsByNode($node->id);
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
-    }
-
-    private function statisticsByNode($node_id): void
-    {
-        $query = UserDataFlowLog::whereNodeId($node_id)->whereBetween('log_time', [strtotime('-1 hour'), time()]);
-
-        $u = $query->sum('u');
-        $d = $query->sum('d');
-        $total = $u + $d;
-
-        if ($total) { // 有数据才记录
-            $obj = new NodeHourlyDataFlow();
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = flowAutoShow($total);
-            $obj->save();
-        }
-    }
-}

+ 0 - 60
app/Console/Commands/AutoStatisticsUserDailyTraffic.php

@@ -1,60 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\Node;
-use App\Models\User;
-use App\Models\UserDailyDataFlow;
-use App\Models\UserDataFlowLog;
-use Illuminate\Console\Command;
-use Log;
-
-class AutoStatisticsUserDailyTraffic extends Command
-{
-    protected $signature = 'autoStatisticsUserDailyTraffic';
-    protected $description = '自动统计用户每日流量';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        foreach (User::activeUser()->get() as $user) {
-            // 统计一次所有节点的总和
-            $this->statisticsByUser($user->id);
-
-            // 统计每个节点产生的流量
-            foreach (Node::whereStatus(1)->orderBy('id')->get() as $node) {
-                $this->statisticsByUser($user->id, $node->id);
-            }
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
-    }
-
-    private function statisticsByUser($user_id, $node_id = null): void
-    {
-        $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');
-        $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->save();
-        }
-    }
-}

+ 0 - 60
app/Console/Commands/AutoStatisticsUserHourlyTraffic.php

@@ -1,60 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\Node;
-use App\Models\User;
-use App\Models\UserDataFlowLog;
-use App\Models\UserHourlyDataFlow;
-use Illuminate\Console\Command;
-use Log;
-
-class AutoStatisticsUserHourlyTraffic extends Command
-{
-    protected $signature = 'autoStatisticsUserHourlyTraffic';
-    protected $description = '自动统计用户每小时流量';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        foreach (User::activeUser()->get() as $user) {
-            // 统计一次所有节点的总和
-            $this->statisticsByNode($user->id);
-
-            // 统计每个节点产生的流量
-            foreach (Node::whereStatus(1)->orderBy('id')->get() as $node) {
-                $this->statisticsByNode($user->id, $node->id);
-            }
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
-    }
-
-    private function statisticsByNode($user_id, $node_id = null): void
-    {
-        $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');
-        $total = $u + $d;
-
-        if ($total) { // 有数据才记录
-            $obj = new UserHourlyDataFlow();
-            $obj->user_id = $user_id;
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = flowAutoShow($total);
-            $obj->save();
-        }
-    }
-}

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

@@ -3,7 +3,6 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use App\Models\Order;
 use App\Models\Ticket;
 use App\Models\User;
 use App\Notifications\TicketClosed;
@@ -16,18 +15,14 @@ class DailyJob extends Command
     protected $signature = 'dailyJob';
     protected $description = '每日任务';
 
-    public function handle(): void
+    public function handle()
     {
         $jobStartTime = microtime(true);
 
-        // 过期用户处理
-        $this->expireUser();
+        $this->expireUser(); // 过期用户处理
+        $this->closeTickets(); // 关闭超时未处理的工单
 
-        // 关闭超过72小时未处理的工单
-        $this->closeTickets();
-
-        // 重置用户流量
-        if (sysConfig('reset_traffic')) {
+        if (sysConfig('reset_traffic')) {// 重置用户流量
             $this->resetUserTraffic();
         }
 
@@ -37,94 +32,93 @@ class DailyJob extends Command
         Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
     }
 
-    private function expireUser(): void
+    private function expireUser()// 过期用户处理
     {
-        // 过期用户处理
-        $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,
-                    'level'           => 0,
-                    'reset_time'      => null,
-                    'ban_time'        => null,
-                    'status'          => -1,
-                ]);
-
-                Helpers::addUserBanLog($user->id, 0, '【禁止登录,清空账户】-账号已过期');
-
-                // 废除其名下邀请码
-                $user->invites()->whereStatus(0)->update(['status' => 2]);
-
-                // 写入用户流量变动记录
-                Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, 0, '[定时任务]账号已过期(禁止登录,清空账户)');
-            } else {
-                $user->update([
-                    'u'               => 0,
-                    'd'               => 0,
-                    'transfer_enable' => 0,
-                    'enable'          => 0,
-                    'level'           => 0,
-                    'reset_time'      => null,
-                    'ban_time'        => null,
-                ]);
-
-                Helpers::addUserBanLog($user->id, 0, '【封禁代理,清空账户】-账号已过期');
-
-                // 写入用户流量变动记录
-                Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, 0, '[定时任务]账号已过期(封禁代理,清空账户)');
-            }
-        }
+        User::activeUser()
+            ->where('expired_at', '<', date('Y-m-d'))
+            ->chunk(config('tasks.chunk'), function ($users) use ($isBanStatus) {
+                foreach ($users as $user) {
+                    if ($isBanStatus) { // 停止服务 或 封禁账号
+                        $user->update([
+                            'u'               => 0,
+                            'd'               => 0,
+                            'transfer_enable' => 0,
+                            'enable'          => 0,
+                            'level'           => 0,
+                            'reset_time'      => null,
+                            'ban_time'        => null,
+                            'status'          => -1,
+                        ]);
+
+                        Helpers::addUserBanLog($user->id, 0, '【禁止登录,清空账户】-账号已过期');
+
+                        // 废除其名下邀请码
+                        $user->invites()->whereStatus(0)->update(['status' => 2]);
+
+                        // 写入用户流量变动记录
+                        Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, 0, '[定时任务]账号已过期(禁止登录,清空账户)');
+                    } else {
+                        $user->update([
+                            'u'               => 0,
+                            'd'               => 0,
+                            'transfer_enable' => 0,
+                            'enable'          => 0,
+                            'level'           => 0,
+                            'reset_time'      => null,
+                            'ban_time'        => null,
+                        ]);
+
+                        Helpers::addUserBanLog($user->id, 0, '【封禁代理,清空账户】-账号已过期');
+
+                        // 写入用户流量变动记录
+                        Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, 0, '[定时任务]账号已过期(封禁代理,清空账户)');
+                    }
+                }
+            });
     }
 
-    // 关闭超过72小时未处理的工单
-    private function closeTickets(): void
+    private function closeTickets()// 关闭超时未处理的工单
     {
-        foreach (Ticket::where('updated_at', '<=', date('Y-m-d', strtotime('-3 days')))->whereStatus(1)->get() as $ticket) {
-            if ($ticket->close()) {
-                $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('replyTicket', ['id' => $ticket->id]), __('You have not responded this ticket in :num hours, System has auto closed your ticket.', ['num' => '72'])));
-            }
-        }
+        Ticket::whereStatus(1)
+            ->where('updated_at', '<=', date('Y-m-d', strtotime('-'.config('tasks.close.ticket').' hours')))
+            ->chunk(config('tasks.chunk'), function ($tickets) {
+                foreach ($tickets as $ticket) {
+                    if ($ticket->close()) {
+                        $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('replyTicket', ['id' => $ticket->id]),
+                            __('You have not responded this ticket in :num hours, System has auto closed your ticket.', ['num' => config('tasks.close.ticket')])));
+                    }
+                }
+            });
     }
 
-    // 重置用户流量
-    private function resetUserTraffic(): void
+    private function resetUserTraffic()// 重置用户流量
     {
-        $userList = User::where('status', '<>', -1)
+        User::where('status', '<>', -1)
             ->where('expired_at', '>', date('Y-m-d'))
             ->where('reset_time', '<=', date('Y-m-d'))
-            ->get();
-        foreach ($userList as $user) {
-            // 跳过 没有重置日期的账号
-            if (! $user->reset_time) {
-                continue;
-            }
-
-            // 取出用户正在使用的套餐
-            $order = Order::userActivePlan($user->id)->first();
-
-            // 无订单用户跳过
-            if (! $order) {
-                continue;
-            }
-
-            // 过期生效中的加油包
-            Order::userActivePackage($user->id)->update(['is_expire' => 1]);
-
-            $oldData = $user->transfer_enable;
-            // 重置流量与重置日期
-            $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 ?: '【无】'));
-            } else {
-                Log::warning('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置失败');
-            }
-        }
+            ->whereNotNull('reset_time')
+            ->with('order')->whereHas('order')
+            ->chunk(config('tasks.chunk'), function ($users) {
+                foreach ($users as $user) {
+                    $order = $user->orders()->activePlan()->first(); // 取出用户正在使用的套餐
+
+                    if (! $order) {// 无套餐用户跳过
+                        continue;
+                    }
+
+                    $user->order()->activePackage()->update(['is_expire' => 1]); // 过期生效中的加油包
+
+                    $oldData = $user->transfer_enable;
+                    // 重置流量与重置日期
+                    if ($user->update((new OrderService($order))->resetTimeAndData($user->expired_at))) {
+                        // 可用流量变动日志
+                        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::warning('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置失败');
+                    }
+                }
+            });
     }
 }

+ 3 - 3
app/Console/Commands/AutoReportNode.php → app/Console/Commands/DailyNodeReport.php

@@ -9,12 +9,12 @@ use Illuminate\Console\Command;
 use Log;
 use Notification;
 
-class AutoReportNode extends Command
+class DailyNodeReport extends Command
 {
-    protected $signature = 'autoReportNode';
+    protected $signature = 'dailyNodeReport';
     protected $description = '自动报告节点昨日使用情况';
 
-    public function handle(): void
+    public function handle()
     {
         $jobStartTime = microtime(true);
 

+ 43 - 0
app/Console/Commands/NodeDailyTrafficStatistics.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Node;
+use Illuminate\Console\Command;
+use Log;
+
+class NodeDailyTrafficStatistics extends Command
+{
+    protected $signature = 'nodeDailyTrafficStatistics';
+    protected $description = '节点每日流量统计';
+
+    public function handle()
+    {
+        $jobStartTime = microtime(true);
+
+        foreach (Node::whereStatus(1)->orderBy('id')->with('userDataFlowLogs')->whereHas('userDataFlowLogs')->get() as $node) {
+            $this->statisticsByNode($node);
+        }
+
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    private function statisticsByNode(Node $node)
+    {
+        $traffic = $node->userDataFlowLogs()
+            ->whereBetween('log_time', [strtotime(date('Y-m-d')), time()])
+            ->selectRaw('sum(`u`) as u, sum(`d`) as d')->first();
+
+        if ($traffic && $total = $traffic->u + $traffic->d) { // 有数据才记录
+            $node->dailyDataFlows()->create([
+                'u'       => $traffic->u,
+                'd'       => $traffic->d,
+                'total'   => $total,
+                'traffic' => flowAutoShow($total),
+            ]);
+        }
+    }
+}

+ 43 - 0
app/Console/Commands/NodeHourlyTrafficStatistics.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Node;
+use Illuminate\Console\Command;
+use Log;
+
+class NodeHourlyTrafficStatistics extends Command
+{
+    protected $signature = 'nodeHourlyTrafficStatistics';
+    protected $description = '节点每小时流量统计';
+
+    public function handle()
+    {
+        $jobStartTime = microtime(true);
+
+        foreach (Node::whereStatus(1)->orderBy('id')->with('userDataFlowLogs')->whereHas('userDataFlowLogs')->get() as $node) {
+            $this->statisticsByNode($node);
+        }
+
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    private function statisticsByNode(Node $node)
+    {
+        $traffic = $node->userDataFlowLogs()
+            ->whereBetween('log_time', [strtotime('-1 hour'), time()])
+            ->selectRaw('sum(`u`) as u, sum(`d`) as d')->first();
+
+        if ($traffic && $total = $traffic->u + $traffic->d) { // 有数据才记录
+            $node->hourlyDataFlows()->create([
+                'u'       => $traffic->u,
+                'd'       => $traffic->d,
+                'total'   => $total,
+                'traffic' => flowAutoShow($total),
+            ]);
+        }
+    }
+}

+ 9 - 14
app/Console/Commands/NodeStatusDetection.php

@@ -18,19 +18,16 @@ class NodeStatusDetection extends Command
     protected $signature = 'nodeStatusDetection';
     protected $description = '节点状态检测';
 
-    public function handle(): void
+    public function handle()
     {
         $jobStartTime = microtime(true);
-        // 检测节点心跳是否异常
-        if (sysConfig('node_offline_notification')) {
+
+        if (sysConfig('node_offline_notification')) {// 检测节点心跳是否异常
             $this->checkNodeStatus();
         }
 
-        // 监测节点网络状态
-        if (sysConfig('node_blocked_notification')) {
-            if (! Cache::has('LastCheckTime')) {
-                $this->checkNodeNetwork();
-            } elseif (Cache::get('LastCheckTime') <= time()) {
+        if (sysConfig('node_blocked_notification')) {// 监测节点网络状态
+            if (! Cache::has('LastCheckTime') || Cache::get('LastCheckTime') <= time()) {
                 $this->checkNodeNetwork();
             } else {
                 Log::info('下次节点阻断检测时间:'.date('Y-m-d H:i:s', Cache::get('LastCheckTime')));
@@ -43,12 +40,12 @@ class NodeStatusDetection extends Command
         Log::info("---【{$this->description}】完成---,耗时 {$jobUsedTime} 秒");
     }
 
-    private function checkNodeStatus(): void
+    private function checkNodeStatus()
     {
         $offlineCheckTimes = sysConfig('offline_check_times');
         $onlineNode = NodeHeartbeat::recently()->distinct()->pluck('node_id')->toArray();
         foreach (Node::whereIsRelay(0)->whereStatus(1)->whereNotIn('id', $onlineNode)->get() as $node) {
-            // 10分钟内无节点负载信息则认为是后端炸了
+            // 近期无节点负载信息则认为是后端炸了
             if ($offlineCheckTimes) {
                 // 已通知次数
                 $cacheKey = 'offline_check_times'.$node->id;
@@ -136,8 +133,7 @@ class NodeStatusDetection extends Command
             }
         }
 
-        //只有在出现阻断线路时,才会发出警报
-        if ($sendText) {
+        if ($sendText) {//只有在出现阻断线路时,才会发出警报
             Notification::send(User::permission('admin.node.edit,update')->orWhere(function ($query) {
                 return $query->role('Super Admin');
             })->get(), new NodeBlocked($message.$additionalMessage));
@@ -145,7 +141,6 @@ class NodeStatusDetection extends Command
             Log::info("阻断日志: \r\n".$message.$additionalMessage);
         }
 
-        // 随机生成下次检测时间
-        Cache::put('LastCheckTime', time() + random_int(3000, Hour), 3700);
+        Cache::put('LastCheckTime', time() + random_int(3000, Hour), 3700); // 随机生成下次检测时间
     }
 }

+ 22 - 21
app/Console/Commands/ServiceTimer.php

@@ -12,12 +12,11 @@ class ServiceTimer extends Command
     protected $signature = 'serviceTimer';
     protected $description = '服务计时器';
 
-    public function handle(): void
+    public function handle()
     {
         $jobStartTime = microtime(true);
 
-        // 扣减用户到期商品的流量
-        $this->decGoodsTraffic();
+        $this->decGoodsTraffic(); // 扣减用户到期商品的流量
 
         $jobEndTime = microtime(true);
         $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
@@ -26,25 +25,27 @@ class ServiceTimer extends Command
     }
 
     // 扣减用户到期商品的流量
-    private function decGoodsTraffic(): void
+    private function decGoodsTraffic()
     {
         //获取失效的套餐
-        foreach (Order::activePlan()->where('expired_at', '<=', date('Y-m-d H:i:s'))->with('user')->whereHas('user')->get() as $order) {
-            // 无用户订单,跳过
-            // 清理全部流量,重置重置日期和等级
-            $user = $order->user;
-
-            $user->update([
-                'u' => 0,
-                'd' => 0,
-                'transfer_enable' => 0,
-                'reset_time' => null,
-                'level' => 0,
-            ]);
-            Helpers::addUserTrafficModifyLog($user->id, $order->id, $user->transfer_enable, 0, '[定时任务]用户所购商品到期,扣减商品对应的流量');
-
-            // 过期本订单
-            $order->update(['is_expire' => 1]);
-        }
+        Order::activePlan()
+            ->where('expired_at', '<=', date('Y-m-d H:i:s'))
+            ->with('user')->whereHas('user') // 无用户订单,跳过
+            ->chunk(config('tasks.chunk'), function ($orders) {
+                foreach ($orders as $order) {
+                    $user = $order->user;
+
+                    $user->update([ // 清理全部流量,重置重置日期和等级
+                        'u'               => 0,
+                        'd'               => 0,
+                        'transfer_enable' => 0,
+                        'reset_time'      => null,
+                        'level'           => 0,
+                    ]);
+                    Helpers::addUserTrafficModifyLog($user->id, $order->id, $user->transfer_enable, 0, '[定时任务]用户所购商品到期,扣减商品对应的流量');
+
+                    $order->update(['is_expire' => 1]); // 过期本订单
+                }
+            });
     }
 }

+ 52 - 0
app/Console/Commands/UserDailyTrafficStatistics.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\User;
+use Illuminate\Console\Command;
+use Log;
+
+class UserDailyTrafficStatistics extends Command
+{
+    protected $signature = 'userDailyTrafficStatistics';
+    protected $description = '用户每日流量统计';
+
+    public function handle()
+    {
+        $jobStartTime = microtime(true);
+        User::activeUser()->with('dataFlowLogs')->WhereHas('dataFlowLogs')->chunk(config('tasks.chunk'), function ($users) {
+            foreach ($users as $user) {
+                $this->statisticsByUser($user);
+            }
+        });
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    private function statisticsByUser(User $user)
+    {
+        $logs = $user->dataFlowLogs()
+            ->whereBetween('log_time', [strtotime(date('Y-m-d')), time()])
+            ->groupBy('node_id')
+            ->selectRaw('node_id, sum(`u`) as u, sum(`d`) as d')
+            ->get();
+
+        if ($logs->isNotEmpty()) { // 有数据才记录
+            $data = $logs->each(function ($log) {
+                $log->total = $log->u + $log->d;
+                $log->traffic = flowAutoShow($log->total);
+            })->flatten()->toArray();
+
+            $data[] = [ // 每日节点流量合计
+                'u'       => $logs->sum('u'),
+                'd'       => $logs->sum('d'),
+                'total'   => $logs->sum('total'),
+                'traffic' => flowAutoShow($logs->sum('total')),
+            ];
+
+            $user->dailyDataFlows()->createMany($data);
+        }
+    }
+}

+ 0 - 41
app/Console/Commands/UserExpireAutoWarning.php

@@ -1,41 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\User;
-use App\Notifications\AccountExpire;
-use Illuminate\Console\Command;
-use Log;
-
-class UserExpireAutoWarning extends Command
-{
-    protected $signature = 'userExpireAutoWarning';
-    protected $description = '用户临近到期自动发邮件提醒';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        // 用户临近到期自动发邮件提醒
-        if (sysConfig('account_expire_notification')) {
-            $this->userExpireWarning();
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
-    }
-
-    private function userExpireWarning(): void
-    {
-        // 只取SSR没被禁用的用户,其他不用管
-        foreach (User::whereEnable(1)->where('expired_at', '<', date('Y-m-d', strtotime(sysConfig('expire_days').' days')))->get() as $user) {
-            // 用户名不是邮箱的跳过
-            if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) {
-                continue;
-            }
-            $user->notify(new AccountExpire($user->expired_at));
-        }
-    }
-}

+ 43 - 0
app/Console/Commands/UserExpireWarning.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\User;
+use App\Notifications\AccountExpire;
+use Illuminate\Console\Command;
+use Log;
+
+class UserExpireWarning extends Command
+{
+    protected $signature = 'userExpireWarning';
+    protected $description = '用户临近到期自动提醒';
+
+    public function handle()
+    {
+        $jobStartTime = microtime(true);
+
+        if (sysConfig('account_expire_notification')) {// 用户临近到期自动提醒
+            $this->userExpireWarning();
+        }
+
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    private function userExpireWarning()
+    {
+        // 只取没被禁用的用户,其他不用管
+        User::whereEnable(1)
+            ->where('expired_at', '<', date('Y-m-d', strtotime(sysConfig('expire_days').' days')))
+            ->chunk(config('tasks.chunk'), function ($users) {
+                foreach ($users as $user) {
+                    if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) { // 用户名不是邮箱的跳过
+                        continue;
+                    }
+                    $user->notify(new AccountExpire($user->expired_at));
+                }
+            });
+    }
+}

+ 69 - 0
app/Console/Commands/UserHourlyTrafficMonitoring.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\User;
+use App\Notifications\DataAnomaly;
+use Illuminate\Console\Command;
+use Log;
+use Notification;
+
+class UserHourlyTrafficMonitoring extends Command
+{
+    protected $signature = 'userHourlyTrafficMonitoring';
+    protected $description = '用户每小时流量监控';
+    private $data_anomaly_notification;
+    private $traffic_ban_value;
+
+    public function handle()
+    {
+        $jobStartTime = microtime(true);
+        $this->data_anomaly_notification = sysConfig('data_anomaly_notification');
+        $this->traffic_ban_value = sysConfig('traffic_ban_value') * GB;
+
+        User::activeUser()->with('dataFlowLogs')->WhereHas('dataFlowLogs')->chunk(config('tasks.chunk'), function ($users) {
+            foreach ($users as $user) {
+                $this->statisticsByUser($user);
+            }
+        });
+
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    private function statisticsByUser(User $user)
+    {
+        $logs = $user->dataFlowLogs()
+            ->whereBetween('log_time', [strtotime('-1 hour'), time()])
+            ->groupBy('node_id')
+            ->selectRaw('node_id, sum(`u`) as u, sum(`d`) as d')
+            ->get();
+
+        if ($logs->isNotEmpty()) { // 有数据才记录
+            $data = $logs->each(function ($log) {
+                $log->total = $log->u + $log->d;
+                $log->traffic = flowAutoShow($log->total);
+            })->flatten()->toArray();
+
+            $data[] = [ // 每小时节点流量合计
+                'u'       => $logs->sum('u'),
+                'd'       => $logs->sum('d'),
+                'total'   => $logs->sum('total'),
+                'traffic' => flowAutoShow($logs->sum('total')),
+            ];
+
+            $user->hourlyDataFlows()->createMany($data);
+
+            if ($this->data_anomaly_notification) { // 用户流量异常警告
+                $traffic = $user->hourlyDataFlows()->whereNodeId(null)->latest()->first();
+                if ($traffic->total >= $this->traffic_ban_value) {
+                    Notification::send(User::permission('admin.user.edit,update')->orWhere(function ($query) {
+                        return $query->role('Super Admin');
+                    })->get(), new DataAnomaly($user->id, flowAutoShow($traffic->u), flowAutoShow($traffic->d), flowAutoShow($traffic->traffic)));
+                }
+            }
+        }
+    }
+}

+ 0 - 58
app/Console/Commands/UserTrafficAbnormalAutoWarning.php

@@ -1,58 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\User;
-use App\Models\UserHourlyDataFlow;
-use App\Notifications\DataAnomaly;
-use Illuminate\Console\Command;
-use Log;
-use Notification;
-
-class UserTrafficAbnormalAutoWarning extends Command
-{
-    protected $signature = 'userTrafficAbnormalAutoWarning';
-    protected $description = '用户流量异常警告';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        // 用户流量异常警告
-        if (sysConfig('data_anomaly_notification')) {
-            $this->userTrafficAbnormalWarning();
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
-    }
-
-    // 用户流量异常警告
-    private function userTrafficAbnormalWarning(): void
-    {
-        // 1小时内流量异常用户(多往前取5分钟,防止数据统计任务执行时间过长导致没有数据)
-        $userTotalTrafficLogs = UserHourlyDataFlow::whereNodeId(null)
-            ->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;
-                $traffic = UserHourlyDataFlow::userRecentUsed($user->id)
-                    ->selectRaw('user_id, sum(`u`) as totalU, sum(`d`) as totalD, sum(total) as totalTraffic')
-                    ->first();
-
-                Notification::send(User::permission('admin.user.edit,update')->orWhere(function ($query) {
-                    return $query->role('Super Admin');
-                })->get(), new DataAnomaly($user->id, flowAutoShow($traffic->totalU), flowAutoShow($traffic->totalD), flowAutoShow($traffic->totalTraffic)));
-            }
-        }
-    }
-}

+ 0 - 46
app/Console/Commands/UserTrafficAutoWarning.php

@@ -1,46 +0,0 @@
-<?php
-
-namespace App\Console\Commands;
-
-use App\Models\User;
-use App\Notifications\DataExhaust;
-use Illuminate\Console\Command;
-use Log;
-
-class UserTrafficAutoWarning extends Command
-{
-    protected $signature = 'userTrafficAutoWarning';
-    protected $description = '用户流量超过警告阈值自动发邮件提醒';
-
-    public function handle(): void
-    {
-        $jobStartTime = microtime(true);
-
-        // 用户流量超过警告阈值自动发邮件提醒
-        if (sysConfig('data_exhaust_notification')) {
-            $this->userTrafficWarning();
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
-    }
-
-    // 用户流量超过警告阈值自动发邮件提醒
-    private function userTrafficWarning(): void
-    {
-        $trafficWarningPercent = sysConfig('traffic_warning_percent');
-        foreach (User::activeUser()->where('transfer_enable', '>', 0)->get() as $user) {
-            // 用户名不是邮箱的跳过
-            if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) {
-                continue;
-            }
-
-            $usedPercent = $user->used_traffic_percentage * 100; // 已使用流量百分比
-            if ($usedPercent >= $trafficWarningPercent) {
-                $user->notify(new DataExhaust($usedPercent));
-            }
-        }
-    }
-}

+ 46 - 0
app/Console/Commands/UserTrafficWarning.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\User;
+use App\Notifications\DataExhaust;
+use Illuminate\Console\Command;
+use Log;
+
+class UserTrafficWarning extends Command
+{
+    protected $signature = 'userTrafficWarning';
+    protected $description = '用户流量超过警告阈值自动发邮件提醒';
+
+    public function handle()
+    {
+        $jobStartTime = microtime(true);
+
+        if (sysConfig('data_exhaust_notification')) {// 用户流量超过警告阈值提醒
+            $this->userTrafficWarning();
+        }
+
+        $jobEndTime = microtime(true);
+        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+
+        Log::info('---【'.$this->description.'】完成---,耗时'.$jobUsedTime.'秒');
+    }
+
+    private function userTrafficWarning()// 用户流量超过警告阈值提醒
+    {
+        $trafficWarningPercent = sysConfig('traffic_warning_percent');
+        User::activeUser()->where('transfer_enable', '>', 0)->chunk(config('tasks.chunk'), function ($users) use ($trafficWarningPercent) {
+            foreach ($users as $user) {
+                // 用户名不是邮箱的跳过
+                if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) {
+                    continue;
+                }
+
+                $usedPercent = $user->used_traffic_percentage * 100; // 已使用流量百分比
+                if ($usedPercent >= $trafficWarningPercent) {
+                    $user->notify(new DataExhaust($usedPercent));
+                }
+            }
+        });
+    }
+}

+ 25 - 28
app/Console/Kernel.php

@@ -2,19 +2,18 @@
 
 namespace App\Console;
 
-use App\Console\Commands\AutoClearLog;
+use App\Console\Commands\AutoClearLogs;
 use App\Console\Commands\AutoJob;
-use App\Console\Commands\AutoReportNode;
-use App\Console\Commands\AutoStatisticsNodeDailyTraffic;
-use App\Console\Commands\AutoStatisticsNodeHourlyTraffic;
-use App\Console\Commands\AutoStatisticsUserDailyTraffic;
-use App\Console\Commands\AutoStatisticsUserHourlyTraffic;
 use App\Console\Commands\DailyJob;
+use App\Console\Commands\DailyNodeReport;
+use App\Console\Commands\NodeDailyTrafficStatistics;
+use App\Console\Commands\NodeHourlyTrafficStatistics;
 use App\Console\Commands\NodeStatusDetection;
 use App\Console\Commands\ServiceTimer;
-use App\Console\Commands\UserExpireAutoWarning;
-use App\Console\Commands\UserTrafficAbnormalAutoWarning;
-use App\Console\Commands\UserTrafficAutoWarning;
+use App\Console\Commands\UserDailyTrafficStatistics;
+use App\Console\Commands\UserExpireWarning;
+use App\Console\Commands\UserHourlyTrafficMonitoring;
+use App\Console\Commands\UserTrafficWarning;
 use Illuminate\Console\Scheduling\Schedule;
 use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
 
@@ -26,19 +25,18 @@ class Kernel extends ConsoleKernel
      * @var array
      */
     protected $commands = [
-        AutoClearLog::class,
+        AutoClearLogs::class,
         AutoJob::class,
-        AutoReportNode::class,
-        AutoStatisticsNodeDailyTraffic::class,
-        AutoStatisticsNodeHourlyTraffic::class,
-        AutoStatisticsUserDailyTraffic::class,
-        AutoStatisticsUserHourlyTraffic::class,
         DailyJob::class,
+        DailyNodeReport::class,
+        NodeDailyTrafficStatistics::class,
+        NodeHourlyTrafficStatistics::class,
         NodeStatusDetection::class,
         ServiceTimer::class,
-        UserExpireAutoWarning::class,
-        UserTrafficAbnormalAutoWarning::class,
-        UserTrafficAutoWarning::class,
+        UserDailyTrafficStatistics::class,
+        UserExpireWarning::class,
+        UserHourlyTrafficMonitoring::class,
+        UserTrafficWarning::class,
     ];
 
     /**
@@ -50,18 +48,17 @@ class Kernel extends ConsoleKernel
     protected function schedule(Schedule $schedule)
     {
         $schedule->command('autoJob')->everyMinute();
-        $schedule->command('serviceTimer')->everyTenMinutes();
-        $schedule->command('autoClearLog')->everyThirtyMinutes();
         $schedule->command('nodeStatusDetection')->everyTenMinutes();
-        $schedule->command('autoStatisticsNodeHourlyTraffic')->hourly();
-        $schedule->command('autoStatisticsUserHourlyTraffic')->hourly();
-        $schedule->command('userTrafficAbnormalAutoWarning')->hourly();
+        $schedule->command('serviceTimer')->everyTenMinutes();
+        $schedule->command('autoClearLogs')->everyThirtyMinutes();
+        $schedule->command('nodeHourlyTrafficStatistics')->hourly();
+        $schedule->command('userHourlyTrafficMonitoring')->hourly();
         $schedule->command('dailyJob')->daily();
-        $schedule->command('autoReportNode')->dailyAt('09:00');
-        $schedule->command('userTrafficAutoWarning')->dailyAt('10:30');
-        $schedule->command('userExpireAutoWarning')->dailyAt('20:00');
-        $schedule->command('autoStatisticsUserDailyTraffic')->dailyAt('23:55');
-        $schedule->command('autoStatisticsNodeDailyTraffic')->dailyAt('23:57');
+        $schedule->command('dailyNodeReport')->dailyAt('09:00');
+        $schedule->command('userTrafficWarning')->dailyAt('10:30');
+        $schedule->command('userExpireWarning')->dailyAt('20:00');
+        $schedule->command('userDailyTrafficStatistics')->dailyAt('23:55');
+        $schedule->command('nodeDailyTrafficStatistics')->dailyAt('23:57');
     }
 
     /**

+ 3 - 8
app/Http/Controllers/Admin/NodeController.php

@@ -34,15 +34,10 @@ class NodeController extends Controller
 
         $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();
+            $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->transfer = flowAutoShow($node->dailyDataFlows()->sum('total')); // 已产生流量
+            $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);

+ 3 - 3
app/Http/Controllers/Admin/UserController.php

@@ -87,7 +87,7 @@ class UserController extends Controller
 
         // 临近过期提醒
         if ($expireWarning) {
-            $query->whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime('+'.sysConfig('expire_days').' days'))]);
+            $query->whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime(sysConfig('expire_days').' days'))]);
         }
 
         // 当前在线
@@ -145,7 +145,7 @@ class UserController extends Controller
         $data['vmess_id'] = $data['uuid'] ?? Str::uuid();
         Arr::forget($data, 'uuid');
         $data['transfer_enable'] *= GB;
-        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('+365 days'));
+        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', 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;
@@ -200,7 +200,7 @@ class UserController extends Controller
         Arr::forget($data, ['roles', 'uuid', 'password']);
         $data['transfer_enable'] *= GB;
         $data['enable'] = $data['status'] < 0 ? 0 : $data['enable'];
-        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('+365 days'));
+        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('365 days'));
         $data['remark'] = str_replace(['atob', 'eval'], '', $data['remark']);
 
         // 只有超级管理员才能赋予超级管理员

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

@@ -37,7 +37,7 @@ class AdminController extends Controller
             'payingUserCount' => Order::whereStatus(2)->where('goods_id', '<>', 0)->whereIsExpire(0)->where('amount', '>', 0)->pluck('user_id')->unique()->count(), // 付费用户数
             'unActiveUserCount' => User::whereEnable(1)->whereBetween('t', [1, $past])->count(), // 不活跃用户数
             'onlineUserCount' => User::where('t', '>=', strtotime('-10 minutes'))->count(), // 10分钟内在线用户数
-            'expireWarningUserCount' => User::whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime('+'.sysConfig('expire_days').' days'))])->count(), // 临近过期用户数
+            'expireWarningUserCount' => User::whereBetween('expired_at', [date('Y-m-d'), date('Y-m-d', strtotime(sysConfig('expire_days').' days'))])->count(), // 临近过期用户数
             'largeTrafficUserCount' => User::whereRaw('(u + d)/transfer_enable >= 0.9')->where('status', '<>', -1)->count(), // 流量使用超过90%的用户
             'flowAbnormalUserCount' => count((new UserHourlyDataFlow)->trafficAbnormal()), // 1小时内流量异常用户
             'nodeCount' => Node::count(),
@@ -72,7 +72,7 @@ class AdminController extends Controller
         for ($i = 0; $i < 10; $i++) {
             $obj = new Invite();
             $obj->code = strtoupper(substr(md5(microtime().Str::random(6)), 8, 12));
-            $obj->dateline = date('Y-m-d H:i:s', strtotime('+'.sysConfig('admin_invite_days').' days'));
+            $obj->dateline = date('Y-m-d H:i:s', strtotime(sysConfig('admin_invite_days').' days'));
             $obj->save();
         }
 

+ 1 - 1
app/Http/Controllers/UserController.php

@@ -380,7 +380,7 @@ class UserController extends Controller
         $obj = new Invite();
         $obj->inviter_id = $user->id;
         $obj->code = strtoupper(mb_substr(md5(microtime().Str::random()), 8, 12));
-        $obj->dateline = date('Y-m-d H:i:s', strtotime('+'.sysConfig('user_invite_days').' days'));
+        $obj->dateline = date('Y-m-d H:i:s', strtotime(sysConfig('user_invite_days').' days'));
         $obj->save();
         if ($obj) {
             $user->update(['invite_num' => $user->invite_num - 1]);

+ 1 - 1
app/Models/NodeHeartbeat.php

@@ -15,6 +15,6 @@ class NodeHeartbeat extends Model
 
     public function scopeRecently($query)
     {
-        return $query->where('log_time', '>=', strtotime('-10 minutes'))->latest('log_time');
+        return $query->where('log_time', '>=', strtotime(config('tasks.recently_heartbeat')))->latest('log_time');
     }
 }

+ 1 - 1
app/Models/Order.php

@@ -43,7 +43,7 @@ class Order extends Model
 
     public function scopeRecentUnPay($query)
     {
-        return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-15 minutes')));
+        return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-'.config('tasks.close.order').' minutes')));
     }
 
     public function scopeUserPrepay($query, $uid = null)

+ 1 - 0
app/Models/ReferralApply.php

@@ -13,6 +13,7 @@ class ReferralApply extends Model
 {
     protected $table = 'referral_apply';
     protected $casts = ['link_logs' => 'array'];
+    protected $guarded = [];
 
     public function scopeUid($query)
     {

+ 6 - 1
app/Models/User.php

@@ -216,6 +216,11 @@ class User extends Authenticatable implements JWTSubject
         return $query->where('status', '<>', -1)->whereEnable(1);
     }
 
+    public function scopeBannedUser($query)
+    {
+        return $query->where('status', '>=', 0)->whereEnable(0);
+    }
+
     public function nodes()
     {
         if ($this->attributes['user_group_id']) {
@@ -272,7 +277,7 @@ class User extends Authenticatable implements JWTSubject
             $expired_status = -1; // 已过期
         } elseif ($this->expired_at === date('Y-m-d')) {
             $expired_status = 0; // 今天过期
-        } elseif ($this->expired_at > date('Y-m-d') && $this->expired_at <= date('Y-m-d', strtotime('+30 days'))) {
+        } elseif ($this->expired_at > date('Y-m-d') && $this->expired_at <= date('Y-m-d', strtotime('30 days'))) {
             $expired_status = 1; // 最近一个月过期
         }
 

+ 1 - 0
app/Models/UserDailyDataFlow.php

@@ -12,6 +12,7 @@ class UserDailyDataFlow extends Model
 {
     public const UPDATED_AT = null;
     protected $table = 'user_daily_data_flow';
+    protected $guarded = [];
 
     public function user(): BelongsTo
     {

+ 1 - 0
app/Models/UserHourlyDataFlow.php

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

+ 1 - 1
app/Models/VerifyCode.php

@@ -14,6 +14,6 @@ class VerifyCode extends Model
 
     public function scopeRecentUnused($query)
     {
-        return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-15 minutes')));
+        return $query->whereStatus(0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-'.config('tasks.close.verify').' minutes')));
     }
 }

+ 2 - 1
app/Notifications/Verification.php

@@ -27,7 +27,8 @@ class Verification extends Notification
         return (new MailMessage)
             ->subject(trans('notification.verification_account'))
             ->line(trans('notification.verification'))
-            ->line($this->code);
+            ->line($this->code)
+            ->line(trans('verification_limit', ['minutes' => config('tasks.close.verify')]));
     }
 
     public function toArray($notifiable)

+ 4 - 4
app/Services/OrderService.php

@@ -100,7 +100,7 @@ class OrderService
     // 激活套餐
     private function activatePlan(): bool
     {
-        Order::whereId(self::$order->id)->update(['expired_at' => date('Y-m-d H:i:s', strtotime('+'.self::$goods->days.' days'))]);
+        Order::whereId(self::$order->id)->update(['expired_at' => date('Y-m-d H:i:s', strtotime(self::$goods->days.' days'))]);
         $oldData = self::$user->transfer_enable;
         $updateData = [
             'invite_num' => self::$user->invite_num + (self::$goods->invite_num ?: 0),
@@ -133,7 +133,7 @@ class OrderService
         $data = ['u' => 0, 'd' => 0];
         // 账号有效期
         if (! $expired_at) {
-            $expired_at = date('Y-m-d', strtotime('+'.self::$goods->days.' days'));
+            $expired_at = date('Y-m-d', strtotime(self::$goods->days.' days'));
             foreach (Order::userPrepay(self::$order->user_id)->get() as $paidOrder) {//拿出可能存在的其余套餐, 推算最新的到期时间
                 //取出对应套餐信息
                 $expired_at = date('Y-m-d', strtotime("$expired_at +".$paidOrder->goods->days.' days'));
@@ -142,7 +142,7 @@ class OrderService
         }
 
         //账号流量重置日期
-        $nextResetTime = date('Y-m-d', strtotime('+'.self::$goods->period.' days'));
+        $nextResetTime = date('Y-m-d', strtotime(self::$goods->period.' days'));
         if ($nextResetTime >= $expired_at) {
             $nextResetTime = null;
         }
@@ -209,7 +209,7 @@ class OrderService
     public function activatePrepaidPlan(): bool
     {
         self::$order->update([
-            'expired_at' => date('Y-m-d H:i:s', strtotime('+'.self::$goods->days.' days')),
+            'expired_at' => date('Y-m-d H:i:s', strtotime(self::$goods->days.' days')),
             'status' => 2,
         ]);
 

+ 0 - 1
config/common.php

@@ -23,6 +23,5 @@ return [
             5 => 'paypal.png',
             6 => 'stripe.png',
         ],
-
     ],
 ];

+ 29 - 0
config/tasks.php

@@ -0,0 +1,29 @@
+<?php
+
+return [
+    'chunk'              => 200, // 大数据量修改,分段处理,减少内存使用
+    'clean'              => [
+        'node_daily_logs'       => '-2 month', // 清除节点每天流量数据日志
+        'node_hourly_logs'      => '-3 days', // 清除节点每小时流量数据日志
+        'notification_logs'     => '-1 month', // 清理通知日志
+        'node_heartbeats'       => '-30 minutes', // 清除节点负载信息日志
+        'node_online_logs'      => '-1 hour', // 清除节点在线用户数日志
+        'payments'              => '-1 year', // 清理在线支付日志
+        'rule_logs'             => '-3 month', // 清理审计触发日志
+        'node_online_ips'       => '-1 week', // 清除用户连接IP
+        'user_baned_logs'       => '-3 month', // 清除用户封禁日志
+        'user_daily_logs_nodes' => '-1 month', // 清除用户各节点的每天流量数据日志
+        'user_daily_logs_total' => '-3 month', // 清除用户节点总计的每天流量数据日志
+        'user_hourly_logs'      => '-3 days', // 清除用户每时各流量数据日志
+        'login_logs'            => '-3 month', // 清除用户登陆日志
+        'subscribe_logs'        => '-1 month', // 清理用户订阅请求日志
+        'traffic_logs'          => '-3 days', // 清除用户流量日志
+    ],
+    'close'              => [
+        'ticket' => 72, // 自动关闭工单,单位:小时
+        'order'  => 15, // 自动关闭订单,单位:分钟
+        'verify' => 15, // 自动失效验证码,单位:分钟
+    ],
+    'release_port'       => 30, // 端口自动释放,单位:天
+    'recently_heartbeat' => '-10 minutes', // 节点近期负载
+];

+ 1 - 1
database/factories/UserFactory.php

@@ -18,7 +18,7 @@ $factory->define(User::class, function (Faker $faker) {
         'protocol' => Helpers::getDefaultProtocol(),
         'obfs' => Helpers::getDefaultObfs(),
         'transfer_enable' => (int) sysConfig('default_traffic') * MB,
-        'expired_at' => date('Y-m-d', strtotime('+'.sysConfig('default_days').' days')),
+        'expired_at' => date('Y-m-d', strtotime(sysConfig('default_days').' days')),
         'user_group_id' => null,
     ];
 });

+ 2 - 1
resources/lang/en/notification.php

@@ -8,7 +8,7 @@ return [
     'account_expired'         => 'Account Going to Expired',
     'account_expired_content' => 'Your account will be expired after【:days】days. For your server experience, please renew your account ahead of time.',
     'account_expired_blade'   => 'Account will be expired after【:days】days, Please renew',
-    'active_email'            => 'Please completed this action under 30 minutes',
+    'active_email'            => 'Please completed this action in 30 minutes',
     'close_ticket'            => 'Ticket #【:id】 - :title Closed',
     'view_web'                => 'View Our Website',
     'view_ticket'             => 'View The Ticket',
@@ -24,6 +24,7 @@ return [
     'traffic_tips'            => 'Please pay attention on the service reset day. You may also cloud consider reset your data before the reset day.',
     'verification_account'    => 'Account Verification',
     'verification'            => 'Your verification code: ',
+    'verification_limit'      => 'Please completed this action in :minutes minutes',
     'data_anomaly'            => 'User Data Traffic Abnormal Warning',
     'data_anomaly_content'    => 'User :id:Recent Hourly Data Usage [Upload: :upload | Download: :download | Total: :total]',
     'node'                    => [

+ 1 - 0
resources/lang/zh-CN/notification.php

@@ -24,6 +24,7 @@ return [
     'traffic_tips'            => '请注意套餐流量重置日,合理分配流量使用或在流量耗尽后,付费重置套餐流量',
     'verification_account'    => '账号验证',
     'verification'            => '您的验证码:',
+    'verification_limit'      => '请在:minutes分钟内完成验证操作',
     'data_anomaly'            => '流量异常用户提醒',
     'data_anomaly_content'    => '用户:id:最近1小时 [上行流量::upload | 下行流量::download | 共计::total]',
     'node'                    => [

+ 2 - 2
resources/views/admin/config/system.blade.php

@@ -1224,11 +1224,11 @@
                                     </div>
                                     <div class="form-group col-lg-6">
                                         <div class="row">
-                                            <label class="col-md-3 col-form-label" for="auto_release_port">端口自动释放</label>
+                                            <label class="col-md-3 col-form-label" for="auto_release_port">端口回收机制</label>
                                             <div class="col-md-9">
                                                 <input type="checkbox" id="auto_release_port" data-plugin="switchery" @if($auto_release_port) checked
                                                        @endif onchange="updateFromOther('switch','auto_release_port')">
-                                                <span class="text-help"> 被封禁和过期一个月的用户端口自动释放 </span>
+                                                <span class="text-help"> 被封禁/过期{{config('tasks.release_port')}}天的账号端口自动释放 </span>
                                             </div>
                                         </div>
                                     </div>

+ 1 - 1
resources/views/admin/logs/order.blade.php

@@ -26,7 +26,7 @@
                             <div class="input-group-prepend">
                                 <span class="input-group-text">至</span>
                             </div>
-                            <input type="text" class="form-control" name="end" id="end" placeholder="{{date('Y-m-d', strtotime('+1 month'))}}"/>
+                            <input type="text" class="form-control" name="end" id="end" placeholder="{{date('Y-m-d', strtotime('1 month'))}}"/>
                         </div>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6">

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

@@ -119,7 +119,7 @@
                                     <span class="badge badge-lg badge-danger"> {{$user->expired_at}} </span>
                                 @elseif ($user->expired_at === date('Y-m-d'))
                                     <span class="badge badge-lg badge-warning"> {{$user->expired_at}} </span>
-                                @elseif ($user->expired_at <= date('Y-m-d', strtotime('+30 days')))
+                                @elseif ($user->expired_at <= date('Y-m-d', strtotime('30 days')))
                                     <span class="badge badge-lg badge-default"> {{$user->expired_at}} </span>
                                 @else
                                     {{$user->expired_at}}

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

@@ -19,7 +19,7 @@
                             @if($days !== 0)
                                 <li class="list-group-item">{{trans('common.available_date').':'.$days.trans('validation.attributes.day')}}</li>
                             @endif
-                            <li class="list-group-item"> {!! trans('user.payment.close_tips', ['minutes' => 15]) !!}</li>
+                            <li class="list-group-item"> {!! trans('user.payment.close_tips', ['minutes' => config('tasks.close.order')]) !!}</li>
                         </ul>
                     </div>
                     <div class="col-auto mx-auto">