|
|
@@ -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) {
|