exam.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. <template>
  2. <view class="content">
  3. <view id="top-box" class="cu-bar bg-white solid-bottom">
  4. <view class="action text-black">
  5. <uni-tag
  6. :text="currentQuestionName"
  7. type="error" :circle="true">
  8. </uni-tag>
  9. </view>
  10. <view class="action">
  11. <button class="cu-btn bg-green shadow"
  12. @tap="commitPaperQuestion" data-target="modalCard">提 交</button>
  13. </view>
  14. </view>
  15. <view class="cu-modal" :class="modalCard=='modalCard'?'show':''" @tap="hideCardModal">
  16. <view class="cu-dialog" @tap.stop>
  17. <scroll-view class="page padding" :scroll-y=true :style="{'height':swiperHeight}" >
  18. <view class="cu-bar solid-bottom">
  19. <view class="action">
  20. <text class="cuIcon-title text-red"></text>答题卡
  21. </view>
  22. </view>
  23. <!-- :class="[item.userInfoAnswer === item.asnwer ? 'line-grey':'bg-red']" -->
  24. <view class="grid col-5 ">
  25. <view class="margin-tb-sm text-center"
  26. v-for="(item, index) in paperQuestionList" :key="index">
  27. <button class="cu-btn round"
  28. :class="{
  29. 'line-green': item.userInfoAnswer,
  30. }"
  31. @click="appointedQuestion(index)" >{{index + 1}}</button>
  32. </view>
  33. </view>
  34. </scroll-view>
  35. </view>
  36. </view>
  37. <view class="cu-modal padding " :class="modalError=='modalError'?'show':''" @tap="hideErrorModal">
  38. <view class="cu-dialog bg-white" @tap.stop>
  39. <view class="cu-bar solid-bottom ">
  40. <view class="action">
  41. <text class="cuIcon-title text-red"></text>试题纠错
  42. </view>
  43. </view>
  44. <textarea @blur="bindTextAreaBlur" :value="questionError" auto-height /></textarea>
  45. <!-- <text class="dialog-text">输入内容:{{value}}</text> -->
  46. <!-- <radio-group class="block" >
  47. <view class="cu-list menu text-left">
  48. <view class="cu-item cu-item-error" v-for="error in errorList" >
  49. <radio :value="error"></radio>
  50. <view class="title text-black margin-left">{{error}}</view>
  51. </view>
  52. </view>
  53. </radio-group>
  54. -->
  55. <view class="padding flex flex-direction ">
  56. <button class="cu-btn bg-red margin-tb-sm lg" @click="SubmitError">提 交</button>
  57. </view>
  58. </view>
  59. </view>
  60. <form>
  61. <swiper
  62. :current="questionIndex"
  63. class="swiper-box" @change="swiperChange" :style="{'height':swiperHeight}">
  64. <swiper-item v-for="(questionInfo, index) in paperQuestionList">
  65. <scroll-view class="scroll-v list" :style="{'height':swiperHeight}" :scroll-y="true">
  66. <view class="cu-bar bg-white solid-bottom">
  67. <view class="action text-black">
  68. <!-- <uni-tag text="1"></uni-tag> -->
  69. <!-- <div>1.</divs> -->
  70. <!-- App端(vue页面V3编译模式)和H5端支持v-html,其他端不支持v-html。-->
  71. <view class="questionInfo_content" style="margin-top: 15px; display: inline-block;">
  72. <!-- <uParse :className="'uParse'" :content="questionInfo.content"/> -->
  73. <rich-text class="uParse" :nodes="questionInfo.content"></rich-text>
  74. </view>
  75. </view>
  76. </view>
  77. <view>
  78. <!-- 判断题 -->
  79. <radio-group
  80. v-if="questionInfo.question_type === 6"
  81. class="block" @change="radioboxChange">
  82. <view class="cu-form-group" >
  83. <radio
  84. value="1"
  85. :checked="questionInfo.userInfoAnswer === 1"></radio>
  86. <view class="title text-black">对</view>
  87. </view>
  88. <!-- :disabled="questionInfo.userInfoAnswer !== ''" -->
  89. <view class="cu-form-group">
  90. <radio
  91. value="0"
  92. :checked="questionInfo.userInfoAnswer === 0"></radio>
  93. <view class="title text-black">错</view>
  94. </view>
  95. </radio-group>
  96. <!-- 单选题 -->
  97. <radio-group
  98. v-if="questionInfo.question_type === 3"
  99. class="block" @change="radioboxChange">
  100. <view class="cu-form-group" v-for="item in questionInfo.options">
  101. <radio
  102. :value="item.value"
  103. :checked="item.userInfoAnswer === item.value">{{item.option}}</radio>
  104. <view class="title text-black"></view>
  105. </view>
  106. </radio-group>
  107. <checkbox-group
  108. v-if="questionInfo.question_type === 4"
  109. class="block" @change="checkboxChange">
  110. <view class="cu-form-group" v-for="item in questionInfo.options">
  111. <checkbox
  112. :value="item.value"
  113. :checked="item.userInfoAnswer === item.value"></checkbox>
  114. <view class="title text-black">{{item.option}}</view>
  115. </view>
  116. </checkbox-group>
  117. </view>
  118. <view v-show="questionInfo.showAnswerFlag" class="margin-top solid-top">
  119. <view class="cu-bar">
  120. <view class="action text-grey">
  121. <text>正确答案:</text>
  122. <uParse :content="questionInfo.show_answer"/>
  123. <!-- <view v-html="questionInfo.show_answer" ></view> -->
  124. <!-- <text class="solid-bottom padding-left text-green">{{subject.answer}}</text> -->
  125. </view>
  126. </view>
  127. <view class="cu-bar cu-bar-title">
  128. <view class="action text-grey">
  129. <text>解析:</text>
  130. </view>
  131. </view>
  132. <view
  133. class="text-content padding text-grey">
  134. <uParse :content="questionInfo.analysis"/>
  135. </view>
  136. </view>
  137. </scroll-view>
  138. </swiper-item>
  139. </swiper>
  140. </form>
  141. <view id="foot-box" class="cu-bar tabbar bg-white shadow foot">
  142. <view class="action" @tap="showErrorModal" data-target="modalError">
  143. <view class="cuIcon-cu-image">
  144. <text class="lg text-gray cuIcon-warn"></text>
  145. </view>
  146. <view class="text-gray">纠错</view>
  147. </view>
  148. <view class="action" @tap="showCardModal"data-target="modalCard">
  149. <uni-icons type="compose" size="30"></uni-icons>
  150. <view :class="[userFavor?'text-red':'text-gray']">答题卡</view>
  151. </view>
  152. <view class="action" @click="changeQuestionInfo(-1)">
  153. <view class="cuIcon-cu-image">
  154. <text class="lg cuIcon-back text-gray"></text>
  155. </view>
  156. <view class="text-gray">上一题</view>
  157. </view>
  158. <view class="action" @click="changeQuestionInfo(1)">
  159. <view class="cuIcon-cu-image">
  160. <text class="lg text-gray cuIcon-right"></text>
  161. </view>
  162. <view class="text-gray">下一题</view>
  163. </view>
  164. <!-- <view class="action" @click="showAnswerChange">
  165. <view class="cuIcon-cu-image">
  166. <text class="lg text-gray cuIcon-question"></text>
  167. </view>
  168. <view class="text-gray">解答</view>
  169. </view> -->
  170. </view>
  171. <uni-popup :show="showCommitErrorMsg" type="center" :custom="true" :mask-click="false">
  172. <view class="uni-tip">
  173. <view class="uni-tip-title">提示</view>
  174. <view class="uni-tip-content">{{commitErrorMsg}}</view>
  175. <view class="uni-tip-group-button">
  176. <view @click="showCommitErrorMsg = false" class="uni-tip-button">取消</view>
  177. <view @click="goToUserForm" class="uni-tip-button">确定</view>
  178. </view>
  179. </view>
  180. </uni-popup>
  181. <uni-popup
  182. :show="userFormFlag"
  183. type="center"
  184. :custom="true" :mask-click="false">
  185. <view class="uni-tip">
  186. <view class="uni-tip-title">完善信息</view>
  187. <view class="uni-tip-content">
  188. <view class="form-container-box">
  189. <!-- 待用活动表单 -->
  190. <active-form
  191. :formDate="formDate"
  192. @sure-btn="sure" @input-val="inputVal">
  193. </active-form>
  194. <cover-view class="submit-data">
  195. {{submitData}}
  196. </cover-view>
  197. <view style="margin: 100rpx; color: red;">
  198. 温馨提示: 请准确填写相关信息帮助系统对您或您的孩子生成精准学习分析报告和推荐的学习路径
  199. </view>
  200. </view>
  201. </view>
  202. <view class="uni-tip-group-button">
  203. <view @click="userFormFlag = false" class="uni-tip-button">取消</view>
  204. <view @click="submitForm" class="uni-tip-button">确定</view>
  205. </view>
  206. </view>
  207. </uni-popup>
  208. </view>
  209. </template>
  210. <script>
  211. import uniTag from '@/components/uni-tag/uni-tag.vue'
  212. import uniPopup from '@/components/uni-popup/uni-popup.vue'
  213. import uniIcons from '@/components/uni-icons/uni-icons.vue'
  214. import activeForm from '@/components/userInfo/active_form.vue'
  215. import uParse from '@/components/uParse/src/wxParse.vue'
  216. import { mapGetters } from 'vuex'
  217. export default {
  218. components: {uniTag, uniPopup, uniIcons, uParse, activeForm},
  219. data() {
  220. return {
  221. // showCommitErrorMsg1: false,
  222. userFormFlag: false,
  223. submitData: "",
  224. formDate: [
  225. {
  226. placeholder: "请输入姓名",
  227. label: "姓名",
  228. type: "text",
  229. rules: {
  230. name: "name",
  231. value: "",
  232. verify: "req",
  233. errMess: "请输入姓名"
  234. }
  235. },
  236. {
  237. placeholder: "请输入就读学校",
  238. label: "就读学校",
  239. type: "text",
  240. rules: {
  241. name: "from_school_name",
  242. value: "",
  243. verify: "req",
  244. errMess: "请输入就读学校"
  245. }
  246. },
  247. {
  248. placeholder: "请填写联系方式",
  249. label: "手机号",
  250. type: "number",
  251. rules: {
  252. name: "mobile",
  253. value: "",
  254. verify: "req|phone",
  255. errMess: "手机号填写不正确"
  256. }
  257. }],
  258. direction: 'prop',
  259. questionError: '',
  260. studentExamTimer: null,
  261. studentExamTime: 0, // 学生考试用时
  262. userQuestionList: [],
  263. commitErrorMsg: '',
  264. showCommitErrorMsg: false,
  265. paperQuestionList: [], // 试卷试题列表
  266. questionTotal: 0, // 试题数量
  267. currentQuestionName: '', // 当前试题名称
  268. userFavor:false,//是否已收藏
  269. currentType: 0, //当前题型
  270. questionIndex: 0,//跳转索引
  271. autoShowAnswer: false,//答错是否显答案
  272. autoRadioNext:true,//判断题、单项题,自动移下一题
  273. swiperHeight: '800px',//
  274. title: '',
  275. examParams: null,
  276. // subjectList:[],
  277. modalCard: null ,//显示答题卡
  278. modalError: null , //纠错卡
  279. errorList:['题目不完整', '答案不正确', '含有错别字', '图片不存在', '解析不完整', '其他错误']
  280. }
  281. },
  282. computed: {
  283. ...mapGetters({
  284. fromSchoolId: 'paper/getFromSchoolId',
  285. paperInfo: 'paper/getPaperInfo'
  286. })
  287. },
  288. onReady() {
  289. var tempHeight = 800;
  290. var _me = this;
  291. uni.getSystemInfo({
  292. //获取手机屏幕高度信息,让swiper的高度和手机屏幕一样高                
  293. success: function(res) {
  294. tempHeight = res.windowHeight;
  295. uni.createSelectorQuery().select("#top-box").fields({
  296. size: true,
  297. scrollOffset: true
  298. }, (data) => {
  299. tempHeight -= data.height;
  300. uni.createSelectorQuery().select("#foot-box").fields({
  301. size: true,
  302. scrollOffset: true
  303. }, (data) => {
  304. tempHeight -= data.height;
  305. _me.swiperHeight = tempHeight + 'px';
  306. }).exec();
  307. }).exec();
  308. }
  309. });
  310. },
  311. destroyed () {
  312. clearInterval(this.studentExamTimer)
  313. },
  314. onLoad() {
  315. uni.setNavigationBarTitle({
  316. title: this.paperInfo ? this.paperInfo.name : 'test测试'
  317. })
  318. this.getPaperQuestionList()
  319. this.studentExamTimer = setInterval(() => {
  320. this.startCountStudentExamTime() // 开始计算考试时间
  321. }, 1000)
  322. },
  323. methods: {
  324. submitForm () {
  325. // 表单验证 可选项 otherPra:otherPra
  326. var otherPra = {
  327. reqEmptyVal: true,
  328. }
  329. if (this.$vervify({
  330. formDate: this.formDate,
  331. otherPra: otherPra
  332. })
  333. ) {
  334. let formArray = []
  335. this.formDate.forEach(item => {
  336. let itemValue = item.rules
  337. if (itemValue.name === 'sex') {
  338. if (itemValue.value === '男') {
  339. itemValue.value = 1
  340. } else if (itemValue.value === '女') {
  341. itemValue.value = 0
  342. }
  343. }
  344. formArray.push({
  345. name: itemValue.name,
  346. value: itemValue.value,
  347. })
  348. })
  349. uni.showLoading({
  350. title: '正在生成测试报告, 请稍后...'
  351. })
  352. this.$httpApi.post('/front/potentialStudentInfo', {formList: formArray, fromSchoolId: parseInt(this.fromSchoolId)})
  353. .then(response => {
  354. if (response.code === 1) {
  355. let studentId = response.data
  356. this.$store.commit('paper/updateStudentId', response.data)
  357. this.sendCommitQuestionHttp(studentId)
  358. } else {
  359. uni.hideLoading()
  360. setTimeout(() => {
  361. uni.showToast({
  362. title: response.message
  363. })
  364. }, 100)
  365. }
  366. })
  367. }
  368. },
  369. sendCommitQuestionHttp (studentId) {
  370. let form = this.examParams
  371. form.potentialStudentInfoId = studentId
  372. this.$httpApi.post('/front/aiCt/commitAiPaperQuestion', form)
  373. .then(response => {
  374. uni.hideLoading()
  375. if (response.code === 1) {
  376. uni.showToast({
  377. icon: 'none',
  378. title: '报告生成成功'
  379. })
  380. setTimeout(() => {
  381. // 跳转测评报告结果页
  382. uni.redirectTo({
  383. url: 'ctReport'
  384. })
  385. }, 100)
  386. } else {
  387. uni.showToast({
  388. icon: 'none',
  389. title: '报告生成失败'
  390. })
  391. }
  392. })
  393. },
  394. bindTextAreaBlur (e) {
  395. this.questionError = e.detail.value
  396. },
  397. startCountStudentExamTime () {
  398. this.studentExamTime++
  399. },
  400. // 获取试卷试题列表
  401. getPaperQuestionList () {
  402. let params = {
  403. sqlId: 'test.paper.question.info.list',
  404. testPaperInfoId: this.paperInfo.id //
  405. }
  406. this.$httpApi.get('/front/paper/getQuestionByPaperId', params)
  407. .then(response => {
  408. //if (response.data.code === 1) {
  409. this.paperQuestionList = response.data
  410. if (this.paperQuestionList.length > 0) {
  411. // 添加字段是否显示答案
  412. this.paperQuestionList.forEach(item => {
  413. item.content= item.content.replace(/\<img/g,'<img style="max-width: 100%;height:auto;"');
  414. this.$set(item, "showAnswerFlag", false);
  415. // 区分 传递到后台的试题答案和显示在前端的试题答案 item.answer
  416. this.$set(item, "show_answer", item.answer);
  417. })
  418. this.questionTotal = this.paperQuestionList.length
  419. this.currentQuestionName = this.paperQuestionList[0].questionName
  420. }
  421. //}
  422. })
  423. },
  424. // 提交试题
  425. commitPaperQuestion () {
  426. let noAnswerQuestionNumber = 0 // 未答题数
  427. this.paperQuestionList.forEach(question => {
  428. if (!question.userInfoAnswer) {
  429. noAnswerQuestionNumber++
  430. }
  431. let userQuestionInfo = {
  432. questionInfoId: question.id,
  433. questionAnswer: question.answer, // 试题答案
  434. questionType: question.question_type, // 试题类型
  435. answerEnclosure: [], // 答案附件
  436. mark: question.mark, // 试题得分
  437. userInfoAnswer: question.userInfoAnswer, //学员试题答案
  438. languagePointsId: question.language_points_id
  439. }
  440. this.userQuestionList.push(userQuestionInfo)
  441. })
  442. if (noAnswerQuestionNumber > 0) {
  443. this.commitErrorMsg = '亲,你还有' + noAnswerQuestionNumber + '道试题未作答,确定提交吗?'
  444. this.showCommitErrorMsg = true
  445. } else {
  446. this.commitErrorMsg = '亲, 确定提交吗?'
  447. this.showCommitErrorMsg = true
  448. }
  449. },
  450. goToUserForm () {
  451. clearInterval(this.studentExamTimer) // 清除定时器
  452. let form = {
  453. studentQuestionAnswerList: this.userQuestionList,
  454. testPaperId: this.paperInfo.id,
  455. subjectId: this.paperInfo.subject_id,
  456. languagePointsIds: this.paperInfo.languagePointsList,
  457. examTime: this.studentExamTime
  458. }
  459. // this.examParams = form
  460. this.$store.commit('paper/updateExamParams', form)
  461. this.showCommitErrorMsg = false
  462. uni.navigateTo({
  463. url: './examCommit'
  464. })
  465. // this.userFormFlag = true
  466. // this.direction = 'center'
  467. //打开弹窗
  468. //this.$refs.pop.show();
  469. /* uni.redirectTo({
  470. url: 'userForm'
  471. }) */
  472. },
  473. showCardModal (e) {
  474. this.modalCard = e.currentTarget.dataset.target
  475. },
  476. hideCardModal (e) {
  477. this.modalCard = null
  478. },
  479. showErrorModal (e) {
  480. this.modalError = e.currentTarget.dataset.target
  481. },
  482. hideErrorModal (e) {
  483. this.modalError = null
  484. },
  485. swiperChange (e) { //滑动事件
  486. let index = e.target.current;
  487. if (index != undefined) {
  488. this.questionIndex = index;
  489. this.currentQuestionName = this.paperQuestionList[this.questionIndex].questionName
  490. }
  491. },
  492. radioboxChange (evt) { //单选选中
  493. var value = evt.detail.value
  494. let questionInfo = this.paperQuestionList[this.questionIndex]
  495. questionInfo.userInfoAnswer = value
  496. /* this.paperQuestionList[this.questionIndex] = que
  497. alert(questionInfo.userInfoAnswer)
  498. alert(value)
  499. alert(questionInfo.userInfoAnswer === value) */
  500. },
  501. checkboxChange (e) { //复选选中
  502. let options = this.paperQuestionList[this.questionIndex].options
  503. let values = e.detail.value
  504. let userInfoAnswer = ''
  505. for (var i = 0, lenI = options.length; i < lenI; ++i) {
  506. const item = options[i]
  507. if (values.includes(item.value)) {
  508. this.$set(item, 'checked', true)
  509. userInfoAnswer += item.value + ','
  510. } else {
  511. this.$set(item, 'checked', false)
  512. }
  513. }
  514. if (userInfoAnswer) {
  515. userInfoAnswer = userInfoAnswer.substr(0, userInfoAnswer.length - 1)
  516. }
  517. this.paperQuestionList[this.questionIndex].userInfoAnswer = userInfoAnswer
  518. },
  519. showAnswerChange (e) { // 显示答案
  520. let item = this.paperQuestionList[this.questionIndex]
  521. if (item.question_type === 6) {
  522. if (parseInt().answer === 1) {
  523. item.show_answer = '对'
  524. } else {
  525. item.show_answer = '错'
  526. }
  527. }
  528. if (item.showAnswer) {
  529. item.showAnswerFlag = false;
  530. } else {
  531. item.showAnswerFlag = true;
  532. }
  533. },
  534. //上一题、下一题
  535. changeQuestionInfo (val) {
  536. if (val === -1 && this.subjectIndex != 0) {
  537. this.questionIndex -= 1;
  538. }
  539. if (val === 1 && this.questionIndex < this.paperQuestionList.length - 1) {
  540. this.questionIndex += 1;
  541. }
  542. else if (this.questionIndex === this.paperQuestionList.length - 1) {
  543. uni.showToast({
  544. icon: 'none',
  545. title: '亲, 已经是最后一题了'
  546. })
  547. }
  548. },
  549. // 答题卡试题切换
  550. appointedQuestion (val) {
  551. this.modalCard = null
  552. this.questionIndex = val
  553. },
  554. SubmitError: function(e) { //提交纠错
  555. let question = this.paperQuestionList[this.questionIndex]
  556. let form = {
  557. questionInfoId: question.id,
  558. content: this.questionError,
  559. modeId: 0
  560. }
  561. this.$httpApi.post('/front/questionFeedback', form)
  562. .then(res => {
  563. if (res.code === 1) {
  564. uni.showToast({
  565. title: '提交成功'
  566. })
  567. }
  568. })
  569. this.modalError = null;
  570. }
  571. }
  572. }
  573. </script>
  574. <style>
  575. .action p {
  576. display: contents !important;
  577. }
  578. </style>
  579. <style scoped>
  580. @import "../../colorui/animation.css";
  581. @import "../../colorui/main.css";
  582. @import "../../colorui/icon.css";
  583. /*每个页面公共css */
  584. page {
  585. background-color: #FFFFFF;
  586. }
  587. uni-radio:before {
  588. content: ''
  589. }
  590. uni-checkbox:before {
  591. content: ''
  592. }
  593. .line-green {
  594. background-color: #409eff !important;
  595. color: #F0F0F0;
  596. }
  597. .cu-form-group {
  598. justify-content: flex-start
  599. }
  600. .cu-form-group .title {
  601. padding-left: 30upx;
  602. padding-right: 0upx;
  603. }
  604. /* 提示窗口 */
  605. .uni-tip {
  606. padding: 15px;
  607. width: 300px;
  608. background: #fff;
  609. box-sizing: border-box;
  610. border-radius: 10px;
  611. }
  612. .uni-tip-title {
  613. text-align: center;
  614. font-weight: bold;
  615. font-size: 16px;
  616. color: #333;
  617. }
  618. .uni-tip-content {
  619. padding: 15px;
  620. font-size: 14px;
  621. color: #666;
  622. }
  623. .uni-tip-group-button {
  624. margin-top: 10px;
  625. display: flex;
  626. }
  627. .uni-tip-button {
  628. width: 100%;
  629. text-align: center;
  630. font-size: 14px;
  631. color: #3b4144;
  632. }
  633. .cu-form-group+.cu-form-group {
  634. border-top: none;
  635. }
  636. .cu-bar-title {
  637. min-height: 50upx;
  638. }
  639. .cu-list.menu>.cu-item-error{justify-content: flex-start;}
  640. </style>