UserLoginLogModel.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <?php
  2. declare (strict_types = 1);
  3. namespace app\model;
  4. use think\Model;
  5. /**
  6. * 用户登录日志模型
  7. */
  8. class UserLoginLogModel extends Model
  9. {
  10. // 设置表名
  11. protected $table = 'merchant_user_login_log';
  12. // 设置主键
  13. protected $pk = 'id';
  14. // 登录状态常量
  15. const STATUS_FAILED = 0; // 登录失败
  16. const STATUS_SUCCESS = 1; // 登录成功
  17. /**
  18. * 记录登录日志
  19. * @param array $data 日志数据
  20. * @return bool
  21. */
  22. public static function recordLogin(array $data): bool
  23. {
  24. try {
  25. $log = new self();
  26. $log->merchant_id = $data['merchant_id'] ?? 0;
  27. $log->user_id = $data['user_id'] ?? 0;
  28. $log->login_device = $data['login_device'] ?? '';
  29. $log->login_ip = $data['login_ip'] ?? '';
  30. $log->login_time = time();
  31. $log->login_status = $data['login_status'] ?? self::STATUS_FAILED;
  32. return $log->save();
  33. } catch (\Exception $e) {
  34. // 记录日志失败不影响登录流程
  35. return false;
  36. }
  37. }
  38. /**
  39. * 获取登录日志列表
  40. * @param int $merchantId 商户ID
  41. * @param int $userId 用户ID(可选)
  42. * @param int $page 页码
  43. * @param int $limit 每页数量
  44. * @param array $filters 过滤条件
  45. * @return array
  46. */
  47. public static function getLoginLogs(int $merchantId, int $userId = 0, int $page = 1, int $limit = 20, array $filters = []): array
  48. {
  49. $where = [
  50. ['merchant_id', '=', $merchantId]
  51. ];
  52. // 如果指定了用户ID
  53. if ($userId > 0) {
  54. $where[] = ['user_id', '=', $userId];
  55. }
  56. // 登录状态筛选
  57. if (isset($filters['login_status']) && $filters['login_status'] !== '') {
  58. $where[] = ['login_status', '=', $filters['login_status']];
  59. }
  60. // IP地址筛选
  61. if (!empty($filters['login_ip'])) {
  62. $where[] = ['login_ip', 'like', '%' . $filters['login_ip'] . '%'];
  63. }
  64. // 时间范围筛选
  65. if (!empty($filters['start_time'])) {
  66. $where[] = ['login_time', '>=', strtotime($filters['start_time'])];
  67. }
  68. if (!empty($filters['end_time'])) {
  69. $where[] = ['login_time', '<=', strtotime($filters['end_time'])];
  70. }
  71. $query = self::where($where);
  72. $total = $query->count();
  73. $list = $query->field('id, merchant_id, user_id, login_device, login_ip, login_time, login_status')
  74. ->order('id', 'desc')
  75. ->page($page, $limit)
  76. ->select();
  77. // 获取相关用户信息
  78. if ($list->count() > 0) {
  79. $userIds = array_unique(array_column($list->toArray(), 'user_id'));
  80. $users = UserModel::whereIn('user_id', $userIds)
  81. ->field('user_id, user_name, nick_name')
  82. ->select()
  83. ->toArray();
  84. $userMap = [];
  85. foreach ($users as $user) {
  86. $userMap[$user['user_id']] = $user;
  87. }
  88. // 添加用户信息到日志记录
  89. foreach ($list as &$log) {
  90. $log['user_name'] = $userMap[$log['user_id']]['user_name'] ?? '';
  91. $log['nick_name'] = $userMap[$log['user_id']]['nick_name'] ?? '';
  92. $log['status_text'] = $log['login_status'] == self::STATUS_SUCCESS ? '成功' : '失败';
  93. }
  94. }
  95. return [
  96. 'list' => $list,
  97. 'total' => $total,
  98. 'page' => $page,
  99. 'limit' => $limit
  100. ];
  101. }
  102. /**
  103. * 获取用户最近登录记录
  104. * @param int $userId 用户ID
  105. * @param int $limit 获取数量
  106. * @return array
  107. */
  108. public static function getRecentLogs(int $userId, int $limit = 10): array
  109. {
  110. return self::where('user_id', $userId)
  111. ->field('login_device, login_ip, login_time, login_status')
  112. ->order('id', 'desc')
  113. ->limit($limit)
  114. ->select()
  115. ->toArray();
  116. }
  117. /**
  118. * 获取登录统计信息
  119. * @param int $merchantId 商户ID
  120. * @param int $userId 用户ID(可选)
  121. * @param string $startDate 开始日期
  122. * @param string $endDate 结束日期
  123. * @return array
  124. */
  125. public static function getLoginStatistics(int $merchantId, int $userId = 0, string $startDate = '', string $endDate = ''): array
  126. {
  127. $where = [
  128. ['merchant_id', '=', $merchantId]
  129. ];
  130. if ($userId > 0) {
  131. $where[] = ['user_id', '=', $userId];
  132. }
  133. if ($startDate) {
  134. $where[] = ['login_time', '>=', strtotime($startDate)];
  135. }
  136. if ($endDate) {
  137. $where[] = ['login_time', '<=', strtotime($endDate . ' 23:59:59')];
  138. }
  139. // 总登录次数
  140. $totalCount = self::where($where)->count();
  141. // 成功次数
  142. $successCount = self::where($where)
  143. ->where('login_status', self::STATUS_SUCCESS)
  144. ->count();
  145. // 失败次数
  146. $failedCount = self::where($where)
  147. ->where('login_status', self::STATUS_FAILED)
  148. ->count();
  149. // 独立IP数
  150. $uniqueIps = self::where($where)
  151. ->group('login_ip')
  152. ->count();
  153. return [
  154. 'total_count' => $totalCount,
  155. 'success_count' => $successCount,
  156. 'failed_count' => $failedCount,
  157. 'success_rate' => $totalCount > 0 ? round($successCount / $totalCount * 100, 2) : 0,
  158. 'unique_ips' => $uniqueIps
  159. ];
  160. }
  161. }