【Vue】考试功能实现
一、需求场景
最近临时加的一个功能模块,让我两天就实现....
部门成员需要进行测验考试,简单来说就是刷题练习
关于题库导入的部分在这篇文章已经写好了:https://www.cnblogs.com/mindzone/p/18362194
分值计算的需求目前没加入进来,只判断对错与否,然后计数题目总数和做对题数
二、表结构
考试题库
DROP TABLE IF EXISTS `trn_ex_qabank`; CREATE TABLE `trn_ex_qabank` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `qa_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考题类型', `qa_subject` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考题题目', `qa_answer` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '考题答案', `qa_analy` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '考题分析', `cre_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `cre_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建人', `upd_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', `upd_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '更新人', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试题库';
考试信息
DROP TABLE IF EXISTS `trn_ex_info`; CREATE TABLE `trn_ex_info` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `in_code` varchar(14) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考试编号', `in_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名', `in_username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名', `qa_sc_total` int(11) NOT NULL COMMENT '单选总数', `qq_sc_hit` int(11) NOT NULL COMMENT '单选正确数', `qa_mc_total` int(11) NOT NULL COMMENT '多选总数', `qa_mc_hit` int(11) NOT NULL COMMENT '多选正确数', `qa_ju_total` int(11) NOT NULL COMMENT '判断总数', `qa_ju_hit` int(11) NOT NULL COMMENT '判断正确数', `qa_sa_total` int(11) NOT NULL COMMENT '简单总数', `qa_sa_hit` int(11) NOT NULL COMMENT '简单正确数', `in_aw_state` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考试状态', `in_ap_state` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '评卷状态', `cre_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建人', `upd_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', `upd_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '更新人', `cre_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试信息';
考试试卷
DROP TABLE IF EXISTS `trn_ex_paper`; CREATE TABLE `trn_ex_paper` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `trn_ex_in_id` int(11) NOT NULL COMMENT '所属考次', `trn_ex_qa_id` int(11) NOT NULL COMMENT '所属题目', `qa_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考题类型', `qa_subject` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考题题目', `qa_sa_answer` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '考题答案', `pa_state` char(1) NOT NULL COMMENT '是否答题', `is_right` char(1) NOT NULL COMMENT '是否正确', `cre_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '创建人', `upd_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '更新人', `upd_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', `cre_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='考试试卷';
三、功能实现
1、生成考卷接口
目前的设计是放到考试表单中让用户自己决定每种题型的数量
SQL实现通过 ORDER BY RAND() LIMIT【题型数】
List<TrnExQabankListVO> fetchRandomCollect(@Param("qaType") String qaType, @Param("limit") Integer limit);
mapper映射文件
<select id="fetchRandomCollect" resultType="cn.anmte.cper.model.TrnExQabankListVO"> SELECT a.* FROM trn_ex_qabank a WHERE a.qa_type = #{qaType} ORDER BY RAND() LIMIT #{limit} </select>
业务方法:
@Override public List<TrnExQabankListVO> createExam(TrnExInfoForm trnExInfoForm) { Integer qaScTotal = trnExInfoForm.getQaScTotal(); Integer qaMcTotal = trnExInfoForm.getQaMcTotal(); Integer qaJuTotal = trnExInfoForm.getQaJuTotal(); Integer qaSaTotal = trnExInfoForm.getQaSaTotal();
List<TrnExQabankListVO> radioTypeList = baseMapper.fetchRandomCollect(DbcpExamUtil.TYPE1_RADIO, qaScTotal); List<TrnExQabankListVO> checkboxTypeList = baseMapper.fetchRandomCollect(DbcpExamUtil.TYPE2_CHECKBOX, qaMcTotal); List<TrnExQabankListVO> trueOrFalseTypeList = baseMapper.fetchRandomCollect(DbcpExamUtil.TYPE3_TRUE_OR_FASE, qaJuTotal); List<TrnExQabankListVO> shortQaTypeList = baseMapper.fetchRandomCollect(DbcpExamUtil.TYPE4_SHORT_QA, qaSaTotal);
List<TrnExQabankListVO> paperList = new ArrayList<>(); paperList.addAll(radioTypeList); paperList.addAll(checkboxTypeList); paperList.addAll(trueOrFalseTypeList); paperList.addAll(shortQaTypeList); return paperList; }
2、界面表单参数:
这里我设置默认题型数量,除了简答题为5题,其他设置为10题
可以生成试卷,也可以重置试卷,刷新题目重做
已经保存的和已经交卷的试卷不能再重新生成试卷
试卷生成方法:
因为要展示生成试卷的序号,正好追加一个序号属性,通过序号对题目元素进行CRUD的操作
createExamItems() { this.$refs['dataForm'].validate((valid) => { if (!valid) return this.btnLoading = true const { qaScTotal, qaMcTotal, qaJuTotal, qaSaTotal } = this.dataForm const allOptions = [qaScTotal, qaMcTotal, qaJuTotal, qaSaTotal] const isEmptyOption = allOptions.every(opt => opt === 0) if (isEmptyOption) return this.$message.error('无效总数,请调整后尝试') createExamPapers({qaScTotal, qaMcTotal, qaJuTotal, qaSaTotal}).then(res => { const totalPapers = res.data.map((x, idx, arr) => { return { ...x, id: '', trnExInId: '', /* 无考次 */ trnExQaId: x.id, qaSaAnswer: '', /* 默认清空答案 */ paState: '0', /* 未答题 */ isRight: '0', /* 错误 */ no: idx + 1 } }) this.dataForm.paperList = [...totalPapers] this.radioTypePapers = [...totalPapers.filter(p => p.qaType === '0')] this.checkTypePapers = [...totalPapers.filter(p => p.qaType === '1')] this.tureFalseTypePapers = [...totalPapers.filter(p => p.qaType === '2')] this.shortQaTypePapers = [...totalPapers.filter(p => p.qaType === '3')] /* 置为当前第一道题 */ this.currentPaperIdx = 1 this.whenPaperIdxChange(this.currentPaperIdx) this.btnLoading = false }); }) },
题目清除方法:
清除当前题目下标和试题及每种题型
clearExamItems() { this.dataForm.paperList = [] this.radioTypePapers = [] this.checkTypePapers = [] this.tureFalseTypePapers = [] this.shortQaTypePapers = [] this.currentPaperIdx = 0 },
currentPaperIdx: 0, currentPaper: { id: '', trnExInId: '', trnExQaId: '', qaType: '', qaSubject: '', qaAnswer: '', qaSaAnswer: '', qaSaCheckboxAnswer: [], paState: '', qaAnaly: '', isRight: '' },
3、题目交互界面
我最开始的项目就是一个集合全渲染出来,但是老板又补了句我想做两三百题目这页面不得卡死来
题目切换方法:
async whenPaperIdxChange(val) { const targetPaper = this.dataForm.paperList.find(p => p.no === val) if (this.dataForm.inAwState === '1') { const { trnExQaId } = targetPaper const { data: qaInfo } = await getQaBankInfo(trnExQaId) if (qaInfo) { this.currentPaper = { ... targetPaper, qaSaCheckboxAnswer: [], qaAnswer: targetPaper.qaType === '3' ? '' : qaInfo.qaAnswer, qaAnaly: targetPaper.qaType === '3' ? qaInfo.qaAnswer : qaInfo.qaAnaly } } else { this.currentPaper = { ... targetPaper, qaSaCheckboxAnswer: [], qaAnswer: '', qaAnaly: '' } } } else { const isCheckBox = targetPaper.qaType === '1' this.currentPaper = { ... targetPaper, qaSaCheckboxAnswer: isCheckBox ? [... targetPaper.qaSaAnswer] : [] } console.log(this.currentPaper) } },
1、所以就想到应该是当前只展示一个题目,然后上面会放上每个题目的单选框和序号,点击序号单选框跳转到这题来
题型组件代码:
<el-row v-if="dataForm.paperList.length > 0" class="nav-div"><i class="el-icon-document nav-title" />考试试题</el-row> <el-row :gutter="15"> <jnpf-form-tip-item label="单选题" prop="" v-if="radioTypePapers.length > 0"> <el-radio-group v-model="currentPaperIdx" @change="whenPaperIdxChange"> <el-badge v-for="(item, idx) in radioTypePapers" :key="`radioTypePapers${idx}`" :is-dot="item.paState === '0'" class="pa-state-0-dot"> <el-radio :label="item.no" class="paper-radio"> {{ item.no }} <el-tag type="success" v-if="item.isRight === '1' && dataForm.inApState === '1'">√</el-tag> <el-tag type="danger" v-if="item.isRight === '0' && dataForm.inApState === '1'" >×</el-tag> </el-radio> </el-badge> </el-radio-group> </jnpf-form-tip-item> <jnpf-form-tip-item label="多选题" prop="" v-if="checkTypePapers.length > 0"> <el-radio-group v-model="currentPaperIdx" @change="whenPaperIdxChange"> <el-badge v-for="(item, idx) in checkTypePapers" :key="`checkTypePapers${idx}`" :is-dot="item.paState === '0'" class="pa-state-0-dot"> <el-radio :label="item.no" class="paper-radio"> {{ item.no }} <el-tag type="success" v-if="item.isRight === '1' && dataForm.inApState === '1'">√</el-tag> <el-tag type="danger" v-if="item.isRight === '0' && dataForm.inApState === '1'" >×</el-tag> </el-radio> </el-badge> </el-radio-group> </jnpf-form-tip-item> <jnpf-form-tip-item label="判断题" prop="" v-if="tureFalseTypePapers.length > 0"> <el-radio-group v-model="currentPaperIdx" @change="whenPaperIdxChange"> <el-badge v-for="(item, idx) in tureFalseTypePapers" :key="`tureFalseTypePapers${idx}`" :is-dot="item.paState === '0'" class="pa-state-0-dot"> <el-radio :label="item.no" class="paper-radio"> {{ item.no }} <el-tag type="success" v-if="item.isRight === '1' && dataForm.inApState === '1'">√</el-tag> <el-tag type="danger" v-if="item.isRight === '0' && dataForm.inApState === '1'" >×</el-tag> </el-radio> </el-badge> </el-radio-group> </jnpf-form-tip-item> <jnpf-form-tip-item label="简答题" prop="" v-if="shortQaTypePapers.length > 0"> <el-radio-group v-model="currentPaperIdx" @change="whenPaperIdxChange"> <el-badge v-for="(item, idx) in shortQaTypePapers" :key="`shortQaTypePapers${idx}`" :is-dot="item.paState === '0'" class="pa-state-0-dot"> <el-radio :label="item.no" class="paper-radio"> {{ item.no }} <el-tag type="success" v-if="item.isRight === '1' && dataForm.inApState === '1'">√</el-tag> <el-tag type="danger" v-if="item.isRight === '0' && dataForm.inApState === '1'" >×</el-tag> </el-radio> </el-badge> </el-radio-group> </jnpf-form-tip-item> </el-row>
2、除了点击序号单选,还可以像翻页一样,跳转到上一题和下一题
goToPrevPaper() { if (this.currentPaperIdx === 1) return this.$message.warning('已经是第一道题了!') const currIdx = this.currentPaperIdx -= 1 this.whenPaperIdxChange(currIdx) }, goToNextPaper() { const lastNo = this.dataForm.paperList.length if (this.currentPaperIdx === lastNo) return this.$message.warning('已经是最后一道题了!') const currIdx = this.currentPaperIdx += 1 this.whenPaperIdxChange(currIdx) },
3、确定是确认当前题目的答题内容,同时设置当前题目为【已答题】状态
4、为了方便展示有些那些题目没做,使用小红点badge标识是否答题
5、最开始设置答题表单项的时候默认统一用文本域处理,然后迭代成根据题型标识动态显示,
单选题、判断题、简答题都可以使用单选框、文本域简单处理
<el-row :gutter="15" v-if="currentPaperIdx !== 0 && dataForm.inApState !== '1'"> <jnpf-form-tip-item label-width="30px"> <div class="qa-subject" v-html="currentPaper.qaSubject ? currentPaper.qaSubject.replaceAll('\n', '<br/>') : ''" /> <el-radio-group v-if="currentPaper.qaType === '0'" v-model="currentPaper.qaSaAnswer"> <el-radio :disabled="isDetail" label="A">A</el-radio> <el-radio :disabled="isDetail" label="B">B</el-radio> <el-radio :disabled="isDetail" label="C">C</el-radio> <el-radio :disabled="isDetail" label="D">D</el-radio> <el-radio :disabled="isDetail" label="E">E</el-radio> <el-radio :disabled="isDetail" label="F">F</el-radio> </el-radio-group> <el-checkbox-group v-if="currentPaper.qaType === '1'" v-model="currentPaper.qaSaCheckboxAnswer"> <el-checkbox :disabled="isDetail" label="A">A</el-checkbox> <el-checkbox :disabled="isDetail" label="B">B</el-checkbox> <el-checkbox :disabled="isDetail" label="C">C</el-checkbox> <el-checkbox :disabled="isDetail" label="D">D</el-checkbox> <el-checkbox :disabled="isDetail" label="E">E</el-checkbox> <el-checkbox :disabled="isDetail" label="F">F</el-checkbox> </el-checkbox-group> <el-radio-group v-if="currentPaper.qaType === '2'" v-model="currentPaper.qaSaAnswer"> <el-radio :disabled="isDetail" label="A">A / 对</el-radio> <el-radio :disabled="isDetail" label="B">B / 错</el-radio> </el-radio-group> <el-input v-if="currentPaper.qaType === '3'" :class="{'cus-detail':isDetail}" v-model="currentPaper.qaSaAnswer" maxlength="1024" show-word-limit type="textarea" :rows="6" placeholder="请输入考题答案" clearable :disabled="isDetail" /> </jnpf-form-tip-item> </el-row>
但是复选框要处理一下,在选中题目的时候 回显选项,确定事件时转换选项保存
回显复选框答案:
展示效果
点击确定时的保存方法处理:
currentPaperSubmit() { const { qaSaAnswer, qaType, qaSaCheckboxAnswer } = this.currentPaper const isCheckBox = qaType === '1' if (isCheckBox && qaSaCheckboxAnswer.length === 0) return this.$message('请填写答案!') else if (!isCheckBox && !qaSaAnswer) return this.$message('请填写答案!') const target = this.dataForm.paperList.find(x => x.no === this.currentPaperIdx) const paperIdx = this.dataForm.paperList.indexOf(target) let optTarget, optIdx switch (qaType) { case '0': optTarget = this.radioTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.radioTypePapers.indexOf(optTarget) this.$set(this.radioTypePapers[optIdx], 'paState', '1') break case '1': optTarget = this.checkTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.checkTypePapers.indexOf(optTarget) this.$set(this.checkTypePapers[optIdx], 'paState', '1') break case '2': optTarget = this.tureFalseTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.tureFalseTypePapers.indexOf(optTarget) this.$set(this.tureFalseTypePapers[optIdx], 'paState', '1') break case '3': optTarget = this.shortQaTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.shortQaTypePapers.indexOf(optTarget) this.$set(this.shortQaTypePapers[optIdx], 'paState', '1') break } this.$set(this.dataForm.paperList[paperIdx], 'qaSaAnswer', isCheckBox ? qaSaCheckboxAnswer.join('') : qaSaAnswer) this.$set(this.dataForm.paperList[paperIdx], 'paState', '1') this.$message.success('答题成功') },
6、存在一次考试做好几百道题的情况,不一定马上交卷
提交按钮就分为【保存】和 【交卷】
保存和交卷逻辑:
examSubmit() { if (this.dataForm.paperList.length === 0) return this.$message.error('没有要提交的试题!') this.$refs['dataForm'].validate((valid) => { if (!valid) return const undoneCount = this.dataForm.paperList.filter(x => x.paState === '0').length const hasUndone = undoneCount > 0 this.$confirm(`还有${undoneCount}道题目未完成, 是否交卷?`, '提示', { type: 'warning' }).then(() => { this.btnLoading = true let _data = this.dataList() examDataSubmit(_data).then((res) => { this.$message({ message: res.msg, type: 'success', duration: 1000, onClose: () => { this.localVisible = false this.btnLoading = false this.$emit('refresh', true) } }) }).catch(() => { this.btnLoading = false }) }).catch(() => { }) }) }, examSave() { if (this.dataForm.paperList.length === 0) return this.$message.error('没有要提交的试题!') this.$refs['dataForm'].validate((valid) => { if (!valid) return const undoneCount = this.dataForm.paperList.filter(x => x.paState === '0').length const hasUndone = undoneCount > 0 this.$confirm(`还有${undoneCount}道题目未完成, 是否保存?`, '提示', { type: 'warning' }).then(() => { this.request() }).catch(() => { }) }) },
三、评卷功能实现
在交卷后,除了简答题外,其他题目可以通过查询题库id判断是否正确
交卷接口的业务实现:
@Override public void evaluationSubmit(TrnExInfoForm form) { Integer trnExId = form.getId(); /* 清除历史存留 */ List<Integer> collect = lambdaQuery().eq(TrnExPaper::getTrnExInId, trnExId).list().stream().map(TrnExPaper::getId).collect(Collectors.toList()); boolean hasExist = CollectionUtils.isNotEmpty(collect); if (hasExist) baseMapper.deleteBatchIds(collect); /* 计算对错,评估得分 */ List<TrnExPaper> paperList = form.getPaperList(); List<Integer> qaIdList = paperList.stream().map(TrnExPaper::getTrnExQaId).collect(Collectors.toList()); List<TrnExQabank> trnExQabanks = trnExQabankMapper.selectBatchIds(qaIdList); for (TrnExPaper trnExPaper : paperList) { trnExPaper.setTrnExInId(form.getId()); /* 简答题默认错误 */ if (DbcpExamUtil.TYPE4_SHORT_QA.equals(trnExPaper.getQaType())) { trnExPaper.setIsRight(TrainingConstant.IS_RIGHT_NO); baseMapper.insert(trnExPaper); continue; } /* 其他类型则判断是否匹配了题库,如果没有则按错误处理,反之匹配是否正确 */ Optional<TrnExQabank> qaOpt = trnExQabanks.stream().filter(qa -> qa.getId().equals(trnExPaper.getTrnExQaId())).findFirst(); boolean matched = qaOpt.isPresent(); if (matched) { TrnExQabank trnExQabank = qaOpt.get(); String qaAnswer = trnExQabank.getQaAnswer(); String qaSaAnswer = trnExPaper.getQaSaAnswer(); boolean isRight = qaAnswer.equalsIgnoreCase(qaSaAnswer); trnExPaper.setIsRight(isRight ? TrainingConstant.IS_RIGHT_YES : TrainingConstant.IS_RIGHT_NO); } else trnExPaper.setIsRight(TrainingConstant.IS_RIGHT_NO); baseMapper.insert(trnExPaper); } /* 在写入完成后统计正确个数 */ Long radioRightCount = paperList.parallelStream().filter(p -> DbcpExamUtil.TYPE1_RADIO.equals(p.getQaType()) && TrainingConstant.IS_RIGHT_YES.equals(p.getIsRight())).count(); Long checkBoxRightCount = paperList.parallelStream().filter(p -> DbcpExamUtil.TYPE2_CHECKBOX.equals(p.getQaType()) && TrainingConstant.IS_RIGHT_YES.equals(p.getIsRight())).count(); Long trueFalseRightCount = paperList.parallelStream().filter(p -> DbcpExamUtil.TYPE3_TRUE_OR_FASE.equals(p.getQaType()) && TrainingConstant.IS_RIGHT_YES.equals(p.getIsRight())).count(); Long shortQaCount = 0L; /* 简答题默认0正确,无法判断 */ form.setQqScHit(radioRightCount.intValue()); form.setQaMcHit(checkBoxRightCount.intValue()); form.setQaJuHit(trueFalseRightCount.intValue()); form.setQaSaHit(shortQaCount.intValue()); /* 更新状态 */ form.setInAwState(TrainingConstant.IN_AW_STATE_FINISH); form.setInApState(TrainingConstant.IN_AP_STATE_AWAIT); }
评卷表单除了之前的内容外,每个题目需要展示对错与否
除了考生提交的答案,还要显示正确答案和解析,并且可以设置是否正确
题目对错的展示处理
试题信息是没有正确答案和解析,所以要通过试卷信息的题库id来查询查询题库信息
阅卷方法保存的是是否正确选项:
currentPaperSubmit() { const { isRight, qaType } = this.currentPaper const target = this.dataForm.paperList.find(x => x.no === this.currentPaperIdx) const paperIdx = this.dataForm.paperList.indexOf(target) let optTarget, optIdx switch (qaType) { case '0': optTarget = this.radioTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.radioTypePapers.indexOf(optTarget) this.$set(this.radioTypePapers[optIdx], 'isRight', isRight) break case '1': optTarget = this.checkTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.checkTypePapers.indexOf(optTarget) this.$set(this.checkTypePapers[optIdx], 'isRight', isRight) break case '2': optTarget = this.tureFalseTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.tureFalseTypePapers.indexOf(optTarget) this.$set(this.tureFalseTypePapers[optIdx], 'isRight', isRight) break case '3': optTarget = this.shortQaTypePapers.find(x => x.no === this.currentPaperIdx) optIdx = this.shortQaTypePapers.indexOf(optTarget) this.$set(this.shortQaTypePapers[optIdx], 'isRight', isRight) break } this.$set(this.dataForm.paperList[paperIdx], 'isRight', isRight) this.$message.success('阅卷成功') },