test.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. <template>
  2. <view class="container">
  3. <view class="topBox">
  4. <view class="topMain" v-if="testList.length>0">
  5. <view class="testTitle">
  6. <view>{{serialIndex+1}}、</view>
  7. <view class="titleStyle">{{typeDice[testList[serialIndex].type]}}</view>
  8. <view class="questionTypes">{{testList[serialIndex].title}}</view>
  9. </view>
  10. <view class="topic">
  11. {{testList[serialIndex].questionStem}}
  12. </view>
  13. <view class="answer">
  14. <!--填空 -->
  15. <view v-if="testList[serialIndex].type=='gap'">
  16. <view v-for="(item,index) in testList[serialIndex].option" :key="index" class="gapStyle">
  17. <uni-easyinput v-model="testList[serialIndex].option[index].answer" placeholder="请输入您的答案"
  18. @input='changeInput' />
  19. </view>
  20. </view>
  21. <!--论述 -->
  22. <view v-else-if="testList[serialIndex].type=='discuss'">
  23. <uni-easyinput type="textarea" maxlength='-1' autoHeight v-model="testList[serialIndex].answer"
  24. placeholder="请输入您的答案" @input='changeInput' />
  25. </view>
  26. <!--单选判断 -->
  27. <view v-else-if="testList[serialIndex].type=='single'||testList[serialIndex].type=='judge'">
  28. <view class="singleClass" v-for="(item,index) in testList[serialIndex].option" :key="index">
  29. <view class="mark" @click="changeSingleIndex(item.id)"
  30. :class="{active: testList[serialIndex].answer==item.id}">
  31. <!-- :class="{active: testList[serialIndex].answer!=''||testList[serialIndex].answer=='0'?index == testList[serialIndex].answer:false}"> -->
  32. {{option[index]}}
  33. </view>
  34. <view style="width: 90%;margin-top: 10rpx;">
  35. {{item.content}}
  36. </view>
  37. </view>
  38. </view>
  39. <!--多选 -->
  40. <view v-else-if="testList[serialIndex].type=='multiple'">
  41. <view class="singleClass" v-for="(item,index) in testList[serialIndex].option" :key="index">
  42. <view class="mark" :class="{active: testList[serialIndex].answer.indexOf(item.id) != -1}"
  43. @click="changeMultipleIndex(item.id)">
  44. {{option[index]}}
  45. </view>
  46. <view style="width: 90%;margin-top: 10rpx;">
  47. {{item.content}}
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. <view>
  53. <button type="primary" class="buttonStyle" @click="nextQuestion">确认下一题</button>
  54. </view>
  55. </view>
  56. </view>
  57. <view class="footer">
  58. <view class="footer_left footer_flex">
  59. <view @click="paper" class="cursorStyle">
  60. <uni-icons type="upload" size="20" color="#606266" class="iconMargin"></uni-icons> 交卷
  61. </view>
  62. </view>
  63. <view class="footer_center footer_flex">
  64. <uni-countdown ref="countDown" :show-day="false" :hour="0" :minute="second" :second="mini"
  65. class="iconMargin" @timeup="handPaper">
  66. </uni-countdown>
  67. </view>
  68. <view class="footer_right footer_flex">
  69. <view @click="popupNumber">
  70. <uni-icons type="wallet" size="20" color="#606266" class="iconMargin"></uni-icons>
  71. {{serialIndex+1}}/{{testList.length}}
  72. </view>
  73. </view>
  74. </view>
  75. <uni-popup ref="popupNumber" type="left">
  76. <view class="popupMain">
  77. <uni-icons type="closeempty" size="20" class="iPosition" @click="popupClose"></uni-icons>
  78. <view class="fontTitile">
  79. 答题目录
  80. </view>
  81. <view class="hr"></view>
  82. <view class="serial">
  83. <view class="mark" v-for="(item,index) in testList" :key="index" @click="changeIndex(index)"
  84. :class="{active: index == serialIndex}">
  85. {{index+1}}
  86. </view>
  87. </view>
  88. </view>
  89. </uni-popup>
  90. </view>
  91. </template>
  92. <script>
  93. import {
  94. startExam,
  95. answerSheet
  96. } from "../../utils/url.js";
  97. export default {
  98. data() {
  99. return {
  100. second: 10,
  101. mini: 0,
  102. // 题型字典
  103. typeDice: {
  104. single: '单选题',
  105. multiple: '多选题',
  106. judge: '判断题',
  107. gap: '填空题',
  108. discuss: '论述题',
  109. },
  110. // 选项前标签
  111. option: {
  112. 0: 'A',
  113. 1: 'B',
  114. 2: 'C',
  115. 3: 'D',
  116. 4: 'E',
  117. 5: 'F',
  118. 6: 'G',
  119. 7: 'H',
  120. 8: 'I',
  121. 9: 'J',
  122. 10: 'K',
  123. 11: 'L',
  124. 12: 'M',
  125. 13: 'N',
  126. 14: 'O',
  127. 15: 'P',
  128. 16: 'Q',
  129. 17: 'R',
  130. 18: 'S',
  131. 19: 'T',
  132. 20: 'U',
  133. 21: 'V',
  134. 22: 'W',
  135. 23: 'X',
  136. 24: 'Y',
  137. 25: 'Z'
  138. },
  139. //当前题的索引
  140. serialIndex: 0,
  141. //单选single 多选multiple 判断judge 填空gap 论述discuss
  142. testList: [
  143. // {
  144. // type: 'gap',
  145. // title: '驾校题',
  146. // questionStem: '驾驶人连续驾驶机动车超过__小时,停车休息时间不得少于__分钟',
  147. // answer: '',
  148. // option: [{
  149. // tiankong: '',
  150. // },
  151. // {
  152. // tiankong: '',
  153. // }
  154. // ]
  155. // },
  156. // {
  157. // type: 'single',
  158. // title: '初一数学',
  159. // questionStem: '一个多边形的每个内角都是144度,这个多边形是()',
  160. // answer: '',
  161. // option: [{
  162. // content: '八边形'
  163. // },
  164. // {
  165. // content: '十边形'
  166. // },
  167. // {
  168. // content: '十二边形'
  169. // },
  170. // {
  171. // content: '十四边形'
  172. // },
  173. // ]
  174. // },
  175. // {
  176. // type: 'multiple',
  177. // title: '初一政治',
  178. // questionStem: '学生学习的三个基本资料本领域包括()',
  179. // answer: [],
  180. // option: [{
  181. // content: '认知'
  182. // },
  183. // {
  184. // content: '情感'
  185. // },
  186. // {
  187. // content: '意识'
  188. // },
  189. // {
  190. // content: '动作技能'
  191. // },
  192. // ]
  193. // },
  194. // {
  195. // type: 'judge',
  196. // title: '驾校题',
  197. // questionStem: '驾驶人连续驾驶机动车超过4小时,停车休息时间不得少于20分钟',
  198. // answer: '',
  199. // option: [{
  200. // content: '正确'
  201. // },
  202. // {
  203. // content: '错误'
  204. // },
  205. // ]
  206. // },
  207. // {
  208. // type: 'discuss',
  209. // title: '论述题',
  210. // questionStem: '谈一谈对学校的看法',
  211. // answer: '',
  212. // option: [{
  213. // tiankong: ''
  214. // }, ]
  215. // },
  216. ],
  217. }
  218. },
  219. onLoad: function(option) { //option为object类型,会序列化上个页面传递的参数
  220. let data = uni.getStorageSync("examData");
  221. let res = uni.getStorageSync("user");
  222. this.second = parseInt(data.paperPeriod);
  223. this.examId = data.id;
  224. let paperData = uni.getStorageSync("paper");
  225. this.studentTestPaperId = paperData.id;
  226. this.changePaperData(paperData.paper.testQuestionsList);
  227. //存在未答试卷
  228. if (option.paper) {
  229. let parmar = uni.getStorageSync("testData");
  230. this.compareTest(parmar);
  231. let seIndex=uni.getStorageSync("serialIndex");
  232. if(seIndex)
  233. {
  234. this.serialIndex=seIndex;
  235. }
  236. }
  237. uni.setStorageSync("oldExamId",data.id);
  238. uni.setStorageSync("oldExamType",data.examType);
  239. uni.setStorageSync("oldLoginName",res.loginName);
  240. uni.setStorageSync("examFlg",1);
  241. // console.log(data.id,'data');
  242. // console.log(res.loginName,'res');
  243. // examFlg
  244. // uni.setStorageSync("examId",);
  245. // if (option.paper) {
  246. // let paperData = uni.getStorageSync("paper");
  247. // this.studentTestPaperId = paperData.id;
  248. // console.log(paperData, 'paperData');
  249. // this.changePaperData(paperData.paper.testQuestionsList);
  250. // } else {
  251. // // console.log(option.paperPeriod, 'option.paperPeriod');
  252. // // this.second = 1;
  253. // this.$refs.countDown.update();
  254. // this.getExam(res.examId, res.loginName, res.loginPassword)
  255. // }
  256. },
  257. onShow() {
  258. uni.setStorageSync("isStop", true);
  259. this.time = this.getTime();
  260. },
  261. methods: {
  262. compareTest(parmar) {
  263. if(!parmar){
  264. return false
  265. }
  266. let is = true;
  267. if (parmar.length === this.testList.length) {
  268. this.testList.map((item, index) => {
  269. if (item.id != parmar[index].id) {
  270. is = false;
  271. }
  272. })
  273. if (is) {
  274. this.testList = parmar;
  275. }
  276. }
  277. },
  278. getTime() {
  279. let date = new Date(),
  280. year = date.getFullYear(),
  281. month = date.getMonth() + 1,
  282. day = date.getDate(),
  283. hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(),
  284. minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(),
  285. second = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
  286. month >= 1 && month <= 9 ? (month = "0" + month) : "";
  287. day >= 0 && day <= 9 ? (day = "0" + day) : "";
  288. let timer = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
  289. return timer;
  290. },
  291. async getExam(examId, loginName, loginPassword) {
  292. uni.showLoading({
  293. title: '加载中'
  294. });
  295. let data = await startExam(examId, loginName, loginPassword);
  296. uni.hideLoading();
  297. this.studentTestPaperId = data.data.id;
  298. this.changePaperData(data.data.paper.testQuestionsList);
  299. },
  300. // qaq 问答题
  301. // singleChoice 单选题
  302. // judgment 判断题
  303. // cloze 填空题
  304. // multipleChoice 多选题
  305. changePaperData(data) {
  306. this.testList = [];
  307. for (var key in data) {
  308. if (data[key]) {
  309. switch (key) {
  310. case 'qaq':
  311. data[key].map(item => {
  312. this.testList.push({
  313. type: 'discuss',
  314. id: item.id,
  315. title: item.courseName,
  316. questionStem: item.stem,
  317. answer: '',
  318. })
  319. });
  320. break;
  321. case 'singleChoice':
  322. data[key].map(item => {
  323. this.testList.push({
  324. type: 'single',
  325. id: item.id,
  326. title: item.courseName,
  327. questionStem: item.stem,
  328. answer: '',
  329. option: item.testAnswerList.map(it => {
  330. return {
  331. id: it.id,
  332. content: it.answer
  333. }
  334. })
  335. })
  336. });
  337. break;
  338. case 'judgment':
  339. data[key].map(item => {
  340. this.testList.push({
  341. type: 'judge',
  342. id: item.id,
  343. title: item.courseName,
  344. questionStem: item.stem,
  345. answer: '',
  346. option: item.testAnswerList.map(it => {
  347. return {
  348. id: it.id,
  349. content: it.answer
  350. }
  351. })
  352. })
  353. });
  354. break;
  355. case 'cloze':
  356. data[key].map(item => {
  357. this.testList.push({
  358. type: 'gap',
  359. id: item.id,
  360. title: item.courseName,
  361. questionStem: item.stem,
  362. answer: '',
  363. option: item.testAnswerList.map(it => {
  364. return {
  365. answer: ''
  366. }
  367. })
  368. })
  369. });
  370. break;
  371. case 'multipleChoice':
  372. data[key].map(item => {
  373. this.testList.push({
  374. type: 'multiple',
  375. id: item.id,
  376. title: item.courseName,
  377. questionStem: item.stem,
  378. answer: [],
  379. option: item.testAnswerList.map(it => {
  380. return {
  381. id: it.id,
  382. content: it.answer
  383. }
  384. })
  385. })
  386. });
  387. break;
  388. default:
  389. break;
  390. }
  391. }
  392. }
  393. },
  394. paper() {
  395. let that = this;
  396. uni.showModal({
  397. title: '提醒',
  398. content: '确实交卷吗?',
  399. success: function(res) {
  400. if (res.confirm) {
  401. that.goPerformance();
  402. // alert('用户点击确认');
  403. } else if (res.cancel) {
  404. // alert('用户点击取消');
  405. }
  406. }
  407. })
  408. },
  409. popupNumber() {
  410. this.$refs.popupNumber.open()
  411. },
  412. popupClose() {
  413. this.$refs.popupNumber.close()
  414. },
  415. async goPerformance() {
  416. let answers = [];
  417. // let indexList=[];
  418. let accomplish = false;
  419. this.testList.map((item, index) => {
  420. // single: '单选题', answer里存索引
  421. // multiple: '多选题',answer里存数组
  422. // judge: '判断题',answer里存索引
  423. // gap: '填空题',答案存在option里面
  424. // discuss: '论述题',answer里存答案
  425. switch (item.type) {
  426. case 'single':
  427. if (item.answer) {} else {
  428. accomplish = true;
  429. }
  430. if (item.answer == "" || item.answer == null || item
  431. .answer == undefined) {
  432. accomplish = true;
  433. } else {
  434. answers.push({
  435. id: item.id,
  436. answer: item.answer
  437. })
  438. }
  439. break;
  440. case 'multiple':
  441. if (item.answer && item.answer.length > 0) {
  442. answers.push({
  443. id: item.id,
  444. answer: item.answer.join(',')
  445. })
  446. } else {
  447. accomplish = true;
  448. }
  449. break;
  450. case 'judge':
  451. if (item.answer) {} else {
  452. accomplish = true;
  453. }
  454. if (item.answer == "" || item.answer == null || item
  455. .answer == undefined) {
  456. accomplish = true;
  457. } else {
  458. answers.push({
  459. id: item.id,
  460. answer: item.answer
  461. })
  462. }
  463. break;
  464. case 'gap':
  465. answers.push({
  466. id: item.id,
  467. answer: item.option.map(item => {
  468. if (item.answer == "" || item.answer == null || item
  469. .answer == undefined) {
  470. accomplish = true;
  471. } else {
  472. return item.answer
  473. }
  474. }).join(',')
  475. })
  476. break;
  477. case 'discuss':
  478. if (item.answer) {
  479. answers.push({
  480. id: item.id,
  481. answer: item.answer
  482. })
  483. } else {
  484. accomplish = true;
  485. }
  486. break;
  487. default:
  488. break;
  489. }
  490. })
  491. uni.showLoading({
  492. title: '加载中'
  493. });
  494. await answerSheet({
  495. answers: JSON.stringify(answers),
  496. studentTestPaperId: this.studentTestPaperId,
  497. answerBegin: this.time
  498. });
  499. uni.hideLoading();
  500. uni.setStorageSync("isStop", false);
  501. uni.setStorageSync("paper", null);
  502. uni.setStorageSync("examFlg",0);
  503. uni.setStorageSync("testData", null);
  504. uni.redirectTo({
  505. url: '/pages/performance/performance?id=' + this.studentTestPaperId
  506. });
  507. },
  508. answerSheet(data) {
  509. uni.showLoading({
  510. title: '加载中'
  511. });
  512. uni.request({
  513. url: 'http://10.16.4.5:8080/education/app/answerSheet/add',
  514. method: 'POST',
  515. header: {
  516. 'Authorization': "app-829f4a08-d148-4d0f-a4ad-e22695f44426",
  517. // 'Authorization': uni.getStorageSync('token'),
  518. // 'content-type': 'application/x-www-form-urlencoded',
  519. 'content-type': 'application/json'
  520. },
  521. data: data,
  522. success: (response) => {
  523. },
  524. fail: (err) => {
  525. return uni.showToast({
  526. title: '请求接口失败' + err
  527. })
  528. reject(err)
  529. },
  530. complete: () => {
  531. uni.hideLoading();
  532. }
  533. })
  534. },
  535. handPaper() {
  536. let that = this;
  537. if (uni.getStorageSync('isStop')) {
  538. uni.showModal({
  539. title: '提醒',
  540. content: '答题时间到,请交卷!',
  541. showCancel: false,
  542. success: function(res) {
  543. if (res.confirm) {
  544. that.goPerformance();
  545. // alert('用户点击确认');
  546. } else if (res.cancel) {
  547. // alert('用户点击取消');
  548. }
  549. }
  550. })
  551. }
  552. },
  553. //单选判断选中
  554. changeSingleClass(index) {
  555. if (index == this.testList[this.serialIndex].answer) {
  556. return 'active'
  557. }
  558. return ''
  559. },
  560. //单选判断点击事件
  561. changeSingleIndex(id) {
  562. this.testList[this.serialIndex].answer = id;
  563. this.saveTest();
  564. },
  565. changeClass(index) {
  566. if (index == this.serialIndex) {
  567. return 'active'
  568. }
  569. return ''
  570. },
  571. changeIndex(index) {
  572. this.serialIndex = index;
  573. },
  574. changeMultipleClass(item, andList) {
  575. if (this.testList[this.serialIndex].answer.indexOf(item) != -1) {
  576. return 'active'
  577. }
  578. return ''
  579. },
  580. changeMultipleIndex(item) {
  581. if (this.testList[this.serialIndex].answer.indexOf(item) != -1) {
  582. this.testList[this.serialIndex].answer.splice(this.testList[this.serialIndex].answer.indexOf(item), 1)
  583. } else {
  584. this.testList[this.serialIndex].answer.push(item)
  585. }
  586. this.saveTest();
  587. },
  588. nextQuestion() {
  589. let that = this;
  590. if ((this.serialIndex + 1) == this.testList.length) {
  591. uni.showModal({
  592. title: '提醒',
  593. content: '已经是最后一题了,是否交卷?',
  594. success: function(res) {
  595. if (res.confirm) {
  596. that.goPerformance();
  597. // alert('用户点击确认');
  598. } else if (res.cancel) {
  599. // alert('用户点击取消');
  600. }
  601. }
  602. })
  603. } else {
  604. this.serialIndex++;
  605. }
  606. },
  607. //简答、填空发生改变 进行本地缓存
  608. changeInput(e) {
  609. this.saveTest();
  610. },
  611. saveTest() {
  612. uni.setStorageSync("testData", this.testList);
  613. uni.setStorageSync("serialIndex", this.serialIndex);
  614. }
  615. }
  616. }
  617. </script>
  618. <style scoped>
  619. .container {
  620. position: absolute;
  621. height: 100%;
  622. width: 100%;
  623. background-color: #FFFFFF !important;
  624. color: #606266;
  625. }
  626. .topBox {
  627. height: 92%;
  628. background-color: #f7f8fa !important;
  629. }
  630. .footer {
  631. height: 8%;
  632. display: flex;
  633. }
  634. .footer_left {
  635. width: 30%;
  636. }
  637. .footer_center {
  638. width: 60%;
  639. }
  640. .footer_right {
  641. width: 30%;
  642. }
  643. .footer_flex {
  644. display: flex;
  645. justify-content: center;
  646. align-items: center;
  647. }
  648. .iconMargin {
  649. margin-right: 10rpx;
  650. }
  651. .topMain {
  652. width: 80%;
  653. height: 100%;
  654. margin: auto;
  655. display: flex;
  656. flex-direction: column;
  657. }
  658. .testTitle {
  659. display: flex;
  660. }
  661. .titleStyle {
  662. background-color: rgb(245, 166, 35) !important;
  663. padding: 4rpx 24rpx;
  664. border-radius: 5rpx;
  665. color: #FFFFFF;
  666. margin-right: 30rpx;
  667. width: 100rpx;
  668. height: 45rpx;
  669. }
  670. .questionTypes {
  671. padding: 4rpx 0;
  672. }
  673. .topic {
  674. margin: 40rpx 0;
  675. }
  676. .answer {
  677. height: 68%;
  678. overflow-y: auto;
  679. }
  680. .buttonStyle {
  681. width: 100%;
  682. /* margin-top: 60rpx; */
  683. font-size: 30rpx;
  684. background-color: rgb(245, 166, 35) !important;
  685. border-radius: inherit;
  686. }
  687. .cursorStyle {
  688. cursor: pointer;
  689. }
  690. .popupMain {
  691. width: 76vw;
  692. height: 100vh;
  693. background-color: #FFFFFF;
  694. position: relative;
  695. }
  696. .iPosition {
  697. position: absolute;
  698. right: 20rpx;
  699. top: 20rpx
  700. }
  701. .serial {
  702. display: flex;
  703. flex-wrap: wrap;
  704. }
  705. .mark {
  706. width: 50rpx;
  707. height: 50rpx;
  708. text-align: center;
  709. line-height: 50rpx;
  710. border-radius: 50%;
  711. margin: 10rpx;
  712. background-color: #e7ebf3;
  713. color: #000000;
  714. }
  715. .fontTitile {
  716. text-align: center;
  717. padding-top: 60rpx;
  718. }
  719. .hr {
  720. background-color: #dcdfe6;
  721. width: 100%;
  722. height: 2rpx;
  723. margin: 20rpx 0;
  724. }
  725. .active {
  726. background-color: rgb(245, 166, 35);
  727. color: #FFFFFF;
  728. }
  729. .singleClass {
  730. display: flex;
  731. }
  732. .gapStyle {
  733. margin-bottom: 20rpx;
  734. }
  735. </style>