QuestionService.php.bak 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: hanl
  5. * Date: 2018/6/8
  6. * Time: 10:13
  7. */
  8. namespace App\Services;
  9. use DB;
  10. use Excel;
  11. use App\Common\Api;
  12. use App\Models\Questions;
  13. use App\Models\Categorys;
  14. use App\Models\Configs;
  15. use Illuminate\Support\Facades\Redis;
  16. class QuestionService
  17. {
  18. public function __construct($configs = [])
  19. {
  20. }
  21. const QUESTION_UPLOAD_FAIL = 'bsb_question_upload_fail:';
  22. /**
  23. * 获取题库详情
  24. * @param $activity_id
  25. * @param $corp_id
  26. * @param $category_id
  27. * @return array|mixed
  28. */
  29. public static function getCategoryInfo($activity_id, $category_id){
  30. $res = Categorys::where('activity_id', $activity_id)->where('category_id', $category_id)->first();
  31. if($res){
  32. $res = collect($res)->toArray();
  33. $res = Api::dateFormat($res);
  34. }
  35. return $res;
  36. }
  37. /**
  38. * 添加题库
  39. * @param $params
  40. * @return array
  41. */
  42. public static function saveCategory($params){
  43. $act_info = ActivityService::getActivityInfo($params['activity_id'], $params['corp_id']);
  44. if(!$act_info){
  45. return Api::arr(config('code.activity_not_exist'), trans('msg.activity_not_exist'));
  46. }
  47. $query = [];
  48. $query['category_name'] = $params['category_name'];
  49. $query['update_time'] = time();
  50. if(!empty($params['category_id']) && isset($params['category_id'])){
  51. $res = Categorys::where('activity_id', $params['activity_id'])->where('corp_id', $params['corp_id'])->where('category_id', $params['category_id'])->update($query);
  52. $category_id = $params['category_id'];
  53. } else {
  54. $query['corp_id'] = $params['corp_id'];
  55. $query['activity_id'] = $params['activity_id'];
  56. $query['create_time'] = time();
  57. $res = Categorys::insertGetId($query);
  58. $category_id = $res;
  59. }
  60. if($res){
  61. $data['category_id'] = $category_id;
  62. return Api::arr(config('code.success'), trans('msg.success'), $data);
  63. } else {
  64. return Api::arr(config('code.sql_error'), trans('msg.sql_error'));
  65. }
  66. }
  67. /**
  68. * 获取题库列表
  69. * @param $params
  70. * @return array
  71. */
  72. public static function getCategoryList($params){
  73. $act_info = ActivityService::getActivityInfo($params['activity_id'], $params['corp_id']);
  74. if(!$act_info){
  75. return Api::arr(config('code.activity_not_exist'), trans('msg.activity_not_exist'));
  76. }
  77. $categorys = Categorys::where('corp_id', $params['corp_id'])->where('activity_id', $params['activity_id'])->get()->toArray();
  78. foreach ($categorys as $k=>$v) {
  79. $question_num = Questions::where('category_id', $v['category_id'])
  80. ->where('corp_id', $params['corp_id'])
  81. ->where('activity_id', $params['activity_id'])
  82. ->where('status', 1) //题目状态 0 无效 1有效
  83. ->count();
  84. $v['questionNum'] = $question_num?$question_num:0;
  85. //时间格式化
  86. $categorys[$k] = Api::dateFormat($v);
  87. }
  88. return Api::arr(config('code.success'), trans('msg.success'), $categorys);
  89. }
  90. /**
  91. * 计算多个题库内的题目总数
  92. */
  93. public static function getQuestionsCount($categorys, $corp_id, $activity_id){
  94. $category = explode(',', $categorys);
  95. $count = 0;
  96. foreach($category as $k=>$v){
  97. $category_count = Questions::where('corp_id', $corp_id)->where('activity_id', $activity_id)->where('category_id', $v)->count();
  98. $count += $category_count;
  99. }
  100. return $count;
  101. }
  102. /**
  103. * 答题设置
  104. * @param $params
  105. * @return array
  106. */
  107. public static function questionConfigDetail($params){
  108. //闯关、必答、PK 题库不能为空 必选项
  109. if(empty($params['must_category_ids']) || empty($params['blockade_category_ids']) || empty($params['pk_category_ids'])){
  110. return Api::arr(config('code.params_error'), trans('msg.category_ids_null'));
  111. }
  112. $must_category_ids = $params['must_category_ids'];
  113. $blockade_category_ids = $params['blockade_category_ids'];
  114. $pk_category_ids = $params['pk_category_ids'];
  115. //计算选中的题库内题目总数
  116. $must_count = self::getQuestionsCount($must_category_ids, $params['corp_id'], $params['activity_id']);
  117. $blockade_count = self::getQuestionsCount($blockade_category_ids, $params['corp_id'], $params['activity_id']);
  118. $pk_count = self::getQuestionsCount($pk_category_ids, $params['corp_id'], $params['activity_id']);
  119. //题目数不能大于选中的题库内题目的总数
  120. if ($must_count < $params['must_question_num'] || $blockade_count < $params['blockade_question_num'] || $pk_count < $params['pk_question_num']) {
  121. return Api::arr(config('code.params_error'), trans('msg.num_greater_category'));
  122. }
  123. //允许答错的题目数不能大于总题目数
  124. if ($params['must_answer_wrong_num'] > $params['must_question_num'] || $params['blockade_answer_wrong_num'] > $params['blockade_question_num']) {
  125. return Api::arr(config('code.params_error'), trans('msg.wrong_greater_num'));
  126. }
  127. //获取配置项信息
  128. $config_info = Configs::where('corp_id', $params['corp_id'])->where('activity_id', $params['activity_id'])->first();
  129. if(!$config_info){
  130. return Api::arr(config('code.activity_not_exist'), trans('msg.activity_not_exist'));
  131. }
  132. //配置项入库
  133. $config_info = collect($config_info)->toArray();
  134. $extend_configs = json_decode($config_info['extend_configs'], true);
  135. $extend_configs['must_question_num'] = $params['must_question_num'];
  136. $extend_configs['must_answer_wrong_num'] = $params['must_answer_wrong_num'];
  137. $extend_configs['must_answer_success_km'] = $params['must_answer_success_km'];
  138. $extend_configs['blockade_question_num'] = $params['blockade_question_num'];
  139. $extend_configs['blockade_answer_wrong_num'] = $params['blockade_answer_wrong_num'];
  140. $extend_configs['blockade_answer_success_km'] = $params['blockade_answer_success_km'];
  141. $extend_configs['pk_question_num'] = $params['pk_question_num'];
  142. $extend_configs['pk_last_double'] = $params['pk_last_double'];
  143. $extend_configs['pk_kms'] = $params['pk_kms'];
  144. $extend_configs['must_category_ids'] = $must_category_ids;
  145. $extend_configs['blockade_category_ids'] = $blockade_category_ids;
  146. $extend_configs['pk_category_ids'] = $pk_category_ids;
  147. $extend_configs['top_prize_open'] = $params['top_prize_open'];
  148. $extend_configs['top_prize_text'] = $params['top_prize_text'];
  149. $extend_configs['top_prize_num'] = $params['top_prize_num'];
  150. $extend_configs['must_answer_count_down'] = isset($params['must_answer_count_down']) && $params['must_answer_count_down']>=5?$params['must_answer_count_down']:10;
  151. $extend_configs['blockade_answer_count_down'] = isset($params['blockade_answer_count_down']) && $params['blockade_answer_count_down']>=5?$params['blockade_answer_count_down']:10;
  152. $extend_configs = json_encode($extend_configs);
  153. $res_config = Configs::where('corp_id', $params['corp_id'])->where('activity_id', $params['activity_id'])->update(['extend_configs' => $extend_configs, 'update_time' => time()]);
  154. return Api::arr(config('code.success'), trans('msg.success'));
  155. }
  156. /**
  157. * 修改/新增题目
  158. * @param $params
  159. * @return array
  160. */
  161. public static function questionModify($params){
  162. $query = [];
  163. $question_options= [];
  164. $answers = [];
  165. if(!empty($params['option_a'])){
  166. $question_options['A'] = Api::trimAll($params['option_a']);
  167. $answers[] = 'A';
  168. }
  169. if(!empty($params['option_b'])){
  170. $question_options['B'] = Api::trimAll($params['option_b']);
  171. $answers[] = 'B';
  172. }
  173. if(!empty($params['option_c'])){
  174. $question_options['C'] = Api::trimAll($params['option_c']);
  175. $answers[] = 'C';
  176. }
  177. if(!empty($params['option_d'])){
  178. $question_options['D'] = Api::trimAll($params['option_d']);
  179. $answers[] = 'D';
  180. }
  181. //题目和答案不可为空
  182. if(empty(Api::trimAll($params['question_title'])) || empty($params['correct_answer'])){
  183. return Api::arr(config('code.params_error'), trans('msg.title_answer_null'));
  184. }
  185. //选项最少需要两个 答案必须在已有选项当中
  186. if(count($question_options)<2 || !in_array(strtoupper($params['correct_answer']), $answers)){
  187. return Api::arr(config('code.params_error'), trans('msg.option_error'));
  188. }
  189. //参数组装
  190. $query['question_title'] = Api::trimAll($params['question_title']);
  191. $query['question_options'] = serialize($question_options);
  192. $query['correct_answer'] = strtoupper($params['correct_answer']);
  193. $query['category_id'] = intval($params['category_id']);
  194. $query['update_time'] = time();
  195. //题目ID存在则修改题目,不存在则新增题目
  196. if(isset($params['question_id']) && $params['question_id'] != 0){
  197. $question = Questions::where('activity_id', $params['activity_id'])->where('corp_id', $params['corp_id'])->where('question_id', $params['question_id'])->first();
  198. if(!$question){
  199. return Api::arr(config('code.question_not_exist'), trans('msg.question_not_exist'));
  200. }
  201. $res = Questions::where('activity_id', $params['activity_id'])->where('corp_id', $params['corp_id'])->where('question_id', $params['question_id'])->update($query);
  202. if(!$res){
  203. return Api::arr(config('code.sql_error'), trans('msg.sql_error'));
  204. }
  205. } else {
  206. $query['corp_id'] = $params['corp_id'];
  207. $query['activity_id'] = $params['activity_id'];
  208. $query['create_time'] = time();
  209. $res = Questions::insert($query);
  210. if(!$res){
  211. return Api::arr(config('code.sql_error'), trans('msg.sql_error'));
  212. }
  213. }
  214. return Api::arr(config('code.success'), trans('msg.success'));
  215. }
  216. /**
  217. * 获取题库内题目数量
  218. * @param $corp_id
  219. * @param $activity_id
  220. * @return array
  221. */
  222. public static function getCategoryCount($corp_id, $activity_id){
  223. $categorys = Categorys::where('activity_id', $activity_id)->where('corp_id', $corp_id)->get()->toArray();
  224. $data = [];
  225. if($categorys) {
  226. foreach ($categorys as $category) {
  227. $data[$category['category_name']] = Questions::where('activity_id', $activity_id)->where('corp_id', $corp_id)->where('category_id', $category['category_id'])->count();
  228. }
  229. }
  230. return $data;
  231. }
  232. /**
  233. * 新增题库及题目上传
  234. * @param $data
  235. * @param $params
  236. * @return array|string
  237. */
  238. public static function questionUpload($data, $params){
  239. if(empty($data)){
  240. return Api::arr(config('code.fail'), trans('msg.question_not_exist'));
  241. }
  242. //添加题库
  243. $categoryRes = self::saveCategory($params);
  244. if($categoryRes['code'] != config('code.success')){
  245. return Api::arr(config('code.fail'), trans('msg.category_add_fail'));
  246. }
  247. $category_id = $categoryRes['data']['category_id'];
  248. DB::beginTransaction();
  249. $errors = [];
  250. $error_num = 0;
  251. foreach ($data as $k => $v) {
  252. $question_options = array();
  253. $question_title = $v[0];
  254. $answers = array();
  255. if(!empty($v[1]) || $v[1] == '0'){
  256. $question_options['A'] = $v[1];
  257. $answers[] = 'A';
  258. }
  259. if(!empty($v[2]) || $v[2] == '0'){
  260. $question_options['B'] = $v[2];
  261. $answers[] = 'B';
  262. }
  263. if(!empty($v[3]) || $v[3] == '0'){
  264. $question_options['C'] = $v[3];
  265. $answers[] = 'C';
  266. }
  267. if(!empty($v[4]) || $v[4] == '0'){
  268. $question_options['D'] = $v[4];
  269. $answers[] = 'D';
  270. }
  271. $correct_answer = $v[5];
  272. $query = array();
  273. $query['corp_id'] = $params['corp_id'];
  274. $query['activity_id'] = $params['activity_id'];
  275. $query['category_id'] = $category_id;
  276. $query['question_title'] = $question_title;
  277. $query['correct_answer'] = strtoupper($correct_answer);
  278. //答案单选 答案不能为空 题目不能为空 选项最少两个 答案不在选项中 都视为错误题目
  279. if(strlen($query['correct_answer']) > 1){
  280. $v[6] = '答案多选';
  281. $errors[] = $v;
  282. $error_num += 1;
  283. continue;
  284. }
  285. if(empty($query['correct_answer'])){
  286. $v[6] = '答案为空';
  287. $errors[] = $v;
  288. $error_num += 1;
  289. continue;
  290. }
  291. if(empty($query['question_title'])){
  292. $v[6] = '题目为空';
  293. $errors[] = $v;
  294. $error_num += 1;
  295. continue;
  296. }
  297. if(count($answers) < 2){
  298. $v[6] = '选项少于2个';
  299. $errors[] = $v;
  300. $error_num += 1;
  301. continue;
  302. }
  303. if(!in_array($query['correct_answer'], $answers)){
  304. $v[6] = '答案不在选项中';
  305. $errors[] = $v;
  306. $error_num += 1;
  307. continue;
  308. }
  309. $query['question_options'] = serialize($question_options); //序列化
  310. $query['create_time'] = time();
  311. $query['update_time'] = time();
  312. $res = Questions::insert($query);
  313. if (!$res) {
  314. DB::rollBack();
  315. return Api::arr(config('code.sql_error'), trans('msg.sql_error'));
  316. }
  317. }
  318. DB::commit();
  319. //错误记录存入redis
  320. Redis::set(self::QUESTION_UPLOAD_FAIL.$params['activity_id'], json_encode($errors),'EX',3600);
  321. $res = [];
  322. $res['total'] = count($data);
  323. $res['error_num'] = $error_num;
  324. $res['success_num'] = $res['total'] - $error_num;
  325. $res['category_id'] = $category_id;
  326. return Api::arr(config('code.success'), trans('msg.success'), $res);
  327. }
  328. /**
  329. * 删除题目
  330. * 2018-06-22 10:32:00
  331. * @param $params
  332. * @return array
  333. */
  334. public static function delQuestion($params){
  335. //题目信息
  336. $questionInfo = Questions::where('activity_id', $params['activity_id'])
  337. ->where('corp_id', $params['corp_id'])
  338. ->where('category_id', $params['category_id'])
  339. ->where('question_id', $params['question_id'])
  340. ->where('status', 1)
  341. ->first();
  342. if(!$questionInfo){
  343. return Api::arr(config('code.question_not_exist'), trans('msg.question_not_exist'));
  344. }
  345. //删除题目
  346. $res = Questions::where('activity_id', $params['activity_id'])
  347. ->where('corp_id', $params['corp_id'])
  348. ->where('category_id', $params['category_id'])
  349. ->where('question_id', $params['question_id'])
  350. ->where('status', 1)
  351. ->delete();
  352. if($res){
  353. return Api::arr(config('code.success'), trans('msg.success'));
  354. } else {
  355. return Api::arr(config('code.sql_error'), trans('msg.sql_error'));
  356. }
  357. }
  358. /**
  359. * 下载上传失败的题目数据
  360. * @param $data
  361. */
  362. public static function downloadQuestionExcel($data){
  363. $cellData = [
  364. ['题目标题', 'A选项', 'B选项', 'C选项', 'D选项', '答案', '错误原因'],
  365. ['填写规则'],
  366. ];
  367. foreach($cellData as $k=>$v){
  368. array_unshift($data, $v);
  369. }
  370. Excel::create('题目导入错误数据'.date('mdHi'),function($excel) use ($data){
  371. $excel->sheet('题目信息', function($sheet) use ($data){
  372. $tot = count($data) ;
  373. $sheet->setWidth(array(
  374. 'A' => 50,
  375. 'B' => 15,
  376. 'C' => 15,
  377. 'D' => 15,
  378. 'E' => 15,
  379. 'F' => 15,
  380. 'G' => 15,
  381. ))->rows($data)->setFontSize(12);
  382. //设置第一行的表格格式
  383. $sheet->setStyle([
  384. 'font' => [
  385. 'size' => 12,
  386. 'bold' => false,
  387. ]
  388. ])
  389. ->mergeCells('A1:G1') //合并单元格
  390. ->setHeight(1, 100) //设置行高
  391. ->setHeight(2, 30)
  392. ->cells('A1:G1', function($cells){ //设置单元格格式
  393. $cells->setValignment('center'); //文本对齐方式
  394. $cells->setFontWeight('bold'); //粗体
  395. })
  396. ->cells('A2:G2', function($cells){
  397. $cells->setValignment('center');
  398. $cells->setBackground('#92D050');
  399. $cells->setFontWeight('bold');
  400. $cells->setFontSize(10);
  401. $cells->setAlignment('center');
  402. })
  403. ->cells('B2:G'.$tot, function($cells) {
  404. $cells->setAlignment('center');
  405. })
  406. ->cells('G3:G'.$tot, function($cells) {
  407. $cells->setFontColor('#ff0000');
  408. $cells->setFontWeight('bold');
  409. });
  410. });
  411. })->export('xls');
  412. }
  413. /**
  414. * 添加默认题库
  415. * @param $activity_id
  416. * @return array
  417. */
  418. public static function addDefault($activity_id){
  419. $activity_info = ActivityService::getActivityInfo($activity_id);
  420. if(!$activity_info){
  421. return Api::arr(config('code.fail'), trans('msg.activity_not_exist'));
  422. }
  423. $default_questions = Questions::where('corp_id', 0)->where('activity_id', 0)->get()->toArray();
  424. $query_category = [];
  425. $query_category['corp_id'] = $activity_info['corp_id'];
  426. $query_category['activity_id'] = $activity_id;
  427. $query_category['category_name'] = '样例题库';
  428. $query_category['create_time'] = time();
  429. $query_category['update_time'] = time();
  430. $res = Categorys::insertGetId($query_category);
  431. if(!$res){
  432. return Api::arr(config('code.sql_error'), trans('msg.sql_error'));
  433. }
  434. foreach($default_questions as $k=>$v){
  435. $query_question = [];
  436. $query_question['corp_id'] = $activity_info['corp_id'];
  437. $query_question['activity_id'] = $activity_id;
  438. $query_question['question_title'] = $v['question_title'];
  439. $query_question['category_id'] = $res;
  440. $query_question['question_options'] = $v['question_options'];
  441. $query_question['correct_answer'] = $v['correct_answer'];
  442. $query_question['create_time'] = time();
  443. $query_question['update_time'] = time();
  444. Questions::insert($query_question);
  445. }
  446. $data['category_id'] = $res;
  447. return Api::arr(config('code.success'), trans('msg.success'), $data);
  448. }
  449. /**
  450. * 删除题库(活动委发布状态才可删除)
  451. * @param $activity_id
  452. * @param $category_id
  453. * @return array
  454. */
  455. public static function delCategory($activity_id, $category_id){
  456. $activityInfo = ActivityService::getActivityInfo($activity_id);
  457. if(!$activityInfo){
  458. return Api::arr(config('code.fail'), trans('msg.activity_not_exist'));
  459. }
  460. if($activityInfo['is_complete_set'] == 1){
  461. return Api::arr(config('code.fail'), '活动已发布,无法删除题库');
  462. }
  463. $categoryInfo = Categorys::where('category_id', $category_id)->first();
  464. if(!$categoryInfo){
  465. return Api::arr(config('code.fail'), trans('msg.category_not_exist'));
  466. }
  467. Categorys::where('category_id', $category_id)->delete();
  468. $questions = Questions::where('category_id', $category_id)->get();
  469. foreach($questions as $k=>$v){
  470. Questions::where('question_id', $v['question_id'])->delete();
  471. }
  472. return Api::arr(config('code.success'), trans('msg.success'));
  473. }
  474. }
  475. ?>