doge 1 неделя назад
Родитель
Сommit
672860f064
1 измененных файлов с 66 добавлено и 41 удалено
  1. 66 41
      app/Services/OnlineUserService.php

+ 66 - 41
app/Services/OnlineUserService.php

@@ -40,60 +40,92 @@ class OnlineUserService
         $hasOs = Schema::hasColumn('user_login', 'os');
         $hasCountry = Schema::hasColumn('user_login', 'country');
 
-        // 每位用户最近一次成功登录
-        $loginBase = DB::table('user_login');
-        if ($hasLoginStatus) {
-            $loginBase->where('status', UserLogin::STATUS_SUCCESS);
-        }
-        $latestLogin = $loginBase
-            ->selectRaw('user_id, MAX(id) as id')
-            ->groupBy('user_id');
-
-        $query = DB::table('users')
-            ->leftJoin('wallets', 'wallets.member_id', '=', 'users.member_id')
-            ->leftJoinSub($latestLogin, 'latest_login', function ($join) {
-                $join->on('latest_login.user_id', '=', 'users.user_id');
-            })
-            ->leftJoin('user_login as ul', 'ul.id', '=', 'latest_login.id')
+        // 先筛在线用户 ID(避免 join 干扰 count / 前缀别名问题)
+        $onlineIdsQuery = DB::table('users')
             ->where(function ($q) use ($now, $activeSince) {
-                // 1) 有效 token 会话
                 $q->whereExists(function ($sub) use ($now) {
                     $sub->select(DB::raw(1))
-                        ->from('user_session as us')
+                        ->from('user_session')
                         ->where(function ($w) {
-                            $w->whereColumn('us.user_id', 'users.user_id')
-                                ->orWhereColumn('us.user_id', 'users.member_id');
+                            $w->whereColumn('user_session.user_id', 'users.user_id')
+                                ->orWhereColumn('user_session.user_id', 'users.member_id');
                         })
-                        ->where('us.expire_time', '>', $now);
-                })
-                // 2) 或最近活跃(unix 秒级时间戳)
-                ->orWhere(function ($q2) use ($activeSince) {
+                        ->where('user_session.expire_time', '>', $now);
+                })->orWhere(function ($q2) use ($activeSince) {
                     $q2->where('users.last_active_time', '>', 1000000000)
                         ->where('users.last_active_time', '>=', $activeSince);
                 });
             })
-            // 排除虚拟游客
             ->where(function ($q) {
-                $q->whereNull('users.from')
-                    ->orWhere('users.from', '<>', 2);
+                $q->whereNull('users.from')->orWhere('users.from', '<>', 2);
             });
 
         if (!empty($params['member_id'])) {
             $mid = $params['member_id'];
-            $query->where(function ($q) use ($mid) {
+            $onlineIdsQuery->where(function ($q) use ($mid) {
                 $q->where('users.member_id', $mid)->orWhere('users.user_id', $mid);
             });
         }
         if (!empty($params['first_name'])) {
-            $query->where('users.first_name', 'like', '%' . $params['first_name'] . '%');
+            $onlineIdsQuery->where('users.first_name', 'like', '%' . $params['first_name'] . '%');
         }
-        if (!empty($params['login_ip'])) {
-            $query->where('ul.login_ip', 'like', '%' . $params['login_ip'] . '%');
+
+        // 需要按登录 IP / 平台筛选时,再关联最近登录
+        $needLoginFilter = !empty($params['login_ip'])
+            || (!empty($params['platform']) && $params['platform'] !== '全部' && $hasPlatform);
+
+        if ($needLoginFilter) {
+            $loginFilter = DB::table('user_login as ul')
+                ->select('ul.user_id')
+                ->whereIn('ul.id', function ($sub) use ($hasLoginStatus) {
+                    $sub->from('user_login')
+                        ->selectRaw('MAX(id)')
+                        ->when($hasLoginStatus, fn ($q) => $q->where('status', UserLogin::STATUS_SUCCESS))
+                        ->groupBy('user_id');
+                });
+            if (!empty($params['login_ip'])) {
+                $loginFilter->where('ul.login_ip', 'like', '%' . $params['login_ip'] . '%');
+            }
+            if (!empty($params['platform']) && $params['platform'] !== '全部' && $hasPlatform) {
+                $loginFilter->where('ul.platform', $params['platform']);
+            }
+            $filteredUserIds = $loginFilter->pluck('ul.user_id')->all();
+            if ($filteredUserIds === []) {
+                return ['total' => 0, 'data' => []];
+            }
+            $onlineIdsQuery->where(function ($q) use ($filteredUserIds) {
+                $q->whereIn('users.user_id', $filteredUserIds)
+                    ->orWhereIn('users.member_id', $filteredUserIds);
+            });
         }
-        if (!empty($params['platform']) && $params['platform'] !== '全部' && $hasPlatform) {
-            $query->where('ul.platform', $params['platform']);
+
+        $total = (int)(clone $onlineIdsQuery)->count('users.id');
+
+        $pageIds = (clone $onlineIdsQuery)
+            ->orderByDesc('users.last_active_time')
+            ->offset(($page - 1) * $limit)
+            ->limit($limit)
+            ->pluck('users.id')
+            ->all();
+
+        if ($pageIds === []) {
+            return ['total' => $total, 'data' => []];
         }
 
+        // 最近登录子查询
+        $latestLoginSql = DB::table('user_login')
+            ->selectRaw('user_id, MAX(id) as max_id')
+            ->when($hasLoginStatus, fn ($q) => $q->where('status', UserLogin::STATUS_SUCCESS))
+            ->groupBy('user_id');
+
+        $detailQuery = DB::table('users')
+            ->leftJoin('wallets', 'wallets.member_id', '=', 'users.member_id')
+            ->leftJoinSub($latestLoginSql, 'll', function ($join) {
+                $join->on('ll.user_id', '=', 'users.user_id');
+            })
+            ->leftJoin('user_login as ul', 'ul.id', '=', 'll.max_id')
+            ->whereIn('users.id', $pageIds);
+
         $select = [
             'users.id',
             'users.member_id',
@@ -119,17 +151,10 @@ class OnlineUserService
         if ($hasOs) {
             $select[] = 'ul.os';
         }
-        $query->select($select);
-
-        $total = (int)(clone $query)
-            ->reorder()
-            ->selectRaw('COUNT(DISTINCT users.id) as aggregate')
-            ->value('aggregate');
 
-        $rows = $query
+        $rows = $detailQuery
+            ->select($select)
             ->orderByDesc('users.last_active_time')
-            ->offset(($page - 1) * $limit)
-            ->limit($limit)
             ->get();
 
         $data = $rows->map(function ($row) {