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.

656 lines
17 KiB

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