AnswerRanksService.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2017~2021 LARAVEL研发中心
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://www.laravel.cn
  8. // +----------------------------------------------------------------------
  9. // | Author: laravel开发员 <laravel.qq.com>
  10. // +----------------------------------------------------------------------
  11. namespace App\Services\Common;
  12. use App\Models\UserModel;
  13. use App\Models\ActionLogModel;
  14. use App\Services\BaseService;
  15. use App\Services\ConfigService;
  16. use Illuminate\Support\Facades\DB;
  17. /**
  18. * 用户管理-服务类
  19. * @author laravel开发员
  20. * @since 2020/11/11
  21. * Class UserService
  22. * @package App\Services\Common
  23. */
  24. class AnswerRanksService extends BaseService
  25. {
  26. /**
  27. * 构造函数
  28. * @author laravel开发员
  29. * @since 2020/11/11
  30. * UserService constructor.
  31. */
  32. public function __construct()
  33. {
  34. }
  35. /**
  36. * 静态入口
  37. */
  38. public static function make()
  39. {
  40. if (!self::$instance) {
  41. self::$instance = new static();
  42. }
  43. return self::$instance;
  44. }
  45. public function getAnswerRanks(array $params)
  46. {
  47. $page = max(1, (int) ($params['page'] ?? 1));
  48. $limit = min(100, max(1, (int) ($params['limit'] ?? 20))); // 限制最大100条
  49. // 时间筛选(可选)
  50. $startTimestamp = !empty($params['start_time']) ? strtotime($params['start_time']) : null;
  51. $endTimestamp = !empty($params['end_time']) ? strtotime($params['end_time']) : null;
  52. // 按用户分组查询答题排行榜
  53. $query = DB::table('member_answer_ranks')
  54. ->leftJoin('member', 'member_answer_ranks.user_id', '=', 'member.id')
  55. ->selectRaw("
  56. lev_member_answer_ranks.user_id,
  57. lev_member.nickname,
  58. lev_member.mobile,
  59. lev_member.avatar,
  60. lev_member.realname,
  61. lev_member.create_time as register_time,
  62. SUM(lev_member_answer_ranks.answer_count) as total_count,
  63. SUM(lev_member_answer_ranks.answer_time) as total_time,
  64. COUNT(lev_member_answer_ranks.id) as answer_days,
  65. AVG(lev_member_answer_ranks.answer_count) as avg_daily_count,
  66. MAX(lev_member_answer_ranks.create_time) as last_answer_time
  67. ")
  68. ->where('member_answer_ranks.status', 1)
  69. ->where('member_answer_ranks.mark', 1);
  70. // ->whereNotNull('member_answer_ranks.user_id')
  71. // ->where('member.status', 1)
  72. // ->where('member.mark', 1);
  73. // 时间筛选
  74. if ($startTimestamp && $endTimestamp) {
  75. $query->whereBetween('member_answer_ranks.create_time', [$startTimestamp, $endTimestamp]);
  76. }
  77. $query->groupBy('member_answer_ranks.user_id', 'member.nickname', 'member.mobile', 'member.avatar', 'member.realname', 'member.create_time')
  78. ->orderBy('total_count', 'desc')
  79. ->orderBy('total_time', 'asc'); // 答题数量相同时,用时少的排前面
  80. // // 打印 SQL 查询语句用于调试
  81. // $sql = $query->toSql();
  82. // $bindings = $query->getBindings();
  83. // $fullSql = vsprintf(str_replace('?', '%s', $sql), $bindings);
  84. // dd([
  85. // 'sql' => $sql,
  86. // 'bindings' => $bindings,
  87. // 'full_sql' => $fullSql,
  88. // 'base_count' => DB::table('member_answer_ranks')->where('status', 1)->where('mark', 1)->whereNotNull('user_id')->count(),
  89. // 'member_count' => DB::table('member')->where('status', 1)->where('mark', 1)->count()
  90. // ]);
  91. // 总条数
  92. $total = DB::table(DB::raw("({$query->toSql()}) as t"))
  93. ->mergeBindings($query)
  94. ->count();
  95. // 分页查询,限制前100名
  96. $list = $query->forPage($page, $limit)->get();
  97. // 打印查询结果
  98. \Log::info('Query Results:', [
  99. 'total' => $total,
  100. 'list_count' => count($list),
  101. 'first_item' => $list->first()
  102. ]);
  103. // 添加排名和格式化数据
  104. $rank = ($page - 1) * $limit + 1;
  105. foreach ($list as $item) {
  106. $item->rank = $rank++;
  107. // 处理头像URL
  108. if ($item->avatar) {
  109. $item->avatar = get_image_url($item->avatar);
  110. } else {
  111. $item->avatar = '/static/images/default-avatar.png';
  112. }
  113. // 格式化注册时间
  114. $item->register_time_text = date('Y-m-d', $item->register_time);
  115. // 格式化最后答题时间
  116. $item->last_answer_time_text = date('Y-m-d H:i', $item->last_answer_time);
  117. // 计算平均每日答题数(保留1位小数)
  118. $item->avg_daily_count = round($item->avg_daily_count, 1);
  119. // 计算答题效率(题/分钟)
  120. if ($item->total_time > 0) {
  121. $item->efficiency = round(($item->total_count * 60) / $item->total_time, 2);
  122. } else {
  123. $item->efficiency = 0;
  124. }
  125. }
  126. return [
  127. 'list' => $list,
  128. 'total' => $total,
  129. 'page' => $page,
  130. 'limit' => $limit,
  131. ];
  132. }
  133. /**
  134. * 删除七天之前标记软删除的数据
  135. */
  136. public function delete()
  137. {
  138. // 设置日志标题
  139. ActionLogModel::setRecord(session('userId'), ['type' => 1, 'title' => "删除答题排行信息", 'content' => json_encode(request()->post(), 256), 'module' => 'admin']);
  140. ActionLogModel::record();
  141. $this->model->where('mark', 0)->where('update_time', '<=', time() - 7 * 86400)->delete();
  142. return parent::delete();
  143. }
  144. }