123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- <?php
- namespace app\admin\service\train;
- use app\admin\model\train\QuestionModel;
- use app\admin\model\train\TrainAdmin;
- use app\admin\model\train\TrainExam;
- use app\admin\model\train\TrainExamReQuestion;
- use app\admin\model\train\TrainExamResult;
- use app\admin\model\train\TrainExamResultRecord;
- use think\Db;
- use think\exception\DbException;
- use think\Request;
- class TrainService
- {
- protected $exam = null;
- protected $examResult = null;
- protected $question = null;
- protected $result_arr = [
- 1 => 'A',
- 2 => 'B',
- 3 => 'C',
- 4 => 'D',
- 5 => 'E',
- 6 => 'F',
- ];
- protected $judge = [
- 1 => '对',
- 2 => '错',
- ];
- protected $type_arr = [
- 1 => '单选',
- 2 => '多选',
- 3 => '判断'
- ];
- protected static $instance;
- protected static $error_message = null;
- public function __construct()
- {
- $this->exam = model(TrainExam::class);
- $this->examResult = model(TrainExamResult::class);
- $this->question = model(QuestionModel::class);
- }
- /**
- * 初始化
- * @param array $options
- * @return object|static
- * @author matielong
- */
- public static function instance($options = [])
- {
- if (is_null(self::$instance)) {
- self::$instance = new static($options);
- }
- return self::$instance;
- }
- public function getError()
- {
- return self::$error_message;
- }
- protected function setError($msg)
- {
- self::$error_message = $msg;
- return false;
- }
- /**
- * 获取未完成的考试
- * @param $phone
- * @return bool|\think\Collection
- */
- public function getUndoneExam($phone)
- {
- try {
- $admin = $this->getAdminByPhone($phone);
- if(!$admin){
- return false;
- }
- $admin_id = $admin['id'];
- $data = $this->examResult->alias('result')
- ->join($this->exam->getTable().' exam', 'exam.id = exam_id')
- ->where('admin_id', $admin_id)
- ->where(function ($query){
- $query->where('result.status', 0)
- ->whereOr('result.status', 1);
- })
- ->field('result.id as result_id, exam_id, title, duration, exam.start_time, end_time, remark, result.status as result_status, result.start_time as result_start_time')
- ->select();
- foreach ($data as &$val){
- $val['residue_time'] = '';
- if($val['result_status'] === 1){
- $val['residue_time'] = date('H:i:s', ($val['duration'] * 60) - time());
- }
- }
- unset($val);
- return $data;
- } catch (DbException $exception){
- return false;
- }
- }
- /**
- * 获取及格/不集合的考试
- * @param $phone
- * @param false $unqualified
- * @return array|false
- */
- public function getQualifiedExam($phone, $unqualified = false)
- {
- try {
- $admin = $this->getAdminByPhone($phone);
- if(!$admin){
- return false;
- }
- $admin_id = $admin['id'];
- $where = [
- 'admin_id' => $admin_id,
- 'result.status' => 2,
- ];
- $data = $this->examResult->alias('result')
- ->join($this->exam->getTable().' exam', 'exam.id = exam_id')
- ->where($where)
- ->field('result.id as result_id, exam_id, title, scores, result.start_time, submit_time, total, is_qualified, 0 as newest')
- ->order('result.id','desc')
- ->select();
- $is_qualified = $unqualified === true ? 0 :1;
- $result = [];
- if($data){
- $data[0]['newest'] = 1;
- foreach ($data as $val){
- if($val['is_qualified'] === $is_qualified){
- $temp = $val;
- // 时长
- $temp['duration'] = '';
- if($temp['start_time'] && $temp['submit_time']){
- $temp['duration'] = date('H:i:s', strtotime($temp['submit_time']) - strtotime($temp['start_time']));
- }
- $result[] = $temp;
- }
- }
- }
- return $result;
- } catch (DbException $exception){
- return false;
- }
- }
- /**
- * 获取缺考的考试
- * @param $phone
- * @return bool|\think\Collection
- */
- public function getMissedExam($phone)
- {
- try {
- $admin = $this->getAdminByPhone($phone);
- if(!$admin){
- return false;
- }
- $admin_id = $admin['id'];
- $now = date('Y-m-d H:i:s', Request::instance()->time());
- return $this->examResult->alias('result')
- ->join($this->exam->getTable().' exam', 'exam.id = exam_id')
- ->where('admin_id', $admin_id)
- ->where(function ($query){
- $query->where('result.status', 0)
- ->whereOr('result.status', 1);
- })
- ->where('exam.end_time','<', $now)
- ->field('exam_id, title, scores, exam.start_time, exam.end_time, total')
- ->order('result.id','desc')
- ->select();
- } catch (DbException $exception){
- return false;
- }
- }
- /**
- * 获取考试的考题
- * @param $exam_id
- * @return array
- */
- public function getExamQuestions($exam_id)
- {
- $question_ids = model(TrainExamReQuestion::class)
- ->where('exam_id', $exam_id)
- ->column('question_id');
- $data = $this->question
- ->whereIn('id', $question_ids)
- ->field('class_id, result, is_del, created_at', true)
- ->order('type')
- ->select();
- $result = [];
- foreach ($data as $val){
- $temp = [
- "id" => $val['id'],
- "title" => $val['title'],
- "type" => $val['type'],
- "answer" => []
- ];
- if($val['answer1']){
- $temp['answer'][] = ['key' => 1, 'title' => $val['answer1'], 'checked' => 0];
- }
- if($val['answer2']){
- $temp['answer'][] = ['key' => 2, 'title' => $val['answer2'], 'checked' => 0];
- }
- if($val['answer3']){
- $temp['answer'][] = ['key' => 3, 'title' => $val['answer3'], 'checked' => 0];
- }
- if($val['answer4']){
- $temp['answer'][] = ['key' => 4, 'title' => $val['answer4'], 'checked' => 0];
- }
- if($val['answer5']){
- $temp['answer'][] = ['key' => 5, 'title' => $val['answer5'], 'checked' => 0];
- }
- if($val['answer6']){
- $temp['answer'][] = ['key' => 6, 'title' => $val['answer6'], 'checked' => 0];
- }
- $result[] = $temp;
- }
- return $result;
- }
- public function getExam($exam_id)
- {
- return $this->exam->get(['id' => $exam_id]);
- }
- public function getResult($result_id)
- {
- return $this->examResult->get($result_id);
- }
- /**
- * 获取最新未开始的考试
- * @param $phone
- * @param $exam_id
- * @return array|bool
- */
- public function getNestExamResult($phone, $exam_id)
- {
- $admin = $this->getAdminByPhone($phone);
- if(!$admin){
- return false;
- }
- $admin_id = $admin['id'];
- return model(TrainExamResult::class)
- ->where('admin_id', $admin_id)
- ->where('exam_id', $exam_id)
- ->where('status', 0)
- ->order('id','desc')
- ->find();
- }
- /**
- * 开始考试
- * @param $result_id
- * @return bool
- */
- public function startExam($result_id)
- {
- $res = model(TrainExamResult::class)
- ->where('id', $result_id)
- ->update([
- 'status' => 1,
- 'start_time' => date('Y-m-d H:i:s')
- ]);
- if(!$res){
- return false;
- }
- return true;
- }
- /**
- * 重考
- * @param $result_id
- * @return array|false
- */
- public function retakeExam($result_id)
- {
- $result = $this->getResult($result_id);
- $number = model(TrainExamResult::class)
- ->where('exam_id', $result['exam_id'])
- ->where('admin_id', $result['admin_id'])
- ->max('number') + 1;
- $res = model(TrainExamResult::class)
- ->insertGetId([
- 'exam_id' => $result['exam_id'],
- 'admin_id' => $result['admin_id'],
- 'number' => $number,
- 'status' => 1,
- 'start_time' => date('Y-m-d H:i:s')
- ]);
- return $res !== false ? ['result_id' => $res] : false;
- }
- /**
- * 获取考题column
- * @param $question_ids
- * @return array|false|string
- */
- public function getQuestionColumn($question_ids)
- {
- return $this->question
- ->whereIn('id', $question_ids)
- ->column('id, type, result');
- }
- /**
- * 提交考试
- * @param $result_id
- * @param $record
- * @return array
- */
- public function subExam($result_id, $record)
- {
- // 创建答题记录
- Db::startTrans();
- $record_save_res = $this->insertResultRecord($result_id, $record);
- if(!$record_save_res){
- Db::rollback();
- $this->setError('插入答题记录失败');
- }
- // 更新考卷数据
- $result = $this->getResult($result_id);
- $total = $this->calculateScore($result['exam_id'], $result_id);
- $exam = $this->getExam($result['exam_id']);
- $is_qualified = $total >= $exam['qualified'] ? 1 : 0;
- $update_res = $this->examResult
- ->where('id', $result_id)
- ->update([
- 'scores' => $total,
- 'status' => 2,
- 'is_qualified' => $is_qualified,
- 'submit_time' => date('Y-m-d H:i:s', Request::instance()->time())
- ]);
- if(!$update_res){
- Db::rollback();
- $this->setError('更新考卷数据失败 ');
- }
- // ok
- Db::commit();
- return [
- 'scores' => $total,
- 'qualified' => $is_qualified,
- ];
- }
- /**
- * 插入答题记录
- * @param $result_id
- * @param $records
- * @return bool
- */
- public function insertResultRecord($result_id, $records)
- {
- $question_ids = array_column($records, 'question_id');
- $question_arr = $this->getQuestionColumn($question_ids);
- $save = [];
- foreach ($records as $record){
- if(!$record){
- continue;
- }
- $question_id = $record['question_id'];
- if(!isset($question_arr[$question_id])){
- continue;
- }
- // 格式化答案
- $right_res = $question_arr[$question_id]['result'];
- $checked_arr = [];
- foreach ($record['answer'] as $answer){
- if((int) $answer['checked'] === 1){
- $checked_arr[] = (int) $answer['key'];
- }
- }
- // 判断对错
- $question_answer = implode('', $checked_arr);
- $result = $this->checkQuestionResult($question_answer, $right_res) ? 1 : 0;
- // 组装数据
- $save[] = [
- 'result_id' => $result_id,
- 'question_id' => $question_id,
- 'answer' => $question_answer,
- 'result' => $result,
- ];
- }
- $res = model(TrainExamResultRecord::class)
- ->insertAll($save);
- return $res !== false;
- }
- /**
- * 检查题目是否正确
- * @param $answer
- * @param $right_result
- * @return bool
- */
- public function checkQuestionResult($answer, $right_result)
- {
- $answer_arr = $this->ch2arr((int) $answer);
- $right_arr = $this->ch2arr((int) $right_result);
- if(array_diff($answer_arr, $right_arr)){
- return false;
- }
- return true;
- }
- /**
- * 计算得分
- * @param $exam_id
- * @param $result_id
- * @return float|int|string
- */
- public function calculateScore($exam_id, $result_id)
- {
- $right_question_ids = model(TrainExamResultRecord::class)
- ->where('result_id', $result_id)
- ->where('result', 1)
- ->column('question_id');
- return model(TrainExamReQuestion::class)
- ->where('exam_id', $exam_id)
- ->whereIn('question_id', $right_question_ids)
- ->sum('score');
- }
- /**
- * 字符串分割数组
- * @param $str
- * @return array
- */
- public function ch2arr($str)
- {
- $length = mb_strlen($str, 'utf-8');
- $array = [];
- for ($i = 0; $i < $length; $i++)
- $array[] = mb_substr($str, $i, 1, 'utf-8');
- return $array;
- }
- /**
- * 获取考试结果根据用户id
- * @param $exam_id
- * @param $admin_ids
- * @return array
- */
- public function getResultByAdminIds($exam_id, $admin_ids)
- {
- $data = model(TrainExamResult::class)
- ->where('exam_id', $exam_id)
- ->whereIn('admin_id', $admin_ids)
- ->field('id, admin_id, number, status, is_qualified, scores')
- ->order('id','desc')
- ->select();
- $result = [];
- foreach ($data as $val){
- if(!isset($result[$val['admin_id']])){
- $result[$val['admin_id']] = [
- 'result_id' => $val['id'],
- 'status' => $val['status'],
- 'scores' => $val['scores'],
- 'is_qualified' => $val['is_qualified']
- ];
- }
- }
- return $result;
- }
- /**
- * 获取考试剩余时间
- * @param $result_id
- * @return false|float|int
- */
- public function getRemainingTime($result_id)
- {
- $result = $this->getResult($result_id);
- $exam = $this->getExam($result['exam_id']);
- return strtotime($result['start_time']) + ($exam['duration'] * 60) - Request::instance()->time();
- }
- public function formatResult($result, $type)
- {
- switch ($type){
- case 1:
- case 2:
- $str = (string) $result;
- $iMax = strlen($str);
- $temp = [];
- for($i=0; $i< $iMax; $i++){//遍历字符串追加给数组
- $temp[] = $this->result_arr[$str[$i]];
- }
- return implode($temp);
- case 3:
- return $this->judge[$result] ?? $result;
- default;
- }
- }
- public function formatType($type){
- return $this->type_arr[$type] ?? $type;
- }
- public function getAdminByPhone($phone)
- {
- return model(TrainAdmin::class)
- ->where('mobile', $phone)
- ->find();
- }
- }
|