exam.vue 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. <template>
  2. <view class="phone-kaoshi-page">
  3. <customNavbarVue :title="data.ksName" :show-back-btn="true" @back="handleBack"></customNavbarVue>
  4. <!-- 第一行 -->
  5. <view class="kaoshi-page-title">
  6. <view v-if="activeSt" class="title-types">{{dlName}}</view>
  7. <!-- 倒计时 -->
  8. <view v-if="!!data.endSecond">
  9. <uni-countdown :show-day="false" :showHour="true" :showMinute="true" :second="data.endSecond"
  10. @timeup="onTimeUp" :start="startCountDown"></uni-countdown>
  11. </view>
  12. </view>
  13. <view class="kaoshi-shiti-content">
  14. <!-- 内容区域 -->
  15. <!-- 试题区域 -->
  16. <view v-if="activeSt">
  17. <template v-if="activeSt.stTypeId == 1">
  18. <!-- 单选 -->
  19. <danxuan :question="activeSt" :key="activeSt.stId"></danxuan>
  20. </template>
  21. <template v-if="activeSt.stTypeId == 2">
  22. <!-- 多选 -->
  23. <duoxuan :question="activeSt" :key="activeSt.stId"></duoxuan>
  24. </template>
  25. <template v-if="activeSt.stTypeId == 3">
  26. <!-- 判断 -->
  27. <panduan :question="activeSt" :key="activeSt.stId"></panduan>
  28. </template>
  29. <template v-if="activeSt.stTypeId == 4">
  30. <!-- 填空 -->
  31. <tiankong :question="activeSt" :key="activeSt.stId"></tiankong>
  32. </template>
  33. <template v-if="activeSt.stTypeId == 5">
  34. <!-- 简答 -->
  35. <jianda :question="activeSt" :key="activeSt.stId"></jianda>
  36. </template>
  37. <template v-if="activeSt.stTypeId == 6">
  38. <!-- 阅读 -->
  39. <yuedu :question="activeSt" :key="activeSt.stId"></yuedu>
  40. </template>
  41. </view>
  42. </view>
  43. <view class="kaoshi-bottom-box">
  44. <button class="phone-green-btn bj-btn" hover-class="none" type="default" size="mini"
  45. @click="handleBiaoji">{{activeSt && activeSt.marked ? '取标':'标记'}}</button>
  46. <view @click="showAnswerCard" class="shiti-num-box">
  47. <icon class="shiti-num-icon"></icon>
  48. <text class="active-num">{{answercartsCount}}</text>/<text>{{data.StListForSearch.length}}</text>
  49. </view>
  50. <button class="phone-green-btn save-btn" hover-class="none" type="default" size="mini"
  51. @click="handleSave(true)">保存</button>
  52. </view>
  53. <template v-if="activeSt">
  54. <button type="default" size="mini" hover-class="none" class="phone-green-btn ks-btn-prev"
  55. @click="handlePrev" v-if="!isFistStId">上一题</button>
  56. <button type="default" size="mini" hover-class="none" class="phone-green-btn ks-btn-next"
  57. @click="handleNext" v-if="!isLastStId">下一题</button>
  58. </template>
  59. <!-- 答题卡 -->
  60. <uni-popup ref="popupRef" background-color="#fff" :animation="false" :is-mask-click="false" :mask-click="false">
  61. <view class="answer-card-popup">
  62. <view class="icon-title-bjcolor-navBar-box">
  63. <view @click="handlePopupBack" class="nav-bar-icon"> </view>
  64. <text class="nav-bar-title">答题卡</text>
  65. </view>
  66. <view class="card-content-box">
  67. <view class="answer-card-content" v-for="(paragraph,paragraphIndex) in questionData"
  68. :key="paragraphIndex">
  69. <view class="paragraph-title">
  70. {{paragraph.name}}
  71. </view>
  72. <view class="paragraph-qa" v-for="(qa,qaIndex) in paragraph.qas" :key="qaIndex"
  73. :class="getQaClass(qa)" @click="answerCardItemClick(qa)">{{qa.onlyNum}}
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. </uni-popup>
  79. <!-- 摄像头确认 -->
  80. <!-- <zhuapaiConfirm ref="zhuapaiConfirmRef" @success="zpConfirmSuccess" @error="zpConfirmError"
  81. @cancel="zpConfirmCancel" key="1"></zhuapaiConfirm> -->
  82. <!-- <template v-if="data.zhuapai && data.zhuapai > 0"> -->
  83. <!-- 抓拍 -->
  84. <!-- <zhuapaiVue ref="zhuapaiRef" @error="zpError" @success="zpSuccess" key="2" @progress="onProgress"></zhuapaiVue> -->
  85. <!-- </template> -->
  86. <!-- 切屏 -->
  87. <!-- <qiepingVue ref="qiepingRef" @zhuapai="qpZhuapai" @forceSubmit="forceSubmit" @qiepingToast="qiepingToast"
  88. key="3"></qiepingVue> -->
  89. <!-- 交卷确认 -->
  90. <answerQueren ref="answerQrRef" @confirm="handleQuerenConfirm"></answerQueren>
  91. <!-- 考试得分 -->
  92. <submitScoreVue ref="subScoreRef" @confirm="handleScoreConfirm" @close="handleScoreClose"></submitScoreVue>
  93. <!-- 切屏确认弹窗 -->
  94. <!-- <qiepingDlVue ref="qiepingDlRef" :content="messageContent" title="注意" okBtn="知道了"></qiepingDlVue> -->
  95. </view>
  96. </template>
  97. <script setup>
  98. import {
  99. ref,
  100. reactive,
  101. computed,
  102. watch,
  103. nextTick
  104. } from "vue";
  105. import zhuapaiVue from "@/components/zhuapaiConfirm/zhuapai.vue";
  106. import qiepingVue from "@/components/zhuapaiConfirm/qieping.vue";
  107. import zhuapaiConfirm from "@/components/zhuapaiConfirm/index.vue";
  108. import answerQueren from "@/components/zhuapaiConfirm/answerQueren.vue";
  109. import submitScoreVue from "@/components/zhuapaiConfirm/submitScore.vue";
  110. import {
  111. onLoad
  112. } from "@dcloudio/uni-app";
  113. import * as ksApi from "@/api/exam.js"
  114. import danxuan from "@/components/questions/danxuan.vue";
  115. import duoxuan from "@/components/questions/duoxuan.vue";
  116. import tiankong from "@/components/questions/tiankong.vue";
  117. import panduan from "@/components/questions/panduan.vue";
  118. import jianda from "@/components/questions/jianda.vue";
  119. import yuedu from "@/components/questions/yuedu.vue";
  120. import {
  121. useQuestionTools
  122. } from "@/components/questions/useQuestionTools.js";
  123. import {
  124. useKaoShiCache
  125. } from "./examTools"
  126. import qiepingDlVue from "@/components/dialog/qiepingDl.vue";
  127. import customNavbarVue from "@/components/custom-navbar/custom-navbar.vue";
  128. const {
  129. checkDanxuanReply,
  130. checkDuoxuanReply,
  131. checkPanduanReply,
  132. checkTiankongReply,
  133. getLetterByIndex,
  134. checkJiandaReply,
  135. checkYueduReply
  136. } = useQuestionTools();
  137. const {
  138. saveCacheKs,
  139. getCacheKs,
  140. removeCacheKs
  141. } = useKaoShiCache();
  142. onLoad((option) => {
  143. data.ksId = option.ksId;
  144. data.zhuapai = option.zhuapai;
  145. if (data.zhuapai && data.zhuapai != 0) {
  146. // 考试前确认摄像头
  147. nextTick(() => {
  148. // initBeforKaoshi();
  149. })
  150. } else {
  151. console.log('初始化')
  152. initKaoshi();
  153. }
  154. })
  155. const popupRef = ref(null)
  156. const zhuapaiRef = ref(null)
  157. const qiepingRef = ref(null)
  158. const zhuapaiConfirmRef = ref(null)
  159. const answerQrRef = ref(null);
  160. const startCountDown = ref(false);
  161. const subScoreRef = ref(null);
  162. const messageContent = ref('');
  163. const qiepingDlRef = ref(null);
  164. const timer1 = ref(null);
  165. const answercartsCount = ref(0); // 已答题数
  166. const data = reactive({
  167. ksId: null,
  168. operId: null,
  169. ksName: '',
  170. stTotal: 0,
  171. stScore: 0,
  172. biaoji: {},
  173. endSecond: 0,
  174. pageSize: 0,
  175. toggleScreenFlag: 0,
  176. toggleScreenSecond: 0,
  177. zhuapai: 0,
  178. duanluo: [],
  179. StListForSearch: [],
  180. from: '',
  181. hisId: '',
  182. })
  183. const markDB = ref([]);
  184. const questionData = ref([]);
  185. const progress = reactive({
  186. dlIndex: 0,
  187. dtIndex: 0
  188. })
  189. const dlName = computed(() => {
  190. if (data.StListForSearch && activeSt.value) {
  191. return data.StListForSearch[activeSt.value.onlyNum - 1].paragraphName
  192. } else {
  193. return ''
  194. }
  195. })
  196. watch(() => questionData, (newVal) => {
  197. // 计算已答试题数量
  198. renderPage(newVal);
  199. }, {
  200. deep: true
  201. })
  202. function renderPage(data) {
  203. let count = 0;
  204. for (const paragraph of data.value) {
  205. for (const qa of paragraph.qas) {
  206. if (qa.stTypeId == 1) {
  207. if (checkDanxuanReply(qa)) {
  208. count++;
  209. }
  210. } else if (qa.stTypeId == 2) {
  211. if (checkDuoxuanReply(qa)) {
  212. count++;
  213. }
  214. } else if (qa.stTypeId == 3) {
  215. if (checkPanduanReply(qa)) {
  216. count++;
  217. }
  218. } else if (qa.stTypeId == 4) {
  219. if (checkTiankongReply(qa)) {
  220. count++;
  221. }
  222. } else if (qa.stTypeId == 5) {
  223. if (checkJiandaReply(qa)) {
  224. count++;
  225. }
  226. } else if (qa.stTypeId == 4) {
  227. if (checkYueduReply(qa)) {
  228. count++;
  229. }
  230. }
  231. }
  232. }
  233. answercartsCount.value = count;
  234. }
  235. const activeSt = computed(() => {
  236. if (questionData.value.length) {
  237. return questionData.value.length && questionData.value[progress.dlIndex].qas[progress.dtIndex];
  238. } else {
  239. return null
  240. }
  241. })
  242. const isFistStId = computed(() => {
  243. if (data.StListForSearch.length) {
  244. return data.StListForSearch[0].stId == activeSt.value.stId
  245. } else {
  246. return false
  247. }
  248. });
  249. const isLastStId = computed(() => {
  250. if (data.StListForSearch.length) {
  251. return data.StListForSearch[data.StListForSearch.length - 1].stId == activeSt.value.stId
  252. } else {
  253. return false
  254. }
  255. });
  256. function handleScoreClose() {
  257. handleBack()
  258. }
  259. // 考试得分相关 start
  260. function handleScoreConfirm() {
  261. // 跳转成绩
  262. uni.redirectTo({
  263. url: `/pages/client/Chengji/ksScoreShijuan?hisId=${data.hisId}`
  264. })
  265. }
  266. // 考试得分相关 end
  267. // 保存相关
  268. function handleSave(showToast) {
  269. if (timer1.value) {
  270. uni.showToast({
  271. title: '请勿连续保存',
  272. icon: 'none'
  273. })
  274. return
  275. }
  276. timer1.value = setTimeout(() => {
  277. clearTimeout(timer1.value);
  278. }, 10 * 1000);
  279. console.log(questionData.value)
  280. const result = []
  281. const option = {
  282. operId: data.operId,
  283. replyList: []
  284. }
  285. questionData.value.forEach(dl => {
  286. dl.qas.forEach(qa => {
  287. console.log('qa:', qa)
  288. if (qa.stTypeId == 5) {
  289. const opt = {
  290. stId: qa.stId,
  291. files: qa.files,
  292. reply: qa.reply,
  293. }
  294. result.push(opt)
  295. option.replyList.push(opt)
  296. } else if (qa.stTypeId != 6) {
  297. const opt = {
  298. stId: qa.stId,
  299. reply: qa.reply,
  300. }
  301. result.push(opt)
  302. option.replyList.push(opt)
  303. } else {
  304. // 阅读题
  305. let danxuanArr = [];
  306. for (const iDanxuan of qa.danxuan) {
  307. danxuanArr.push(iDanxuan.reply);
  308. }
  309. let duoxuanArr = [];
  310. for (const iDuoxuan of qa.duoxuan) {
  311. duoxuanArr.push(iDuoxuan.reply);
  312. }
  313. let panduanArr = [];
  314. for (const iPanduan of qa.panduan) {
  315. panduanArr.push(iPanduan.reply);
  316. }
  317. let tiankongArr = [];
  318. for (const iTiankong of qa.tiankong) {
  319. tiankongArr.push(iTiankong.reply);
  320. }
  321. let jiandaArr = [];
  322. for (const iJianda of qa.jianda) {
  323. const c = {
  324. files: iJianda.files,
  325. reply: iJianda.reply,
  326. };
  327. jiandaArr.push(c);
  328. }
  329. result.push({
  330. reply: {
  331. danxuan: danxuanArr,
  332. duoxuan: duoxuanArr,
  333. panduan: panduanArr,
  334. tiankong: tiankongArr,
  335. jianda: jiandaArr,
  336. },
  337. stId: qa.stId,
  338. })
  339. option.replyList.push({
  340. reply: {
  341. danxuan: danxuanArr,
  342. duoxuan: duoxuanArr,
  343. panduan: panduanArr,
  344. tiankong: tiankongArr,
  345. jianda: jiandaArr,
  346. },
  347. stId: qa.stId,
  348. });
  349. }
  350. })
  351. })
  352. // 保存试题答案
  353. saveCacheKs(data.operId, {
  354. replyList: result,
  355. position: {
  356. dlIndex: progress.dlIndex,
  357. dtIndex: progress.dtIndex
  358. }
  359. })
  360. // 保存答题进度
  361. ksApi.getClientKsSave(option).then(res => {
  362. if (res.data && showToast) {
  363. uni.showToast({
  364. title: '保存成功',
  365. })
  366. }
  367. })
  368. }
  369. // 交卷相关功能 start
  370. function checkJiaojuan() {
  371. const result = []
  372. let count = 0;
  373. let total = 0;
  374. questionData.value.forEach(item => {
  375. item.qas.forEach(qa => {
  376. total++;
  377. if (qa.stTypeId == 1 && !checkDanxuanReply(qa)) {
  378. count++;
  379. }
  380. if (qa.stTypeId == 2 && !checkDuoxuanReply(qa)) {
  381. count++;
  382. }
  383. if (qa.stTypeId == 3 && !checkPanduanReply(qa)) {
  384. count++;
  385. }
  386. if (qa.stTypeId == 4 && !checkTiankongReply(qa)) {
  387. count++;
  388. }
  389. if (qa.stTypeId == 5 && !checkJiandaReply(qa)) {
  390. count++;
  391. }
  392. if (qa.stTypeId == 6 && !checkYueduReply(qa)) {
  393. count++;
  394. }
  395. })
  396. })
  397. return {
  398. total,
  399. count,
  400. }
  401. }
  402. function handleJiaojuan() {
  403. const result = checkJiaojuan()
  404. if (result.count) {
  405. // 提示
  406. answerQrRef.value.showDialog({
  407. answercartsCount: result.total - result.count,
  408. answercartsTotal: result.total,
  409. })
  410. } else {
  411. handleSubmit()
  412. }
  413. }
  414. function handleQuerenConfirm() {
  415. handleSubmit()
  416. }
  417. function handleSubmit(force = false) {
  418. const result = {
  419. force,
  420. operId: data.operId,
  421. replyList: []
  422. };
  423. questionData.value.forEach(dl => {
  424. dl.qas.forEach(st => {
  425. if (st.stTypeId == 5) {
  426. // 简答题
  427. const opt = {
  428. stId: st.stId,
  429. reply: st.reply,
  430. files: st.files,
  431. }
  432. result.replyList.push(opt)
  433. } else if (st.stTypeId == 6) {
  434. // 阅读题
  435. // 阅读题
  436. let danxuanArr = [];
  437. for (const iDanxuan of qa.danxuan) {
  438. danxuanArr.push(iDanxuan.reply);
  439. }
  440. let duoxuanArr = [];
  441. for (const iDuoxuan of qa.duoxuan) {
  442. duoxuanArr.push(iDuoxuan.reply);
  443. }
  444. let panduanArr = [];
  445. for (const iPanduan of qa.panduan) {
  446. panduanArr.push(iPanduan.reply);
  447. }
  448. let tiankongArr = [];
  449. for (const iTiankong of qa.tiankong) {
  450. tiankongArr.push(iTiankong.reply);
  451. }
  452. let jiandaArr = [];
  453. for (const iJianda of qa.jianda) {
  454. const c = {
  455. files: iJianda.files,
  456. reply: iJianda.reply,
  457. };
  458. jiandaArr.push(c);
  459. }
  460. result.replyList.push({
  461. reply: {
  462. danxuan: danxuanArr,
  463. duoxuan: duoxuanArr,
  464. panduan: panduanArr,
  465. tiankong: tiankongArr,
  466. jianda: jiandaArr,
  467. },
  468. stId: qa.stId,
  469. })
  470. } else {
  471. // 其他
  472. const opt = {
  473. stId: st.stId,
  474. reply: st.reply
  475. }
  476. result.replyList.push(opt)
  477. }
  478. })
  479. })
  480. ksApi.getClientKsSubmit(result).then(res => {
  481. if (res.code == 0) {
  482. subScoreRef.value.showDialog(res.data);
  483. data.hisId = res.data.hisId;
  484. // 清空缓存
  485. removeCacheKs(data.operId);
  486. }
  487. })
  488. }
  489. function onTimeUp() {
  490. handleSubmit();
  491. }
  492. // 交卷相关功能 end
  493. // 切屏功能 start
  494. function qiepingToast(count) {
  495. messageContent.value = `已离开${count}次。${data.toggleScreenFlag}次将自动交卷!`
  496. qiepingDlRef.value.handleShow()
  497. }
  498. function forceSubmit() {
  499. // 强制交卷
  500. console.log('强制交卷')
  501. handleSubmit(true)
  502. }
  503. function qpZhuapai() {
  504. // 重新开启抓拍
  505. zhuapaiRef.value && zhuapaiRef.value.showVideoBtn();
  506. }
  507. // 切屏功能 end
  508. // 摄像头抓拍相关功能 start
  509. function zpSuccess() {}
  510. function zpError() {
  511. uni.showToast({
  512. title: '抓拍图片异常',
  513. icon: 'none'
  514. })
  515. handleBack()
  516. }
  517. // 摄像头抓拍相关功能 end
  518. // 摄像头确认相关功能 start
  519. function onProgress() {
  520. uni.showToast({
  521. icon: 'none',
  522. title: '摄像头运行环境异常,请重新进入考试',
  523. duration: 8000
  524. })
  525. handleBack();
  526. }
  527. function zpConfirmSuccess() {
  528. console.log('zpConfirmSuccess')
  529. initKaoshi();
  530. }
  531. function zpConfirmError() {
  532. handleBack()
  533. }
  534. function zpConfirmCancel() {
  535. handleBack()
  536. }
  537. // 摄像头确认相关功能 end
  538. function getQaClass(qa) {
  539. if (qa.marked && qa.marked === true) {
  540. return 'paragraph-qa-block-mark';
  541. } else {
  542. if (qa.stTypeId == 1) {
  543. if (checkDanxuanReply(qa)) {
  544. return 'paragraph-qa-block-done';
  545. } else {
  546. return 'paragraph-qa-block-init';
  547. }
  548. } else if (qa.stTypeId == 2) {
  549. if (checkDuoxuanReply(qa)) {
  550. return 'paragraph-qa-block-done';
  551. } else {
  552. return 'paragraph-qa-block-init';
  553. }
  554. } else if (qa.stTypeId == 3) {
  555. if (checkPanduanReply(qa)) {
  556. return 'paragraph-qa-block-done';
  557. } else {
  558. return 'paragraph-qa-block-init';
  559. }
  560. } else if (qa.stTypeId == 4) {
  561. if (checkTiankongReply(qa)) {
  562. return 'paragraph-qa-block-done';
  563. } else {
  564. return 'paragraph-qa-block-init';
  565. }
  566. } else if (qa.stTypeId == 5) {
  567. if (checkJiandaReply(qa)) {
  568. return 'paragraph-qa-block-done';
  569. } else {
  570. return 'paragraph-qa-block-init';
  571. }
  572. } else if (qa.stTypeId == 6) {
  573. if (checkYueduReply(qa)) {
  574. return 'paragraph-qa-block-done';
  575. } else {
  576. return 'paragraph-qa-block-init';
  577. }
  578. }
  579. }
  580. }
  581. function skipQuestion(dlIndex, dtIndex) {
  582. progress.dlIndex = dlIndex;
  583. progress.dtIndex = dtIndex;
  584. handlePopupBack()
  585. }
  586. function answerCardItemClick(qa) {
  587. const actQa = data.StListForSearch.find(item => item.stId == qa.stId);
  588. console.log('actQa', actQa)
  589. skipQuestion(actQa.dlIndex, actQa.dtIndex)
  590. }
  591. function handleBack() {
  592. // const pages = getCurrentPages();
  593. // if (pages.length > 1) {
  594. // uni.navigateBack()
  595. // } else {
  596. // history.back();
  597. // }
  598. uni.navigateBack()
  599. }
  600. function showAnswerCard() {
  601. popupRef.value.open('top')
  602. }
  603. function handlePopupBack() {
  604. popupRef.value.close()
  605. }
  606. function handlePrev() {
  607. const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
  608. const index = qa.onlyNum - 1;
  609. if (index > 0) {
  610. const result = data.StListForSearch[index - 1];
  611. progress.dlIndex = result.dlIndex;
  612. progress.dtIndex = result.dtIndex
  613. }
  614. }
  615. function handleNext() {
  616. const qa = data.StListForSearch.find(item => item.stId == activeSt.value.stId);
  617. const index = qa.onlyNum - 1;
  618. if (index < data.StListForSearch.length) {
  619. const result = data.StListForSearch[index + 1];
  620. progress.dlIndex = result.dlIndex;
  621. progress.dtIndex = result.dtIndex
  622. }
  623. }
  624. function formatDuanluoList(dlData) {
  625. let uIndex = 0; // 试题onlyNum
  626. let iDuanluo = 0; // 段落onlyNum
  627. let result = [];
  628. for (const duanluo of data.duanluo) {
  629. let paragraph = {
  630. qas: [],
  631. };
  632. paragraph.name = duanluo.name;
  633. let iQa = 0; // 当前试题序号
  634. let order = 0; // 当前题型中第几题
  635. for (const iDanxuan of duanluo.danxuan) {
  636. iDanxuan.type = 'danxuan';
  637. iDanxuan.marked = data.biaoji[iDanxuan.stId] ? true : false;
  638. iDanxuan.onlyNum = uIndex + 1;
  639. iDanxuan.order = order;
  640. iDanxuan.iQa = iQa;
  641. paragraph.qas.push(iDanxuan);
  642. uIndex++;
  643. order++;
  644. iQa++;
  645. data.StListForSearch.push({
  646. stId: iDanxuan.stId,
  647. paragraphName: paragraph.name,
  648. dlIndex: iDuanluo,
  649. dtIndex: iDanxuan.iQa,
  650. onlyNum: iDanxuan.onlyNum
  651. })
  652. }
  653. order = 0;
  654. for (const iDuoxuan of duanluo.duoxuan) {
  655. iDuoxuan.type = 'duoxuan';
  656. iDuoxuan.marked = data.biaoji[iDuoxuan.stId] ? true : false;
  657. iDuoxuan.onlyNum = uIndex + 1;
  658. iDuoxuan.order = order;
  659. paragraph.qas.push(iDuoxuan);
  660. iDuoxuan.iQa = iQa;
  661. iDuoxuan.reply = [];
  662. uIndex++;
  663. order++;
  664. iQa++;
  665. data.StListForSearch.push({
  666. stId: iDuoxuan.stId,
  667. paragraphName: paragraph.name,
  668. dlIndex: iDuanluo,
  669. dtIndex: iDuoxuan.iQa,
  670. onlyNum: iDuoxuan.onlyNum
  671. })
  672. }
  673. order = 0;
  674. for (const iPanduan of duanluo.panduan) {
  675. iPanduan.type = 'panduan';
  676. iPanduan.marked = data.biaoji[iPanduan.stId] ? true : false;
  677. iPanduan.onlyNum = uIndex + 1;
  678. iPanduan.order = order;
  679. paragraph.qas.push(iPanduan);
  680. iPanduan.iQa = iQa;
  681. uIndex++;
  682. order++;
  683. iQa++;
  684. data.StListForSearch.push({
  685. stId: iPanduan.stId,
  686. paragraphName: paragraph.name,
  687. dlIndex: iDuanluo,
  688. dtIndex: iPanduan.iQa,
  689. onlyNum: iPanduan.onlyNum
  690. })
  691. }
  692. order = 0;
  693. for (const iTiankong of duanluo.tiankong) {
  694. iTiankong.type = 'tiankong';
  695. iTiankong.marked = data.biaoji[iTiankong.stId] ? true : false;
  696. iTiankong.onlyNum = uIndex + 1;
  697. iTiankong.order = order;
  698. paragraph.qas.push(iTiankong);
  699. iTiankong.iQa = iQa;
  700. iTiankong.reply = new Array(iTiankong.count).fill('');
  701. uIndex++;
  702. order++;
  703. iQa++;
  704. data.StListForSearch.push({
  705. stId: iTiankong.stId,
  706. paragraphName: paragraph.name,
  707. dlIndex: iDuanluo,
  708. dtIndex: iTiankong.iQa,
  709. onlyNum: iTiankong.onlyNum
  710. })
  711. }
  712. order = 0;
  713. for (const iJianda of duanluo.jianda) {
  714. iJianda.marked = data.biaoji[iJianda.stId] ? true : false;
  715. iJianda.type = 'jianda';
  716. iJianda.onlyNum = uIndex + 1;
  717. iJianda.order = order;
  718. iJianda.iQa = iQa;
  719. paragraph.qas.push(iJianda);
  720. iJianda.reply = '';
  721. uIndex++;
  722. order++;
  723. iQa++;
  724. data.StListForSearch.push({
  725. stId: iJianda.stId,
  726. paragraphName: paragraph.name,
  727. dlIndex: iDuanluo,
  728. dtIndex: iJianda.iQa,
  729. onlyNum: iJianda.onlyNum
  730. })
  731. }
  732. order = 0;
  733. for (const iYuedu of duanluo.yuedu) {
  734. iYuedu.marked = data.biaoji[iYuedu.stId] ? true : false;
  735. iYuedu.type = 'yuedu';
  736. iYuedu.onlyNum = uIndex + 1;
  737. iYuedu.order = order;
  738. iYuedu.iQa = iQa;
  739. if (iYuedu.duoxuan && iYuedu.duoxuan.length) {
  740. iYuedu.duoxuan.map((qIt) => {
  741. qIt.reply = qIt.reply || [];
  742. return qIt
  743. })
  744. }
  745. if (iYuedu.tiankong && iYuedu.tiankong.length) {
  746. iYuedu.tiankong.map((qIt) => {
  747. qIt.reply = new Array(qIt.count).fill('');
  748. return qIt;
  749. });
  750. }
  751. paragraph.qas.push(iYuedu);
  752. iYuedu.reply = [];
  753. uIndex++;
  754. order++;
  755. iQa++;
  756. data.StListForSearch.push({
  757. stId: iYuedu.stId,
  758. paragraphName: paragraph.name,
  759. dlIndex: iDuanluo,
  760. dtIndex: iYuedu.iQa,
  761. onlyNum: iYuedu.onlyNum
  762. })
  763. }
  764. iDuanluo++;
  765. questionData.value.push(paragraph)
  766. }
  767. }
  768. function handleBiaoji() {
  769. activeSt.value.marked = !activeSt.value.marked;
  770. data.biaoji[activeSt.value.stId] = activeSt.value.marked
  771. ksApi.getClientKaoshiBiaoji({
  772. operId: data.operId,
  773. biaoji: JSON.stringify(data.biaoji)
  774. }).catch(err => {
  775. /* uni.redirectTo({
  776. url: '/pages/client/Kaoshi/list'
  777. }) */
  778. setTimeout(() => {
  779. handleBack()
  780. },1000)
  781. })
  782. }
  783. function formatKaoshiData() {
  784. const historyData = getCacheKs(data.operId);
  785. if (historyData) {
  786. const {
  787. replyList,
  788. position
  789. } = historyData;
  790. if (replyList) {
  791. questionData.value.forEach(dl => {
  792. dl.qas.forEach(st => {
  793. if (st.stTypeId == 5) {
  794. // 简答题
  795. st.reply = replyList.find(item => item.stId == st.stId).reply;
  796. st.files = replyList.find(item => item.stId == st.stId).files;
  797. } else if (st.stTypeId != 6) {
  798. st.reply = replyList.find(item => item.stId == st.stId).reply
  799. } else {
  800. // 阅读题
  801. const hisSt = replyList.find(item => item.stId == st.stId);
  802. if (hisSt) {
  803. st.danxuan.forEach((itm, index) => {
  804. itm.reply = hisSt.reply['danxuan'][index];
  805. })
  806. st.duoxuan.forEach((itm, index) => {
  807. itm.reply = hisSt.reply['duoxuan'][index];
  808. })
  809. st.panduan.forEach((itm, index) => {
  810. itm.reply = hisSt.reply['panduan'][index];
  811. })
  812. st.tiankong.forEach((itm, index) => {
  813. itm.reply = hisSt.reply['tiankong'][index];
  814. })
  815. st.jianda.forEach((itm, index) => {
  816. itm.reply = hisSt.reply['jianda'][index].reply;
  817. itm.files = hisSt.reply['jianda'][index].files;
  818. })
  819. }
  820. }
  821. })
  822. })
  823. }
  824. if (position) {
  825. progress.dlIndex = position.dlIndex;
  826. progress.dtIndex = position.dtIndex;
  827. }
  828. }
  829. }
  830. // 摄像头确认初始化
  831. function initBeforKaoshi() {
  832. console.log(zhuapaiConfirmRef.value)
  833. zhuapaiConfirmRef.value.showDialog()
  834. }
  835. function initKaoshi() {
  836. ksApi.getClientKsStart({
  837. ksId: data.ksId,
  838. }).then(res => {
  839. const {
  840. ksId,
  841. operId,
  842. ksName,
  843. stTotal,
  844. stScore,
  845. biaoji,
  846. endSecond,
  847. pageSize,
  848. toggleScreenFlag,
  849. toggleScreenSecond,
  850. zhuapai,
  851. duanluoList
  852. } = res.data;
  853. data.ksId = ksId;
  854. data.operId = operId;
  855. data.ksName = ksName;
  856. data.stTotal = stTotal;
  857. data.stScore = stScore;
  858. data.biaoji = biaoji ? JSON.parse(biaoji) : {};
  859. data.endSecond = endSecond;
  860. data.pageSize = pageSize;
  861. data.toggleScreenFlag = toggleScreenFlag;
  862. data.toggleScreenSecond = toggleScreenSecond;
  863. // data.zhuapai = zhuapai;
  864. data.duanluo = duanluoList;
  865. formatDuanluoList(data.duanluo);
  866. // 设置缓存
  867. formatKaoshiData();
  868. // 设置抓拍监听
  869. // if (data.zhuapai && data.zhuapai > 0) {
  870. // zhuapaiRef.value.init({
  871. // zhuapai: zhuapai,
  872. // operId: operId
  873. // });
  874. // }
  875. // 设置切屏监听
  876. // qiepingRef.value.init({
  877. // zhuapaiFlag: !!zhuapai,
  878. // toggleScreenFlag: toggleScreenFlag,
  879. // toggleScreenSecond: toggleScreenSecond,
  880. // ksId: data.ksId
  881. // })
  882. startCountDown.value = true;
  883. uni.setNavigationBarTitle({
  884. title: data.ksName
  885. });
  886. }).catch(err => {
  887. console.log('asdasd', err)
  888. setTimeout(() => {
  889. handleBack()
  890. },1000)
  891. })
  892. }
  893. </script>
  894. <style lang="scss">
  895. .phone-kaoshi-page {
  896. display: flex;
  897. flex-direction: column;
  898. background-color: #f4f6fa;
  899. position: relative;
  900. .kaoshi-page-title {
  901. height: 80rpx;
  902. line-height: 80rpx;
  903. background-color: #fff;
  904. margin-top: 20rpx;
  905. font-size: 26rpx;
  906. color: #333;
  907. display: flex;
  908. justify-content: space-between;
  909. padding: 0 24rpx;
  910. border-bottom: 1rpx solid #ebebeb;
  911. .title-types {
  912. font-size: 32rpx;
  913. color: #000;
  914. }
  915. }
  916. .kaoshi-shiti-content {
  917. padding: 24rpx 24rpx 0 24rpx;
  918. background-color: #fff;
  919. flex: 1;
  920. }
  921. .kaoshi-bottom-box {
  922. width: 100%;
  923. height: 100rpx;
  924. background-color: #f0f0f0;
  925. display: flex;
  926. align-items: center;
  927. justify-content: space-between;
  928. padding: 0 24rpx;
  929. box-sizing: border-box;
  930. position: fixed;
  931. bottom: var(--window-bottom);
  932. .bj-btn,
  933. .jx-btn,
  934. .save-btn {
  935. height: 60rpx;
  936. line-height: 58rpx;
  937. box-sizing: border-box;
  938. }
  939. .bj-btn {
  940. margin-left: unset;
  941. }
  942. .jx-btn,
  943. .save-btn {
  944. margin-right: unset;
  945. }
  946. .shiti-num-icon {
  947. width: 27px;
  948. height: 24px;
  949. vertical-align: middle;
  950. // background-image: url("@/static/images/exam/shiti-num-icon.png");
  951. @include ezy-no-repeat-cover();
  952. }
  953. .active-num {
  954. color: #30c190;
  955. }
  956. }
  957. .ks-btn-prev {
  958. position: fixed;
  959. bottom: 130rpx;
  960. left: 24rpx;
  961. }
  962. .ks-btn-next {
  963. position: fixed;
  964. bottom: 130rpx;
  965. right: 24rpx;
  966. }
  967. }
  968. </style>