|
@@ -491,6 +491,10 @@ class User extends Controller
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 用户登录日志
|
|
* 用户登录日志
|
|
|
|
|
+ *
|
|
|
|
|
+ * 返回字段:user_id/member_id、first_name、login_ip、country(国家/地区)、
|
|
|
|
|
+ * browser(浏览器)、os(操作系统)、status/status_text(登录成功或失败)、
|
|
|
|
|
+ * created_at(登录时间)、logout_time(登出时间)、online_duration(在线时长分钟)
|
|
|
*/
|
|
*/
|
|
|
public function loginLog()
|
|
public function loginLog()
|
|
|
{
|
|
{
|
|
@@ -501,35 +505,79 @@ class User extends Controller
|
|
|
'user_id' => ['nullable'],
|
|
'user_id' => ['nullable'],
|
|
|
'member_id' => ['nullable'],
|
|
'member_id' => ['nullable'],
|
|
|
'first_name' => ['nullable'],
|
|
'first_name' => ['nullable'],
|
|
|
|
|
+ 'status' => ['nullable', 'integer', 'in:0,1'],
|
|
|
'start_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:end_time'],
|
|
'start_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:end_time'],
|
|
|
'end_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:start_time'],
|
|
'end_time' => ['nullable', 'date', 'date_format:Y-m-d', 'required_with:start_time'],
|
|
|
]);
|
|
]);
|
|
|
$page = request()->input('page', 1);
|
|
$page = request()->input('page', 1);
|
|
|
$limit = request()->input('limit', 15);
|
|
$limit = request()->input('limit', 15);
|
|
|
|
|
|
|
|
- $query = UserLogin::join('users', 'user_login.user_id', '=', 'users.user_id');
|
|
|
|
|
|
|
+ // leftJoin:失败日志也可能没有对应用户,仍需展示日志本身
|
|
|
|
|
+ $query = UserLogin::query()
|
|
|
|
|
+ ->leftJoin('users', 'user_login.user_id', '=', 'users.user_id')
|
|
|
|
|
+ ->select([
|
|
|
|
|
+ 'user_login.id',
|
|
|
|
|
+ 'user_login.user_id',
|
|
|
|
|
+ 'user_login.login_ip',
|
|
|
|
|
+ 'user_login.country',
|
|
|
|
|
+ 'user_login.browser',
|
|
|
|
|
+ 'user_login.os',
|
|
|
|
|
+ 'user_login.status',
|
|
|
|
|
+ 'user_login.logout_time',
|
|
|
|
|
+ 'user_login.online_duration',
|
|
|
|
|
+ 'user_login.user_agent',
|
|
|
|
|
+ 'user_login.created_at',
|
|
|
|
|
+ 'user_login.updated_at',
|
|
|
|
|
+ 'users.member_id',
|
|
|
|
|
+ 'users.first_name',
|
|
|
|
|
+ 'users.account',
|
|
|
|
|
+ 'users.username',
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
if (!empty($params['user_id'])) {
|
|
if (!empty($params['user_id'])) {
|
|
|
- $query = $query->where('user_login.user_id', $params['user_id']);
|
|
|
|
|
|
|
+ $query->where('user_login.user_id', $params['user_id']);
|
|
|
}
|
|
}
|
|
|
if (!empty($params['member_id'])) {
|
|
if (!empty($params['member_id'])) {
|
|
|
- $query = $query->where('user_login.user_id', $params['member_id']);
|
|
|
|
|
|
|
+ $query->where('user_login.user_id', $params['member_id']);
|
|
|
}
|
|
}
|
|
|
if (!empty($params['first_name'])) {
|
|
if (!empty($params['first_name'])) {
|
|
|
- $query = $query->where('users.first_name', 'like', "%{$params['first_name']}%");
|
|
|
|
|
|
|
+ $query->where('users.first_name', 'like', "%{$params['first_name']}%");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isset($params['status']) && $params['status'] !== '' && $params['status'] !== null) {
|
|
|
|
|
+ $query->where('user_login.status', (int)$params['status']);
|
|
|
}
|
|
}
|
|
|
if (!empty($params['start_time'])) {
|
|
if (!empty($params['start_time'])) {
|
|
|
$startTime = $params['start_time'] . " 00:00:00";
|
|
$startTime = $params['start_time'] . " 00:00:00";
|
|
|
- $query = $query->where('user_login.created_at', '>=', $startTime);
|
|
|
|
|
|
|
+ $query->where('user_login.created_at', '>=', $startTime);
|
|
|
}
|
|
}
|
|
|
if (!empty($params['end_time'])) {
|
|
if (!empty($params['end_time'])) {
|
|
|
$endTime = $params['end_time'] . " 23:59:59";
|
|
$endTime = $params['end_time'] . " 23:59:59";
|
|
|
- $query = $query->where('user_login.updated_at', '<=', $endTime);
|
|
|
|
|
|
|
+ $query->where('user_login.created_at', '<=', $endTime);
|
|
|
}
|
|
}
|
|
|
- $count = $query->count();
|
|
|
|
|
|
|
+ $count = (clone $query)->count();
|
|
|
$list = $query
|
|
$list = $query
|
|
|
->forPage($page, $limit)
|
|
->forPage($page, $limit)
|
|
|
- ->orderByDesc('user_login.created_at')
|
|
|
|
|
- ->get();
|
|
|
|
|
|
|
+ ->orderByDesc('user_login.id')
|
|
|
|
|
+ ->get()
|
|
|
|
|
+ ->map(function ($item) {
|
|
|
|
|
+ // 未登出时:若仍在线可按当前时间估算在线时长(仅展示,不写库)
|
|
|
|
|
+ if (
|
|
|
|
|
+ (int)$item->status === UserLogin::STATUS_SUCCESS
|
|
|
|
|
+ && empty($item->getRawOriginal('logout_time'))
|
|
|
|
|
+ && empty($item->online_duration)
|
|
|
|
|
+ && !empty($item->getRawOriginal('created_at'))
|
|
|
|
|
+ ) {
|
|
|
|
|
+ $loginAt = strtotime($item->getRawOriginal('created_at'));
|
|
|
|
|
+ if ($loginAt) {
|
|
|
|
|
+ $item->online_duration = (int)ceil(max(0, time() - $loginAt) / 60);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 国家/地区等空值统一给前端可展示的占位
|
|
|
|
|
+ $item->country = $item->country ?: '';
|
|
|
|
|
+ $item->browser = $item->browser ?: '';
|
|
|
|
|
+ $item->os = $item->os ?: '';
|
|
|
|
|
+ return $item;
|
|
|
|
|
+ });
|
|
|
} catch (Exception $e) {
|
|
} catch (Exception $e) {
|
|
|
return $this->error(HttpStatus::CUSTOM_ERROR,$e->getMessage());
|
|
return $this->error(HttpStatus::CUSTOM_ERROR,$e->getMessage());
|
|
|
}
|
|
}
|