exam.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. <template>
  2. <view>
  3. <view class="content1">
  4. <view class="hand-bar">
  5. <view class="timer-col">
  6. <uni-countdown v-if="timerFlag" :show-day="false" :hour="countHour" :minute="countMin"
  7. :second="countSec" @timeup="doHandler()"></uni-countdown>
  8. </view>
  9. <view class="hand-col">
  10. <button type="warn" @click="handHandExam(0)">交卷</button>
  11. </view>
  12. </view>
  13. <view v-if="paperData.actionOn && paperData.actionInterval>0" style="margin-top: -15px;">
  14. <action-checker :action-on="paperData.actionOn" :action-interval="paperData.actionInterval"
  15. :trigger="actionTrigger" @break="doHandler(3)" />
  16. </view>
  17. <!-- 导入组件 -->
  18. <view style="margin-bottom: 80px;">
  19. <exam-qu-item v-model="quData" @rest="handleRest" />
  20. </view>
  21. </view>
  22. <view class="bottom-bar">
  23. <uni-row :gutter="20">
  24. <uni-col :span="8">
  25. <button @click="handleNext(-1)" :disabled="!showPrevious">上题</button>
  26. </uni-col>
  27. <uni-col :span="8">
  28. <button @click="handleNext(1)" :disabled="!showNext">下题</button>
  29. </uni-col>
  30. <uni-col :span="8">
  31. <button type="primary" @click="showCard()">答题卡</button>
  32. </uni-col>
  33. </uni-row>
  34. </view>
  35. <uni-drawer ref="cardDrawer">
  36. <scroll-view scroll-y="true" class="scroll-y">
  37. <view>
  38. <view>
  39. <view class="card-title">答题卡</view>
  40. <view class="card-context">
  41. <view class="card-num card-com">未作答</view>
  42. <view class="card-num card-com right">已作答</view>
  43. </view>
  44. <view v-for="type in paperData.groupList">
  45. <view class="card-title">{{ type.quType_dictText }}</view>
  46. <view class="card-context">
  47. <view v-for="item in type.quList"
  48. :class="{'card-num ': true, 'current': item.quId === cardItem.quId, 'answered': item.answered}"
  49. @click="fetchQuData(item)">
  50. {{ item.sort}}
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. </view>
  56. </scroll-view>
  57. </uni-drawer>
  58. <!-- 页面离开检测 -->
  59. <leave-checker v-if="paperData.leaveOn && paperData.leaveCount>0" :pageShow="pageShow"
  60. :leave-on="paperData.leaveOn" :leave-check="paperData.leaveCheck" :leave-count="paperData.leaveCount"
  61. :paper-id="paperData.id" @break="doHandler(2)" />
  62. </view>
  63. </template>
  64. <script>
  65. import {
  66. paperDetail,
  67. paperQuDetail,
  68. handExam
  69. } from '@/api/exam.js'
  70. import ExamQuItem from "./components/ExamQuItem.vue"
  71. import ActionChecker from "./components/ActionChecker.vue"
  72. import LeaveChecker from "./components/LeaveChecker.vue"
  73. import CamVideo from '../video/video.vue'
  74. export default {
  75. components: {
  76. ExamQuItem,
  77. ActionChecker,
  78. LeaveChecker
  79. },
  80. data() {
  81. return {
  82. // 全屏/不全屏
  83. showPrevious: false,
  84. showNext: true,
  85. cardShow: false,
  86. // 试卷ID
  87. paperId: '',
  88. // 当前答题卡
  89. cardItem: {},
  90. allItem: [],
  91. // 当前题目内容
  92. quData: {
  93. answerList: []
  94. },
  95. // 试卷信息
  96. paperData: {
  97. leftSeconds: 99999,
  98. radioList: [],
  99. multiList: [],
  100. judgeList: [],
  101. saqList: []
  102. },
  103. // 单选选定值
  104. radioValue: '',
  105. // 简答题值
  106. saqValue: '',
  107. // 多选选定值
  108. multiValue: [],
  109. // 已答ID
  110. answeredIds: [],
  111. timerFlag: false,
  112. countHour: 0,
  113. countMin: 0,
  114. countSec: 0,
  115. // 动作检测
  116. actionTrigger: 0,
  117. // 页面显示
  118. pageShow: true
  119. }
  120. },
  121. onHide: function() {
  122. // 程序隐藏
  123. this.pageShow = false
  124. },
  125. onShow: function() {
  126. console.log('显示了...')
  127. this.pageShow = true
  128. },
  129. onLoad: function(option) {
  130. this.paperId = option.id;
  131. this.fetchData(this.paperId);
  132. },
  133. mounted() {
  134. // #ifdef H5
  135. var a = document.getElementsByClassName('uni-page-head-hd')[0]
  136. a.style.display = 'none'
  137. // #endif
  138. },
  139. methods: {
  140. textBlur(e) {
  141. this.saqValue = e;
  142. },
  143. showCard() {
  144. // 触发变化
  145. this.actionTrigger = new Date().getTime()
  146. this.$refs.cardDrawer.open()
  147. },
  148. closeCard() {
  149. // 触发变化
  150. this.actionTrigger = new Date().getTime()
  151. this.cardShow = false
  152. },
  153. // 倒计时
  154. countdown() {
  155. // 剩余秒数
  156. const leftSeconds = this.paperData.leftSeconds
  157. // 转换时分
  158. this.countHour = parseInt(leftSeconds / 60 / 60)
  159. this.countMin = parseInt(leftSeconds / 60 % 60)
  160. this.countSec = parseInt(leftSeconds % 60)
  161. // 开始计时
  162. this.timerFlag = true
  163. },
  164. // 填充已答标签
  165. handleRest(fill) {
  166. this.cardItem.answered = fill
  167. this.actionTrigger = new Date().getTime()
  168. },
  169. // 答题卡样式
  170. cardItemClass(answered, quId) {
  171. if (quId === this.cardItem.quId) {
  172. return 'warning'
  173. }
  174. if (answered) {
  175. return 'success'
  176. }
  177. if (!answered) {
  178. return 'info'
  179. }
  180. },
  181. /**
  182. * 统计有多少题没答的
  183. * @returns {number}
  184. */
  185. countNotAnswered() {
  186. let notAnswered = 0
  187. // 判断全部未答
  188. this.paperData.groupList.forEach(function(item) {
  189. item.quList.forEach(function(qu) {
  190. if (!qu.answered) {
  191. notAnswered += 1
  192. }
  193. })
  194. })
  195. return notAnswered
  196. },
  197. // 上一题下一题
  198. handleNext(num) {
  199. let index = 0
  200. for (let i = 0; i < this.allItem.length; i++) {
  201. if (this.allItem[i].id === this.quData.id) {
  202. index = i
  203. }
  204. }
  205. index += num
  206. this.fetchQuData(this.allItem[index])
  207. },
  208. doHandler(flag) {
  209. // 打开
  210. uni.showLoading({
  211. title: '阅卷中...'
  212. });
  213. const params = {
  214. id: this.paperId,
  215. handFlag: flag
  216. }
  217. handExam(params).then(() => {
  218. uni.showToast({
  219. title: '交卷成功!',
  220. icon: 'none',
  221. duration: 2000
  222. });
  223. // 查看考试详情
  224. uni.redirectTo({
  225. url: '/pages/paper/detail?id=' + this.paperId
  226. });
  227. uni.hideLoading()
  228. })
  229. },
  230. // 交卷操作
  231. handHandExam() {
  232. const that = this
  233. const notAnswered = that.countNotAnswered()
  234. let msg = '确认要交卷吗?'
  235. if (notAnswered > 0) {
  236. msg = '您还有' + notAnswered + '题未作答,确认要交卷吗?'
  237. }
  238. uni.showModal({
  239. title: '提示',
  240. content: msg,
  241. success: function(res) {
  242. if (res.confirm) {
  243. that.doHandler(0)
  244. }
  245. }
  246. });
  247. },
  248. // 更新上下一题索引
  249. refreshIndex(item) {
  250. if (item.id === this.allItem[0].id) {
  251. this.showPrevious = false
  252. } else {
  253. this.showPrevious = true
  254. }
  255. // 最后一个索引
  256. const last = this.allItem.length - 1
  257. if (item.id === this.allItem[last].id) {
  258. this.showNext = false
  259. } else {
  260. this.showNext = true
  261. }
  262. },
  263. // 试卷详情
  264. fetchQuData(item) {
  265. // 打开
  266. uni.showLoading({
  267. title: '加载中...'
  268. });
  269. // 刷新索引
  270. this.refreshIndex(item)
  271. // 获得详情
  272. this.cardItem = item
  273. paperQuDetail(this.paperId, item.quId).then(data => {
  274. this.quData = data
  275. // 关闭详情
  276. uni.hideLoading()
  277. // 切换题目后滑动到顶部
  278. uni.pageScrollTo({
  279. duration: 500,
  280. scrollTop: 0
  281. })
  282. }).catch(err => {
  283. console.log(err)
  284. // 试题被删除
  285. if (err.code === 20010001) {
  286. setTimeout(() => {
  287. uni.switchTab({
  288. url: '/pages/exam/index'
  289. });
  290. }, 1500)
  291. }
  292. })
  293. // 触发变化
  294. this.actionTrigger = new Date().getTime()
  295. },
  296. // 试卷详情
  297. fetchData(id) {
  298. // 打开
  299. uni.showLoading({
  300. title: '加载中...'
  301. });
  302. paperDetail(id).then(data => {
  303. // 试卷内容
  304. this.paperData = data
  305. // 已经考完了,不允许
  306. if (this.paperData.state !== 0) {
  307. this.$router.push({
  308. name: 'ShowExam',
  309. params: {
  310. id: this.paperData.id
  311. }
  312. })
  313. }
  314. const that = this
  315. // 展开全部题目
  316. this.paperData.groupList.forEach(function(item) {
  317. item.quList.forEach(function(qu) {
  318. that.allItem.push(qu)
  319. })
  320. })
  321. if (!that.allItem || that.allItem.length == 0) {
  322. uni.showModal({
  323. title: '试卷内容出现问题,无法继续考试!',
  324. content: msg,
  325. success: function(res) {
  326. if (res.confirm) {
  327. }
  328. }
  329. });
  330. return
  331. }
  332. this.cardItem = that.allItem[0]
  333. // 当前选定
  334. this.fetchQuData(this.cardItem)
  335. // 倒计时
  336. this.countdown()
  337. })
  338. }
  339. }
  340. }
  341. </script>
  342. <style>
  343. .content1 {
  344. padding: 15px;
  345. padding-bottom: 60px;
  346. }
  347. </style>