exam = Dever::db('question/exam')->one($id); if (!$this->exam) { Dever::alert('规则不存在'); } $question = array(); if ($this->exam['type'] == 1) { # 首次抽取题目,题目保存在user表中,user表保存答题进度 $question = $this->getQuestion($this->exam['cate_id'], $this->exam['num']); } elseif ($this->exam['type'] == 3) { # 固定id得到题目,题目保存在user表中,user表保存答题进度 $question = $this->getQuestion($this->exam['cate_id'], 0, $this->exam['info_ids']); } $this->initUser($question); $result['exam'] = $this->exam; $result['user'] = $this->user; $yes = Dever::input('yes', 1); # 未完成,并且设置了yes==1,则立即开始答题 if ($yes == 1 && $this->user && $this->user['status'] < 3) { $result['question'] = $this->getQuestionInfo(); } $result['exam']['continue_num'] = $this->getOverContinueNum(); unset($result['exam']['level_ids']); return $result; } private function getOverContinueNum() { $continue = $this->getContinueNum(); if ($continue['id'] > 0) { $this->exam['continue_num'] = $this->exam['continue_num'] - $continue['num']; } return $this->exam['continue_num']; } /** * 获取用户信息接口 api.getUserInfo?uid=1 * * @return mixed */ public function getUserInfo() { $this->getUser(true); if ($this->user['uid'] > 0) { $info = Dever::db('question/ranking')->one(array('uid' => $this->user['uid'])); $this->user['ranking_score'] = $this->user['score']; if ($info) { $this->user['ranking_score'] = $info['score']; } $this->result(); $result['user'] = $this->user; $where['score'] = $this->user['score']; $result['total'] = Dever::db('question/ranking')->getTotal($where); } else { $this->user['ranking_score'] = $this->user['score']; $result['user'] = $this->user; $result['total'] = 0; } $result['exam'] = $this->exam; return $result; } /** * 排行榜接口 * * @return mixed */ public function ranking() { $uid = Dever::input('uid'); $this->redis(); $result = array(); if ($this->redis) { $ranking = $this->redis->zRevRange($this->rank, 0, 7, true); $rank = -1; $data = array(); if ($ranking) { $i = 0; foreach ($ranking as $k => $v) { if ($k) { $data[$i] = Dever::db('passport/user')->one($k); $data[$i]['score'] = $v; $data[$i]['rank'] = $i; # 这个用户是不是自己 $data[$i]['my'] = 2; if ($k == $uid) { $data[$i]['my'] = 1; $rank = $i; } $i++; } } } $result['list'] = $data; if ($uid) { if ($rank < 0) { # 获取当前用户的排名 $rank = $this->redis->zRevRank($this->rank, $uid); } $user = Dever::db('passport/user')->one($uid); $ranking = Dever::db('question/ranking')->one(array('option_uid' => $uid)); $user['score'] = $ranking['score']; $result['user'] = $user; $result['user']['rank'] = $rank; } } return $result; } /** * 定时更新所有排行榜数据接口 可以将这个放到cron中,定时执行 question/api.upRanking * * @return mixed */ public function upRanking() { $this->redis(); if ($this->redis) { $data = Dever::db('question/ranking')->state(); if ($data) { foreach ($data as $k => $v) { $this->redis->zAdd($this->rank, $v['score'], $v['uid']); } } } return true; } /** * 从某个活动中抽取题目并保存下来 * $category 分类id * $num 取多少题 * $ids 题目id * $index 当前是第几题 * $level_ids 难度数量 * * @return mixed */ private function getQuestion($category, $num, $ids = false, $index = 0, $level_ids = false) { $where = array(); $where['cate_id'] = $category; if ($ids) { $where['ids'] = $ids; } if ($level_ids) { $where['level_id'] = $this->getLevel($level_ids, $index); } $question_id = Dever::input('question_id'); $data = Dever::db('question/info')->getAll($where); if ($question_id > 0) { if (isset($data[$question_id])) { return array($data[$question_id]); } else { Dever::alert('错误的题目信息'); } } $result = array(); if ($data && $num) { $result = $this->getQuestionOne($question_id, $data, $num); } return $result; } private function getQuestionOne($question_id, $data, $num) { $one['user_id'] = $this->user['id']; $one['uid'] = Dever::input('uid'); if (!$question_id && $num == 1) { $answer = Dever::db('question/user_answer')->getAll($one); # 去除已经答过的题 if ($answer) { $data = array_diff_key($data, $answer); } } $count = count($data); if ($num > $count) { $num = $count; } $result = array(); $keys = array_rand($data, $num); if (is_array($keys)) { foreach ($keys as $k => $v) { $result[$v] = $data[$v]; } } else { $result[0] = $data[$keys]; } return $result; } /** * 获取等级id * * @return mixed */ private function getLevel($level_ids, $index) { # 如果有难度 比较自由的模式 1,3 换行 2,3 $level = explode("\r\n", $level_ids); $level_data = Dever::db('question/level')->all(); $index = $index + 1; $level_info = array(); $i = 1; foreach ($level as $v) { $v = explode(',', $v); $start = $i; $end = $v[1]; $i = $end + $i; $end = $start + $end - 1; if ($index >= $start && $index <= $end) { if (isset($level_data[$v[0]])) { $level_info = $level_data[$v[0]]; } break; } } /* 3,3,4形式,已废弃 $level = explode(',', $level_ids); $level_data = Dever::db('question/level')->getAll(); $index = $index + 1; $level_info = array(); $i = 1; foreach ($level as $k => $v) { $start = $i; $end = $v; $i = $end + $i; $end = $start + $end - 1; if ($index >= $start && $index <= $end) { if (isset($level_data[$k])) { $level_info = $level_data[$k]; } break; } } */ if (isset($level_info)) { return $level_info['id']; } else { Dever::alert('难度获取失败'); } } /** * 初始化用户信息 * * @return mixed */ private function initUser($question = array()) { if (!$this->exam) { Dever::alert('规则不存在'); } $uid = $this->getUid(); # 获取当前最新的一条已完成记录 if ($this->exam['continue'] == 1) { # 答错可以继续答题 则答完所有题才算完成 $where['where_status'] = 4; } elseif ($this->exam['continue'] >= 2) { # 答错不可以继续答题 则错误也算完成 $where['where_status'] = 3; } $where['where_uid'] = $uid; $where['where_exam_id'] = $this->exam['id']; # 获取已完成记录 $finish = Dever::db('question/user')->getFinish($where); if ($this->exam['continue'] == 3 && $finish && $finish['status'] == 3) { # 最新一次如果是错误的,则停止继续 $this->user = $finish; return; } # 获取正在进行中的记录 $this->user = Dever::db('question/user')->getUnFinish($where); $times = 1; if($finish) { if ($this->user && $finish['times'] >= $this->user['times']) { $update['where_id'] = $this->user['id']; $update['status'] = 3; Dever::db('question/user')->update($update); return $this->initUser($question); } $times = $finish['times'] + 1; } if (!$this->user) { $insert = array(); $insert['num'] = $this->exam['num']; if ($question) { $question = array_keys($question); $insert['num'] = count($question); $insert['info_ids'] = implode(',', $question); } $insert['uid'] = $uid; $insert['exam_id'] = $this->exam['id']; $insert['index'] = 0; $insert['score'] = 0; $insert['status'] = 1; # 检查答题次数 第一次 $insert['times'] = $times; $id = Dever::db('question/user')->insert($insert); $this->user = Dever::db('question/user')->one($id); } else { $id = $this->user['id']; } # 获取规则 $this->result(); } private function result() { if ($this->user['status'] >= 3) { $this->exam['content'] = Dever::array_decode($this->exam['content']); $this->exam['result'] = array(); foreach ($this->exam['content'] as $k => $v) { if (strstr($v['score'], '~')) { $temp = explode('~', $v['score']); if ($this->user['score'] >= $temp[0] && $this->user['score'] <= $temp[1]) { unset($v['score']); $this->exam['result'] = $v; break; } } else { if ($this->user['score'] == $v['score']) { unset($v['score']); $this->exam['result'] = $v; break; } } } if (isset($this->exam['result']['info']) && $this->exam['result']['info']) { $this->exam['result']['info_text'] = strip_tags($this->exam['result']['info']); } if (isset($this->exam['result']['pic']) && $this->exam['result']['pic']) { $this->exam['result']['pic_https'] = str_replace('http://' , 'https://', $this->exam['result']['pic']); } unset($this->exam['content']); } else { unset($this->exam['content']); } } /** * 获取用户id * * @return mixed */ private function getUid() { $id = Dever::input('uid'); if (!$id) { $save = new \Dever\Session\Oper(DEVER_PROJECT, 'cookie'); $id = $save->get('uid'); if (!$id) { $id = Dever::id(); $save->add('uid', $id); } } return $id; } /** * 获取题目接口:api.getInfo?user_data_id=1&uid=1 * * @return mixed */ public function getInfo() { $this->getUser(); return $this->getQuestionInfo(); } /** * 获取最新一条用户参与信息 * * @return mixed */ private function getUser($state = false) { $uid = $this->getUid(); //$id = Dever::input('user_data_id'); $this->user = Dever::db('question/user')->get(array('where_uid' => $uid)); if (!$this->user) { if ($state == false) { Dever::alert('错误的用户信息'); } else { $this->user['id'] = -1; $this->user['uid'] = -1; $this->user['score'] = 0; } } $this->exam = Dever::db('question/exam')->one($this->user['exam_id']); } /** * 获取题目 * * @return mixed */ private function getQuestionInfo() { if ($this->user && $this->exam) { # 验证是否答完 if ($this->user['status'] == 4) { Dever::alert('已经答完所有题目'); } # 验证是否答错 if ($this->exam['continue'] >= 2 && $this->user['status'] == 3) { Dever::alert('不能继续答题'); } # 进行中 Dever::db('question/user')->update(array('where_id' => $this->user['id'], 'status' => 2)); if ($this->exam['type'] == 1 && $this->user['info_ids']) { $question = explode(",", $this->user['info_ids']); } elseif ($this->exam['type'] == 2) { # 随机抽取 $data = $this->getQuestion($this->exam['cate_id'], 1, false, $this->user['index']); $question[$this->user['index']] = $data[0]; } elseif ($this->exam['type'] == 3 && $this->exam['info_ids']) { # 固定的 $question = explode("\r\n", $this->exam['info_ids']); } elseif ($this->exam['type'] == 4) { # 随机抽取并且按照难度抽取 $data = $this->getQuestion($this->exam['cate_id'], 1, false, $this->user['index'], $this->exam['level_ids']); $question[$this->user['index']] = $data[0]; } else { Dever::alert('错误的题目类型'); } } if (isset($question[$this->user['index']])) { $data = $question[$this->user['index']]; if (!is_array($data)) { $data = Dever::db('question/info')->one($data); } $data['index'] = $this->user['index']; $data['num'] = $this->user['num']; $data['content'] = Dever::array_decode($data['content']); if ($this->hidden == true) { foreach ($data['content'] as $k => $v) { unset($data['content'][$k]['score']); } } else { //$data['user_info_ids'] = $this->user['user_info_ids']; $data['score'] = $this->user['score']; $data['total'] = $this->exam['num']; } $data['user_data_id'] = $this->user['id']; return $data; } Dever::alert('错误的题目信息'); } /** * 开始答题接口: api.submit?question_id=1&option=0&uid=1 * 返回参数:status 2为进行中 3答题错误 4答题正确 * * @return mixed */ public function submit() { $this->getUser(); $question_id = Dever::input('question_id'); if (!$question_id) { Dever::alert('错误的题目信息'); } $option = Dever::input('option', 0); $one['user_id'] = $this->user['id']; $one['uid'] = Dever::input('uid'); $one['info_id'] = Dever::input('question_id'); $one = Dever::db('question/user_answer')->one($one); if ($one) { $update['status'] = $this->user['status']; } else { /* if ($this->exam['continue'] >= 2 && $this->exam['continue_times'] > 0) { $cur = time(); # 后端超时设置 $times = $this->exam['continue_times']; if ($cur - $this->user['cdate'] > $times) { # 超时 $option = -1; } } */ $this->hidden = false; $data = $this->getQuestionInfo(); if ($option == -1) { # 超时 $data['content'][$option] = array(); $data['content'][$option]['score'] = 0; $data['content'][$option]['title'] = '超时'; } if (!isset($data['content'][$option])) { Dever::alert('错误的选项信息'); } /* $update['user_info_ids'] = $data['user_info_ids']; if ($update['user_info_ids']) { $update['user_info_ids'] = explode(',', $update['user_info_ids']); $update['user_info_ids'][] = $data['id']; $update['user_info_ids'] = implode(',', $update['user_info_ids']); } else { $update['user_info_ids'] = $data['id']; } */ $update['score'] = $data['score'] + $data['content'][$option]['score']; $update['where_id'] = $data['user_data_id']; $update['status'] = 2; if ($this->exam['continue'] >= 2 && $data['content'][$option]['score'] == 0) { # 答题错误 进度不变 $update['status'] = 3; # 将当前分数同步到排行榜中去 $this->setRanking($update['score']); # 答题完成后,进度变化 if ($this->exam['continue_index'] == 2) { $update['index'] = $data['index'] + 1; } else { $update['index'] = $data['index']; } } else { $update['index'] = $data['index'] + 1; } if ($update['index'] >= $data['num'] && $update['status'] == 2) { # 答题完成 $update['status'] = 4; # 将当前分数同步到排行榜中去 $this->setRanking($update['score']); } Dever::db('question/user')->update($update); if ($update['index'] > $data['index']) { $insert['user_id'] = $data['user_data_id']; $insert['info_id'] = $data['id']; $insert['score'] = $data['content'][$option]['score']; $insert['option'] = $option; $insert['uid'] = $this->user['uid']; $insert['option_name'] = $data['content'][$option]['title']; Dever::db('question/user_answer')->insert($insert); } } $result = array(); $result['status'] = $update['status']; $result['question_id'] = $question_id; $result['option'] = $option; $result['continue_num'] = $this->getOverContinueNum(); return $result; } /** * 积分榜单 * * @return mixed */ private function setRanking($score) { $ranking = Dever::db('question/ranking')->one(array ( 'uid' => $this->user['uid'], 'exam_id' => $this->user['exam_id'], )); $state = false; if ($ranking) { if ($ranking['score'] < $score) { $state = true; $update['uid'] = $this->user['uid']; $update['exam_id'] = $this->user['exam_id']; $update['score'] = $score; $update['times'] = $this->user['times']; $update['where_id'] = $ranking['id']; Dever::db('question/ranking')->update($update); } } else { $state = true; $insert['uid'] = $this->user['uid']; $insert['exam_id'] = $this->user['exam_id']; $insert['score'] = $score; $insert['times'] = $this->user['times']; Dever::db('question/ranking')->insert($insert); } if ($state == true) { $this->redis(); if ($this->redis) { $this->redis->zAdd($this->rank, $score, $this->user['uid']); } } } /** * 复活接口 把当前的status状态值为2即可 * * @return mixed */ public function go_continue() { $this->getUser(); # 先验证当前的状态是否是3 if ($this->user['status'] == 3) { $this->checkContinue(); $update['where_id'] = $this->user['id']; if ($this->user['index'] >= $this->user['num']) { $update['status'] = 4; } else { $update['status'] = 2; } Dever::db('question/user')->update($update); } return true; } /** * 无限复活接口 慎用 * * @return mixed */ public function go_all_continue() { $this->getUser(); # 先验证当前的状态是否是3 if ($this->user['status'] == 3) { $update['where_id'] = $this->user['id']; if ($this->user['index'] >= $this->user['num']) { $update['status'] = 4; } else { $update['status'] = 2; } Dever::db('question/user')->update($update); } return true; } /** * 验证当前的复活次数够不够 * * @return mixed */ private function checkContinue() { $continue_num = $this->exam['continue_num']; if ($continue_num > 0) { $continue = $this->getContinueNum(); if ($continue['id'] > 0) { if ($continue['num'] < $continue_num) { #可以继续复活 $update['where_id'] = $continue['id']; $update['num'] = $continue['num'] + 1; Dever::db('question/continue')->update($update); } else { Dever::alert('无法复活'); } } else { $insert['exam_id'] = $this->user['exam_id']; $insert['uid'] = $this->user['uid']; $insert['user_id'] = $this->user['id']; $insert['num'] = 1; Dever::db('question/continue')->insert($insert); } } } private function getContinueNum() { $continue_num_user = $this->exam['continue_num_user']; $where['exam_id'] = $this->user['exam_id']; if ($continue_num_user == 1) { $where['uid'] = $this->user['uid']; } elseif ($continue_num_user == 2) { $where['user_id'] = $this->user['id']; } $continue = Dever::db('question/continue')->one($where); if ($continue) { $time = time(); $continue_num_type = $this->exam['continue_num_type']; $continue_num_type_times = $this->exam['continue_num_type_times']; # 查看时间间隔 if ($continue_num_type == 1) { # 按照自然天 $continue_num_type_times = 0; $date = Dever::maketime(date('Y-m-d 00:00:00', strtotime("+1 day", $continue['cdate']))); if ($time >= $date) { $continue['num'] = 0; } } elseif ($continue_num_type == 2) { # 按照小时 $continue_num_type_times = $continue_num_type_times * 3600; } elseif ($continue_num_type == 3) { # 按照天 $continue_num_type_times = $continue_num_type_times * 86400; } if ($continue_num_type_times > 0 && $time - $continue['cdate'] >= $continue_num_type_times) { $continue['num'] = 0; } } else { $continue['id'] = 0; $continue['num'] = 0; } return $continue; } /** * 重新挑战接口,重新开始,当前结束 * * @return mixed */ public function reset() { $this->getUser(); $update['where_id'] = $this->user['id']; $update['status'] = 4; Dever::db('question/user')->update($update); return true; } /** * 初始化redis * * @return mixed */ private function redis() { $this->redis = false; if ($this->redis) { return $this->redis; } $config = Dever::config('database')->redis; if ($config) { if (class_exists('\\Redis')) { $this->redis = new \Redis; $this->redis->connect($config['host'], $config['port']); } } return $this->redis; } }