mockExam.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <view class="content" :class="{night:nightFlag}">
  3. <view class="top-box">
  4. <view class="icon"></view>
  5. <selectSwitch class='btn' @change="changeSwitch" :defaultSwitch='kemu==1' :switchList="['科一题目','科四题目']" checked_bj_color='#E31818' />
  6. <van-icon class='set' name="/static/imgs/sz.png" size='20' @click='show=true' />
  7. </view>
  8. <van-popup :show="show" @close="show=false" position="bottom">
  9. <van-cell title="选完跳转下一题 " clickable :data-index="index" @click="answerjump=!answerjump">
  10. <van-switch slot="right-icon" :checked="answerjump" size="24px" active-color="#16CC16" />
  11. </van-cell>
  12. <van-cell title="夜间模式" clickable :data-index="index" @click="nightFlag=!nightFlag">
  13. <van-switch slot="right-icon" :checked="nightFlag" size="24px" active-color="#16CC16" />
  14. </van-cell>
  15. </van-popup>
  16. <van-skeleton class='skeleton' avatar row="6" :row-width="['100%','40%','70%','70%','70%','70%']" avatar-shape='square'
  17. :loading="loading">
  18. <swiper class="swiper-box" :current="swiperIndex" @change="swiperChange" circular>
  19. <swiper-item v-for="(itembox,indexbox) in questionList" :key='indexbox'>
  20. <view class="swiper-item">
  21. <view class="topic-box">
  22. <view class="topic-right">
  23. <view class="topic-top">
  24. <view class="topic-left">
  25. <text class="topic-type">{{questionType(itembox.type)}}</text>
  26. <van-icon name="star-o" size='20' />
  27. </view>
  28. <!-- <rich-text class="topic-tit" :nodes="itembox.id+'、'+itembox.question"></rich-text> -->
  29. <view class="topic-tit" v-html="(indexbox+1)+'、'+itembox.question"></view>
  30. </view>
  31. <video v-if="itembox.videoUrl" class="topic-img" :muted='true' :loop='true' :autoplay='true' :controls='false'
  32. :src="encodeURI(itembox.mediaUrl)"></video>
  33. <image v-if="itembox.sinaimg" class="topic-img" :src="itembox.mediaUrl" mode="aspectFit"></image>
  34. <view class="topic-opt" v-if='itembox.type==2'>
  35. <van-radio-group :value="userAnswer[itembox.id]">
  36. <van-cell-group>
  37. <van-cell :class='{answer:(itembox.answerTrue.includes(index+1) && (answerflag))}' v-for="(item,index) in choiceList"
  38. :key="index" :title="itembox[item]" v-show='itembox[item]' clickable :data-index="index+1" @click="singleToggle($event,itembox)">
  39. <van-icon v-if="(itembox.answerTrue.includes(index+1) && (answerflag))" slot="icon" name="/static/imgs/true.png"
  40. size='20' />
  41. <van-radio slot="right-icon" :ref="`checkboxes${itembox.id}`" checked-color="#1464cc" :name="index+1" />
  42. </van-cell>
  43. </van-cell-group>
  44. </van-radio-group>
  45. <!-- <button @click="submit(itembox)" class="submit" type="default" v-show="!(answerflag || completeAnswer[itembox.id])">提交答案</button> -->
  46. </view>
  47. <view class="topic-opt" v-if='itembox.type==1'>
  48. <van-radio-group :value="userAnswer[itembox.id]">
  49. <van-cell-group>
  50. <van-cell :class='{answer:(itembox.answerTrue.includes(index+1) && (answerflag))}' v-for="(item,index) in 2"
  51. :key="index" :title="index?'错误':'正确'" clickable :data-index="index+1" @click="singleToggle($event,itembox)">
  52. <van-icon v-if="(itembox.answerTrue.includes(index+1) && (answerflag))" slot="icon" name="/static/imgs/true.png"
  53. size='20' />
  54. <van-radio slot="right-icon" :ref="`checkboxes${itembox.id}`" checked-color="#1464cc" :name="index+1" />
  55. </van-cell>
  56. </van-cell-group>
  57. </van-radio-group>
  58. <!-- <button @click="submit(itembox)" class="submit" type="default" v-show="!(answerflag || completeAnswer[itembox.id])">提交答案</button> -->
  59. </view>
  60. <view class="topic-opt" v-else-if='itembox.type==3'>
  61. <van-checkbox-group :value="userAnswer[itembox.id]" @change="onChange($event,itembox)">
  62. <van-cell-group>
  63. <van-cell :class='{answer:(itembox.answerTrue.includes(index+1) && (answerflag))}' v-for="(item,index) in choiceList"
  64. :key="index" :title="itembox[item]" v-show='itembox[item]' clickable @click='toggle($event,itembox)'
  65. :data-index="index">
  66. <van-icon v-if="(itembox.answerTrue.includes(index+1) && (answerflag))" slot="icon" name="/static/imgs/true.png"
  67. size='20' />
  68. <van-checkbox shape="square" catch:tap="noop" slot="right-icon" :ref="`checkboxes${itembox.id}`"
  69. checked-color="#1464cc" :name="index+1" />
  70. </van-cell>
  71. </van-cell-group>
  72. </van-checkbox-group>
  73. <!-- <button @click="submit(itembox)" class="submit" type="default" v-show="!(answerflag)">提交答案</button> -->
  74. </view>
  75. </view>
  76. </view>
  77. <view v-show="answerflag">
  78. <view class="flag">
  79. <text v-if="itembox.type==2" class="result">正确答案: {{itembox[choiceList[itembox.answerTrue-1]]}}</text>
  80. <text v-else-if="itembox.type==1" class="result">正确答案: {{itembox.answerTrue==1?'正确':'错误'}}</text>
  81. <text v-else-if="itembox.type==3" class="result">正确答案: {{itembox.answerTrue.split('').map((key)=>{
  82. return itembox[choiceList[key-1]]
  83. })}}</text>
  84. </view>
  85. <view class="parsing">
  86. <view class="item-titBox">
  87. <text class="item-tit">题目解析</text>
  88. </view>
  89. <view class="parsing-text">
  90. <text class="item-tit">{{itembox.explain1 ? itembox.explain1 : "无"}}</text>
  91. </view>
  92. </view>
  93. </view>
  94. </view>
  95. </swiper-item>
  96. </swiper>
  97. <view class="carryOut" v-if="!answerflag">
  98. <van-count-down id='count' :auto-start='false' :time="remainingTime * 60 * 1000" />
  99. <button @click="statistics" class="carryOut-btn" type="default">我要交卷</button>
  100. </view>
  101. <van-dialog id="van-dialog" />
  102. </van-skeleton>
  103. </view>
  104. </template>
  105. <script>
  106. import selectSwitch from "@/components/xuan-switch/xuan-switch.vue";
  107. import Dialog from '@/wxcomponents/vant/dialog/dialog';
  108. import {
  109. questionListRandom
  110. } from "@/api/answer.js"
  111. export default {
  112. components: {
  113. selectSwitch
  114. },
  115. data() {
  116. return {
  117. loading: true,
  118. answerflag: false,
  119. answerjump: true,
  120. nightFlag: false,
  121. kemu: uni.getStorageSync('kemu') || 1,
  122. completeAnswer: {},
  123. show: false,
  124. checked: true,
  125. radio: null,
  126. result: [],
  127. userAnswer: {},
  128. questionList: {},
  129. choiceList: ['an1', 'an2', 'an3', 'an4', 'an5', 'an6', 'an7'],
  130. swiperIndex: 0,
  131. shakeIndex: 0,
  132. pageNum: 1,
  133. shake: 0,
  134. trueNum: 0,
  135. errorBox: [],
  136. remainingTime: 60,
  137. startDate:new Date().getTime(),
  138. }
  139. },
  140. watch: {
  141. kemu(val) {
  142. uni.setStorageSync('kemu', val)
  143. this.pageNum = 1
  144. this.listInit()
  145. }
  146. },
  147. mounted() {
  148. this.listInit()
  149. },
  150. methods: {
  151. async listInit() {
  152. this.loading=true
  153. await questionListRandom({
  154. num: 5,
  155. kemu: this.kemu
  156. }).then((res) => {
  157. this.questionList = res.rows
  158. this.$nextTick(() => {
  159. this.loading = false
  160. this.selectComponent('#count').start()
  161. })
  162. })
  163. await questionListRandom({
  164. num: 95,
  165. kemu: this.kemu
  166. }).then((res) => {
  167. this.questionList = this.questionList.concat(res.rows)
  168. })
  169. },
  170. questionType(index) {
  171. switch (index) {
  172. case 1:
  173. return '判断';
  174. case 2:
  175. return '单选';
  176. case 3:
  177. return '多选';
  178. }
  179. },
  180. swiperChange(e) {
  181. this.swiperIndex = e.detail.current
  182. },
  183. onChange(event, itembox) {
  184. if (this.completeAnswer[itembox.id] || this.answerflag) {
  185. return
  186. }
  187. this.$set(this.userAnswer, itembox.id, event.detail)
  188. },
  189. singleToggle(event, itembox) {
  190. if (this.completeAnswer[itembox.id] || this.answerflag) {
  191. return
  192. }
  193. const {
  194. index
  195. } = event.currentTarget.dataset;
  196. this.$set(this.userAnswer, itembox.id, index)
  197. if (this.answerjump) {
  198. let index = this.swiperIndex
  199. this.swiperIndex = ++index % 100
  200. }
  201. },
  202. toggle(event, itembox) {
  203. const {
  204. index
  205. } = event.currentTarget.dataset;
  206. const checkbox = this.$refs[`checkboxes${itembox.id}`][index];
  207. checkbox.toggle();
  208. },
  209. noop() {},
  210. submit(itembox, index) {
  211. this.$set(this.completeAnswer, itembox.id, true)
  212. let flag = (this.userAnswer[itembox.id] + '').split(',').sort().join('') == itembox.answerTrue.split('').sort().join(
  213. '')
  214. if (flag) {
  215. this.trueNum += 1
  216. } else {
  217. this.errorBox.push(index + 1)
  218. }
  219. },
  220. statistics() {
  221. this.questionList.map((itembox, index) => {
  222. this.submit(itembox, index)
  223. })
  224. this.selectComponent('#count').pause()
  225. Dialog.alert({
  226. title: '模拟考试结果',
  227. message: `考试结果: ${this.trueNum}分\n答题用时: ${this.calcTime()}\n答错题目: \n${this.errorBox}`,
  228. messageAlign: 'left',
  229. confirmButtonText: '查看答案及解析'
  230. }).then(() => {
  231. this.answerflag = true
  232. });
  233. },
  234. calcTime(){
  235. let time=new Date().getTime()-this.startDate
  236. return new Date(time).toJSON().slice(11,-5)
  237. },
  238. changeSwitch(e) {
  239. if (e) {
  240. this.kemu = 1
  241. } else {
  242. this.kemu = 4
  243. }
  244. }
  245. }
  246. }
  247. </script>
  248. <style lang="scss" scoped>
  249. .carryOut {
  250. position: fixed;
  251. bottom: 120rpx;
  252. left: 50%;
  253. transform: translateX(-50%);
  254. display: flex;
  255. flex-direction: column;
  256. justify-content: center;
  257. align-items: center;
  258. .carryOut-btn {
  259. height: 80rpx;
  260. background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
  261. border-radius: 35rpx;
  262. display: flex;
  263. justify-content: center;
  264. align-items: center;
  265. color: #FFFFFF;
  266. }
  267. }
  268. /deep/ .answer .van-cell {
  269. background-color: #16CC16 !important;
  270. color: #ffffff;
  271. }
  272. /deep/ .van-cell {
  273. // background-color: #16CC16 !important;
  274. margin: 10rpx;
  275. border-radius: 20rpx;
  276. }
  277. .content {
  278. width: 100%;
  279. height: 100vh;
  280. background-color: #FFFFFF;
  281. }
  282. .skeleton {
  283. // margin: 0rpx 20rpx;
  284. }
  285. .swiper-box {
  286. height: calc(100vh - 120rpx);
  287. margin: 0rpx 20rpx;
  288. swiper-item {
  289. overflow: auto;
  290. }
  291. }
  292. .top-box {
  293. height: 60rpx;
  294. padding: 30rpx;
  295. display: flex;
  296. justify-content: space-between;
  297. align-items: center;
  298. .icon {
  299. width: 60rpx;
  300. }
  301. .btn {}
  302. .set {
  303. color: red;
  304. }
  305. }
  306. .topic-box {
  307. // padding: 20rpx;
  308. display: flex;
  309. justify-content: center;
  310. // border: 2px solid red;
  311. .topic-top {
  312. display: flex;
  313. // border: 2px solid red;
  314. padding: 10rpx;
  315. .topic-left {
  316. display: flex;
  317. flex-direction: column;
  318. .topic-type {
  319. background: #E31818;
  320. border-radius: 10rpx;
  321. // border: 2px solid red;
  322. color: #FFFFFF;
  323. width: 66rpx;
  324. height: 30rpx;
  325. display: flex;
  326. justify-content: center;
  327. align-items: center;
  328. border-radius: 15px 15px 0px 15px;
  329. padding: 10rpx;
  330. margin-bottom: 18rpx;
  331. }
  332. }
  333. .topic-tit {
  334. padding: 10rpx;
  335. }
  336. }
  337. .topic-right {
  338. flex: 1;
  339. display: flex;
  340. flex-direction: column;
  341. padding: 0 10rpx;
  342. .topic-img {
  343. padding: 10rpx;
  344. margin: auto;
  345. width: 500rpx;
  346. height: 250rpx;
  347. // border: 2px solid red;
  348. }
  349. .topic-opt {
  350. // border: 2px solid red;
  351. padding: 30rpx 5rpx;
  352. .submit {
  353. margin: auto;
  354. margin-top: 150rpx;
  355. height: 80rpx;
  356. background: linear-gradient(90deg, #E31818, #ED3E24, #ED4F24);
  357. border-radius: 35rpx;
  358. display: flex;
  359. justify-content: center;
  360. align-items: center;
  361. color: #FFFFFF;
  362. }
  363. }
  364. }
  365. }
  366. .flag {
  367. // border: 2px solid red;
  368. padding: 30rpx 5rpx;
  369. display: flex;
  370. justify-content: center;
  371. .result {
  372. display: inline-block;
  373. background-color: #16CC16;
  374. // border: 2px solid red;
  375. width: 690rpx;
  376. // height: 70rpx;
  377. padding: 20rpx;
  378. display: flex;
  379. align-items: center;
  380. justify-content: center;
  381. border-radius: 20rpx;
  382. color: #ffffff;
  383. }
  384. }
  385. .item-titBox {
  386. display: flex;
  387. justify-content: space-between;
  388. align-items: center;
  389. padding: 20rpx;
  390. border-bottom: 1rpx solid #e8e8e8;
  391. .item-tit {
  392. border-left: 8rpx solid #E31818;
  393. font-size: 30rpx;
  394. // line-height: 38rpx;
  395. padding: 0 11rpx;
  396. }
  397. }
  398. .parsing-text {
  399. padding: 30rpx;
  400. // border: 2px solid red;
  401. }
  402. </style>