Parcourir la source

游戏时长统计优化

Tree il y a 1 semaine
Parent
commit
b2b2368bb9

+ 15 - 10
app/Http/Controllers/Admin/GameEnterLogController.php

@@ -3,24 +3,25 @@
 namespace App\Http\Controllers\Admin;
 
 use App\Http\Controllers\Controller;
-use App\Models\GameEnterLog;
+use App\Models\GameEnterDailyStat;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 
 class GameEnterLogController extends Controller
 {
     /**
-     * Average game enter duration statistics per game.
+     * Daily per-game enter duration statistics (from aggregate table).
      */
     public function statistics(Request $request)
     {
-        $startDate = $request->input('start_date', date('Y-m-d', strtotime('-7 days')));
-        $endDate = $request->input('end_date', date('Y-m-d'));
+        $today = date('Y-m-d');
+        $startDate = $request->input('start_date', $today);
+        $endDate = $request->input('end_date', $today);
 
-        $rows = DB::table(GameEnterLog::TABLE)
+        $rows = DB::connection('read')->table(GameEnterDailyStat::TABLE)
             ->whereBetween('log_date', [$startDate, $endDate])
-            ->selectRaw('game_id, COUNT(*) as enter_count, AVG(CAST(duration_ms AS FLOAT)) as avg_duration_ms')
-            ->groupBy('game_id')
+            ->select('log_date', 'game_id', 'enter_count', 'total_duration_ms')
+            ->orderByDesc('log_date')
             ->orderByDesc('enter_count')
             ->get();
 
@@ -40,17 +41,21 @@ class GameEnterLogController extends Controller
         $statistics = [];
         foreach ($rows as $row) {
             $gameId = (int) $row->game_id;
-            $avgMs = (float) $row->avg_duration_ms;
-            $gameName = __('auto.未知游�');
+            $enterCount = (int) $row->enter_count;
+            $totalMs = (int) $row->total_duration_ms;
+            $avgMs = $enterCount > 0 ? $totalMs / $enterCount : 0;
+
+            $gameName = __('auto.δ֪ÓÎÏ·');
             if (isset($games[$gameId])) {
                 $game = $games[$gameId];
                 $gameName = $game->brand . ' - ' . $game->title;
             }
 
             $statistics[] = [
+                'log_date' => $row->log_date,
                 'game_id' => $gameId,
                 'game_name' => $gameName,
-                'enter_count' => (int) $row->enter_count,
+                'enter_count' => $enterCount,
                 'avg_duration_ms' => round($avgMs, 2),
                 'avg_duration_sec' => round($avgMs / 1000, 3),
             ];

+ 59 - 0
app/Models/GameEnterDailyStat.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\QueryException;
+use Illuminate\Support\Facades\DB;
+
+class GameEnterDailyStat extends Model
+{
+    const TABLE = 'agent.dbo.game_enter_daily_stat';
+
+    protected $table = self::TABLE;
+
+    public $timestamps = false;
+
+    /**
+     * Increment daily aggregate for game enter duration.
+     */
+    public static function incrementStat(int $gameId, string $logDate, int $durationMs): void
+    {
+        $now = date('Y-m-d H:i:s');
+        $updated = DB::connection('write')->table(self::TABLE)
+            ->where('game_id', $gameId)
+            ->where('log_date', $logDate)
+            ->update([
+                'enter_count' => DB::raw('enter_count + 1'),
+                'total_duration_ms' => DB::raw('total_duration_ms + ' . (int) $durationMs),
+                'updated_at' => $now,
+            ]);
+
+        if ($updated > 0) {
+            return;
+        }
+
+        try {
+            DB::connection('write')->table(self::TABLE)->insert([
+                'game_id' => $gameId,
+                'log_date' => $logDate,
+                'enter_count' => 1,
+                'total_duration_ms' => $durationMs,
+                'updated_at' => $now,
+            ]);
+        } catch (QueryException $e) {
+            if (stripos($e->getMessage(), 'duplicate key') === false
+                && stripos($e->getMessage(), 'unique') === false) {
+                throw $e;
+            }
+            DB::connection('write')->table(self::TABLE)
+                ->where('game_id', $gameId)
+                ->where('log_date', $logDate)
+                ->update([
+                    'enter_count' => DB::raw('enter_count + 1'),
+                    'total_duration_ms' => DB::raw('total_duration_ms + ' . (int) $durationMs),
+                    'updated_at' => $now,
+                ]);
+        }
+    }
+}

+ 29 - 9
app/Models/GameEnterLog.php

@@ -3,6 +3,7 @@
 namespace App\Models;
 
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\DB;
 
 class GameEnterLog extends Model
 {
@@ -21,19 +22,38 @@ class GameEnterLog extends Model
     ];
 
     /**
+     * Insert detail log and update daily aggregate.
+     *
      * @param array $data user_id, game_id, duration_ms, log_date (optional)
      * @return bool
      */
     public static function addLog(array $data)
     {
-        $logData = [
-            'user_id' => (int) ($data['user_id'] ?? 0),
-            'game_id' => (int) ($data['game_id'] ?? 0),
-            'duration_ms' => (int) ($data['duration_ms'] ?? 0),
-            'log_date' => $data['log_date'] ?? date('Y-m-d'),
-            'created_at' => date('Y-m-d H:i:s'),
-        ];
-
-        return self::insert($logData);
+        $userId = (int) ($data['user_id'] ?? 0);
+        $gameId = (int) ($data['game_id'] ?? 0);
+        $durationMs = (int) ($data['duration_ms'] ?? 0);
+        $logDate = $data['log_date'] ?? date('Y-m-d');
+
+        if ($gameId <= 0 || $durationMs < 0) {
+            return false;
+        }
+
+        return DB::connection('write')->transaction(function () use ($userId, $gameId, $durationMs, $logDate) {
+            $inserted = DB::connection('write')->table(self::TABLE)->insert([
+                'user_id' => $userId,
+                'game_id' => $gameId,
+                'duration_ms' => $durationMs,
+                'log_date' => $logDate,
+                'created_at' => date('Y-m-d H:i:s'),
+            ]);
+
+            if (!$inserted) {
+                return false;
+            }
+
+            GameEnterDailyStat::incrementStat($gameId, $logDate, $durationMs);
+
+            return true;
+        });
     }
 }

+ 2 - 1
resources/lang/en_US/auto.php

@@ -1918,11 +1918,12 @@ return [
     '单控池累计成功吐分:'=>'Single-control pool accumulative successful points:'
     '进游戏时长统计'=>'Game enter duration stats',
     '各游戏进游戏平均时长'=>'Average game enter duration by game',
-    '进游戏时长统计说明'=>'Client reports time from tap to load complete (ms). Table shows averages for the selected date range.',
+    '进游戏时长统计说明'=>'Client reports enter duration; admin shows daily per-game aggregates (detail log for programs only).',
     '上报次数'=>'Report count',
     '平均耗时(秒)'=>'Avg duration (sec)',
     '平均耗时(毫秒)'=>'Avg duration (ms)',
     '暂无进游戏时长统计数据'=>'No data. Change the date range or confirm the client is reporting and the table exists.',
     '未知游戏'=>'Unknown game',
     '至'=>'to',
+    '统计日期'=>'Stat date',
 ];

+ 2 - 1
resources/lang/zh_CN/auto.php

@@ -1920,11 +1920,12 @@ return [
     '单控池累计成功吐分:'=>'单控池累计成功吐分:'
     '进游戏时长统计'=>'进游戏时长统计',
     '各游戏进游戏平均时长'=>'各游戏进游戏平均时长',
-    '进游戏时长统计说明'=>'客户端上报从点击进游戏到加载完成的耗时(毫秒),下表为所选日期范围内的平均值。',
+    '进游戏时长统计说明'=>'客户端上报进游戏耗时;后台按日按游戏展示汇总数据(明细表仅程序使用)。',
     '上报次数'=>'上报次数',
     '平均耗时(秒)'=>'平均耗时(秒)',
     '平均耗时(毫秒)'=>'平均耗时(毫秒)',
     '暂无进游戏时长统计数据'=>'暂无统计数据,请选择其他时间范围,或确认客户端已上报且数据表已创建。',
     '未知游戏'=>'未知游戏',
     '至'=>'至',
+    '统计日期'=>'统计日期',
 ];

+ 4 - 5
resources/views/admin/game_enter_log/statistics.blade.php

@@ -28,25 +28,24 @@
                                 <span style="padding-left: 10px">{{ __('auto.至') }}</span>
                                 <input type="date" name="end_date" class="form-control" value="{{ $end_date }}" />
                                 <input type="submit" class="btn btn-sm btn-gradient-dark btn-icon-text" value="{{ __('auto.搜索') }}"/>&nbsp;&nbsp;
-                                <a href="/admin/game_enter_log/statistics" class="btn btn-sm btn-gradient-warning btn-icon-text">{{ __('auto.清空') }}</a>
                             </form>
                             <br>
                             <table class="table table-bordered">
                                 <thead>
                                 <tr>
-                                    <th width="35%">{{ __('auto.游戏') }}</th>
+                                    <th width="12%">{{ __('auto.统计日期') }}</th>
+                                    <th width="28%">{{ __('auto.游戏') }}</th>
                                     <th width="15%">{{ __('auto.上报次数') }}</th>
-                                    <th width="25%">{{ __('auto.平均耗时(秒)') }}</th>
-                                    <th width="25%">{{ __('auto.平均耗时(毫秒)') }}</th>
+                                    <th width="22%">{{ __('auto.平均耗时(秒)') }}</th>
                                 </tr>
                                 </thead>
                                 <tbody>
                                 @foreach($statistics as $stat)
                                     <tr>
+                                        <td>{{ $stat['log_date'] }}</td>
                                         <td>{{ $stat['game_name'] }} <small class="text-muted">(ID: {{ $stat['game_id'] }})</small></td>
                                         <td>{{ $stat['enter_count'] }}</td>
                                         <td>{{ $stat['avg_duration_sec'] }}</td>
-                                        <td>{{ $stat['avg_duration_ms'] }}</td>
                                     </tr>
                                 @endforeach
                                 </tbody>