You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

655 lines
17 KiB

5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
2 days ago
5 days ago
  1. <template>
  2. <view class="content">
  3. <up-navbar leftText=" " title="" :safeAreaInsetTop="false" :autoBack="true">
  4. <template #center>
  5. <view class="flex">
  6. <view class="lastText">剩余时间</view>
  7. <view class="lastText" style="margin-left: 8rpx;">4400</view>
  8. </view>
  9. </template>
  10. </up-navbar>
  11. <view class="top_row flex">
  12. <view class="itemCount">
  13. <up-icon name="checkmark-circle-fill" color="#55ff7f" size="20" ></up-icon>
  14. <view class="count">{{ yesNum }}</view>
  15. </view>
  16. <view class="itemCount">
  17. <up-icon name="close-circle-fill" color="#ff0000" size="20" ></up-icon>
  18. <view class="count">{{ noNum }}</view>
  19. </view>
  20. <view class="mr">
  21. <view class="count">{{currentIndex}}/<text>{{questionBankList.length}}</text></view>
  22. </view>
  23. </view>
  24. <view class="con padding">
  25. <view class="h1_row">
  26. <text class="tag" :class="{red: questionBank.types==2, blue: questionBank.types==3}">{{types[questionBank.types-1]}}</text>
  27. <text class="h1" @click="speak(questionBank.title)">{{ questionBank.title}}</text>
  28. </view>
  29. <view class="imgBox" style="width: 100%;padding: 0 0 30rpx 0;" v-if="questionBank.img">
  30. <image :src="questionBank.img" mode="widthFix"></image>
  31. </view>
  32. <view class="option">
  33. <view v-for="(item,index) in questionBank.optionArr" @click="chooseOption(item)">
  34. <!-- 多选题 -->
  35. <view class="optionItem flex" v-if="questionBank.types ==2&& (!curOption.answer||curOption.answer==questionBank.answer)">
  36. <up-icon name="checkmark-circle-fill" color="#55ff7f" size="20" v-if="curOption.ans?.includes(item.key)"></up-icon>
  37. <view class="icon" v-else></view>
  38. <view class="text"><text >{{item.key}}</text> {{item.text}}</view>
  39. </view>
  40. <!-- 正常答案 -->
  41. <view class="optionItem flex" v-else >
  42. <view class="icon" v-if="!curOption.key&&questionBank.types !=2"></view>
  43. <up-icon name="checkmark-circle-fill" color="#55ff7f" size="20" v-else-if="questionBank.answer.includes(item.key)"></up-icon>
  44. <up-icon name="close-circle-fill" color="#ff0000" size="20" v-else></up-icon>
  45. <view class="text"><text v-if="questionBank.types!=3">{{item.key}}</text> {{item.text}}</view>
  46. </view>
  47. <!-- ans -->
  48. </view>
  49. </view>
  50. <view class="answerCss flex" v-if="curOption.answer&&questionBank.answer!=curOption.answer">
  51. <view class="ans">正确答案是
  52. <text v-if="questionBank.types==3" >{{ questionBank.answer=='false'?'错误':'正确' }}</text>
  53. <text v-else >{{ questionBank.answer }}</text>
  54. </view>
  55. <view class="ans">您的答案是
  56. <text v-if="questionBank.types==3" class="red">{{ curOption.answer=='false'?'错误':'正确' }}</text>
  57. <text v-else class="red">{{ curOption.answer }}</text>
  58. </view>
  59. </view>
  60. <view class="btn_row flex-b">
  61. <!-- @click="$goPage('/pages/exercises/lastPage/lastPage')" -->
  62. <button class="btn border" @click="debounce(nextQuestion(-1), 500)" :class="{disable: currentIndex==1}" :disabled="currentIndex==1">上一题</button>
  63. <button class="btn bg" @click="debounce(nextQuestion(1), 500)" :class="{disable: currentIndex>=questionBankList.length}" :disabled="currentIndex>=questionBankList.length">下一题</button>
  64. </view>
  65. <view class="analysis" v-if="currentNav==2||(curOption.answer&&curOption.answer!=questionBank.answer)">
  66. <view class="tit">题目解析</view>
  67. <view class="txt">{{ questionBank.resolving }}</view>
  68. </view>
  69. </view>
  70. <view class="bottomBar">
  71. <view class="ul">
  72. <!-- <view class="li">
  73. <view class="icon" style="color: #55ff7f;">{{ yesNum }}</view>
  74. <view class="text">答对</view>
  75. </view>
  76. <view class="li">
  77. <view class="icon" style="color: #ff0000;">{{ noNum }}</view>
  78. <view class="text">答错</view>
  79. </view>
  80. <view class="li">
  81. <view class="icon">{{currentIndex}}/<text style="color: #999; font-size: 24rpx;">{{quesIdList.length}}</text></view>
  82. <view class="text">题目</view>
  83. </view> -->
  84. <view class="flex leftCotrl">
  85. <view class="li" @click="showCommt=true">
  86. <view class="icon">
  87. <image src="@/static/images/theory/fankui.png" mode=""></image>
  88. </view>
  89. <view class="text">反馈</view>
  90. </view>
  91. <view class="li" @click="openPopup">
  92. <view class="icon">
  93. <image src="@/static/images/theory/dtk.png" mode=""></image>
  94. </view>
  95. <view class="text">答题卡</view>
  96. </view>
  97. <view class="li" @click="questionWrongColleFn">
  98. <view class="icon">
  99. <image src="@/static/images/theory/scActive.png" mode="" v-if="questionBank.isCollect=='1'"></image>
  100. <image src="@/static/images/theory/sc.png" mode="" v-else></image>
  101. </view>
  102. <view class="text">收藏</view>
  103. </view>
  104. </view>
  105. <view class="submitBtn">交卷</view>
  106. </view>
  107. </view>
  108. <up-popup :show="show" @close="closePopup" @open="openPopup" mode="bottom" round="20" closeable>
  109. <view class="popupCon">
  110. <view class="h3">答题卡</view>
  111. <view class="ulRow">
  112. <view class="ul">
  113. <view class="li">
  114. <view class="icon" style="color: #55ff7f;">{{ yesNum }}</view>
  115. <view class="text">答对</view>
  116. </view>
  117. <view class="li">
  118. <view class="icon" style="color: #ff0000;">{{ noNum }}</view>
  119. <view class="text">答错</view>
  120. </view>
  121. <view class="li" style="margin-left: auto;">
  122. <view class="icon">{{currentIndex}}/<text style="color: #999; font-size: 24rpx;">{{quesIdList.length}}</text></view>
  123. <view class="text">题目</view>
  124. </view>
  125. </view>
  126. </view>
  127. <view class="ul2">
  128. <view class="li2" v-for="(item,index) in questionBankList" :key="index" @click="quesIdListClick(item,index)">
  129. <view class="num" :class="{active: index+1==currentIndex}">{{ index+1 }}</view>
  130. </view>
  131. </view>
  132. </view>
  133. </up-popup>
  134. <up-popup :show="showCommt" @close="showCommtClose" mode="bottom" round="20rpx" closeable>
  135. <view class="commtCon" style="padding: 30rpx">
  136. <up-textarea v-model.trim="contentStr" placeholder="请输入反馈内容" style="margin-top: 50rpx;" maxlength="300"></up-textarea>
  137. <up-button text="提 交" style="margin-top: 20rpx;" type="primary" @click="submitCommt"></up-button>
  138. </view>
  139. </up-popup>
  140. </view>
  141. </template>
  142. <script setup>
  143. function speak(text) {
  144. const speech = new SpeechSynthesisUtterance(text); // 创建语音消息
  145. window.speechSynthesis.speak(speech); // 播报消息
  146. }
  147. import { startExam, submitAnswerResultApi, getQuestionApi, questionCommentAdd, startExamDo, questionWrongColle } from '@/config/api.js'
  148. import { debounce } from '@/uni_modules/uview-plus';
  149. import {
  150. ref,
  151. reactive,
  152. watch
  153. } from 'vue';
  154. const currentNav = ref('1')
  155. const types = ref([
  156. '单选题',
  157. '多选题',
  158. '判断题'
  159. ])
  160. const yesNum = ref(0)
  161. const noNum = ref(0)
  162. import carStore from '@/store/modules/car.js'
  163. let usecarStore = carStore()
  164. import {
  165. onLoad,
  166. onReady
  167. } from "@dcloudio/uni-app"
  168. // 1:单选题,2:多选题,3:判断题
  169. function changeNav(val) {
  170. console.log(window)
  171. if(currentNav.value == val) return
  172. currentNav.value = val
  173. }
  174. function goEmam() {
  175. uni.navigateTo({
  176. // url: '/pages/exercises/exam/exam',
  177. // url: '/pages/exercises/beforeExam/beforeExam',
  178. // url: '/pages/exercises/examResults/examResults',
  179. // url: '/pages/exercises/wrongQuestion/wrongQuestion',
  180. // url: '/pages/exercises/theoryStudy/theoryStudy',
  181. url: '/pages/vip/vipEntry/vipEntry'
  182. })
  183. }
  184. function changeTabbar(val) {
  185. console.log(val)
  186. }
  187. const show = ref(false)
  188. function closePopup() {
  189. show.value = false
  190. }
  191. function openPopup() {
  192. show.value = true
  193. }
  194. let showCommt = ref(false)
  195. let contentStr = ref('')
  196. function showCommtClose() {
  197. showCommt.value = false
  198. contentStr.value = ''
  199. }
  200. // 提交反馈
  201. async function submitCommt() {
  202. if(!contentStr.value) return uni.$u.toast('请输入内容')
  203. let obj = {
  204. content: contentStr.value,
  205. questionId: questionBank.value.id
  206. }
  207. const res = await questionCommentAdd(obj)
  208. if(res.errorcode==0) {
  209. uni.$u.toast('提交成功,感谢您的反馈')
  210. showCommt.value = false
  211. }
  212. }
  213. // 请求数据
  214. const questionBank = ref({})
  215. const questionBankList = ref([])
  216. let quesIdList = ref([])
  217. let currentIndex = ref(1)
  218. async function startQuestionFn() {
  219. try{
  220. uni.showLoading({
  221. title: '正在加载...'
  222. })
  223. let obj = {
  224. carType: usecarStore.carInfo.carType,
  225. stepType: usecarStore.carInfo.stepType,
  226. examType: 1,
  227. }
  228. const {data: res} = await startExam(obj)
  229. uni.hideLoading()
  230. questionBank.value = res.questionBank[0]
  231. questionBankList.value = res.questionBank
  232. initOptionArr()
  233. quesIdList.value = res.quesIdList
  234. }catch(e){
  235. uni.hideLoading()
  236. }
  237. }
  238. startQuestionFn()
  239. watch(()=>questionBankList, (newVal, oldVal)=>{
  240. yesNum.value = oldVal.value.filter(item=>item.yes).length
  241. noNum.value = oldVal.value.filter(item=>item.yes==0).length
  242. }, {deep: true})
  243. function initOptionArr() {
  244. questionBank.value.optionArr = []
  245. let abcd = [
  246. 'a',
  247. 'b',
  248. 'c',
  249. 'd',
  250. 'e',
  251. 'f'
  252. ]
  253. abcd.forEach((k,i)=>{
  254. let option = 'option'+k
  255. if(questionBank.value[option]) {
  256. let obj = {
  257. key: k.toLocaleUpperCase(),
  258. text: questionBank.value[option],
  259. index: i+1
  260. }
  261. questionBank.value.optionArr.push(obj)
  262. // console.log(questionBank.value.optionArr)
  263. }
  264. })
  265. // 如果是判断题
  266. if(questionBank.value.types==3) {
  267. questionBank.value.optionArr[0].key = 'true'
  268. questionBank.value.optionArr[1].key = 'false'
  269. }
  270. }
  271. // 下一题
  272. async function nextQuestion(num) {
  273. // 如果是多选题,什么时候不直接请求下一题,是多选题 ,并且有答案,答错了,并且不是next
  274. if(questionBank.value.types==2 && curOption.value.ans) {
  275. // 如果没有请求就请求一下
  276. if(!curOption.value.answer) {
  277. curOption.value.answer = curOption.value.ans
  278. await submitAnswerResultFn()
  279. }
  280. // 如果答案不一样,并且是第一次请求
  281. if(questionBank.value.answer != curOption.value.ans&&curOption.value.isNext != 'next') {
  282. curOption.value.isNext = 'next'
  283. return false
  284. }
  285. }
  286. curOption.value = {}
  287. currentIndex.value = currentIndex.value + num
  288. getQuestionFn()
  289. }
  290. // 请求下一题
  291. async function getQuestionFn() {
  292. console.log(currentIndex.value)
  293. // let questionId = quesIdList.value[currentIndex.value-1]
  294. // let obj = {
  295. // "carType": usecarStore.carInfo.carType,
  296. // "questionId": questionId,
  297. // "sort": currentIndex.value,
  298. // "stepType": usecarStore.carInfo.stepType,
  299. // 'tempId': questionBank.value.questionDoTemp.id
  300. // }
  301. // const {data: res} = await getQuestionApi(obj)
  302. questionBank.value = questionBankList.value[currentIndex.value]
  303. curOption.value.isNext = ''
  304. initOptionArr()
  305. }
  306. async function quesIdListClick(id, index) {
  307. curOption.value = {}
  308. currentIndex.value = index + 1
  309. getQuestionFn()
  310. show.value = false
  311. }
  312. async function questionWrongColleFn() {
  313. let isAdd = questionBank.value.isCollect==1?'0':'1'
  314. const obj = {
  315. "carType": usecarStore.carInfo.carType,
  316. "isAdd": isAdd,
  317. "questionId": questionBank.value.id,
  318. "stepType": usecarStore.carInfo.stepType
  319. }
  320. const res = await questionWrongColle(obj)
  321. questionBank.value.isCollect = isAdd
  322. console.log(questionBank.value.isCollect)
  323. }
  324. // 选择答案
  325. const curOption = ref({})
  326. async function chooseOption(item) {
  327. console.log(item)
  328. if(curOption.value.answer) return
  329. if(questionBank.value.types != 2) {
  330. // 如果答案正确 下一题
  331. if(questionBank.value.answer==item.key) {
  332. questionBank.value.yes = 1
  333. currentIndex.value = currentIndex.value + 1
  334. curOption.value = {}
  335. getQuestionFn()
  336. }else {
  337. item.answer = item.key
  338. curOption.value = item
  339. questionBank.value.yes = 0
  340. }
  341. }else if(questionBank.value.types == 2){
  342. if(!curOption.value.ans) curOption.value.ans = ''
  343. if(curOption.value.ans.includes(item.key)) {
  344. curOption.value.ans = curOption.value.ans.replace(item.key, '')
  345. return
  346. }
  347. curOption.value.ans = curOption.value.ans + item.key
  348. // console.log(curOption.value.ans)
  349. }
  350. }
  351. // 提交请求
  352. async function submitAnswerResultFn() {
  353. let obj = {
  354. answer: curOption.value.answer,
  355. carType: 'car',
  356. questionId: questionBank.value.id,
  357. result: '0',
  358. stepType: 1,
  359. tempId: questionBank.value.questionDoTemp.id
  360. }
  361. const res = await submitAnswerResultApi(obj)
  362. if(res.errorcode!=0) return
  363. if(curOption.value.answer==questionBank.value.answer) {
  364. console.log('答对了')
  365. curOption.value = {}
  366. yesNum.value ++
  367. nextQuestion(1)
  368. }else {
  369. noNum.value ++
  370. }
  371. // console.log(res)
  372. }
  373. </script>
  374. <style lang="scss" scoped>
  375. .top_row {
  376. height: 88rpx;
  377. font-weight: 500;
  378. font-size: 24rpx;
  379. color: #333333;
  380. border-bottom: 2rpx solid #F4F4F4;
  381. padding: 0 30rpx;
  382. margin-bottom: 30rpx;
  383. .itemCount {
  384. margin-right: 60rpx;
  385. display: flex;
  386. align-items: center;
  387. .count {
  388. margin-left: 20rpx;
  389. }
  390. }
  391. .mr {
  392. margin-left: auto;
  393. }
  394. }
  395. image {display: block;width: 100%;height: 100%;}
  396. .bottomBar {
  397. position: fixed;
  398. bottom: 0;
  399. left: 0;
  400. width: 100%;
  401. height: 98rpx;
  402. background: #FFFFFF;
  403. border-top: 1rpx solid #F4F4F4;
  404. }
  405. .ul {
  406. display: flex;
  407. justify-content: space-between;
  408. height: 100%;
  409. align-items: center;
  410. .leftCotrl {
  411. flex: 1;
  412. }
  413. .submitBtn {
  414. width: 100rpx;
  415. height: 50rpx;
  416. background: linear-gradient(0deg, #4FACFE 0%, #00F2FE 100%);
  417. border-radius: 25rpx;
  418. font-size: 24rpx;
  419. line-height: 50rpx;
  420. text-align: center;
  421. margin-right: 32rpx;
  422. color: #fff;
  423. }
  424. .li {
  425. // width: 16.6%;
  426. padding: 0 30rpx;
  427. display: flex;
  428. flex-direction: column;
  429. align-items: center;
  430. justify-content: center;
  431. .icon {
  432. font-size: 30rpx;
  433. height: 30rpx;
  434. line-height: 30rpx;
  435. image {
  436. display: block;
  437. margin-top: 4rpx;
  438. width: 26rpx;
  439. height: 26rpx;
  440. }
  441. }
  442. .text {
  443. font-weight: 500;
  444. font-size: 24rpx;
  445. color: #999999;
  446. margin-top: 10rpx;
  447. }
  448. }
  449. }
  450. .content {
  451. padding: 120rpx 0;
  452. min-height: 100vh;
  453. .u-nav-slot {
  454. width: 306rpx;
  455. height: 54rpx;
  456. border-radius: 10rpx;
  457. border: 1px solid #333333;
  458. display: flex;
  459. .btn {
  460. font-size: 24rpx;
  461. color: #333333;
  462. flex: 1;
  463. text-align: center;
  464. line-height: 54rpx;
  465. &.active {
  466. background-color: #333333;
  467. color: #fff;
  468. }
  469. }
  470. }
  471. .btn_row {
  472. padding: 60rpx 0 30rpx 0;
  473. .btn {
  474. width: 44%;
  475. height: 76rpx;
  476. border-radius: 38rpx;
  477. border: 1rpx solid $themC;
  478. line-height: 76rpx;
  479. text-align: center;
  480. font-size: 28rpx;
  481. color: $themC;
  482. &.disable {
  483. opacity: 0.4;
  484. }
  485. &.bg {
  486. background: #3776FF;
  487. border-radius: 38rpx;
  488. color: #fff;
  489. }
  490. }
  491. }
  492. .con {
  493. .h1_row {
  494. margin-bottom: 50rpx;
  495. .tag {
  496. display: inline-block;
  497. // width: 66px;
  498. height: 36rpx;
  499. line-height: 36rpx;
  500. padding: 4rpx 6rpx;
  501. background: #63C168;
  502. border-radius: 6rpx;
  503. margin-top: -2rpx;
  504. margin-right: 16rpx;
  505. font-size: 28rpx;
  506. color: #fff;
  507. &.blue {
  508. background: #3776FF;
  509. }
  510. &.red {
  511. background: orangered;
  512. }
  513. }
  514. text.h1 {
  515. font-size: 36rpx;
  516. }
  517. }
  518. .option {
  519. width: 100%;
  520. .optionItem {
  521. margin-bottom: 50rpx;
  522. align-items: center;
  523. .icon {
  524. width: 36rpx;
  525. height:36rpx;
  526. border-radius: 50%;
  527. border: 1rpx solid #999;
  528. }
  529. .text {
  530. font-size: 32rpx;
  531. margin-left: 16rpx;
  532. }
  533. }
  534. }
  535. .answerCss {
  536. height: 90rpx;
  537. background: #F4F4F4;
  538. padding: 30rpx;
  539. margin-top: 20rpx;
  540. justify-content: space-around;
  541. .ans {
  542. font-size: 30rpx;
  543. text {
  544. &.red {
  545. color: red;
  546. }
  547. }
  548. }
  549. }
  550. .analysis {
  551. margin-top: 60rpx;
  552. .tit {
  553. font-weight: 700;
  554. font-size: 32rpx;
  555. position: relative;
  556. padding-left: 30rpx;
  557. &::after {
  558. content: '';
  559. position: absolute;
  560. left: 0;
  561. top: 8rpx;
  562. width: 6rpx;
  563. height: 30rpx;
  564. background: linear-gradient(0deg, #43EA80 0%, #38F8D4 100%);
  565. border-radius: 3rpx;
  566. }
  567. }
  568. .txt {
  569. margin-top: 39rpx;
  570. font-size: 32rpx;
  571. color: #333333;
  572. }
  573. }
  574. }
  575. }
  576. .popupCon {
  577. width: 100%;
  578. height: calc(100vh - 200rpx);
  579. .h3 {
  580. height: 88rpx;
  581. border-bottom: 1px solid #F4F4F4;
  582. line-height: 88rpx;
  583. font-size: 30rpx;
  584. padding: 0rpx 0 0 30rpx;
  585. }
  586. .ulRow {
  587. height: 100rpx;
  588. padding: 30rpx 0;
  589. }
  590. .ul2 {
  591. display: flex;
  592. flex-wrap: wrap;
  593. padding: 30rpx 10rpx;
  594. height: calc(100vh - 388rpx);
  595. overflow-y: auto;
  596. .li2 {
  597. width: 16.6%;
  598. margin-bottom: 20rpx;
  599. .num {
  600. width: 100rpx;
  601. height: 100rpx;
  602. border-radius: 50%;
  603. margin: auto;
  604. background: #F6F7FA;
  605. font-size: 32rpx;
  606. line-height: 100rpx;
  607. text-align: center;
  608. &.active {
  609. border: 1px solid #63C168;
  610. background: rgba(99,193,104,0.1);
  611. color: #63C168;
  612. }
  613. }
  614. }
  615. }
  616. }
  617. </style>