alroyso 1 개월 전
부모
커밋
ed0ae48ffe

+ 13 - 10
.idea/workspace.xml

@@ -5,17 +5,10 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="09451f28-815a-407f-8951-727d305b50a4" name="Changes" comment="Changes">
-      <change afterPath="$PROJECT_DIR$/public/assets/global/vendor/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/app/Console/Commands/AutoJob.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Console/Commands/AutoJob.php" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/app/Console/Commands/DailyJob.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Console/Commands/DailyJob.php" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/app/Console/Commands/AutoStatisticsUserHourlyTraffic.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Console/Commands/AutoStatisticsUserHourlyTraffic.php" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/app/Http/Controllers/Admin/LogsController.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Http/Controllers/Admin/LogsController.php" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/app/Http/Controllers/Api/Client/V1Controller.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Http/Controllers/Api/Client/V1Controller.php" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/app/Http/Controllers/Api/Client/V2Controller.php" beforeDir="false" afterPath="$PROJECT_DIR$/app/Http/Controllers/Api/Client/V2Controller.php" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/resources/views/admin/logs/traffic.blade.php" beforeDir="false" afterPath="$PROJECT_DIR$/resources/views/admin/logs/traffic.blade.php" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/resources/views/admin/logs/userBanHistory.blade.php" beforeDir="false" afterPath="$PROJECT_DIR$/resources/views/admin/logs/userBanHistory.blade.php" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/resources/views/admin/user/index.blade.php" beforeDir="false" afterPath="$PROJECT_DIR$/resources/views/admin/user/index.blade.php" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/resources/views/admin/user/info.blade.php" beforeDir="false" afterPath="$PROJECT_DIR$/resources/views/admin/user/info.blade.php" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -394,7 +387,9 @@
       <workItem from="1746161383498" duration="16509000" />
       <workItem from="1746179823316" duration="256000" />
       <workItem from="1746180473097" duration="1874000" />
-      <workItem from="1746240782987" duration="12456000" />
+      <workItem from="1746240782987" duration="12486000" />
+      <workItem from="1746684360963" duration="4587000" />
+      <workItem from="1746762309565" duration="2899000" />
     </task>
     <task id="LOCAL-00001" summary="Changes">
       <option name="closed" value="true" />
@@ -724,7 +719,15 @@
       <option name="project" value="LOCAL" />
       <updated>1746182343209</updated>
     </task>
-    <option name="localTasksCounter" value="42" />
+    <task id="LOCAL-00042" summary="Changes">
+      <option name="closed" value="true" />
+      <created>1746256658398</created>
+      <option name="number" value="00042" />
+      <option name="presentableId" value="LOCAL-00042" />
+      <option name="project" value="LOCAL" />
+      <updated>1746256658398</updated>
+    </task>
+    <option name="localTasksCounter" value="43" />
     <servers />
   </component>
   <component name="TypeScriptGeneratedFilesManager">

+ 74 - 17
app/Console/Commands/AutoStatisticsUserHourlyTraffic.php

@@ -18,42 +18,46 @@ class AutoStatisticsUserHourlyTraffic extends Command
 
     public function handle(): void
     {
+        $logPrefix = '[用户流量统计]';
         $jobStartTime = microtime(true);
         echo "🟢 开始执行 autoStatisticsUserHourlyTraffic...\n";
-        Log::info('🟢 开始执行 autoStatisticsUserHourlyTraffic');
+        Log::info("$logPrefix 🟢 开始执行 autoStatisticsUserHourlyTraffic");
 
         $startTime = strtotime('-1 hour');
         $endTime = time();
 
-        // 获取 [user_id, node_id] 的流量聚合
         $records = UserDataFlowLog::whereBetween('log_time', [$startTime, $endTime])
             ->selectRaw('user_id, node_id, SUM(u) as sum_u, SUM(d) as sum_d')
             ->groupBy('user_id', 'node_id')
             ->get();
 
         $userTotals = [];
+        $userWeightedTotals = [];
         $checkedUsers = [];
         $checkedNodes = [];
+        $maxUserId = null;
+        $maxTraffic = 0;
 
         foreach ($records as $record) {
             $user_id = $record->user_id;
             $node_id = $record->node_id;
 
-            // 缓存判断用户是否存在
+            // 判断用户是否存在(带缓存)
             if (!isset($checkedUsers[$user_id])) {
                 $checkedUsers[$user_id] = User::where('id', $user_id)->exists();
             }
             if (!$checkedUsers[$user_id]) {
-                Log::warning("跳过记录,用户不存在: user_id=$user_id");
+                Log::warning("$logPrefix 跳过记录,用户不存在: user_id=$user_id");
                 continue;
             }
 
-            // 缓存判断节点是否存在
+            // 判断节点是否存在(带缓存)
             if (!isset($checkedNodes[$node_id])) {
-                $checkedNodes[$node_id] = Node::where('id', $node_id)->exists();
+                $node = Node::find($node_id);
+                $checkedNodes[$node_id] = $node ?: false;
             }
             if (!$checkedNodes[$node_id]) {
-                Log::warning("跳过记录,节点不存在: node_id=$node_id");
+                Log::warning("$logPrefix 跳过记录,节点不存在: node_id=$node_id");
                 continue;
             }
 
@@ -61,7 +65,8 @@ class AutoStatisticsUserHourlyTraffic extends Command
             $d = $record->sum_d ?? 0;
             $total = $u + $d;
 
-            //Log::info("📊 保存流量记录 - user: $user_id, node: $node_id, u: $u, d: $d, total: $total");
+            $rate = floatval($checkedNodes[$node_id]->traffic_rate ?? 1);
+            $weighted = $rate > 0 ? $total / $rate : $total;
 
             UserHourlyDataFlow::create([
                 'user_id' => $user_id,
@@ -72,28 +77,80 @@ class AutoStatisticsUserHourlyTraffic extends Command
                 'traffic' => flowAutoShow($total),
             ]);
 
-            // 累计每个用户的总流量
-            if (!isset($userTotals[$user_id])) {
-                $userTotals[$user_id] = 0;
+            $userTotals[$user_id] = ($userTotals[$user_id] ?? 0) + $total;
+            $userWeightedTotals[$user_id] = ($userWeightedTotals[$user_id] ?? 0) + $weighted;
+
+            if ($userWeightedTotals[$user_id] > $maxTraffic) {
+                $maxTraffic = $userWeightedTotals[$user_id];
+                $maxUserId = $user_id;
             }
-            $userTotals[$user_id] += $total;
         }
 
-        // 判断是否超出阈值
         $trafficBanValue = sysConfig('traffic_ban_value');
 
-        foreach ($userTotals as $user_id => $total) {
+        foreach ($userWeightedTotals as $user_id => $total) {
             if ($total > $trafficBanValue * GB) {
                 $user = User::find($user_id);
                 $email = $user->email ?? '未知邮箱';
-                Log::warning("⚠️ 用户 [ID: $user_id, 邮箱: $email] 最近1小时流量异常:已使用 ".flowAutoShow($total));
-                echo "⚠️ 异常用户: $email, 使用 ".flowAutoShow($total)."\n";
+                Log::warning("$logPrefix ⚠️ 用户 [ID: $user_id, 邮箱: $email] 最近1小时流量异常:已使用 " . flowAutoShow($total));
+                echo "⚠️ 异常用户: $email, 使用 " . flowAutoShow($total) . "\n";
+            }
+        }
+
+        if ($maxUserId !== null) {
+            $maxUser = User::find($maxUserId);
+            $email = $maxUser->email ?? '未知邮箱';
+
+            $rawTraffic = 0;
+            $rawUpload = 0;
+            $rawDownload = 0;
+            $convertedTraffic = $userWeightedTotals[$maxUserId] ?? 0;
+            $details = [];
+
+            foreach ($records as $record) {
+                if ($record->user_id == $maxUserId) {
+                    $u = $record->sum_u ?? 0;
+                    $d = $record->sum_d ?? 0;
+                    $total = $u + $d;
+
+                    $node = $checkedNodes[$record->node_id];
+                    $rate = floatval($node->traffic_rate ?? 1);
+                    $nodeName = $node->name ?? "未知节点";
+
+                    if ($rate == 1) {
+                        $rawUpload += $u;
+                        $rawDownload += $d;
+                        $rawTraffic += $total;
+                    } else {
+                        $converted = $rate > 0 ? $total / $rate : $total;
+                        $details[] = "节点[$nodeName] 倍率 $rate => 上传: " . flowAutoShow($u) .
+                            ", 下载: " . flowAutoShow($d) .
+                            ", 总计: " . flowAutoShow($total) .
+                            " => 换算后(按倍率 {$rate}): " . flowAutoShow($converted);
+                    }
+                }
             }
+
+            $detailsText = count($details) > 0 ? " 🔁 明细: " . implode(",", $details) : "未使用大于1倍的线路";
+
+            $message = "🚨 过去1小时使用流量最多的用户:$email (ID: $maxUserId),🟦 上行: " . flowAutoShow($rawUpload) .
+                ",🟥 下行: " . flowAutoShow($rawDownload) .
+                ",原始流量: " . flowAutoShow($rawTraffic) .
+                "(仅倍率为1的线路),换算为1倍率流量: " . flowAutoShow($convertedTraffic) .
+                $detailsText;
+
+            echo "$message\n";
+            Log::info("$logPrefix $message");
         }
 
         $jobUsedTime = round((microtime(true) - $jobStartTime), 4);
-        Log::info("✅ autoStatisticsUserHourlyTraffic 执行完成,耗时 {$jobUsedTime} 秒");
+        Log::info("$logPrefix ✅ autoStatisticsUserHourlyTraffic 执行完成,耗时 {$jobUsedTime} 秒");
         echo "✅ 执行完成,耗时 {$jobUsedTime} 秒\n";
+
+        $nextRunTimestamp = time() + 3600;
+        $nextRunTimeFormatted = date('Y-m-d H:i:s', $nextRunTimestamp);
+        echo "⏰ 下次预计运行时间:$nextRunTimeFormatted\n";
+        Log::info("$logPrefix ⏰ 下次预计运行时间:$nextRunTimeFormatted");
     }
 
 

+ 16 - 2
app/Http/Controllers/Admin/LogsController.php

@@ -192,8 +192,22 @@ class LogsController extends Controller
             $weighted = ($log->u + $log->d) / $rate;
             $log->weighted_traffic = $weighted;
             $log->is_abnormal = $weighted > $baseTrafficBanValue;
-            $log->u = flowAutoShow($log->u);
-            $log->d = flowAutoShow($log->d);
+            
+            // 先保存原始流量值
+            $original_u = $log->u;
+            $original_d = $log->d;
+            
+            // 转换为可读格式
+            $log->u = flowAutoShow($original_u);
+            $log->d = flowAutoShow($original_d);
+            
+            // 增加转换后的流量显示(转换为1倍流量)
+            if ($rate != 1) {
+                $converted_u = $original_u / $rate;
+                $converted_d = $original_d / $rate;
+                $log->converted_u = flowAutoShow($converted_u);
+                $log->converted_d = flowAutoShow($converted_d);
+            }
             $log->log_time = date('Y-m-d H:i:s', $log->log_time);
         }
 

+ 12 - 1
resources/views/admin/logs/traffic.blade.php

@@ -77,6 +77,7 @@
                         <th> 上传流量</th>
                         <th> 下载流量</th>
                         <th> 总流量</th>
+                        <th> 转换后流量</th>
                         <th> 记录时间</th>
                     </tr>
                     </thead>
@@ -96,10 +97,20 @@
                                 @endif
                             </td>
                             <td> {{$log->node->name ?? '【节点已删除】'}} </td>
-                            <td> {{$log->rate}} </td>
+                            <td> {{$log->node->traffic_rate ?? 1}} </td>
                             <td> {{$log->u}} </td>
                             <td> {{$log->d}} </td>
                             <td><span class="badge badge-danger"> {{$log->traffic}} </span></td>
+                            <td>
+                                @if(isset($log->converted_u))
+                                    <span class="badge badge-warning">
+                                        上传: {{$log->converted_u}}<br>
+                                        下载: {{$log->converted_d}}
+                                    </span>
+                                @else
+                                    -
+                                @endif
+                            </td>
                             <td> {{$log->log_time}} </td>
                         </tr>
                     @endforeach