paperQuestionInfo.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. <template>
  2. <view class="paperQuestionInfo-container">
  3. <template v-if="currentQuestion.questionId">
  4. <view class="box-body">
  5. <view style=" background: #fff; padding: 30rpx 32rpx;">
  6. <view class="head">
  7. <view class="tit">{{ currentQuestion.typeName }}({{ currentQuestion.questionScore }}分)</view>
  8. <view class="count">{{ currentIndex + 1 }}/{{ questionList.length }}</view>
  9. </view>
  10. <view class="item-content">
  11. {{ currentQuestion.name }}
  12. </view>
  13. <view class="option">
  14. <!-- 复选 -->
  15. <u-checkbox-group
  16. v-model="currentQuestion.useAnswer"
  17. v-if="currentQuestion.type === 2"
  18. :disabled="isExplain"
  19. placement="column"
  20. @change="checkboxChange">
  21. <u-checkbox
  22. :customStyle="{ marginBottom: '16px' }"
  23. v-for="(item, index) in currentQuestionOption"
  24. :key="index"
  25. :label="item.label"
  26. :name="item.value">
  27. </u-checkbox>
  28. </u-checkbox-group>
  29. <!-- 单选 -->
  30. <u-radio-group
  31. v-model="currentQuestion.useAnswer"
  32. v-else
  33. placement="column"
  34. :disabled="isExplain"
  35. @change="checkboxChange">
  36. <u-radio
  37. :customStyle="{ marginBottom: '16px' }"
  38. v-for="(item, index) in currentQuestionOption"
  39. :key="index"
  40. :label="item.label"
  41. :name="item.value">
  42. </u-radio>
  43. </u-radio-group>
  44. </view>
  45. </view>
  46. <view style=" background: #fff; padding: 30rpx 32rpx;margin-top: 20rpx;" v-if="isExplain">
  47. <view class="head">
  48. <view class="tit">答题解析</view>
  49. </view>
  50. <!-- 解析 -->
  51. <view class="explain">
  52. <!-- <view class="explain-content">你的选择:{{ getanswer(currentQuestion.useAnswer) }}</view> -->
  53. <view class="explain-title">正确答案:{{ getanswer(currentQuestion.answer) }}</view>
  54. <view class="explain-content">得分:{{ currentQuestion.score }}分</view>
  55. </view>
  56. </view>
  57. </view>
  58. <!-- 底部 -->
  59. <view class="operation">
  60. <u-button text="上一题" :disabled="currentIndex === 0" @click="previousQuestion"></u-button>
  61. <u-button text="答题卡" @click="show = true"></u-button>
  62. <u-button text="下一题" @click="nextQuestion"
  63. v-if="currentIndex < questionList.length - 1"></u-button>
  64. <u-button type="primary" @click="saveUserPaper"
  65. v-if="currentIndex === questionList.length - 1 && !isExplain" text="立即交卷"></u-button>
  66. </view>
  67. </template>
  68. <!-- 答题卡 -->
  69. <u-popup :show="show" @close="close" @open="open" v-if="!isExplain">
  70. <view class="answer-cardsheet">
  71. <view class="item-box" v-for="(item, index) in questionList">
  72. <view class="item" @click="toCurrentIndex(index)"
  73. :class="{ 'item1': item.useAnswer, 'item2': index === currentIndex }" :key="index">{{ index + 1
  74. }}
  75. </view>
  76. </view>
  77. <view class="button-box">
  78. <u-button text="继续答题" @click="close"></u-button>
  79. <u-button type="primary" @click="saveUserPaper" text="立即交卷"></u-button>
  80. </view>
  81. </view>
  82. </u-popup>
  83. <!-- 解析答题卡 -->
  84. <u-popup :show="show" @close="close" @open="open" v-if="isExplain">
  85. <view class="answer-cardsheet">
  86. <view class="item-box" v-for="(item, index) in questionList">
  87. <view class="item" @click="toCurrentIndex(index)"
  88. :class="{ 'item1': item.status === 1, 'item3': item.status === 0 }" :key="index">{{ index + 1
  89. }}
  90. </view>
  91. </view>
  92. <view class="button-box">
  93. <u-button type="primary" @click="close" text="关闭"></u-button>
  94. </view>
  95. </view>
  96. </u-popup>
  97. <!-- 确认提示框 -->
  98. <u-popup :show="warnShow" @close="warnShow = false" @open="warnShow = true">
  99. <view class="answer-cardsheet">
  100. <view class="is-sub">
  101. <u-icon type="warn" class="error-circle-fill" name="error-circle-fill" size="24"
  102. color="#fb6547"></u-icon>
  103. <view class="warn">
  104. <span v-if="notReach">您有{{ notReach }}道题未答,确定提交吗?</span>
  105. <span v-else>试卷提交后不可更改,确定提交吗?</span>
  106. </view>
  107. </view>
  108. <view class="button-box">
  109. <u-button text="取消" @click="warnShow = false"></u-button>
  110. <u-button type="primary" @click="saveUserPaper(true)" text="确定"></u-button>
  111. </view>
  112. </view>
  113. </u-popup>
  114. <!-- 结果 -->
  115. <u-popup :show="resultShow" mode="center" :closeOnClickOverlay="false" @close="resultShow = false"
  116. @open="resultShow = true">
  117. <view class="answer-cardsheet">
  118. <view class="is-sub">
  119. <!-- 通过 -->
  120. <template v-if="resultData.viaStatus === 1">
  121. <image
  122. class="result-img"
  123. src="@/static/icon/pass.png"
  124. style="width: 300rpx;height: 300px;"
  125. mode="widthFix"></image>
  126. <view style="font-size: 48rpx;color: red;">
  127. 恭喜您通过考试!
  128. </view>
  129. </template>
  130. <!-- 不通过 -->
  131. <template v-if="resultData.viaStatus === 0">
  132. <image
  133. class="result-img"
  134. src="@/static/icon/not.png"
  135. style="width: 300rpx;height: 300px;"
  136. mode="widthFix"></image>
  137. <view style="font-size: 48rpx;color: red;">
  138. 未通过考试!
  139. </view>
  140. </template>
  141. <view style="font-size: 48rpx;color: brown;margin-top: 10rpx;">
  142. {{ resultData.score }}分
  143. </view>
  144. <view style="margin-top: 30rpx;">
  145. 总分:{{ resultData.totalScore }}分&nbsp;&nbsp;&nbsp;&nbsp;答对:<span style="color: red;">{{
  146. resultData.answerNum
  147. }}</span>/{{ resultData.totalQuestion }}
  148. </view>
  149. </view>
  150. <view class="button-box">
  151. <u-button text="查看解析" @click="userExaminationRecord"></u-button>
  152. <template>
  153. <u-button type="primary" v-if="resultData.useNum === resultData.limitNum" @click="navigateBack"
  154. text="返回"></u-button>
  155. <u-button type="primary" @click="getData" v-else text="再考一次"></u-button>
  156. </template>
  157. </view>
  158. </view>
  159. </u-popup>
  160. <!-- 人脸校验 -->
  161. <tq-face ref="faceRef"
  162. @success="faceSuccess"
  163. @close="faceClose"
  164. ></tq-face>
  165. </view>
  166. </template>
  167. <script>
  168. import { paperQuestionInfo, saveUserPaper, userExaminationRecord, recordByPaperId } from "@/api/learnMobile/index";
  169. export default {
  170. paperQuestionInfo: '',
  171. data() {
  172. return {
  173. oldData: {},
  174. id: '',
  175. recordId: '',
  176. show: false,
  177. warnShow: false,
  178. cardsheet: [],
  179. currentIndex: 0,//当前题下标
  180. currentQuestion: {},
  181. questionList: [],
  182. options: [
  183. // {
  184. // name: '苹果',
  185. // disabled: false
  186. // },
  187. // {
  188. // name: '香蕉',
  189. // disabled: false
  190. // },
  191. // {
  192. // name: '橙子',
  193. // disabled: false
  194. // }, {
  195. // name: '榴莲',
  196. // disabled: false
  197. // }
  198. ],
  199. startTime: '',
  200. notReach: 0,
  201. isPass: false,
  202. resultShow: false,
  203. resultData: {}, //考试结果
  204. isExplain: false ,//是否是解析状态
  205. isValidFace: false, //是否检验人脸
  206. }
  207. },
  208. //计算属性得到当前的题目
  209. computed: {
  210. currentQuestionOption() {
  211. let item = this.questionList[this.currentIndex]
  212. if (item.type === 3) {//判断
  213. return [{
  214. label: '对',
  215. value: '1',
  216. }, {
  217. label: '错',
  218. value: '0',
  219. }]
  220. } else {
  221. return item.option.map(e => {
  222. return {
  223. ...e,
  224. label: e.optionKey + ' ' + e.optionValue,//
  225. value: e.optionKey
  226. }
  227. })
  228. }
  229. },
  230. isAllUseAnswer() {
  231. //判断questionList数组的所有选项都有useAnswer参数值
  232. return this.questionList.every(question => question.useAnswer);
  233. }
  234. },
  235. watch: {
  236. currentIndex: {
  237. handler(newVal) {
  238. let item = this.questionList[newVal]
  239. this.$nextTick(() => {
  240. console.log('用户答案', item.useAnswer)
  241. this.currentQuestion = item
  242. })
  243. }
  244. }
  245. },
  246. onLoad({ id, recordId, paperStatus }) {
  247. this.id = id
  248. if (!this.recordId) {
  249. this.recordId = recordId
  250. }
  251. let status = paperStatus * 1
  252. if (status === 0) { //未作答
  253. this.getData()
  254. } else if (status === 1) { //已作答
  255. this.recordByPaperId()
  256. } else {
  257. this.userExaminationRecord()
  258. }
  259. // this.getData();
  260. // this.userExaminationRecord();
  261. // this.recordByPaperId()
  262. this.startTime = this.dayjs().format('YYYY-MM-DD HH:mm:ss')
  263. },
  264. methods: {
  265. /**获取结果 */
  266. async recordByPaperId() {
  267. let { data, code } = await recordByPaperId({
  268. paperId: this.id
  269. })
  270. if (code == '0') {
  271. this.resultShow = true
  272. this.resultData = data
  273. }
  274. },
  275. getanswer(e) {
  276. if (e === '0') return '错'
  277. if (e === '1') return '对'
  278. return e
  279. },
  280. /**查看考试记录信息(试题解析) */
  281. async userExaminationRecord() {
  282. let { data, code } = await userExaminationRecord({
  283. recordId: this.recordId
  284. })
  285. if (code == '0') {
  286. this.questionList = data.questionList.map(e => {
  287. return {
  288. ...e,
  289. useAnswer: e.type === 2 ? e.useAnswer.split(',') : e.useAnswer
  290. }
  291. })
  292. this.currentQuestion = this.questionList[0]
  293. this.currentIndex = 0
  294. this.resultShow = false
  295. this.isExplain = true
  296. }
  297. },
  298. navigateBack() {
  299. uni.navigateBack()
  300. },
  301. async saveUserPaper(is) { //提交试卷
  302. this.show = false
  303. if (!is) { //非直接提交 判断
  304. this.notReach = this.questionList.filter(e => !e.useAnswer).length
  305. return this.warnShow = true //提示框
  306. }
  307. this.warnShow = false
  308. let datas = this.questionList.map(e => {
  309. return {
  310. ...e,
  311. useAnswer: e.useAnswer ? e.useAnswer.toString() : ''
  312. }
  313. })
  314. if(!this.isValidFace) {
  315. this.openFace()
  316. }
  317. let { data, code } = await saveUserPaper({
  318. ...this.oldData,
  319. questionList: datas,
  320. startTime: this.startTime,
  321. })
  322. if (code == '0') {
  323. this.resultShow = true
  324. this.resultData = data
  325. this.recordId = data.recordId
  326. }
  327. },
  328. previousQuestion() {
  329. this.currentIndex--
  330. },
  331. nextQuestion() {
  332. this.currentIndex++
  333. },
  334. async getData() {
  335. let { data, code } = await paperQuestionInfo({
  336. id: this.id
  337. })
  338. if (code == '0') {
  339. this.questionList = data.questionList
  340. this.currentQuestion = this.questionList[0]
  341. this.oldData = data
  342. this.resultShow = false
  343. }
  344. },
  345. toCurrentIndex(e) {
  346. this.currentIndex = e
  347. },
  348. checkboxChange(e) {
  349. console.log('选择', e)
  350. },
  351. open() {
  352. // console.log('open');
  353. },
  354. close() {
  355. this.show = false
  356. // console.log('close');
  357. },
  358. openFace() {
  359. this.$refs.faceRef.show()
  360. },
  361. faceClose() {
  362. uni.navigateBack()
  363. },
  364. faceSuccess() {
  365. this.isValidFace = true
  366. this.saveUserPaper(true)
  367. }
  368. }
  369. }
  370. </script>
  371. <style lang="scss" scoped>
  372. .paperQuestionInfo-container {
  373. .head {
  374. border-left: solid 10rpx #2979FF;
  375. display: flex;
  376. align-items: center;
  377. justify-content: space-between;
  378. padding-left: 20rpx;
  379. .tit {
  380. font-size: 36rpx;
  381. font-weight: bolder;
  382. color: #333;
  383. }
  384. }
  385. .box-body {
  386. .item-content {
  387. padding: 40rpx 0 20rpx 0;
  388. color: #333;
  389. }
  390. }
  391. .operation {
  392. display: flex;
  393. position: fixed;
  394. bottom: 0;
  395. width: 100%;
  396. left: 0;
  397. }
  398. .answer-cardsheet {
  399. display: flex;
  400. flex-wrap: wrap;
  401. padding-top: 20rpx;
  402. max-height: 400px;
  403. overflow-y: auto;
  404. // justify-content: space-between;
  405. .item-box {
  406. display: flex;
  407. justify-content: center;
  408. width: 20%;
  409. .item {
  410. width: 80rpx;
  411. height: 80rpx;
  412. border: 1px solid #9e9b9b;
  413. border-radius: 50%;
  414. flex-shrink: 0;
  415. display: flex;
  416. align-items: center;
  417. justify-content: center;
  418. margin: 20rpx 0;
  419. }
  420. .item1 {
  421. //已答 正确
  422. background: rgba(60, 156, 255, 0.4);
  423. border: 1px solid rgba(60, 156, 255, 0.4);
  424. color: #2979FF;
  425. }
  426. .item2 {
  427. //当前
  428. background: #fff;
  429. color: #2979FF;
  430. border: 1px solid rgba(60, 156, 255, 0.4);
  431. }
  432. .item3 {
  433. //错误
  434. background: rgba(217, 159, 159, 0.5);
  435. border: 1px solid rgba(217, 159, 159, 0.5);
  436. color: rgba(255, 25, 25, 0.337);
  437. }
  438. }
  439. .button-box {
  440. margin-top: 20rpx;
  441. display: flex;
  442. width: 100%;
  443. }
  444. }
  445. .is-sub {
  446. display: flex;
  447. justify-content: center;
  448. flex-direction: column;
  449. padding: 40rpx 0;
  450. width: 100%;
  451. text-align: center;
  452. .error-circle-fill {
  453. margin: 0 auto;
  454. }
  455. .warn {
  456. font-size: 32rpx;
  457. margin-top: 12rpx;
  458. }
  459. .result-img {
  460. margin: 0 auto;
  461. }
  462. }
  463. .explain {
  464. margin-top: 20px;
  465. }
  466. }
  467. </style>