123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- import {
- commitExamineePaper,
- commitExamineeQuestion,
- loadExamineePaper,
- openExamineePaper,
- scoreExamineeQuestion,
- scoreFinish,
- teacherScoreExamineeQuestions
- } from '@/api/webApi/studentEvaluating.js'
- import config from '@/common/mx-config.js'
- import consts from '@/common/mx-const'
- import { mapGetters } from 'vuex'
- import { formatDuration } from '@/utils/index'
- import eventMixin from './mx-question-event-mixin'
- import EventBus from '@/components/EventBus'
- export default {
- mixins: [eventMixin],
- props: {
- options: {
- type: Object,
- default: _ => ({
- paper: null,
- navigatorSpan: 6,
- extData: {},
- currentTab: 0,
- questionOptionsCache: {},
- committingQuestions: [],
- loading: false,
- committing: false,
- initWithAnswerOfPrevQuestion: false,
- // extra
- customScoredAction: false,
- customCommittedAction: false
- })
- }
- },
- computed: {
- ...mapGetters(['isFrontTeacher', 'isFrontStudent', 'currentUser', 'firstClassName']),
- // properties
- paper() {
- return this.options.paper
- },
- extData() {
- return this.options.extData
- },
- questionOptionsCache() {
- return this.options.questionOptionsCache
- },
- allowAnswer() {
- return this.paper.allowAnswer
- },
- allowScore() {
- return this.paper.allowScore
- },
- examineeId() {
- return this.extData.examineeId || this.paper.examineeId
- },
- examineeType() {
- return this.extData.examineeType ||
- this.paper?.examineeType ||
- consts.enum.paper.examineeType.evaluation
- },
- evaluationClassId() {
- return this.extData.evaluationClassId
- },
- studentName() {
- return this.extData.studentName || this.currentUser.nickName
- },
- studentClassName() {
- return this.extData.class || this.firstClassName
- },
- avatar() {
- return this.extData.avatar || config.avatar_default
- },
- loading() {
- return this.options.loading
- },
- committing() {
- return this.options.committing
- },
- currentTab() {
- return this.options.currentTab
- },
- committingQuestions() {
- return this.options.committingQuestions
- },
- // business data
- countdownDisplay() {
- return formatDuration(this.paper.remaining)
- },
- stateStr() {
- if (this.paper.allowAnswer || this.paper.allowScore) return ''
- return this.paper.stateStr
- },
- scoreColor() {
- return this.paper.allowAnswer ? '' : config.color.error
- },
- currentQuestion() {
- if (this.paper?.questions?.length > this.currentTab) {
- return this.paper.questions[this.currentTab]
- }
- return null
- },
- currentQuestionOptions() {
- if (!this.currentQuestion) return null
- return this.questionOptionsCache[this.currentTab]
- },
- hasPrevious() {
- return this.currentTab > 0
- },
- hasNext() {
- return this.currentTab < this.paper.questions?.length - 1
- },
- queryApi() {
- return this.isFrontStudent ? openExamineePaper : loadExamineePaper
- },
- scoreApi() {
- return this.isFrontStudent ? scoreExamineeQuestion : teacherScoreExamineeQuestions
- }
- },
- methods: {
- // for shortcut
- forceBlur() {
- // Give the document focus
- if (document.activeElement) {
- document.activeElement.blur()
- }
- this.$el.focus()
- },
- loadPaper(extData, overrideOptions) {
- // set ext
- this.options.extData = extData
- if (overrideOptions) {
- Object.keys(overrideOptions).forEach(key => this.options[key] = overrideOptions[key])
- }
- // query
- let queryApi = this.queryApi
- this.options.loading = true
- queryApi(extData).then(res => {
- this.options.currentTab = 0 // reset position
- const paper = res.data
- const autoScoreQuestions = this.eventProcessPaper(paper, this.questionOptionsCache)
- this.options.paper = paper
- this.autoScoreObjectives(autoScoreQuestions)
- }).finally(() => {
- return this.options.loading = false
- })
- },
- beforeQuestionChangeAction() {
- this.triggerAutoCommitQuestion()
- },
- goIndexAction(index) {
- if (this.currentTab != index) {
- this.triggerAutoCommitQuestion()
- this.options.currentTab = index
- }
- },
- goPreviousAction() {
- this.triggerAutoCommitQuestion()
- this.options.currentTab = this.currentTab - 1
- },
- goNextAction() {
- this.triggerAutoCommitQuestion()
- this.options.currentTab = this.currentTab + 1
- },
- goUnfinishedQuestionAction(index) {
- this.options.currentTab = index
- },
- commitQuestionAction(commit) {
- // 部分提交,断点续传
- this.committingQuestions.push(commit)
- this.commitQuestionCore()
- },
- autoScoreObjectives(scoredQuestions) {
- if (!scoredQuestions?.length) return
- // 静默提交
- const func = this.scoreApi
- func({
- examineeId: this.examineeId,
- examineeType: this.examineeType,
- questions: scoredQuestions
- }).then(res => {
- // donothing
- })
- },
- paperTimeUpAction() {
- this.$once('singleCommitCompleted', _ => this.commitPaper())
- this.triggerAutoCommitQuestion()
- },
- paperSubmitAction() {
- this.$once('singleCommitCompleted', _ => {
- const unfinishedList = this.eventUnfinishedQuestions(this.paper)
- if (unfinishedList.length) {
- const msg = `检测到您还有第(${unfinishedList.map(q => q.seq)})题没有完成,是否做完再交卷?!`
- this.$confirm(msg, '提示', {
- distinguishCancelAndClose: true,
- confirmButtonText: '继续做题',
- cancelButtonText: '确认交卷'
- }).then(() => {
- this.goUnfinishedQuestionAction(unfinishedList.first().seq - 1)
- }).catch(action => {
- if (action == 'cancel') {
- this.commitPaper()
- }
- })
- } else {
- const msg = '检测到您已完成答题'
- this.$confirm(msg, '提示', {
- confirmButtonText: '确认提交',
- cancelButtonText: '再检查一遍'
- }).then(() => this.commitPaper())
- }
- })
- this.triggerAutoCommitQuestion()
- },
- triggerAutoCommitQuestion() {
- if (!this.paper.allowAnswer) return
- const commit = this.eventBuildCommitAnswerData(this.currentQuestion)
- this.commitQuestionAction(commit)
- },
- commitQuestionCore() {
- if (this.committingQuestions.length == 0) {
- this.$emit('singleCommitCompleted')
- return
- }
- const target = this.committingQuestions[0]
- const commit = {
- examineeId: this.examineeId,
- examineeType: this.examineeType,
- questions: [{
- ...target,
- examineeType: this.examineeType
- }]
- }
- // 对比历史作答与现在提交内容是否有差异,防止切换时重复计时
- const rawQuestion = this.paper.questions.find(q => q.questionId == target.questionId)
- if (target.answer == rawQuestion.answer &&
- target.attachments?.toString() == rawQuestion.attachments?.toString()) {
- // 答题没有变化,不需要重复提交
- this.committingQuestions.shift()
- setTimeout(_ => this.commitQuestionCore(), 200)
- return
- }
- commitExamineeQuestion(commit)
- .then(res => {
- // 成功后可用提交属性覆盖题目属性
- this.eventHandleAnswerSubmitted(target, rawQuestion)
- this.committingQuestions.shift()
- setTimeout(_ => this.commitQuestionCore(), 200)
- }).catch(e => {
- // 失败后可尝试重复提交
- // TODO: hht 2022.1.2 这里如果一直异常了会陷入死循环
- // setTimeout(_ => this.commitQuestionCore(), 200)
- })
- },
- commitPaper() {
- if (this.committing) return
- this.options.committing = true
- const commit = {
- examineeId: this.examineeId,
- examineeType: this.examineeType,
- questions: this.paper.questions.map(q => ({
- questionId: q.questionId,
- answer: q.answer,
- attachments: q.attachments,
- duration: q.duration,
- examineeType: this.examineeType
- }))
- }
- commitExamineePaper(commit).then(res => {
- this.$alert('交卷成功').then(() => this.customCommitCompleted())
- }).finally(() => this.options.committing = false)
- },
- async scoreFinishAction() {
- const unScoredQuestions = this.eventUnScoredQuestions(this.paper)
- if (unScoredQuestions.length > 0) {
- const msg = `第${unScoredQuestions.map(q => q.seq)}题未完成评分`
- this.msgError(msg)
- this.goUnfinishedQuestionAction(unScoredQuestions.first().seq - 1)
- return
- }
- await this.$confirm('确认提交?')
- if (this.committing) return
- this.options.committing = true
- scoreFinish({
- examineeId: this.examineeId,
- examineeType: this.examineeType
- }).then(res => {
- this.$alert('阅卷完毕').then(() => this.customScoreCompleted())
- }).finally(() => this.options.committing = false)
- },
- customCommitCompleted() {
- if (this.options.customCommittedAction) {
- // NOTE: 用eventBus解耦组件层级限制
- // TODO: 这里的if-else分支不是唯一做法,也可以重写包含提交逻辑的组件,用slot装载,不知道哪种方式会更好
- this.$nextTick(() => EventBus.instance.$emit('customCommittedAction'))
- } else {
- this.$router.back()
- }
- },
- customScoreCompleted() {
- if (this.options.customScoredAction) {
- // NOTE: 用eventBus解耦组件层级限制
- // TODO: 这里的if-else分支不是唯一做法,也可以重写包含提交逻辑的组件,用slot装载,不知道哪种方式会更好
- this.$nextTick(() => EventBus.instance.$emit('customScoredAction'))
- } else {
- this.$router.back()
- }
- }
- }
- }
|