| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- <?php
- namespace App\Services;
- use App\Models\User;
- use App\Models\UserLogin;
- use Carbon\Carbon;
- /**
- * 在线用户列表(只读,不写库、不打外网)
- */
- class OnlineUserService
- {
- /** 最近活跃秒数 */
- public const ONLINE_WINDOW_SECONDS = 1800;
- /**
- * @param array{page?:int,limit?:int,member_id?:string,first_name?:string,login_ip?:string,platform?:string} $params
- * @return array{total:int,data:list<array>}
- */
- public static function list(array $params): array
- {
- $page = max(1, (int)($params['page'] ?? 1));
- $limit = min(200, max(1, (int)($params['limit'] ?? 15)));
- $since = time() - self::ONLINE_WINDOW_SECONDS;
- $latestLogin = UserLogin::query()
- ->selectRaw('user_id, MAX(id) as id')
- ->where('status', UserLogin::STATUS_SUCCESS)
- ->groupBy('user_id');
- $query = User::query()
- ->from('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')
- ->where('users.last_active_time', '>=', $since)
- ->where(function ($q) {
- $q->whereNull('users.from')->orWhere('users.from', '<>', '2');
- });
- if (!empty($params['member_id'])) {
- $mid = $params['member_id'];
- $query->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'] . '%');
- }
- if (!empty($params['login_ip'])) {
- $query->where('ul.login_ip', 'like', '%' . $params['login_ip'] . '%');
- }
- if (!empty($params['platform']) && $params['platform'] !== '全部') {
- $query->where('ul.platform', $params['platform']);
- }
- $query->select([
- 'users.id',
- 'users.member_id',
- 'users.user_id',
- 'users.first_name',
- 'users.last_active_time',
- 'wallets.available_balance',
- 'ul.login_ip',
- 'ul.country',
- 'ul.login_domain',
- 'ul.platform',
- 'ul.browser',
- 'ul.os',
- 'ul.created_at as login_time',
- ]);
- $total = (int)(clone $query)->toBase()->distinct()->count('users.id');
- $list = $query
- ->orderByDesc('users.last_active_time')
- ->forPage($page, $limit)
- ->get()
- ->map(function ($row) {
- return [
- 'member_id' => $row->member_id ?: $row->user_id,
- 'first_name' => (string)($row->first_name ?? ''),
- 'available_balance' => (float)($row->available_balance ?? 0),
- 'login_ip' => (string)($row->login_ip ?? ''),
- 'location' => (string)($row->country ?? ''),
- 'login_domain' => (string)($row->login_domain ?? ''),
- 'platform' => (string)($row->platform ?: self::guessPlatformFromOs((string)($row->os ?? ''))),
- 'browser' => (string)($row->browser ?? ''),
- 'os' => (string)($row->os ?? ''),
- 'login_time' => self::formatTime($row->login_time ?? null),
- 'last_active_time' => $row->last_active_time,
- ];
- })
- ->values()
- ->all();
- return ['total' => $total, 'data' => $list];
- }
- private static function formatTime($value): string
- {
- if (empty($value)) {
- return '';
- }
- try {
- return Carbon::parse($value)->setTimezone('Asia/Shanghai')->format('Y-m-d H:i:s');
- } catch (\Throwable $e) {
- return (string)$value;
- }
- }
- private static function guessPlatformFromOs(string $os): string
- {
- $os = strtolower($os);
- if (str_contains($os, 'android')) {
- return 'Android';
- }
- if (str_contains($os, 'ios') || str_contains($os, 'iphone') || str_contains($os, 'ipad')) {
- return 'iOS';
- }
- return 'PC';
- }
- }
|