QuestionController.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller\Api\v1;
  4. use App\Controller\AbstractController;
  5. use App\Service\QueueService;
  6. use App\Utils\AppResult;
  7. use App\Utils\Control\AuthUser;
  8. use Hyperf\DbConnection\Db;
  9. //
  10. use App\Request\Api\v1\Question\SubmitRequest;
  11. use App\Request\Api\v1\Question\BindjigouRequest;
  12. use App\Master\Enum\RedisKeyEnum;
  13. use App\Utils\RedisUtil;
  14. use Hyperf\Di\Annotation\Inject;
  15. /**
  16. * 选手接口
  17. * PlayerController
  18. */
  19. class QuestionController extends AbstractController
  20. {
  21. // 日志模块名称
  22. const LOG_MODULE = 'v1/QuestionController';
  23. #[Inject]
  24. protected QueueService $service;
  25. //用户绑定机构
  26. public function bindjigou(BindjigouRequest $request){
  27. //验证活动开始时间,结束时间
  28. if( time() < strtotime(site('subject_starttime')) )
  29. {
  30. return AppResult::error('活动开始时间:'.site('subject_starttime'));
  31. }
  32. if( strtotime(site('subject_endtime')) < time() )
  33. {
  34. return AppResult::error('活动在'.site('subject_endtime').'就结束了');
  35. }
  36. $params = $request->validated();// 获取校验通过的参数
  37. $user = AuthUser::getInstance()->get();
  38. $jigou_id = $params['jigou_id'];
  39. $jigou_info = Db::table('vote_jigou')->where('id',$jigou_id)->first();
  40. if(!$jigou_info){
  41. return AppResult::error('不存在的单位');
  42. }
  43. $times = site('bind_jigou_times');
  44. if($user['bind_jigou_times'] >= $times){
  45. return AppResult::error('最多修改绑定单位'.$times.'次');
  46. }
  47. if($user['bind_jigou_id'] == $jigou_id){
  48. return AppResult::error('绑定单位没有改变');
  49. }
  50. $data = [
  51. 'bind_jigou_id' => $jigou_id,
  52. 'bind_jigou_times' => $user['bind_jigou_times'] + 1,
  53. ];
  54. $rs = Db::table('user')->where('id',$user['id'])->update($data);
  55. if(!$rs){
  56. return AppResult::error('修改绑定失败');
  57. }
  58. //曾经 答题贡献的分数,用户曾经都要给到新机构
  59. if(!empty($user['bind_jigou_id'])){
  60. $this->service->bindjigouPush(['user_id' => $user['id'], 'old_jigou_id' => $user['bind_jigou_id'], 'new_jigou_id' => $jigou_id], 0);
  61. }
  62. return AppResult::success('绑定成功');
  63. }
  64. /**
  65. * 答题
  66. */
  67. public function submit(SubmitRequest $request)
  68. {
  69. //验证活动开始时间,结束时间
  70. if( time() < strtotime(site('subject_starttime')) )
  71. {
  72. return AppResult::error('活动开始时间:'.site('subject_starttime'));
  73. }
  74. if( strtotime(site('subject_endtime')) < time() )
  75. {
  76. return AppResult::error('活动在'.site('subject_endtime').'就结束了');
  77. }
  78. $params = $request->validated();// 获取校验通过的参数
  79. $user = AuthUser::getInstance()->get();
  80. if (!RedisUtil::getInstance(RedisKeyEnum::API_REQUEST_TRAFFIC.':'.$user['id'])->tryTimes(1, 5)) {
  81. return AppResult::error('操作太快了,休息一下吧');
  82. }
  83. //上次绑定选手的时间不是今天
  84. if(empty($user['bind_jigou_id'])){
  85. return AppResult::response_fast(2,'先绑定单位再答题');//给不同的code,0报错,2跳到答题
  86. }
  87. //检查今日答题次数
  88. $exam_times_user_eday = site('exam_times_user_eday');
  89. $count = RedisUtil::getInstance(RedisKeyEnum::EAXM_TIMES.date('Y-m-d').':'.$user['id'])->get();
  90. if($count >= $exam_times_user_eday){
  91. return AppResult::error('今日答题次数用完了,明天再来吧');
  92. }
  93. //答题
  94. $user_questions = htmlspecialchars_decode($params['questions']);
  95. $user_questions = json_decode($user_questions,true);
  96. if (!$user_questions) {
  97. return AppResult::error('提交数据有误');
  98. }
  99. //避免超次数
  100. if(count($user_questions) + $count > $exam_times_user_eday){
  101. return AppResult::error('今日答题次数用完了,明天再来吧!');
  102. }
  103. $questions_ids = array_column($user_questions, 'id'); // 答题id
  104. $answers = array_column($user_questions, 'answer'); // 用户答案
  105. $is_right_number = 0;
  106. $log_data = [];
  107. $questions = Db::table('exam_question')->select(['id','kind','answer'])->whereIn('id',$questions_ids)->orderByRaw('FIELD(id, '. implode(',', $questions_ids) .')')->get();
  108. $questions = json_decode(json_encode($questions),true);
  109. foreach($questions as $key => $question){
  110. $is_right = $this->paperExam($question,$answers[$key]);
  111. if($is_right){
  112. $is_right_number ++;
  113. }
  114. $log_data[] = [
  115. 'user_id' => $user['id'],
  116. 'question_id' => $question['id'],
  117. 'is_right' => $is_right ? 1 : 0,
  118. 'score' => $is_right ? site('question_right_getscore') : 0,
  119. 'jigou_id' => $user['bind_jigou_id'],
  120. 'createtime' => time(),
  121. 'createdate' => strtotime(date('Y-m-d')),
  122. ];
  123. }
  124. //今日答题次数,自增一次
  125. $count = RedisUtil::getInstance(RedisKeyEnum::EAXM_TIMES.date('Y-m-d').':'.$user['id'])->incrby_expire(count($user_questions),86400);
  126. if($is_right_number > 0){
  127. //今日答对次数,自增一次
  128. RedisUtil::getInstance(RedisKeyEnum::EAXM_RIGHT.date('Y-m-d').':'.$user['id'])->incrby_expire($is_right_number,86400);
  129. }
  130. //答题日志
  131. $right_score = intval(bcmul((string)$is_right_number,(string)site('question_right_getscore'),0));//乘以基数,也就是答题获得的分数
  132. $this->service->questionPush(['log_data' => $log_data, 'is_right_number' => $right_score, 'bind_jigou_id' => $user['bind_jigou_id']], 0);
  133. //给机构加分
  134. //返回正确了几道题,剩余答题次数
  135. $right_vote = intval(bcmul((string)$is_right_number,(string)site('question_right_getvotenum'),0));//乘以基数,也就是答题获得的票数
  136. $question_vote = intval(bcmul((string)$exam_times_user_eday,(string)site('question_right_getvotenum'),0));//乘以基数,也就是答题获得的票数
  137. $result = [
  138. 'remark' => '答对'.$is_right_number.'题,获得'.$right_vote.'次投票次数,答题最多可获得'.$question_vote.'次投票机会',
  139. 'submit_number'=> count($user_questions),
  140. 'right_number' => $is_right_number,
  141. 'remain' => $exam_times_user_eday - $count,
  142. ];
  143. return AppResult::success('答题完毕',$result);
  144. }
  145. /**
  146. * 试题
  147. * @param $question_id
  148. * @param $answer
  149. * @return bool
  150. */
  151. private function paperExam($question,$answer)
  152. {
  153. $is_right = false;
  154. if(empty($question)){
  155. return false;
  156. }
  157. $question = json_decode(json_encode($question),true);
  158. switch ($question['kind']) {
  159. case 'JUDGE': // 判断题
  160. case 'SINGLE': // 单选题
  161. case 'MULTI': // 多选题
  162. // 答题正确
  163. if (strtoupper($answer) == $question['answer']) {
  164. $is_right = true;
  165. } else {
  166. $is_right = false;
  167. }
  168. break;
  169. case 'SHORT': // 简答题
  170. // 答案得分配置
  171. $answer_config = is_string($question['answer']) ? json_decode($question['answer'], true) : $question['answer'];
  172. $user_answers = $answer;
  173. foreach ($answer_config['config'] as $answer_item) {
  174. // 匹配答案关键词
  175. if (strpos($user_answers, $answer_item['answer']) !== false) {
  176. $is_right = true;
  177. break;
  178. }
  179. }
  180. break;
  181. }
  182. return $is_right;
  183. }
  184. }