question_result.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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"}
  13. <style>
  14. .certificate-image {
  15. position: fixed;
  16. top: 50%;
  17. left: 50%;
  18. z-index: 56;
  19. width: 6rem;
  20. -webkit-transform: translate(-50%, -50%);
  21. transform: translate(-50%, -50%);
  22. }
  23. body {
  24. padding: .76rem .3rem .46rem;
  25. background-color: #F5F5F5;
  26. }
  27. </style>
  28. {/block}
  29. {block name="content"}
  30. <div v-cloak id="app">
  31. <div class="question-result">
  32. <div class="header">
  33. <div class="avatar"><img src="{$userInfo.avatar}"></div>
  34. <div class="nickname">{$userInfo.nickname}</div>
  35. <vue-circle-progress
  36. ref="circle"
  37. id="circle"
  38. :progress="0"
  39. :size="133"
  40. :reverse="false"
  41. line-cap="round"
  42. :fill="fill"
  43. empty-fill="rgba(213, 224, 236, 0.6)"
  44. :animation-start-value="0.0"
  45. :start-angle="Math.PI / 2"
  46. insert-mode="append"
  47. :thickness="5"
  48. inner-text="正确率"
  49. :show-percent="true"
  50. style="text-align: center;margin-top: .5rem;font-size: 0;"
  51. >
  52. <p>正确率</p>
  53. </vue-circle-progress>
  54. <div class="title">{{ result.title }}</div>
  55. <div v-if="result.is_score" class="scores">
  56. <div class="score">
  57. <div class="name">本次得分</div>
  58. <div class="value">{{ result.score }}</div>
  59. </div>
  60. <div v-if="result.grade" class="score grade">
  61. <div class="name">评分标准</div>
  62. <div class="value">{{ result.grade }}</div>
  63. </div>
  64. </div>
  65. <div class="basic">
  66. <div class="item">
  67. <div>题目数</div>
  68. <div class="value">{{ result.test_paper_question.length }}</div>
  69. </div>
  70. <div class="item">
  71. <div>错题数</div>
  72. <div class="value">{{ result.wrong_question }}</div>
  73. </div>
  74. <div class="item">
  75. <div>未答数</div>
  76. <div class="value">{{ result.not_questions }}</div>
  77. </div>
  78. <div class="item">
  79. <div>本次用时</div>
  80. <div class="value">{{ result.duration_time }}</div>
  81. </div>
  82. </div>
  83. </div>
  84. <div class="answer">
  85. <div class="answer-header">
  86. <div>答题情况</div>
  87. <div class="prompt">
  88. <div class="item">正确</div>
  89. <div class="item">错误</div>
  90. <div class="item">未答</div>
  91. </div>
  92. </div>
  93. <div class="answer-body">
  94. <a v-for="(item, index) in result.test_paper_question" :class="{ no: item.is_correct === 1, ok: item.is_correct === 2 }" href="javascript:">{{ index + 1 }}</a>
  95. </div>
  96. <div v-if="!footerHidden" class="answer-footer">
  97. <a :href="'{:url('topic/question_sheet')}?is_analysis=1&test_id=' + test_id + '&record_id=' + result.id">查看解析</a>
  98. <a :href="'{:url('special/question_index')}?id=' + test_id">再考一次</a>
  99. </div>
  100. </div>
  101. <div :class="{ mask: imgSrc }" @touchmove.prevent @click="imgSrc = ''"></div>
  102. <img v-if="imgSrc" :src="imgSrc" class="certificate-image">
  103. </div>
  104. <quick-menu></quick-menu>
  105. </div>
  106. <script>
  107. require([
  108. 'vue',
  109. 'helper',
  110. 'store',
  111. 'vue-circle-progress',
  112. 'axios',
  113. 'layer',
  114. 'moment',
  115. 'quick'
  116. ], function (Vue, $h, $http, VueCircle, axios, layer, moment) {
  117. var vm = new Vue({
  118. el: '#app',
  119. components: {
  120. 'vue-circle-progress': VueCircle
  121. },
  122. data: {
  123. test_id: 0,
  124. result: {
  125. title: '--',
  126. score: 0,
  127. grade: '--',
  128. test_paper_question: [],
  129. wrong_question: 0,
  130. duration_time: '00:00:00'
  131. },
  132. fill : { gradient: ["rgba(44, 142, 255, 1)", "rgba(44, 142, 255, 0.05)"] },
  133. footerHidden: false,
  134. imgSrc: ''
  135. },
  136. created: function () {
  137. this.test_id = $h.getParmas('test_id');
  138. this.footerHidden = $h.getParmas('from') === 'question_user';
  139. this.getResult();
  140. $h.delCookie('exam_time');
  141. },
  142. methods: {
  143. // 获取答题结果
  144. getResult: function () {
  145. $h.loadFFF();
  146. return $http.baseGet($h.U({
  147. c: 'topic',
  148. a: 'examinationResults',
  149. q: {
  150. test_id: this.test_id,
  151. type: 2
  152. }
  153. }), function (res) {
  154. var result = res.data.data;
  155. var questions = result.test_paper_question;
  156. var duration = result.duration
  157. var hours = Math.floor(duration / 3600000);
  158. var minutes = Math.floor((duration - hours * 3600000) / 60000);
  159. var seconds = Math.floor((duration - hours * 3600000 - minutes * 60000) / 1000);
  160. if (hours < 10) {
  161. hours = '0' + hours;
  162. }
  163. if (minutes < 10) {
  164. minutes = '0' + minutes;
  165. }
  166. if (seconds < 10) {
  167. seconds = '0' + seconds;
  168. }
  169. result.duration_time = hours + ':' + minutes + ':' + seconds;
  170. for (var i = questions.length; i--;) {
  171. if (!Array.isArray(questions[i].userAnswer)) {
  172. Object.assign(questions[i], questions[i].userAnswer);
  173. }
  174. }
  175. vm.$refs.circle.updateProgress(parseInt(result.accuracy));
  176. vm.result = result;
  177. $h.loadClear();
  178. vm.getInspect();
  179. }, function () {
  180. window.location.replace($h.U({
  181. c: 'topic',
  182. a: 'question_user'
  183. }));
  184. });
  185. },
  186. // 是否可以发放证书
  187. getInspect: function () {
  188. $h.loadFFF();
  189. axios.get($h.U({
  190. c: 'topic',
  191. a: 'inspect',
  192. q: {
  193. test_id: this.test_id
  194. }
  195. })).then(function (res) {
  196. $h.loadClear();
  197. if (200 === res.data.code) {
  198. layer.confirm('恭喜您已达到证书发放标准,是否领取?', {
  199. title: false,
  200. closeBtn: 0,
  201. btn: ['领取', '取消']
  202. }, function (index) {
  203. vm.getCertificate();
  204. layer.close(index);
  205. });
  206. }
  207. }).catch(function () {
  208. $h.loadClear();
  209. });
  210. },
  211. // 领取证书
  212. getCertificate: function () {
  213. $h.loadFFF();
  214. $http.baseGet($h.U({
  215. c: 'topic',
  216. a: 'getTheCertificate',
  217. q: {
  218. test_id: this.test_id
  219. }
  220. }), function (res) {
  221. $h.loadClear();
  222. layer.msg('领取成功<br>证书正在生成…', {
  223. anim: 0
  224. }, function () {
  225. vm.getCertificateInfo(res.data.msg);
  226. });
  227. }, function (err) {
  228. $h.loadClear();
  229. console.error(err);
  230. });
  231. },
  232. // 获取证书信息
  233. getCertificateInfo: function (id) {
  234. $h.loadFFF();
  235. $http.baseGet($h.U({
  236. c: 'topic',
  237. a: 'viewCertificate',
  238. q: {
  239. id: id,
  240. obtain: 2
  241. }
  242. }), function (res) {
  243. $h.loadClear();
  244. vm.createCertificate(res.data.data);
  245. }, function (err) {
  246. $h.loadClear();
  247. console.error(err);
  248. });
  249. },
  250. // 加载图片
  251. loadImage: function (path) {
  252. return new Promise(function (resolve, reject) {
  253. var image = new Image();
  254. image.crossOrigin = 'anonymous';
  255. image.onload = function () {
  256. resolve(image);
  257. };
  258. image.onerror = function () {
  259. reject('error-image');
  260. };
  261. image.src = path + '?' + new Date().getTime();
  262. });
  263. },
  264. // 生成证书图片
  265. createCertificate: function (certificate) {
  266. $h.loadFFF();
  267. Promise.all([
  268. this.loadImage(certificate.certificate.background),
  269. this.loadImage(certificate.certificate.qr_code)
  270. ]).then(function (images) {
  271. var canvas = document.createElement('canvas');
  272. var context = canvas.getContext('2d');
  273. canvas.width = images[0].width;
  274. canvas.height = images[0].height;
  275. context.drawImage(images[0], 0, 0);
  276. context.drawImage(images[1], 220, 557, 160, 160);
  277. context.fillStyle = 'rgba(255, 255, 255, 1)';
  278. context.fillRect(220, 724, 160, 36);
  279. context.font = '20px sans-serif';
  280. context.textAlign = 'center';
  281. context.fillStyle = '#666666';
  282. context.fillText('长按二维码查看', 300, 748);
  283. context.font = 'bold 34px sans-serif';
  284. context.fillStyle = '#29466D';
  285. context.fillText(certificate.nickname, 300, 296);
  286. context.font = '24px sans-serif';
  287. context.fillText('颁发时间:' + moment(certificate.add_time * 1000).format('YYYY.MM.DD'), 300, 481);
  288. context.font = '28px sans-serif';
  289. context.textAlign = 'start';
  290. context.fillStyle = '#333333';
  291. for (var i = Math.ceil(certificate.certificate.explain.length % 16); i--;) {
  292. context.fillText(certificate.certificate.explain.substr(i * 16, 16), 83, i * 40 + 370);
  293. }
  294. vm.imgSrc = canvas.toDataURL('image/jpeg');
  295. canvas = null;
  296. $h.loadClear();
  297. }).catch(function (error) {
  298. $h.loadClear();
  299. console.error(error);
  300. });
  301. }
  302. }
  303. });
  304. });
  305. </script>
  306. {/block}