problem_detail.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. <!-- +---------------------------------------------------------------------- -->
  2. <!-- | CRMEB [ CRMEB赋能开发者,助力企业发展 ] -->
  3. <!-- +---------------------------------------------------------------------- -->
  4. <!-- | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved. -->
  5. <!-- +---------------------------------------------------------------------- -->
  6. <!-- | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权 -->
  7. <!-- +---------------------------------------------------------------------- -->
  8. <!-- | Author: CRMEB Team <admin@crmeb.com> -->
  9. <!-- +---------------------------------------------------------------------- -->
  10. {extend name="public/container"}
  11. {block name="title"}练习答题{/block}
  12. {block name="head_top"}
  13. <style>
  14. body {
  15. background-color: #f5f5f5;
  16. }
  17. .share-mask {
  18. position: fixed;
  19. top: 0;
  20. right: 0;
  21. bottom: 0;
  22. left: 0;
  23. z-index: 6;
  24. width: 100%;
  25. height: 100%;
  26. }
  27. </style>
  28. {/block}
  29. {block name="content"}
  30. <div v-cloak id="app" class="question-paper">
  31. <div v-show="questionSwiper" class="header">
  32. <div class="message">温馨提示:请点击“答题卡”前去提交考试哦!</div>
  33. <div class="header-bd">
  34. <a :href="'{:url('topic/problem_sheet')}?test_id=' + test_id + '&record_id=' + e_id + '&index=' + activeIndex">答题卡</a>
  35. <a v-if="isWechat" href="javascript:" @click="isShare = true">分享</a>
  36. </div>
  37. </div>
  38. <div class="swiper-container swiper-no-swiping">
  39. <div class="swiper-wrapper">
  40. <div v-for="item in virtualData.slides" :key="item.id" :style="{ left: virtualData.offset + 'px' }" class="swiper-slide">
  41. <div class="type">{{ item.questionType }}</div>
  42. <div class="question">
  43. <div>{{ item.stem }}</div>
  44. <img v-if="item.image" :src="item.image">
  45. <div :class="{ image: item.is_img }" class="label-group">
  46. <template v-for="option in item.options">
  47. <label v-if="option.value" :key="option.code">
  48. <input v-if="item.question_type === 2" v-model="item.user_answer" :value="option.code" :disabled="!!item.is_correct" type="checkbox" hidden>
  49. <input v-else v-model="item.user_answer" :value="option.code" :disabled="!!item.is_correct" type="radio" hidden>
  50. <div :class="{
  51. ok: option.right && item.is_correct && item.user_answer.includes(option.code),
  52. no: !option.right && item.is_correct && item.user_answer.includes(option.code)
  53. }">
  54. <img v-if="item.is_img" :src="option.value">
  55. <template v-else>{{ option.value }}</template>
  56. </div>
  57. </label>
  58. </template>
  59. </div>
  60. </div>
  61. <div v-show="item.is_correct" class="analysis">
  62. <div :class="{ no: item.is_correct === 1 }">回答{{ item.is_correct === 1 ? '错误' : '正确' }}</div>
  63. <div>
  64. <div>正确答案:<div>{{ item.answer }}</div>
  65. </div>
  66. <div>您的答案:<div>{{ item.user_answer.toString() }}</div>
  67. </div>
  68. </div>
  69. <div>试题难度:<span v-for="star in 5" :key="star" :class="{ on: item.difficulty >= star }" class="iconfont iconxing"></span></div>
  70. <div>答案解析:</div>
  71. <div v-html="item.analysis"></div>
  72. <div v-if="item.special.length">关联知识点:</div>
  73. <a v-for="special in item.special" :key="special.id"
  74. :href="(special.is_light ? '{:url('special/single_details')}' : '{:url('special/details')}') + '?id=' + special.id">{{ special.title }}</a>
  75. </div>
  76. </div>
  77. </div>
  78. <div class="swiper-pagination"></div>
  79. </div>
  80. <div v-if="questionSwiper" class="footer">
  81. <button :disabled="!questionSwiper.activeIndex" @click="slidePrev">
  82. <i class="iconfont iconshangyige"></i>
  83. <div>上一题</div>
  84. </button>
  85. <button :disabled="!!questions[questionSwiper.activeIndex].is_correct" @click="submitQuestion">
  86. <i class="iconfont icontijiao"></i>
  87. <div>确认提交</div>
  88. </button>
  89. <button :disabled="questionSwiper.activeIndex === questionSwiper.virtual.slides.length - 1" @click="slideNext">
  90. <i class="iconfont iconxiayige"></i>
  91. <div>下一题</div>
  92. </button>
  93. </div>
  94. <img v-show="isShare" class="share-mask" src="{__WAP_PATH}zsff/images/share-info.png" @touchmove.prevent @click="isShare = false">
  95. <quick-menu></quick-menu>
  96. <question-guide :visible.sync="guideVisible"></question-guide>
  97. </div>
  98. {/block}
  99. {block name="foot"}
  100. <script>
  101. window.overallShare = false;
  102. var wechat_share =<?php echo isset($overallShareWechat) ? $overallShareWechat : '{}'; ?>;
  103. var uid = '{$uid}';
  104. var titles = '{$titles}';
  105. require([
  106. 'vue',
  107. 'helper',
  108. 'axios',
  109. 'swiper',
  110. 'layer',
  111. 'components/question-guide/index',
  112. 'quick'
  113. ], function (Vue, $h, axios, Swiper, layer, questionGuide) {
  114. var isWechat = '{$isWechat}';
  115. var app = new Vue({
  116. el: '#app',
  117. components: {
  118. 'question-guide': questionGuide
  119. },
  120. data: {
  121. questions: [],
  122. test_id: '',
  123. e_id: '',
  124. isWechat: isWechat,
  125. is_analysis: 0,
  126. isShare: false,
  127. activeIndex: 0,
  128. virtualData: {
  129. slides: []
  130. },
  131. questionSwiper: null,
  132. guideVisible: false
  133. },
  134. watch: {
  135. guideVisible: function (value) {
  136. if (!value) {
  137. localStorage.setItem('problem-guide', new Date());
  138. }
  139. }
  140. },
  141. created: function () {
  142. var vm = this;
  143. this.test_id = $h.getParmas('test_id');
  144. this.activeIndex = Number($h.getParmas('index'));
  145. if (parseInt($h.getParmas('is_analysis'))) {
  146. this.is_analysis = 1;
  147. // this.e_id = $h.getParmas('e_id');
  148. // this.getQuestions();
  149. } else {
  150. // this.getSituation();
  151. }
  152. if ($h.getParmas('e_id')) {
  153. this.e_id = $h.getParmas('e_id');
  154. this.getQuestions();
  155. }
  156. if (this.isWechat) {
  157. mapleWx($jssdk(), function () {
  158. this.onMenuShareAll({
  159. title: titles,
  160. desc: titles,
  161. imgUrl: wechat_share.wechat_share_img,
  162. link: window.location.origin + "{:url('topic/problem_index')}?spread_uid=" + uid + "&id=" + vm.test_id
  163. });
  164. });
  165. }
  166. },
  167. methods: {
  168. // 获取状态
  169. getSituation: function () {
  170. var vm = this;
  171. var load = layer.load(1);
  172. axios.get('/wap/topic/situationRecord', {
  173. params: {
  174. id: this.test_id
  175. }
  176. }).then(function (res) {
  177. if (res.data.code === 400) {
  178. return layer.msg(res.data.msg);
  179. }
  180. switch (res.data.data) {
  181. case 0:
  182. vm.getAnswer();
  183. break;
  184. case 1:
  185. vm.getAnswerAgain();
  186. break;
  187. case 2:
  188. vm.getAnswerContinue();
  189. break;
  190. }
  191. }).catch(function () {
  192. }).then(function () {
  193. layer.close(load);
  194. });
  195. },
  196. // 开始答题
  197. getAnswer: function () {
  198. var vm = this;
  199. var load = layer.load(1);
  200. axios.get('/wap/topic/userAnswer', {
  201. params: {
  202. test_id: this.test_id,
  203. type: 1
  204. }
  205. }).then(function (res) {
  206. if (res.data.code === 200) {
  207. vm.e_id = res.data.data;
  208. $h.setCookie('e_id', vm.e_id);
  209. vm.getQuestions();
  210. } else {
  211. layer.msg(res.data.msg, function () {
  212. window.location.assign('{:url(\'topic/question_user\')}?type=1');
  213. });
  214. }
  215. }).catch(function () {
  216. }).then(function () {
  217. layer.close(load);
  218. });
  219. },
  220. // 再次答题
  221. getAnswerAgain: function () {
  222. var vm = this;
  223. var load = layer.load(1);
  224. axios.get('/wap/topic/takeTheTestAgain', {
  225. params: {
  226. test_id: this.test_id,
  227. type: 1
  228. }
  229. }).then(function (res) {
  230. if (res.data.code === 200) {
  231. vm.e_id = res.data.data;
  232. $h.setCookie('e_id', vm.e_id);
  233. vm.getQuestions();
  234. } else {
  235. layer.msg(res.data.msg, function () {
  236. window.location = "{:url('topic/question_user')}?type=1";
  237. });
  238. }
  239. }).catch(function () {
  240. }).then(function () {
  241. layer.close(load);
  242. });
  243. },
  244. // 继续答题
  245. getAnswerContinue: function () {
  246. var vm = this;
  247. var load = layer.load(1);
  248. axios.get('/wap/topic/continueAnswer', {
  249. params: {
  250. test_id: this.test_id,
  251. type: 1
  252. }
  253. }).then(function (res) {
  254. if (res.data.code === 200) {
  255. vm.e_id = res.data.data;
  256. $h.setCookie('e_id', vm.e_id);
  257. vm.getQuestions();
  258. } else {
  259. layer.msg(res.data.msg, function () {
  260. window.location = "{:url('topic/question_user')}?type=1";
  261. });
  262. }
  263. }).catch(function () {
  264. }).then(function () {
  265. layer.close(load);
  266. });
  267. },
  268. // 获取练习题
  269. getQuestions: function () {
  270. var vm = this;
  271. var load = layer.load(1);
  272. axios.get('/wap/topic/testPaperQuestions', {
  273. params: {
  274. test_id: this.test_id,
  275. record_id: this.e_id,
  276. type: 1
  277. }
  278. }).then(function (res) {
  279. var questions = res.data.data;
  280. questions.forEach(function (question) {
  281. question.options = [];
  282. if (Array.isArray(question.option)) {
  283. question.option.forEach(function (option, index) {
  284. var code = String.fromCharCode(index + 65);
  285. question.options.push({
  286. code: code,
  287. value: option,
  288. right: question.answer.includes(code)
  289. });
  290. });
  291. } else {
  292. for (var key in question.option) {
  293. if (Object.hasOwnProperty.call(question.option, key)) {
  294. question.options.push({
  295. code: key,
  296. value: question.option[key],
  297. right: question.answer.includes(key)
  298. });
  299. }
  300. }
  301. }
  302. if (!Array.isArray(question.userAnswer)) {
  303. Object.assign(question, question.userAnswer);
  304. }
  305. if (!('is_correct' in question)) {
  306. question.is_correct = 0;
  307. }
  308. if (!('user_answer' in question)) {
  309. question.user_answer = '';
  310. }
  311. if (question.question_type === 2) {
  312. question.user_answer = question.user_answer ? question.user_answer.split(',') : [];
  313. }
  314. switch (question.question_type) {
  315. case 1:
  316. question.questionType = '单选题';
  317. break;
  318. case 2:
  319. question.questionType = '多选题';
  320. break;
  321. case 3:
  322. question.questionType = '判断题';
  323. break;
  324. }
  325. });
  326. vm.questions = questions;
  327. vm.questionSwiper = new Swiper('.swiper-container', {
  328. initialSlide: vm.activeIndex,
  329. pagination: {
  330. el: '.swiper-pagination',
  331. type: 'fraction'
  332. },
  333. virtual: {
  334. slides: questions,
  335. renderExternal: function (data) {
  336. vm.virtualData = data;
  337. }
  338. },
  339. on: {
  340. init: function () {
  341. vm.guideVisible = !localStorage.getItem('problem-guide');
  342. },
  343. slideChange: function () {
  344. vm.activeIndex = this.activeIndex;
  345. if (vm.activeIndex === vm.questions.length - 1) {
  346. layer.msg('答完全部考题后<br>点击左上角“答题卡”前去提交练习');
  347. }
  348. }
  349. }
  350. });
  351. }).catch(function () {
  352. }).then(function () {
  353. layer.close(load);
  354. });
  355. },
  356. // 提交本题
  357. submitQuestion: function () {
  358. var question = this.questions[this.activeIndex];
  359. var data = {
  360. e_id: this.e_id,
  361. questions_id: question.questions_id,
  362. answer: question.answer,
  363. score: question.score,
  364. type: 1
  365. };
  366. if (!question.user_answer.length) {
  367. return layer.msg('请作答后提交本题');
  368. }
  369. if (question.question_type === 2) {
  370. question.user_answer.sort();
  371. data.user_answer = question.user_answer.toString();
  372. } else {
  373. data.user_answer = question.user_answer;
  374. }
  375. data.is_correct = data.user_answer === question.answer ? 2 : 1;
  376. var load = layer.load(1);
  377. axios.post('/wap/topic/submitQuestions', data).then(function (res) {
  378. if (res.data.code === 200) {
  379. question.is_correct = data.is_correct;
  380. } else {
  381. layer.msg(res.data.msg);
  382. }
  383. }).catch(function () {
  384. }).then(function () {
  385. layer.close(load);
  386. });
  387. },
  388. // 上一题
  389. slidePrev: function () {
  390. this.questionSwiper.slidePrev();
  391. },
  392. // 下一题
  393. slideNext: function () {
  394. this.questionSwiper.slideNext();
  395. },
  396. }
  397. });
  398. });
  399. </script>
  400. {/block}