|
|
|
@ -1,8 +1,8 @@ |
|
|
|
|
<template> |
|
|
|
|
<div class="page"> |
|
|
|
|
<Breadcrumb :data="crumbs" /> |
|
|
|
|
<p class="page-name mb">试卷</p> |
|
|
|
|
<el-form :model="form" :rules="rules" class="input-form model" ref="form" label-width="140px"> |
|
|
|
|
<p class="page-name mb">试卷基础信息</p> |
|
|
|
|
<el-form-item prop="name" label="试卷名称"> |
|
|
|
|
<el-input style="width: 940px" placeholder="请输入试卷名称" v-model="form.name" clearable maxlength="100" /> |
|
|
|
|
</el-form-item> |
|
|
|
@ -14,7 +14,7 @@ |
|
|
|
|
</el-form-item> |
|
|
|
|
<el-form-item prop="classificationId" label="所属试卷分类"> |
|
|
|
|
<el-cascader filterable placeholder="请选择所属试卷分类" :options="types" v-model="form.classificationId" |
|
|
|
|
:props="cascaderProps" clearable style="width: 100%"> |
|
|
|
|
:props="cascaderProps" style="width: 100%"> |
|
|
|
|
</el-cascader> |
|
|
|
|
</el-form-item> |
|
|
|
|
</div> |
|
|
|
@ -38,7 +38,8 @@ |
|
|
|
|
</el-select> |
|
|
|
|
</el-form-item> |
|
|
|
|
<el-form-item prop="difficult" label="试卷难度"> |
|
|
|
|
<el-select v-model="form.difficult" placeholder="系统自动评估,也可手动选择" @change="difficultSelected = true"> |
|
|
|
|
<el-select v-model="form.difficult" clearable placeholder="系统自动评估,也可手动选择" |
|
|
|
|
@change="val => difficultSelected = !!val"> |
|
|
|
|
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option> |
|
|
|
|
</el-select> |
|
|
|
|
<el-tooltip placement="top"> |
|
|
|
@ -67,9 +68,10 @@ |
|
|
|
|
|
|
|
|
|
<div class="line"></div> |
|
|
|
|
|
|
|
|
|
<div class="flex j-between m-b-20"> |
|
|
|
|
<p>默认模板</p> |
|
|
|
|
<el-button type="primary" size="small" @click="showTemplate">选择大纲模板</el-button> |
|
|
|
|
<p class="page-name mb">试卷大纲</p> |
|
|
|
|
<div class="relative text-center m-b-40"> |
|
|
|
|
<p class="fs-16">{{ templateName }}</p> |
|
|
|
|
<el-button class="tem-btn" type="primary" size="small" @click="showTemplate">选择大纲模板</el-button> |
|
|
|
|
</div> |
|
|
|
|
<el-table :data="form.paperOutline" stripe header-align="center" row-key="id"> |
|
|
|
|
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
|
|
|
@ -105,7 +107,7 @@ |
|
|
|
|
<div class="line"></div> |
|
|
|
|
|
|
|
|
|
<div class="flex j-between a-center"> |
|
|
|
|
<h6 class="page-name" style="margin-bottom: 0">选择试题</h6> |
|
|
|
|
<h6 class="page-name" style="margin-bottom: 0">试卷试题</h6> |
|
|
|
|
<div> |
|
|
|
|
<el-button type="primary" @click="allocationAll">一键分配分值</el-button> |
|
|
|
|
<el-button type="primary" @click="showAuto">自动选题</el-button> |
|
|
|
@ -144,7 +146,7 @@ |
|
|
|
|
<span class="label">{{ j + 1 }} / {{ item.examQuestions.length }}</span> |
|
|
|
|
<span class="label">{{ questionTypes.find(e => e.id === item.questionType).name }}</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="stem" :id="'stem' + ques.questionVersionId" v-html="getQuesStem(ques)"></div> |
|
|
|
|
<div class="stem" :id="'stem' + ques.questionVersionId" v-html="ques.stem"></div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
@ -162,6 +164,7 @@ |
|
|
|
|
【{{ item.questionType === 'essay' ? '参考答案' : '正确答案' }}】: |
|
|
|
|
<div v-html="getCorrectAnswer(ques)"></div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<div class="actions"> |
|
|
|
|
<p v-if="item.questionType !== 'fill_blank'" class="m-r-10 input-wrap"> |
|
|
|
|
(<el-input class="l-input" placeholder="请输入分值" v-model="ques.score" />分)</p> |
|
|
|
@ -175,7 +178,7 @@ |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<div slot="reference" class="input-wrap"> |
|
|
|
|
查看每空分值<el-input class="l-input" placeholder="请输入分值" v-model="ques.score" /> |
|
|
|
|
查看每空分值<el-input class="l-input" placeholder="请输入分值" v-model="ques.score" readonly /> |
|
|
|
|
</div> |
|
|
|
|
</el-popover> |
|
|
|
|
|
|
|
|
@ -191,15 +194,14 @@ |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</draggable> |
|
|
|
|
</div> |
|
|
|
|
</li> |
|
|
|
|
</ul> |
|
|
|
|
</el-form> |
|
|
|
|
<div class="btns"> |
|
|
|
|
<el-button @click="submit(1)">保存草稿</el-button> |
|
|
|
|
<el-button type="primary" @click="submit(0)">发布</el-button> |
|
|
|
|
<el-button @click="submit(0)">保存草稿</el-button> |
|
|
|
|
<el-button type="primary" @click="submit(1)">发布</el-button> |
|
|
|
|
<el-button v-if="paperId" @click="preview">预览</el-button> |
|
|
|
|
<el-button @click="back">取消</el-button> |
|
|
|
|
</div> |
|
|
|
@ -224,6 +226,7 @@ import dayjs from 'dayjs' |
|
|
|
|
import QuesConst from '@/const/ques' |
|
|
|
|
import TestPaperConst from '@/const/testPaper' |
|
|
|
|
import Decimal from 'decimal.js' |
|
|
|
|
import { template } from 'lodash' |
|
|
|
|
|
|
|
|
|
export default { |
|
|
|
|
components: { UeditorPlus, Breadcrumb, Template, Manual, Auto, RepeatQues, Draggable }, |
|
|
|
@ -333,6 +336,7 @@ export default { |
|
|
|
|
{ required: true, message: '请输入试卷名称', trigger: 'blur' } |
|
|
|
|
], |
|
|
|
|
}, |
|
|
|
|
templateName: '默认模板', |
|
|
|
|
templateVisible: false, |
|
|
|
|
manualVisible: false, |
|
|
|
|
curType: {}, |
|
|
|
@ -399,11 +403,12 @@ export default { |
|
|
|
|
e.examQuestions.map((n, j) => { |
|
|
|
|
n.originSort = j + 1 |
|
|
|
|
Object.assign(n, n.question) |
|
|
|
|
this.handleFillScore(n) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
}) |
|
|
|
|
if (r.particularYear) r.particularYear = r.particularYear + '' |
|
|
|
|
if (r.professionalId) r.professionalId = r.professionalId.split(',').map(e => +e) |
|
|
|
|
r.professionalId = r.professionalId ? r.professionalId.split(',').map(e => +e) : [] |
|
|
|
|
this.form = r |
|
|
|
|
} |
|
|
|
|
} catch (e) { } |
|
|
|
@ -530,14 +535,11 @@ export default { |
|
|
|
|
data.avgValueList.map((e, i) => { |
|
|
|
|
// scores里有-1则不用循环 |
|
|
|
|
if (!e.scores.includes(-1)) { |
|
|
|
|
const stem = document.querySelector(`#stem` + e.questionVersionId) |
|
|
|
|
if (stem) { |
|
|
|
|
const inputs = stem.querySelectorAll('.fill-input') |
|
|
|
|
if (inputs) { |
|
|
|
|
for (const j in e.scores) { |
|
|
|
|
const item = inputs[j] |
|
|
|
|
inputs[j].value = e.scores[j] |
|
|
|
|
} |
|
|
|
|
const { fillScores } = list[i] |
|
|
|
|
debugger |
|
|
|
|
if (fillScores) { |
|
|
|
|
for (const j in fillScores) { |
|
|
|
|
fillScores[j].val = e.scores[j] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -588,35 +590,45 @@ export default { |
|
|
|
|
} else if (e.questionType === 'essay') { // 问答题取参考答案 |
|
|
|
|
return e.questionAnswerVersionsList[0].referenceAnswer || '暂无' |
|
|
|
|
} else { |
|
|
|
|
if (e.questionAnswerVersionsList) { |
|
|
|
|
const correct = e.questionAnswerVersionsList.filter(e => e.answerIsCorrect) |
|
|
|
|
return correct ? (e.questionType === 'judgement' ? correct[0].optionText : correct.map(e => Util.numToLetter(e.optionNumber - 1)).join('')) : '' // 单选多选显示ABC选项,判断题显示选项内容 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 处理题干显示 |
|
|
|
|
getQuesStem (ques) { |
|
|
|
|
let { stem } = ques |
|
|
|
|
|
|
|
|
|
// 填空题的小空分数处理 |
|
|
|
|
handleFillScore (ques) { |
|
|
|
|
try { |
|
|
|
|
if (ques.questionType === 'fill_blank') { // 填空题 |
|
|
|
|
const opts = ques.questionAnswerVersionsList |
|
|
|
|
if (ques.questionType === 'fill_blank' && opts && opts.length) { |
|
|
|
|
// 填空题小空json |
|
|
|
|
let { answerData } = opts[0] |
|
|
|
|
if (answerData) { |
|
|
|
|
answerData = JSON.parse(answerData) |
|
|
|
|
|
|
|
|
|
// 正确答案 |
|
|
|
|
let { jsonText } = ques |
|
|
|
|
let scores |
|
|
|
|
if (jsonText) { |
|
|
|
|
jsonText = JSON.parse(jsonText) |
|
|
|
|
const scores = jsonText.scores.map(e => { |
|
|
|
|
scores = jsonText.scores |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const fillScores = answerData.map((e, i) => { |
|
|
|
|
return { |
|
|
|
|
val: e |
|
|
|
|
val: scores ? scores[i] : '' |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
console.log("🚀 ~ getQuesStem ~ ques.scores:", scores) |
|
|
|
|
// this.$set(ques, 'fillScores', scores) |
|
|
|
|
ques.fillScores = fillScores |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (e) { } |
|
|
|
|
return stem |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 填空题分数输入回调 |
|
|
|
|
fillScoreChange (ques) { |
|
|
|
|
let total = 0 |
|
|
|
|
ques.scores.map(e => { |
|
|
|
|
ques.fillScores.map(e => { |
|
|
|
|
if (e.val && !isNaN(e.val)) total = Decimal(total).add(e.val).toNumber() |
|
|
|
|
}) |
|
|
|
|
ques.score = total |
|
|
|
@ -707,10 +719,11 @@ export default { |
|
|
|
|
if (e.questionType !== 'fill_blank' && e.questionType !== 'essay') { |
|
|
|
|
// 判断每个选项的内容是否相同 |
|
|
|
|
const opts = e.questionAnswerVersionsList |
|
|
|
|
if (opts) { |
|
|
|
|
let diff = 0 |
|
|
|
|
for (const j in opts) { |
|
|
|
|
// debugger |
|
|
|
|
if (!n.questionAnswerVersionsList[j] || n.questionAnswerVersionsList[j].optionText !== opts[j].optionText) { |
|
|
|
|
if (!n.questionAnswerVersionsList || !n.questionAnswerVersionsList[j] || n.questionAnswerVersionsList[j].optionText !== opts[j].optionText) { |
|
|
|
|
diff = 1 |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
@ -720,6 +733,7 @@ export default { |
|
|
|
|
e.repeat = true |
|
|
|
|
n.repeat = true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// 填空/问答:题干+题型一样即重复 |
|
|
|
|
if (e.questionType === n.questionType && e.stem === n.stem) { |
|
|
|
@ -741,7 +755,7 @@ export default { |
|
|
|
|
}, |
|
|
|
|
// 提交 |
|
|
|
|
submit (status) { |
|
|
|
|
if (status) { |
|
|
|
|
if (!status) { |
|
|
|
|
// 草稿只需判断名字有没有填 |
|
|
|
|
if (!this.form.name) return Util.warningMsg('请输入试卷名称') |
|
|
|
|
this.validForm(status) |
|
|
|
@ -750,7 +764,7 @@ export default { |
|
|
|
|
const { form } = this |
|
|
|
|
if (form.name === '') return Util.warningMsg('请输入试卷名称') |
|
|
|
|
if (!form.particularYear) return Util.warningMsg('请选择年份') |
|
|
|
|
if (!form.classificationId.length) return Util.warningMsg('请选择所属试卷分类') |
|
|
|
|
if (!form.classificationId) return Util.warningMsg('请选择所属试卷分类') |
|
|
|
|
if (form.paperType === '') return Util.warningMsg('请选择建议用途') |
|
|
|
|
if (form.suggestTime === '') return Util.warningMsg('请输入估计用时') |
|
|
|
|
if (valid) { |
|
|
|
@ -778,7 +792,7 @@ export default { |
|
|
|
|
const allQues = [] |
|
|
|
|
|
|
|
|
|
// 发布才需要校验 |
|
|
|
|
if (!status) { |
|
|
|
|
if (status) { |
|
|
|
|
if (isNaN(form.suggestTime) || form.suggestTime < 1 || form.suggestTime % 1) return Util.warningMsg('估计用时请输入正整数') |
|
|
|
|
let invalid = 0 |
|
|
|
|
for (const i in paper) { |
|
|
|
@ -816,13 +830,10 @@ export default { |
|
|
|
|
if (e.questionType === 'fill_blank') { |
|
|
|
|
let totalScore = 0 |
|
|
|
|
e.examQuestions.map(n => { |
|
|
|
|
const stem = document.querySelector(`#stem` + n.questionVersionId) |
|
|
|
|
if (stem) { |
|
|
|
|
const inputs = stem.querySelectorAll('.fill-input') |
|
|
|
|
if (inputs) { |
|
|
|
|
for (const e of inputs) { |
|
|
|
|
totalScore = Decimal(totalScore).add(e.value || 0).toNumber() |
|
|
|
|
} |
|
|
|
|
const { fillScores } = n |
|
|
|
|
if (fillScores) { |
|
|
|
|
for (const e of fillScores) { |
|
|
|
|
totalScore = Decimal(totalScore).add(e.val || 0).toNumber() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
@ -876,21 +887,13 @@ export default { |
|
|
|
|
e.examQuestions = e.examQuestions.map((n, j) => { |
|
|
|
|
// 填空题的各个填空分数处理 |
|
|
|
|
if (n.questionType === 'fill_blank') { |
|
|
|
|
const stem = document.querySelector(`#stem` + n.questionVersionId) |
|
|
|
|
const scores = [] |
|
|
|
|
if (stem) { |
|
|
|
|
const inputs = stem.querySelectorAll('.fill-input') |
|
|
|
|
if (inputs) { |
|
|
|
|
for (const e of inputs) { |
|
|
|
|
scores.push(e.value) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
const { fillScores } = n |
|
|
|
|
n.jsonText = JSON.stringify({ |
|
|
|
|
questionVersionId: n.questionVersionId, |
|
|
|
|
scores |
|
|
|
|
scores: fillScores ? fillScores.map(m => m.val) : [] |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
questionVersionId: n.questionVersionId, |
|
|
|
|
serialNumber: n.serialNumber, |
|
|
|
@ -925,8 +928,19 @@ export default { |
|
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
|
.input-form.model { |
|
|
|
|
height: calc(100vh - 130px); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.tem-btn { |
|
|
|
|
position: absolute; |
|
|
|
|
top: 0; |
|
|
|
|
right: 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.ques { |
|
|
|
|
li { |
|
|
|
|
padding-bottom: 10px; |
|
|
|
|
margin: 20px 0 10px; |
|
|
|
|
border: 1px solid #dbdbdb; |
|
|
|
|
} |
|
|
|
@ -980,6 +994,10 @@ export default { |
|
|
|
|
padding: 15px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/deep/img { |
|
|
|
|
max-width: 100%; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.ques-info { |
|
|
|
|
position: relative; |
|
|
|
|
width: calc(100% - 40px); |
|
|
|
@ -1070,26 +1088,6 @@ export default { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/deep/.fill-input { |
|
|
|
|
width: 100px; |
|
|
|
|
height: 28px; |
|
|
|
|
padding: 0 15px; |
|
|
|
|
margin: 0 10px; |
|
|
|
|
font-size: 13px; |
|
|
|
|
line-height: 28px; |
|
|
|
|
color: #606266; |
|
|
|
|
border: 1px solid #DCDEE0; |
|
|
|
|
border-radius: 2px; |
|
|
|
|
|
|
|
|
|
&::placeholder { |
|
|
|
|
color: #cfd1db; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&:focus { |
|
|
|
|
outline: none; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.opt { |
|
|
|
|
display: flex; |
|
|
|
|
flex-wrap: wrap; |
|
|
|
@ -1117,8 +1115,10 @@ export default { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.actions { |
|
|
|
|
display: inline-flex; |
|
|
|
|
display: flex; |
|
|
|
|
justify-content: flex-end; |
|
|
|
|
align-items: center; |
|
|
|
|
margin-top: 10px; |
|
|
|
|
|
|
|
|
|
.el-button { |
|
|
|
|
margin: 0 20px 0 0; |
|
|
|
|