|
|
|
@ -1,22 +1,37 @@ |
|
|
|
|
<template> |
|
|
|
|
<div class="page"> |
|
|
|
|
<Breadcrumb :data="crumbs" /> |
|
|
|
|
<div class="page h-full"> |
|
|
|
|
<Breadcrumb v-if="!paperType" :data="crumbs" /> |
|
|
|
|
<p class="page-name mb">试题</p> |
|
|
|
|
<el-form :model="form" :rules="rules" class="input-form model" ref="form" label-width="110px" |
|
|
|
|
:disabled="detailType === 2"> |
|
|
|
|
<el-form :model="form" :rules="rules" :class="['input-form model', { paper: paperType }]" ref="form" |
|
|
|
|
label-width="110px" :disabled="detailType === 2"> |
|
|
|
|
<div class="item-line"> |
|
|
|
|
<el-form-item label="题库分类"> |
|
|
|
|
<el-input v-model="questionBankCategory" disabled /> |
|
|
|
|
</el-form-item> |
|
|
|
|
<el-form-item label="题库"> |
|
|
|
|
<el-input v-model="questionBankName" disabled /> |
|
|
|
|
</el-form-item> |
|
|
|
|
<template v-if="paperType === 1"> |
|
|
|
|
<el-form-item prop="questionBankTypeId" label="题库分类"> |
|
|
|
|
<el-cascader placeholder="请选择题库分类" v-model="form.questionBankTypeId" :options="questionBankTypes" |
|
|
|
|
:props="{ value: 'id', label: 'name', checkStrictly: true }" clearable |
|
|
|
|
@change="getQuesBank"></el-cascader> |
|
|
|
|
</el-form-item> |
|
|
|
|
<el-form-item prop="questionBankId" label="题库"> |
|
|
|
|
<el-select v-model="form.questionBankId" filterable placeholder="请选择题库" @change="getKnowledge"> |
|
|
|
|
<el-option v-for="(item, i) in questionBanks" :key="i" :label="item.questionBankName" |
|
|
|
|
:value="item.id"></el-option> |
|
|
|
|
</el-select> |
|
|
|
|
</el-form-item> |
|
|
|
|
</template> |
|
|
|
|
<template v-else> |
|
|
|
|
<el-form-item label="题库分类"> |
|
|
|
|
<el-input v-model="questionBankCategory" disabled /> |
|
|
|
|
</el-form-item> |
|
|
|
|
<el-form-item label="题库"> |
|
|
|
|
<el-input v-model="questionBankName" disabled /> |
|
|
|
|
</el-form-item> |
|
|
|
|
</template> |
|
|
|
|
</div> |
|
|
|
|
<div class="item-line"> |
|
|
|
|
<el-form-item prop="specialtyIds" label="所属专业"> |
|
|
|
|
<el-select v-model="form.specialtyIds" clearable multiple filterable placeholder="请选择所属专业"> |
|
|
|
|
<el-option v-for="(item, i) in professionals" :key="i" :label="item.professionalName" |
|
|
|
|
:value="item.professionalId" filter></el-option> |
|
|
|
|
:value="item.professionalId"></el-option> |
|
|
|
|
</el-select> |
|
|
|
|
</el-form-item> |
|
|
|
|
<el-form-item prop="knowledgePointIds" label="所属知识点"> |
|
|
|
@ -57,7 +72,8 @@ |
|
|
|
|
</el-form-item> |
|
|
|
|
|
|
|
|
|
<!-- 单选、多选、判断特有 --> |
|
|
|
|
<el-form-item v-if="form.questionType !== 'fill_blank' && form.questionType !== 'essay'" label="正确答案" required> |
|
|
|
|
<el-form-item v-if="form.questionType !== 'fill_blank' && form.questionType !== 'essay'" |
|
|
|
|
prop="questionAnswerVersions" label="正确答案"> |
|
|
|
|
<div class="opts"> |
|
|
|
|
<div v-for="(item, i) in form.questionAnswerVersions" :key="i" class="opt"> |
|
|
|
|
<el-checkbox v-if="form.questionType === 'multiple_choice'" class="correct-check" |
|
|
|
@ -72,8 +88,9 @@ |
|
|
|
|
<UeditorPlus v-else class="opt-editor" :ref="'opt' + item.optionNumber" :config="editorConfig" |
|
|
|
|
v-model="item.optionText" @ready="editor => optReady(editor, item)" /> |
|
|
|
|
<template v-if="form.questionType !== 'judgement'"> |
|
|
|
|
<i class="icon el-icon-circle-plus-outline" @click="addOpt(i)"></i> |
|
|
|
|
<i class="icon el-icon-remove-outline" @click="delOpt(i)"></i> |
|
|
|
|
<i class="icon el-icon-circle-plus-outline m-t-8" @click="addOpt(i)"></i> |
|
|
|
|
<i v-if="form.questionAnswerVersions.length > 2" class="icon el-icon-remove-outline m-t-8" |
|
|
|
|
@click="delOpt(i)"></i> |
|
|
|
|
</template> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
@ -89,8 +106,8 @@ |
|
|
|
|
<div v-if="item.fills" class="fill-items"> |
|
|
|
|
<div v-for="(fill, j) in item.fills" :key="j" class="fill-item"> |
|
|
|
|
<el-input type="textarea" autosize resize="none" placeholder="请输入" v-model="fill.val" /> |
|
|
|
|
<span v-if="j !== item.fills.length - 1" class="m-r-8">或</span> |
|
|
|
|
<i v-if="j" class="action-icon el-icon-remove-outline" @click="item.fills.splice(j, 1)"></i> |
|
|
|
|
<span v-if="j !== item.fills.length - 1">或</span> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
@ -187,15 +204,6 @@ |
|
|
|
|
<el-button type="primary" @click="saveQues">确定</el-button> |
|
|
|
|
</span> |
|
|
|
|
</el-dialog> |
|
|
|
|
|
|
|
|
|
<el-dialog :visible.sync="richEditor.dialogVisible" width="1000px" :show-close="false" center |
|
|
|
|
:close-on-click-modal="false"> |
|
|
|
|
<!-- <UeditorPlus ref="title2" @ready="editorReady" /> --> |
|
|
|
|
<span slot="footer" class="dialog-footer"> |
|
|
|
|
<el-button type="primary" @click="editorSubmit">确定</el-button> |
|
|
|
|
<el-button @click="richEditor.dialogVisible = false">取消</el-button> |
|
|
|
|
</span> |
|
|
|
|
</el-dialog> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
<script> |
|
|
|
@ -209,6 +217,7 @@ import dayjs from 'dayjs' |
|
|
|
|
import _ from 'lodash' |
|
|
|
|
import Const from '@/const/ques' |
|
|
|
|
export default { |
|
|
|
|
props: ['paperType', 'curQues'], // 会接收父组件传值的场景都是组卷里新增或者编辑试题进来的 |
|
|
|
|
components: { Breadcrumb, UeditorPlus, Upload }, |
|
|
|
|
data () { |
|
|
|
|
return { |
|
|
|
@ -218,26 +227,17 @@ export default { |
|
|
|
|
questionBankId: this.$route.query.questionBankId, // 题库id |
|
|
|
|
questionBankName: this.$route.query.questionBankName, |
|
|
|
|
questionBankCategory: this.$route.query.questionBankCategory, |
|
|
|
|
detailType: this.$route.query.detailType, |
|
|
|
|
detailType: +this.$route.query.detailType, |
|
|
|
|
numToLetter: Util.numToLetter, |
|
|
|
|
detailTypes: ['', '复制', '查看', '编辑', '编辑'], |
|
|
|
|
types: [], |
|
|
|
|
cascaderValue: [], |
|
|
|
|
cascaderProps: { |
|
|
|
|
checkStrictly: true, |
|
|
|
|
label: "classificationName", |
|
|
|
|
value: "classificationId" |
|
|
|
|
}, |
|
|
|
|
questionBankTypes: [], |
|
|
|
|
questionBanks: [], |
|
|
|
|
professionals: [], |
|
|
|
|
difficults: Const.difficults, |
|
|
|
|
questionTypes: Const.questionTypes, |
|
|
|
|
knowledges: [], |
|
|
|
|
|
|
|
|
|
editorConfig: {}, |
|
|
|
|
richEditor: { |
|
|
|
|
object: null, |
|
|
|
|
parameterName: '', |
|
|
|
|
instance: null |
|
|
|
|
editorConfig: { |
|
|
|
|
zIndex: 2500, |
|
|
|
|
}, |
|
|
|
|
originForm: {}, |
|
|
|
|
originOpt: { |
|
|
|
@ -252,6 +252,7 @@ export default { |
|
|
|
|
fillBlanks: [], |
|
|
|
|
uploadList: [], |
|
|
|
|
form: { |
|
|
|
|
questionBankTypeId: '', |
|
|
|
|
difficulty: '', |
|
|
|
|
givenYear: new Date(), |
|
|
|
|
knowledgePointIds: [], |
|
|
|
@ -265,6 +266,9 @@ export default { |
|
|
|
|
uploadInstructions: '', |
|
|
|
|
}, |
|
|
|
|
rules: { |
|
|
|
|
questionBankId: [ |
|
|
|
|
{ required: true, message: '请选择题库', trigger: 'change' } |
|
|
|
|
], |
|
|
|
|
knowledgePointIds: [ |
|
|
|
|
{ required: true, message: '请选择知识点', trigger: 'change' } |
|
|
|
|
], |
|
|
|
@ -274,6 +278,9 @@ export default { |
|
|
|
|
questionType: [ |
|
|
|
|
{ required: true, message: '请选择题型', trigger: 'change' } |
|
|
|
|
], |
|
|
|
|
questionAnswerVersions: [ |
|
|
|
|
{ required: true, message: '请选择正确答案', trigger: 'change' } |
|
|
|
|
], |
|
|
|
|
}, |
|
|
|
|
templateVisible: false, |
|
|
|
|
submiting: false, |
|
|
|
@ -302,20 +309,30 @@ export default { |
|
|
|
|
}, |
|
|
|
|
mounted () { |
|
|
|
|
const { query } = this.$route |
|
|
|
|
this.crumbs = [ |
|
|
|
|
{ |
|
|
|
|
name: '试题管理', |
|
|
|
|
route: 'list', |
|
|
|
|
query: { |
|
|
|
|
questionBankId: query.questionBankId, |
|
|
|
|
questionBankName: query.questionBankName, |
|
|
|
|
questionBankCategory: query.questionBankCategory, |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: this.diaTitle |
|
|
|
|
}, |
|
|
|
|
] |
|
|
|
|
if (!this.paperType) { |
|
|
|
|
this.crumbs = [ |
|
|
|
|
{ |
|
|
|
|
name: '试题管理', |
|
|
|
|
route: 'list', |
|
|
|
|
query: { |
|
|
|
|
questionBankId: query.questionBankId, |
|
|
|
|
questionBankName: query.questionBankName, |
|
|
|
|
questionBankCategory: query.questionBankCategory, |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
name: this.diaTitle |
|
|
|
|
}, |
|
|
|
|
] |
|
|
|
|
this.form.questionBankId = query.questionBankId |
|
|
|
|
} else if (this.curQues) { |
|
|
|
|
this.questionId = this.curQues.questionId |
|
|
|
|
this.version = this.curQues.version |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.editorConfig = this.paperType ? { |
|
|
|
|
zIndex: 2500 |
|
|
|
|
} : {} |
|
|
|
|
|
|
|
|
|
this.originForm = _.cloneDeep(this.form) |
|
|
|
|
// this.originFillBlank = _.cloneDeep(this.fillBlanks[0]) |
|
|
|
@ -328,13 +345,15 @@ export default { |
|
|
|
|
this.form = _.cloneDeep(this.originForm) |
|
|
|
|
|
|
|
|
|
const type = this.detailType |
|
|
|
|
// 外面知识点树形选中的知识点默认选中到表单里(选的是知识点才需要默认选中,知识点分类不用) |
|
|
|
|
if (!type) { |
|
|
|
|
if (this.paperType === 1) { |
|
|
|
|
this.getQuesBankType() |
|
|
|
|
this.getQuesBank() |
|
|
|
|
} else if (!type) { |
|
|
|
|
// 外面知识点树形选中的知识点默认选中到表单里(选的是知识点才需要默认选中,知识点分类不用) |
|
|
|
|
const { path } = this.$route.query |
|
|
|
|
if (path) this.form.knowledgePointIds = [path.split('/').map(e => +e)] |
|
|
|
|
} else if (type === 4) { |
|
|
|
|
// this.questionBankId = this.row.questionBankId |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const { stem, answerAnalysis, referenceAnswer, uploadInstructions } = this.$refs |
|
|
|
|
stem && stem.instance && stem.setText('') |
|
|
|
|
answerAnalysis && answerAnalysis.instance && answerAnalysis.setText('') |
|
|
|
@ -363,17 +382,12 @@ export default { |
|
|
|
|
// 获取题目详情 |
|
|
|
|
async getDetail () { |
|
|
|
|
try { |
|
|
|
|
const { questionId, version } = this |
|
|
|
|
let { questionId, version } = this |
|
|
|
|
if (questionId) { |
|
|
|
|
const res = await this.$post(`${this.api.findQuestion}?questionId=${questionId}&version=${version}`) |
|
|
|
|
const r = res.message |
|
|
|
|
const opts = r.questionAnswerVersionsList |
|
|
|
|
|
|
|
|
|
if (this.detailType === 4) { |
|
|
|
|
this.questionBankName = r.questionBankName |
|
|
|
|
// this.questionBankCategory = r.questionBankCategory |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
opts.map(e => e.focus = 0) |
|
|
|
|
this.form = { |
|
|
|
|
questionId: r.questionId, |
|
|
|
@ -391,9 +405,10 @@ export default { |
|
|
|
|
stemAttachment: r.stemAttachment, |
|
|
|
|
uploadInstructions: r.uploadInstructions, |
|
|
|
|
questionAnswerVersions: opts, |
|
|
|
|
questionBankId: r.questionBankId, |
|
|
|
|
} |
|
|
|
|
this.answerAnalysis = opts[0].answerAnalysis |
|
|
|
|
this.fillBlanks = JSON.parse(opts[0].answerData) |
|
|
|
|
this.fillBlanks = opts[0].answerData ? JSON.parse(opts[0].answerData) : [] |
|
|
|
|
|
|
|
|
|
// 题干文件 |
|
|
|
|
const file = r.allowAttachment |
|
|
|
@ -403,19 +418,29 @@ export default { |
|
|
|
|
url: file |
|
|
|
|
}] |
|
|
|
|
} |
|
|
|
|
// 试卷里点击编辑试题进来的 |
|
|
|
|
if (this.paperType === 2) { |
|
|
|
|
this.questionBankName = r.questionBankName |
|
|
|
|
console.log("🚀 ~ getKnowledge ~ id:", this.form) |
|
|
|
|
// this.questionBankCategory = r.questionBankCategory |
|
|
|
|
this.$nextTick(() => { |
|
|
|
|
this.getKnowledge() |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (e) { } |
|
|
|
|
}, |
|
|
|
|
// 获取知识点 |
|
|
|
|
async getKnowledge () { |
|
|
|
|
if (this.questionBankId) { |
|
|
|
|
const { questionBankId: id } = this.form |
|
|
|
|
if (id) { |
|
|
|
|
try { |
|
|
|
|
const { data } = await this.$post(this.api.TreeStructure, { |
|
|
|
|
createSource: 1, |
|
|
|
|
questionBankId: this.questionBankId, |
|
|
|
|
questionBankId: id, |
|
|
|
|
keyword: '', |
|
|
|
|
}) |
|
|
|
|
this.handleType(data) |
|
|
|
|
this.handleType(data, 1) |
|
|
|
|
this.knowledges = data |
|
|
|
|
} catch (e) { } |
|
|
|
|
} |
|
|
|
@ -432,16 +457,42 @@ export default { |
|
|
|
|
} catch (e) { } |
|
|
|
|
}, |
|
|
|
|
// 处理树形 |
|
|
|
|
handleType (list) { |
|
|
|
|
handleType (list, disable) { |
|
|
|
|
list.map(e => { |
|
|
|
|
if (!e.type) e.disabled = true |
|
|
|
|
if (disable && !e.type) e.disabled = true |
|
|
|
|
if (e.children && e.children.length) { |
|
|
|
|
this.handleType(e.children) |
|
|
|
|
this.handleType(e.children, disable) |
|
|
|
|
} else { |
|
|
|
|
delete e.children |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
}, |
|
|
|
|
// 获取启用的题库分类 |
|
|
|
|
async getQuesBankType () { |
|
|
|
|
try { |
|
|
|
|
const { data } = await this.$post(this.api.getAllQuestionBankCategories, { |
|
|
|
|
createSource: 1, |
|
|
|
|
status: 1, |
|
|
|
|
}) |
|
|
|
|
this.handleType(data) |
|
|
|
|
this.questionBankTypes = data |
|
|
|
|
} catch (e) { } |
|
|
|
|
}, |
|
|
|
|
// 获取题库列表 |
|
|
|
|
async getQuesBank () { |
|
|
|
|
try { |
|
|
|
|
let type |
|
|
|
|
const val = this.form.questionBankTypeId |
|
|
|
|
if (val.length) type = val[val.length - 1] |
|
|
|
|
const res = await this.$post(this.api.questionBankList, { |
|
|
|
|
status: 1, |
|
|
|
|
pageNum: 1, |
|
|
|
|
pageSize: 1000, |
|
|
|
|
questionCategoryId: type || '', |
|
|
|
|
}) |
|
|
|
|
this.questionBanks = res.message.records |
|
|
|
|
} catch (e) { } |
|
|
|
|
}, |
|
|
|
|
// 单选多选初始化 |
|
|
|
|
handleSingleMultiple () { |
|
|
|
|
// 选项默认 |
|
|
|
@ -537,31 +588,6 @@ export default { |
|
|
|
|
editor.focus() |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
editorReady (instance) { |
|
|
|
|
console.log("🚀 ~ editorReady ~ instance:", instance) |
|
|
|
|
// this.richEditor.instance = instance |
|
|
|
|
// let currentContent = this.richEditor.object[this.richEditor.parameterName] |
|
|
|
|
// this.richEditor.instance.setContent(currentContent) |
|
|
|
|
// // 光标定位到Ueditor |
|
|
|
|
// this.richEditor.instance.focus(true) |
|
|
|
|
}, |
|
|
|
|
inputClick (object, parameterName) { |
|
|
|
|
this.richEditor.object = object |
|
|
|
|
this.richEditor.parameterName = parameterName |
|
|
|
|
this.richEditor.dialogVisible = true |
|
|
|
|
}, |
|
|
|
|
editorSubmit () { |
|
|
|
|
let content = this.richEditor.instance.getContent() |
|
|
|
|
if (this.richEditor.parameterName === 'title') { // 题干的正确答案重置 |
|
|
|
|
// if (this.questionItemReset(content)) { |
|
|
|
|
// this.richEditor.object[this.richEditor.parameterName] = content |
|
|
|
|
// this.richEditor.dialogVisible = false |
|
|
|
|
// } |
|
|
|
|
} else { |
|
|
|
|
this.richEditor.object[this.richEditor.parameterName] = content |
|
|
|
|
this.richEditor.dialogVisible = false |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 监听题干里的填空题下划线 |
|
|
|
|
questionItemReset (content) { |
|
|
|
|
let spanRegex = new RegExp('<span class="gapfilling-span" (.*?)>(.*?)______(.*?)<\\/span>', 'g') |
|
|
|
@ -637,7 +663,7 @@ export default { |
|
|
|
|
try { |
|
|
|
|
this.beforeSubmitForm = _.cloneDeep(form) |
|
|
|
|
form.stem = stem |
|
|
|
|
form.questionBankId = this.questionBankId |
|
|
|
|
if (!this.paperType) form.questionBankId = this.questionBankId |
|
|
|
|
form.knowledgePointIds = form.knowledgePointIds.map(e => { |
|
|
|
|
return e[e.length - 1] |
|
|
|
|
}) |
|
|
|
@ -669,7 +695,7 @@ export default { |
|
|
|
|
} |
|
|
|
|
if (form.questionId) { |
|
|
|
|
try { |
|
|
|
|
await this.$confirm(`<p style="margin-bottom: 10px;">您确定要保存对本题所做的更改吗?</p>${this.detailType === 4 ? '' : '<p style="margin-bottom: 10px;">保存后,所有关联的试卷将会自动更新</p>'}${keep ? '<p>系统未识别到与本题相似的题目</p>' : ''}`, '提示', { |
|
|
|
|
await this.$confirm(`<p style="margin-bottom: 10px;">您确定要保存对本题所做的更改吗?</p>${this.detailType === 4 ? '' : `<p style="margin-bottom: 10px;">保存后,所有关联的试卷将会自动更新。${keep ? '系统未识别到与本题相似的题目' : ''}</p>`}`, '提示', { |
|
|
|
|
confirmButtonText: '确定', |
|
|
|
|
cancelButtonText: '取消', |
|
|
|
|
type: 'warning', |
|
|
|
@ -697,9 +723,10 @@ export default { |
|
|
|
|
try { |
|
|
|
|
const form = this.tempForm |
|
|
|
|
const type = this.detailType |
|
|
|
|
const paperEdit = this.curQues // 试卷里编辑试题进来的 |
|
|
|
|
// type: 1复制(调新增接口),2查看,3编辑,4是试卷里点编辑试题进来的(调createNewVersion创建新的版本) |
|
|
|
|
const res = await this.$post(this.api[type === 4 ? 'createNewVersion' : type === 1 || !form.questionId ? 'addQuestion' : 'updateQuestion'], form) |
|
|
|
|
type === 4 && this.$emit('updateQues', this.tempForm, res.questionVersionId) |
|
|
|
|
const res = await this.$post(this.api[paperEdit ? 'createNewVersion' : type === 1 || !form.questionId ? 'addQuestion' : 'updateQuestion'], form) |
|
|
|
|
paperEdit && this.$emit('updateQues', form, res.questionVersionId) |
|
|
|
|
|
|
|
|
|
Util.successMsg('保存成功') |
|
|
|
|
!form.questionId && this.keep ? this.init(form) : this.back() |
|
|
|
@ -709,15 +736,21 @@ export default { |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
back () { |
|
|
|
|
this.$router.back() |
|
|
|
|
if (this.paperType) { |
|
|
|
|
// 从试卷里进来的,则直接关闭弹框 |
|
|
|
|
this.$emit('closeAdd') |
|
|
|
|
} else { |
|
|
|
|
this.$router.back() |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
</script> |
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
|
.action-icon { |
|
|
|
|
margin-right: 10px; |
|
|
|
|
.input-form.model.paper { |
|
|
|
|
height: calc(100vh - 172px); |
|
|
|
|
padding-bottom: 30px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.ques { |
|
|
|
@ -807,6 +840,10 @@ export default { |
|
|
|
|
margin-right: 15px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.el-radio { |
|
|
|
|
margin-top: 8px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.opt-input { |
|
|
|
|
width: 100%; |
|
|
|
|
min-height: 32px; |
|
|
|
|