parent
2ae0f95eaf
commit
d2a9e6721c
18 changed files with 1370 additions and 755 deletions
@ -1,3 +0,0 @@ |
||||
export default { |
||||
|
||||
} |
@ -0,0 +1,42 @@ |
||||
export default { |
||||
difficults: [ |
||||
{ |
||||
id: 'basic', |
||||
name: '基础' |
||||
}, |
||||
{ |
||||
id: 'easy', |
||||
name: '普通' |
||||
}, |
||||
{ |
||||
id: 'medium', |
||||
name: '较难' |
||||
}, |
||||
{ |
||||
id: 'hard', |
||||
name: '难' |
||||
}, |
||||
], |
||||
questionTypes: [ |
||||
{ |
||||
id: 'single_choice', |
||||
name: '单选题' |
||||
}, |
||||
{ |
||||
id: 'multiple_choice', |
||||
name: '多选题' |
||||
}, |
||||
{ |
||||
id: 'judgement', |
||||
name: '判断题' |
||||
}, |
||||
{ |
||||
id: 'fill_blank', |
||||
name: '填空题' |
||||
}, |
||||
{ |
||||
id: 'essay', |
||||
name: '问答题' |
||||
}, |
||||
], |
||||
} |
@ -0,0 +1,551 @@ |
||||
<template> |
||||
<div> |
||||
<el-dialog :title="readonly ? '查看试题' : !form.questionId ? '新增试题' : '编辑试题'" :visible.sync="quesVisible" |
||||
width="1000px" :close-on-click-modal="false" @closed="closeDia"> |
||||
<el-form :model="form" :rules="rules" ref="form" label-width="110px" :disabled="readonly"> |
||||
<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> |
||||
<el-form-item prop="specialtyIds" label="所属专业"> |
||||
<el-select v-model="form.specialtyIds" clearable multiple placeholder="请选择所属专业"> |
||||
<el-option v-for="(item, i) in professionals" :key="i" :label="item.professionalName" |
||||
:value="item.professionalId" filter></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="knowledgePointIds" label="所属知识点"> |
||||
<el-cascader placeholder="请选择所属知识点" v-model="form.knowledgePointIds" :options="knowledges" |
||||
:props="{ value: 'id', label: 'name', multiple: true, checkStrictly: true }" clearable></el-cascader> |
||||
</el-form-item> |
||||
<el-form-item prop="givenYear" label="年份"> |
||||
<el-date-picker v-model="form.givenYear" type="year" placeholder="请选择年份" format="yyyy" value-format="yyyy"> |
||||
</el-date-picker> |
||||
</el-form-item> |
||||
<el-form-item prop="difficulty" label="难度"> |
||||
<el-select v-model="form.difficulty" clearable placeholder="请选择试卷难度"> |
||||
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="questionType" label="题型"> |
||||
<el-radio-group v-model="form.questionType" @change="questionTypeChange"> |
||||
<el-radio v-for="(item, i) in questionTypes" :key="i" :label="item.id">{{ item.name }}</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item class="is-required" prop="stem" label="题干"> |
||||
<Ueditor ref="stem" @ready="stemReady" v-model="form.stem" /> |
||||
</el-form-item> |
||||
<el-form-item v-if="form.questionType !== 'fill_blank' && form.questionType !== 'essay'" label="正确答案" required> |
||||
<div class="opts"> |
||||
<div v-for="(item, i) in form.questionAnswerVersions" :key="i" class="line"> |
||||
<el-checkbox v-if="form.questionType === 'multiple_choice'" class="correct-check" |
||||
v-model="item.answerIsCorrect" :true-label="1">选项{{ |
||||
numToLetter(i) |
||||
}}</el-checkbox> |
||||
<el-radio v-else v-model="item.answerIsCorrect" :true-label="1" :label="1" @change="correctChange(i)">选项{{ |
||||
numToLetter(i) |
||||
}}</el-radio> |
||||
<el-input placeholder="请输入" v-model="item.optionText"></el-input> |
||||
<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> |
||||
</template> |
||||
</div> |
||||
</div> |
||||
</el-form-item> |
||||
|
||||
|
||||
<!-- 填空题特有 --> |
||||
<template v-if="form.questionType === 'fill_blank'"> |
||||
<el-form-item label="正确答案" required> |
||||
<div class="opts fill-blanks"> |
||||
<div v-for="(item, i) in fillBlanks" :key="i" class="line j-between"> |
||||
<div class="fills"> |
||||
<span>填空{{ i + 1 }}:</span> |
||||
<div v-for="(fill, j) in item.fills" :key="i" class="fill-item"> |
||||
<el-input placeholder="请输入" v-model="fill.val" /> |
||||
<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> |
||||
|
||||
<el-button class="add-fill" type="primary" size="small" @click="addFill(item)">新增答案</el-button> |
||||
</div> |
||||
<div class="score-wrap"> |
||||
<span>分值占比</span> |
||||
<el-input class="score" placeholder="请输入" size="small" v-model="item.scoreProportion" /> |
||||
<span>%</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</el-form-item> |
||||
<el-form-item prop="gradingStandard" label="判分标准" required> |
||||
<el-select :value="form.questionAnswerVersions[0].gradingStandard" placeholder="请选择判分标准" disabled> |
||||
<el-option label="完全一致" value="exact_match"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="referenceAnswer" label="判分标准"> |
||||
<div> |
||||
<el-switch disabled active-text="判分时忽略答案中的字母大小写"></el-switch> |
||||
</div> |
||||
<div> |
||||
<el-switch disabled active-text="判分时忽略答案中的空格"></el-switch> |
||||
</div> |
||||
<div> |
||||
<el-switch disabled active-text="允许学生每个填空的答案与正确答案的顺序不一致"></el-switch> |
||||
</div> |
||||
<div> |
||||
<el-switch disabled active-text="判分时允许数值相等"></el-switch> |
||||
</div> |
||||
</el-form-item> |
||||
</template> |
||||
|
||||
<!-- 问答题特有 --> |
||||
<template v-if="form.questionType === 'essay'"> |
||||
<el-form-item prop="userName" label="上传题干文件"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="allowAttachment" label="支持学生上传附件" label-width="130px"> |
||||
<el-radio-group v-model="form.allowAttachment"> |
||||
<el-radio :label="0">否</el-radio> |
||||
<el-radio :label="1">是</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item prop="gradingStandard" label="判分标准"> |
||||
<el-select :value="form.questionAnswerVersions[0].gradingStandard" placeholder="请选择判分标准" disabled> |
||||
<el-option label="人工判分" value="manual"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="referenceAnswer" label="参考答案"> |
||||
<Ueditor ref="referenceAnswer" @ready="referenceAnswerReady" |
||||
v-model="form.questionAnswerVersions[0].referenceAnswer" /> |
||||
</el-form-item> |
||||
</template> |
||||
|
||||
<el-form-item prop="answerAnalysis" label="解析"> |
||||
<Ueditor ref="answerAnalysis" @ready="answerAnalysisReady" v-model="answerAnalysis" /> |
||||
</el-form-item> |
||||
</el-form> |
||||
<span slot="footer" class="dialog-footer"> |
||||
<el-button type="primary" :loading="submiting && keep === 0" @click="submit(0)">保存</el-button> |
||||
<el-button type="primary" :loading="submiting && keep === 1" @click="submit(1)">保存并继续新增</el-button> |
||||
<el-button @click="quesVisible = false">取消</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
|
||||
|
||||
<el-dialog title="提示" :visible.sync="repeatVisible" width="800px" :close-on-click-modal="false"> |
||||
<el-alert title="与当前题库中已有的试题重复(如下),是否继续保存?" type="warning" effect="dark" :closable="false"> |
||||
</el-alert> |
||||
<el-table class="m-t-10" :data="repeats" stripe header-align="center" row-key="id"> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="name" label="题型" align="center" min-width="120"> |
||||
<template slot-scope="scope">{{ questionTypes.find(e => e.id === scope.row.questionType) ? |
||||
questionTypes.find(e => e.id === scope.row.questionType).name : '' }}</template> |
||||
</el-table-column> |
||||
<el-table-column prop="stem" label="题干" align="center" min-width="120" show-overflow-tooltip></el-table-column> |
||||
<el-table-column label="操作" align="center" width="240"> |
||||
<template slot-scope="scope"> |
||||
<el-button type="text">详情</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
|
||||
<span slot="footer" class="dialog-footer"> |
||||
<el-button @click="repeatVisible = false">取消</el-button> |
||||
<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"> |
||||
<!-- <Ueditor 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> |
||||
import Setting from '@/setting' |
||||
import Util from '@/libs/util' |
||||
import Ueditor from '@/components/ueditor' |
||||
import dayjs from 'dayjs' |
||||
import _ from 'lodash' |
||||
import Const from '@/const/ques' |
||||
export default { |
||||
props: ['visible', 'row', 'readonly'], |
||||
components: { Ueditor }, |
||||
data () { |
||||
return { |
||||
typeId: this.$route.query.id, |
||||
questionBankName: this.$route.query.questionBankName, |
||||
questionBankCategory: this.$route.query.questionBankCategory, |
||||
numToLetter: Util.numToLetter, |
||||
radio: '', |
||||
types: [], |
||||
cascaderValue: [], |
||||
cascaderProps: { |
||||
checkStrictly: true, |
||||
label: "classificationName", |
||||
value: "classificationId" |
||||
}, |
||||
professionals: [], |
||||
difficults: Const.difficults, |
||||
questionTypes: Const.questionTypes, |
||||
knowledges: [], |
||||
|
||||
richEditor: { |
||||
object: null, |
||||
parameterName: '', |
||||
instance: null |
||||
}, |
||||
originForm: {}, |
||||
originOpt: { |
||||
answerAnalysis: '', |
||||
answerIsCorrect: '', |
||||
optionNumber: '', |
||||
optionText: '', |
||||
}, |
||||
answerAnalysis: '', |
||||
fillBlanks: [ |
||||
{ |
||||
serial: 1, |
||||
fills: [{ |
||||
val: '' |
||||
}], |
||||
scoreProportion: '' |
||||
} |
||||
], |
||||
form: { |
||||
difficulty: '', |
||||
givenYear: new Date(), |
||||
knowledgePointIds: [], |
||||
questionAnswerVersions: [], |
||||
questionBankId: '', |
||||
questionType: 'single_choice', |
||||
specialtyIds: [1], |
||||
stem: '', |
||||
allowAttachment: 0, |
||||
stemAttachment: '', |
||||
uploadInstructions: '', |
||||
}, |
||||
rules: { |
||||
knowledgePointIds: [ |
||||
{ required: true, message: '请选择知识点', trigger: 'change' } |
||||
], |
||||
difficulty: [ |
||||
{ required: true, message: '请选择难度', trigger: 'change' } |
||||
], |
||||
questionType: [ |
||||
{ required: true, message: '请选择题型', trigger: 'change' } |
||||
], |
||||
}, |
||||
templateVisible: false, |
||||
quesVisible: false, |
||||
submiting: false, |
||||
tempForm: {}, |
||||
keep: 0, |
||||
|
||||
repeatVisible: false, |
||||
repeats: [] |
||||
}; |
||||
}, |
||||
watch: { |
||||
visible () { |
||||
this.quesVisible = this.visible |
||||
this.visible && this.init() |
||||
} |
||||
}, |
||||
mounted () { |
||||
this.originForm = _.cloneDeep(this.form) |
||||
}, |
||||
methods: { |
||||
init () { |
||||
this.form = _.cloneDeep(this.originForm) |
||||
// 选项默认 |
||||
for (let i = 1; i < 5; i++) { |
||||
const opt = _.cloneDeep(this.originOpt) |
||||
opt.optionNumber = i |
||||
this.form.questionAnswerVersions.push(opt) |
||||
} |
||||
this.form.questionAnswerVersions[0].answerIsCorrect = 1 |
||||
|
||||
this.$refs.stem.setText('') |
||||
this.$refs.answerAnalysis.setText('') |
||||
|
||||
this.getDetail() |
||||
this.getKnowledge() |
||||
this.getProfessional() |
||||
}, |
||||
// 获取题目详情 |
||||
async getDetail () { |
||||
try { |
||||
const { row } = this |
||||
if (row.questionId) { |
||||
const res = await this.$post(`${this.api.findQuestion}?questionId=${this.row.questionId}&version=${this.row.version}`) |
||||
const r = res.message |
||||
const opts = r.questionAnswerVersionsList |
||||
this.form = { |
||||
questionId: r.questionId, |
||||
questionType: r.questionType, |
||||
questionVersionId: r.questionVersionId, |
||||
version: r.version, |
||||
givenYear: r.givenYear, |
||||
difficulty: r.difficulty, |
||||
stem: r.stem, |
||||
knowledgePointIds: r.knowledgePointList.map(e => { |
||||
return e.path.split('/').map(n => +n) |
||||
}), |
||||
specialtyIds: r.professionalList.map(e => e.specialtyId), |
||||
questionAnswerVersions: opts, |
||||
} |
||||
this.answerAnalysis = opts[0].answerAnalysis |
||||
} |
||||
} catch (e) { } |
||||
}, |
||||
// 获取知识点 |
||||
async getKnowledge () { |
||||
try { |
||||
const { data } = await this.$post(this.api.TreeStructure, { |
||||
createSource: 1, |
||||
questionBankId: this.typeId, |
||||
keyword: '' |
||||
}) |
||||
this.handleType(data) |
||||
this.knowledges = data |
||||
} catch (e) { } |
||||
}, |
||||
// 获取所属专业 |
||||
async getProfessional () { |
||||
try { |
||||
const res = await this.$post(this.api.queryProfessional, { |
||||
pageNum: 1, |
||||
pageSize: 1000, |
||||
}) |
||||
this.professionals = res.pageList.records |
||||
} catch (e) { } |
||||
}, |
||||
// 处理树形 |
||||
handleType (list) { |
||||
list.map(e => { |
||||
if (!e.type) e.disabled = true |
||||
if (e.children && e.children.length) { |
||||
this.handleType(e.children) |
||||
} else { |
||||
delete e.children |
||||
} |
||||
}) |
||||
}, |
||||
// 题型选择回调 |
||||
questionTypeChange (val) { |
||||
// 判断题 |
||||
if (val === 'judgement') { |
||||
const opts = [] |
||||
for (let i = 1; i < 3; i++) { |
||||
const opt = _.cloneDeep(this.originOpt) |
||||
opt.optionNumber = i |
||||
opts.push(opt) |
||||
} |
||||
opts[0].answerIsCorrect = 1 |
||||
opts[0].optionText = '正确' |
||||
opts[1].optionText = '错误' |
||||
this.form.questionAnswerVersions = opts |
||||
} else if (val === 'essay') { |
||||
// 简答题 |
||||
const opt = _.cloneDeep(this.originOpt) |
||||
opt.gradingStandard = 'manual' |
||||
opt.referenceAnswer = '' |
||||
this.form.questionAnswerVersions = [opt] |
||||
} |
||||
}, |
||||
// 题干富文本加载完毕回调 |
||||
stemReady (editor) { |
||||
this.form.stem && editor.setContent(this.form.stem) |
||||
}, |
||||
// 解析富文本加载完毕回调 |
||||
answerAnalysisReady (editor) { |
||||
this.form.answerAnalysis && editor.setContent(this.answerAnalysis) |
||||
}, |
||||
// 正确答案选择回调 |
||||
correctChange (i) { |
||||
this.form.questionAnswerVersions.map(e => { |
||||
e.answerIsCorrect = 0 |
||||
}) |
||||
this.form.questionAnswerVersions[i].answerIsCorrect = 1 |
||||
}, |
||||
// 新增选项 |
||||
addOpt (i) { |
||||
const opt = _.cloneDeep(this.originOpt) |
||||
opt.optionNumber = i + 2 |
||||
this.form.questionAnswerVersions.splice(i + 1, 0, opt) |
||||
}, |
||||
// 移除选项 |
||||
delOpt (i) { |
||||
this.form.questionAnswerVersions.length > 2 && this.form.questionAnswerVersions.splice(i, 1) |
||||
}, |
||||
|
||||
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') |
||||
let _this = this |
||||
let newFormItem = [] |
||||
let gapfillingItems = content.match(spanRegex) |
||||
if (gapfillingItems === null) { |
||||
this.$message.error('请插入填空') |
||||
return false |
||||
} |
||||
gapfillingItems.forEach(function (span, index) { |
||||
let pairRegex = /<span class="gapfilling-span (.*?)">(.*?)<\/span>/ |
||||
pairRegex.test(span) |
||||
newFormItem.push({ id: null, itemUuid: RegExp.$1, prefix: RegExp.$2, content: '', score: '0' }) |
||||
}) |
||||
|
||||
newFormItem.forEach(function (item) { |
||||
_this.form.items.some((oldItem, index) => { |
||||
if (oldItem.itemUuid === item.itemUuid) { |
||||
item.content = oldItem.content |
||||
item.id = oldItem.id |
||||
item.score = oldItem.score |
||||
return true |
||||
} |
||||
}) |
||||
}) |
||||
_this.form.items = newFormItem |
||||
return true |
||||
}, |
||||
// 填空题新增填空项 |
||||
addFill (item) { |
||||
item.fills.push({ val: '' }) |
||||
}, |
||||
// 题目提交 |
||||
submit (keep) { |
||||
if (this.submiting) return false |
||||
this.$refs.form.validate(async (valid) => { |
||||
if (valid) { |
||||
const form = _.cloneDeep(this.form) |
||||
const stem = this.$refs.stem.getUEContent() |
||||
const answerAnalysis = this.$refs.answerAnalysis.getUEContent() |
||||
const opt = form.questionAnswerVersions |
||||
if (!stem) return Util.warningMsg('请输入题干') |
||||
let invalid = 0 |
||||
for (const e of opt) { |
||||
if (!e.optionText) { |
||||
Util.warningMsg('选项请输入完整') |
||||
invalid = 1 |
||||
break |
||||
} |
||||
} |
||||
// debugger |
||||
if (invalid) return false |
||||
if (!opt.find(e => e.answerIsCorrect)) return Util.warningMsg('请设置正确答案') |
||||
this.submiting = true |
||||
try { |
||||
form.stem = stem |
||||
form.questionBankId = this.typeId |
||||
form.knowledgePointIds = form.knowledgePointIds.map(e => { |
||||
return e[e.length - 1] |
||||
}) |
||||
form.givenYear = dayjs(form.givenYear).format('YYYY') |
||||
if (answerAnalysis) form.questionAnswerVersions[0].answerAnalysis = answerAnalysis // 解析保存在选项里第一个对象里 |
||||
|
||||
|
||||
// 判断是否有重复试题,如果有,则弹出重复的试题 |
||||
this.tempForm = form |
||||
this.keep = keep |
||||
const res = await this.$post(this.api.checkQuestion, form) |
||||
// 没有重复的试题,直接保存 |
||||
if (res.status === 200) { |
||||
this.saveQues() |
||||
} |
||||
} catch (e) { |
||||
// 有重复的 |
||||
setTimeout(() => { |
||||
this.repeatVisible = true |
||||
this.repeats = Util.removeTag(e) |
||||
this.submiting = false |
||||
}, 1500) |
||||
} |
||||
} |
||||
}) |
||||
}, |
||||
// 保存题目 |
||||
async saveQues () { |
||||
const form = this.tempForm |
||||
await this.$post(this.api[form.id ? 'updateQuestion' : 'addQuestion'], form) |
||||
Util.successMsg('保存成功') |
||||
this.submiting = false |
||||
this.keep ? this.init() : (this.quesVisible = false) |
||||
this.repeatVisible = false |
||||
}, |
||||
// 弹框关闭回调 |
||||
closeDia () { |
||||
this.$emit('update:visible', false) |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.action-icon { |
||||
margin-right: 10px; |
||||
font-size: 18px; |
||||
color: $main-color; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.ques { |
||||
li { |
||||
padding: 15px; |
||||
margin: 20px 0 10px; |
||||
border: 1px solid #dbdbdb; |
||||
} |
||||
|
||||
.top { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
} |
||||
|
||||
.serial { |
||||
margin-right: 10px; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
.sum { |
||||
margin: 15px 0; |
||||
font-size: 13px; |
||||
color: $main-color; |
||||
} |
||||
} |
||||
|
||||
/deep/.correct-check { |
||||
margin-right: 15px; |
||||
} |
||||
</style> |
@ -1,694 +0,0 @@ |
||||
<template> |
||||
<div> |
||||
<Breadcrumb :data="crumbs" /> |
||||
<div class="page"> |
||||
<div class="side"> |
||||
<div class="m-b-20"> |
||||
<el-radio-group v-model="type" @change="typeChange"> |
||||
<div class="m-b-20"> |
||||
<el-radio :label="1">所有试题</el-radio> |
||||
</div> |
||||
<div> |
||||
<el-radio :label="2">未分配知识点的试题</el-radio> |
||||
</div> |
||||
</el-radio-group> |
||||
</div> |
||||
<el-divider></el-divider> |
||||
<div> |
||||
<div class="flex-between m-b-10"> |
||||
<h6 class="page-name" style="margin-bottom: 0">知识点框架</h6> |
||||
<el-button type="text" @click="toSet">设置</el-button> |
||||
</div> |
||||
<el-input class="m-b-10" placeholder="请输入知识点分类、知识点名称" prefix-icon="el-icon-search" size="small" |
||||
v-model="keyword" clearable></el-input> |
||||
<div style="height: 504px; max-height: 504px; overflow: auto"> |
||||
<el-tree :data="types" default-expand-all ref="orgTree" node-key="id" highlight-current |
||||
:expand-on-click-node="false" @node-click="handleNodeClick" :props="{ label: 'name', isLeaf: 'leaf' }"> |
||||
<span class="custom-tree-node" slot-scope="{ node, data }"> |
||||
<img v-if="data.type" class="m-r-5" src="@/assets/images/knowledge.svg" alt=""> |
||||
<span class="org-name">{{ data.name }}</span> |
||||
</span> |
||||
</el-tree> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="right"> |
||||
<h6 class="page-name">筛选</h6> |
||||
<div class="tool"> |
||||
<ul class="filter"> |
||||
<li> |
||||
<label>题目类型</label> |
||||
<el-select v-model="filter.status" clearable placeholder="请选择题目类型" @change="getList"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>专业</label> |
||||
<el-select v-model="filter.status" clearable placeholder="请选择专业" @change="getList"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>试题难度</label> |
||||
<el-select v-model="filter.status" clearable placeholder="请选择试题难度" @change="getList"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>知识点</label> |
||||
<el-select v-model="filter.status" clearable placeholder="请选择知识点" @change="getList"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>正确率</label> |
||||
<el-input style="width: 80px;" placeholder="请输入" v-model="filter.keyWord" clearable /> |
||||
<span style="margin: 0 10px;">% -- </span> |
||||
<el-input style="width: 80px;" placeholder="请输入" v-model="filter.keyWord" clearable /> |
||||
<span style="margin-left: 10px;">%</span> |
||||
</li> |
||||
<li> |
||||
<label>状态</label> |
||||
<el-select v-model="filter.status" clearable placeholder="请选择状态" @change="getList"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>搜索</label> |
||||
<el-input style="width: 250px;" placeholder="请输入题干" prefix-icon="el-icon-search" v-model="filter.keyWord" |
||||
clearable /> |
||||
</li> |
||||
<div style="margin-bottom: 15px;"> |
||||
<el-button type="primary" @click="add">新增试题</el-button> |
||||
<el-button type="primary" @click="batchImport">批量导入</el-button> |
||||
<!-- <el-button type="primary" @click="add">批量转移</el-button> --> |
||||
<el-button type="primary" @click="add">批量移除 </el-button> |
||||
<el-button type="primary" @click="add">批量删除</el-button> |
||||
</div> |
||||
</ul> |
||||
</div> |
||||
|
||||
<el-table :data="list" class="table" ref="table" stripe header-align="center" |
||||
@selection-change="handleSelectionChange" row-key="id"> |
||||
<el-table-column type="selection" width="55" align="center" :reserve-selection="true"></el-table-column> |
||||
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="userName" label="题干" align="center" min-width="100"></el-table-column> |
||||
<el-table-column prop="account" label="题型" align="center" min-width="100"></el-table-column> |
||||
<el-table-column prop="phone" label="专业" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="invitationAccount" label="知识点" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="invitationAccount" label="年份" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="invitationAccount" label="难度" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="invitationAccount" label="正确率" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="loginNumber" label="更新时间" align="center" width="120"></el-table-column> |
||||
<el-table-column prop="lastLoginTime" label="最近编辑人" align="center" width="120"></el-table-column> |
||||
<el-table-column prop="lastLoginTime" label="已引用试卷(套)" align="center" width="120"></el-table-column> |
||||
<el-table-column label="操作" align="center" width="300"> |
||||
<template slot-scope="scope"> |
||||
<el-button type="text" @click="edit(scope.row)">复制</el-button> |
||||
<el-button type="text" @click="edit(scope.row)">查看</el-button> |
||||
<el-button type="text" @click="edit(scope.row)">编辑</el-button> |
||||
<el-button type="text" @click="del(scope.row)">移除</el-button> |
||||
<el-button type="text" @click="del(scope.row)">删除</el-button> |
||||
<el-switch v-model="scope.row.ztOpen" :active-value="0" :inactive-value="1" style="margin: 0 10px 0 5px" |
||||
:active-text="scope.row.ztOpen ? '关' : '开'" |
||||
@change="switchOff($event, scope.row, scope.$index)"></el-switch> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<div class="pagination"> |
||||
<el-pagination background @current-change="currentChange" :current-page="page" |
||||
layout="total, prev, pager, next" :total="total"></el-pagination> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<el-dialog :title="!form.id ? '创建题目' : '编辑题目'" :visible.sync="quesVisible" width="1000px" |
||||
:close-on-click-modal="false"> |
||||
<el-form label-width="110px"> |
||||
<el-form-item prop="userName" label="题库分类"> |
||||
<el-select style="width: 100%" v-model="form.provinceId" placeholder="请选择题库分类"> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.provinceName" |
||||
:value="item.provinceId"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="题库"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name" disabled></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="所属专业"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="所属知识点"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="年份"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="难度"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="题型"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="题干"> |
||||
<Ueditor ref="title" /> |
||||
</el-form-item> |
||||
<el-form-item label="正确答案" required> |
||||
<div class="opts"> |
||||
<div class="line"> |
||||
<el-radio v-model="radio" label="1">选项A</el-radio> |
||||
<el-input placeholder="请输入" v-model="form.name"></el-input> |
||||
<i class="icon el-icon-circle-plus-outline" @click="addOpt"></i> |
||||
<i class="icon el-icon-remove-outline" @click="delOpt"></i> |
||||
</div> |
||||
<div class="line"> |
||||
<el-radio v-model="radio" label="1">选项B</el-radio> |
||||
<el-input placeholder="请输入" v-model="form.name"></el-input> |
||||
<i class="icon el-icon-circle-plus-outline"></i> |
||||
<i class="icon el-icon-remove-outline"></i> |
||||
</div> |
||||
</div> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="解析"> |
||||
<Ueditor ref="title1" @ready="editorReady" /> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="上传题干文件"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name"></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="支持学生上传附件"> |
||||
<el-radio-group v-model="radio"> |
||||
<el-radio :label="3">否</el-radio> |
||||
<el-radio :label="6">是</el-radio> |
||||
</el-radio-group> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="判分标准"> |
||||
<el-select style="width: 100%" v-model="form.provinceId" placeholder="请选择判分标准"> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.provinceName" |
||||
:value="item.provinceId"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-form> |
||||
<span slot="footer" class="dialog-footer"> |
||||
<el-button type="primary" @click="quesSubmit(0)">保存</el-button> |
||||
<el-button type="primary" @click="quesSubmit(1)">保存并继续新增</el-button> |
||||
<el-button @click="quesVisible = false">取消</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
|
||||
|
||||
<el-dialog :visible.sync="richEditor.dialogVisible" width="1000px" :show-close="false" center |
||||
:close-on-click-modal="false"> |
||||
<Ueditor 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> |
||||
|
||||
|
||||
<el-dialog title="批量导入试题" :visible.sync="importVisible" width="520px" :close-on-click-modal="false" |
||||
:modal-append-to-body="false"> |
||||
<el-form label-width="110px"> |
||||
<el-form-item prop="userName" label="题库分类"> |
||||
<el-select style="width: 100%" v-model="form.provinceId" placeholder="请选择题库分类"> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.provinceName" |
||||
:value="item.provinceId"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="当前题库"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name" disabled></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="模板文件"> |
||||
<el-button type="primary" @click="download">模板下载<i class="el-icon-download el-icon--right"></i></el-button> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="选择文件上传"> |
||||
<el-upload name="file" accept=".xls,.xlsx" ref="upload" class="import-file" drag :before-upload="beforeUpload" |
||||
:on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" |
||||
:limit="1" :data="{ |
||||
// competitionId: id, |
||||
platformId: 2 |
||||
}" :disabled="uploading" :on-exceed="handleExceed" :action="this.api.batchImportPersonalData" |
||||
:file-list="uploadList" :headers="headers"> |
||||
<i class="el-icon-upload"></i> |
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
||||
<div class="el-upload__tip" slot="tip" style="line-height: 1.8;"> |
||||
<p>上传说明:</p> |
||||
<p>1.请按照模板要求,正确填写后上传</p> |
||||
<p>2.上传文件大小限制50M</p> |
||||
<p>3.仅支持上传.xls、 .xlsx文件格式</p> |
||||
</div> |
||||
</el-upload> |
||||
</el-form-item> |
||||
</el-form> |
||||
<span slot="footer" class="dialog-footer"> |
||||
<el-button @click="importVisible = false">关闭</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Util from '@/libs/util' |
||||
import Setting from '@/setting' |
||||
import Ueditor from '@/components/ueditor' |
||||
import Breadcrumb from '@/components/breadcrumb' |
||||
export default { |
||||
components: { Ueditor, Breadcrumb }, |
||||
data () { |
||||
return { |
||||
crumbs: [ |
||||
{ |
||||
name: this.$route.query.name || '题库管理', |
||||
route: '/quesBank' |
||||
}, |
||||
{ |
||||
name: '试题管理' |
||||
}, |
||||
], |
||||
typeId: this.$route.query.id, |
||||
loading: false, |
||||
createSource: 1, |
||||
keyword: '', |
||||
radio: '', |
||||
type: 1, |
||||
types: [], |
||||
status: [ |
||||
{ |
||||
id: 1, |
||||
name: '启用' |
||||
}, |
||||
{ |
||||
id: 2, |
||||
name: '禁用' |
||||
}, |
||||
], |
||||
filter: { |
||||
status: '', |
||||
keyWord: '', |
||||
}, |
||||
list: [], |
||||
page: 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
multipleSelection: [], |
||||
|
||||
form: { |
||||
userName: '', |
||||
provinceId: '', |
||||
cityId: '', |
||||
roleList: [] |
||||
}, |
||||
richEditor: { |
||||
dialogVisible: false, |
||||
object: null, |
||||
parameterName: '', |
||||
instance: null |
||||
}, |
||||
rules: { |
||||
userName: [ |
||||
{ required: true, message: "请输入姓名", trigger: "blur" } |
||||
], |
||||
provinceId: [ |
||||
{ required: true, message: '请选择省份', trigger: "change" } |
||||
], |
||||
cityId: [ |
||||
{ required: true, message: '请选择城市', trigger: "change" } |
||||
], |
||||
roleList: [ |
||||
{ required: true, message: '请选择角色', trigger: "change" } |
||||
], |
||||
}, |
||||
quesVisible: false, |
||||
|
||||
|
||||
submiting: false, // 新增编辑防抖标识 |
||||
setKey: '', |
||||
transferVisible: false, |
||||
chooseVisible: false, |
||||
members: [], |
||||
choosePartnerId: '', |
||||
curRow: '', |
||||
provinces: [], |
||||
cities: [], |
||||
editVisible: false, |
||||
|
||||
importVisible: false, |
||||
uploadList: [], |
||||
uploadFaild: false, |
||||
uploadTips: '', |
||||
exportCode: '', |
||||
headers: { |
||||
token: Util.local.get(Setting.tokenKey) |
||||
}, |
||||
uploading: false, |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(this.getType, 500); |
||||
}, |
||||
keyWord: function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(this.initData, 500); |
||||
} |
||||
}, |
||||
mounted () { |
||||
this.getType() |
||||
}, |
||||
methods: { |
||||
// 获取知识点 |
||||
async getType () { |
||||
try { |
||||
this.loading = true |
||||
const { data } = await this.$post(this.api.TreeStructure, { |
||||
createSource: 1, |
||||
questionBankId: this.typeId, |
||||
keyword: this.keyword, |
||||
}) |
||||
this.types = data |
||||
// this.getList() |
||||
} finally { |
||||
this.loading = false |
||||
} |
||||
}, |
||||
// 前往知识点 |
||||
toSet () { |
||||
this.$router.push(`/knowledge?id=${this.typeId}`) |
||||
}, |
||||
// 类型回调 |
||||
typeChange () { |
||||
this.$refs.orgTree.setCurrentKey(null) |
||||
this.curTeamId = '' |
||||
this.initData() |
||||
}, |
||||
// 获得点击层级里的第一个城市合伙人id |
||||
getTeamId (list) { |
||||
for (const i in list) { |
||||
const e = list[i] |
||||
if (e.isTeam && !this.curTeamId) { |
||||
this.curTeamId = e.id |
||||
break |
||||
} else { |
||||
this.getTeamId(e.children) |
||||
} |
||||
} |
||||
}, |
||||
// 点击树节点查询列表数据 |
||||
handleNodeClick (data) { |
||||
this.type = '' |
||||
this.curTeamId = '' |
||||
if (data.isTeam) { |
||||
this.curTeamId = data.id |
||||
} else { |
||||
// this.getTeamId(data.children) |
||||
} |
||||
if (!this.curTeamId) this.curTeamId = data.id |
||||
this.initData() |
||||
this.$refs.table.clearSelection() |
||||
}, |
||||
// 查询全部 |
||||
getAll () { |
||||
this.curTeamId = '' |
||||
this.getList() |
||||
}, |
||||
// 员工列表 |
||||
getList () { |
||||
this.$post(this.api[this.type ? 'partnerAccountMergeList' : 'partnerAccountList'], { |
||||
type: this.type || 1, |
||||
partnerClassificationId: this.curTeamId, |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize |
||||
}).then(({ pageList }) => { |
||||
pageList.records.forEach((e, i) => { |
||||
e.id = i |
||||
}) |
||||
this.list = pageList.records |
||||
this.total = pageList.total |
||||
}).catch(err => { }) |
||||
}, |
||||
// 切换页码 |
||||
currentChange (val) { |
||||
this.page = val |
||||
this.getList() |
||||
}, |
||||
handleSelectionChange (val) { // 多选 |
||||
this.multipleSelection = val |
||||
}, |
||||
initData () { |
||||
this.$refs.table.clearSelection() |
||||
this.page = 1 |
||||
this.getList() |
||||
}, |
||||
// 删除 |
||||
del (row) { |
||||
this.$confirm("确定要删除吗?", "提示", { |
||||
type: "warning" |
||||
}).then(() => { |
||||
this.$post(`${this.api.delPartnerAccount}?accountId=${row.accountId}`).then(res => { |
||||
Util.successMsg("删除成功") |
||||
this.getList() |
||||
}).catch(res => { }) |
||||
}).catch(() => { }) |
||||
}, |
||||
async switchOff (val, row) { |
||||
this.$post(this.api.disabledEventsCompetition, { |
||||
competitionId: row.id, |
||||
isOpen: val, |
||||
type: 0 // 禁用平台来源(0中台,1职站) |
||||
}).then(res => { |
||||
Util.successMsg(val == 1 ? '禁用成功' : '启用成功') |
||||
}).catch(err => { }) |
||||
|
||||
await this.$post(`${this.api.refreshPageNotification}?content=1`) |
||||
}, |
||||
// 编辑 |
||||
edit (row) { |
||||
if (!row.provinceId) row.provinceId = '' |
||||
if (!row.cityId) row.cityId = '' |
||||
row.roleList = row.roleId.split(',').map(e => +e) |
||||
this.editVisible = true |
||||
this.form = JSON.parse(JSON.stringify(row)) |
||||
}, |
||||
// 新增选项 |
||||
addOpt (i) { |
||||
|
||||
}, |
||||
// 移除选项 |
||||
delOpt (i) { |
||||
|
||||
}, |
||||
|
||||
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') |
||||
let _this = this |
||||
let newFormItem = [] |
||||
let gapfillingItems = content.match(spanRegex) |
||||
if (gapfillingItems === null) { |
||||
this.$message.error('请插入填空') |
||||
return false |
||||
} |
||||
gapfillingItems.forEach(function (span, index) { |
||||
let pairRegex = /<span class="gapfilling-span (.*?)">(.*?)<\/span>/ |
||||
pairRegex.test(span) |
||||
newFormItem.push({ id: null, itemUuid: RegExp.$1, prefix: RegExp.$2, content: '', score: '0' }) |
||||
}) |
||||
|
||||
newFormItem.forEach(function (item) { |
||||
_this.form.items.some((oldItem, index) => { |
||||
if (oldItem.itemUuid === item.itemUuid) { |
||||
item.content = oldItem.content |
||||
item.id = oldItem.id |
||||
item.score = oldItem.score |
||||
return true |
||||
} |
||||
}) |
||||
}) |
||||
_this.form.items = newFormItem |
||||
return true |
||||
}, |
||||
|
||||
// 编辑提交 |
||||
submitEdit () { |
||||
this.$refs.form.validate((valid) => { |
||||
if (valid) { |
||||
if (this.submiting) return false |
||||
this.submiting = true |
||||
const form = JSON.parse(JSON.stringify(this.form)) |
||||
form.classificationId = form.partnerClassificationId |
||||
this.$post(this.api.editProvinceCity, form).then(res => { |
||||
this.getList() |
||||
Util.successMsg("编辑成功!") |
||||
this.editVisible = false |
||||
setTimeout(() => { |
||||
this.submiting = false |
||||
}, 2000) |
||||
}).catch(res => { |
||||
setTimeout(() => { |
||||
this.submiting = false |
||||
}, 2000) |
||||
}) |
||||
} |
||||
}) |
||||
}, |
||||
// 添加 |
||||
add () { |
||||
this.quesVisible = true |
||||
}, |
||||
editorReady (instance) { |
||||
// this.richEditor.instance = instance |
||||
// let currentContent = this.richEditor.object[this.richEditor.parameterName] |
||||
// this.richEditor.instance.setContent(currentContent) |
||||
// // 光标定位到Ueditor |
||||
// this.richEditor.instance.focus(true) |
||||
}, |
||||
// 题目提交 |
||||
quesSubmit () { |
||||
console.log(55, this.richEditor, this.$refs.title.getUEContent(), this.$refs.title1.getUEContent()) |
||||
}, |
||||
|
||||
// 批量导入 |
||||
batchImport () { |
||||
this.importVisible = true |
||||
this.uploadList = [] |
||||
this.uploadFaild = false |
||||
}, |
||||
// 模板下载 |
||||
download () { |
||||
location.href = this.api[this.info.completeCompetitionSetup.competitionType ? 'competionTeamTemplate' : 'competionPersonTemplate'] |
||||
}, |
||||
// 上传文件 |
||||
handleExceed (files, fileList) { |
||||
Util.warningMsg( |
||||
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!` |
||||
) |
||||
}, |
||||
// 下载失败文件 |
||||
showFaild () { |
||||
axios.get(`${this.api.TeamDataExportFailure}?exportCode=${this.exportCode}&platformId=2&type=${this.info.completeCompetitionSetup.competitionType ? 1 : 2}`, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}).then((res) => { |
||||
const name = res.headers['content-disposition'] |
||||
Util.downloadFileDirect(name ? decodeURI(name) : '批量导入报名人员失败数据导出.xlsx', new Blob([res.data])) |
||||
}).catch(res => { }) |
||||
}, |
||||
uploadSuccess ({ data, status }) { |
||||
this.uploading = false |
||||
this.uploadFaild = false |
||||
this.uploadTips = '' |
||||
if (status === 200) { |
||||
this.init() |
||||
const { tip } = data |
||||
if (data.exportCode) { |
||||
this.exportCode = data.exportCode |
||||
this.uploadFaild = true |
||||
this.uploadTips = tip |
||||
} else { |
||||
Util[tip.includes('5000') ? 'errorMsg' : 'successMsg'](tip, 3000) |
||||
this.importVisible = false |
||||
} |
||||
} else { |
||||
Util.errorMsg(res.message || '上传失败,请检查数据', 3000) |
||||
} |
||||
}, |
||||
uploadError (err, file, fileList) { |
||||
this.uploading = false |
||||
this.$message({ |
||||
message: "上传出错,请重试!", |
||||
type: "error", |
||||
center: true |
||||
}) |
||||
}, |
||||
beforeUpload (file) { |
||||
this.uploading = true |
||||
}, |
||||
beforeRemove (file, fileList) { |
||||
return this.$confirm(`确定移除 ${file.name}?`) |
||||
}, |
||||
handleRemove (file, fileList) { |
||||
this.uploadList = fileList |
||||
this.uploadFaild = false |
||||
}, |
||||
cancelUpload () { |
||||
this.uploading = false |
||||
this.$refs.upload.abort() |
||||
this.keyword = '' |
||||
this.init() |
||||
this.importVisible = false |
||||
}, |
||||
// 后台上传 |
||||
backstageUpload () { |
||||
this.isBackstage = 1 |
||||
this.importVisible = false |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.page { |
||||
display: flex; |
||||
padding: 0 24px; |
||||
|
||||
.side { |
||||
width: 300px; |
||||
padding: 24px 10px 24px 0; |
||||
margin-right: 24px; |
||||
border-right: 1px solid rgba(0, 0, 0, 0.06); |
||||
} |
||||
|
||||
.right { |
||||
width: calc(100% - 324px); |
||||
padding: 24px 0; |
||||
} |
||||
} |
||||
|
||||
.tool { |
||||
margin-bottom: 0; |
||||
|
||||
.filter { |
||||
flex-wrap: wrap; |
||||
justify-content: space-between; |
||||
|
||||
li { |
||||
margin-bottom: 15px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/deep/.opts { |
||||
.line { |
||||
display: flex; |
||||
align-items: center; |
||||
margin-bottom: 15px; |
||||
} |
||||
|
||||
.el-radio { |
||||
margin-right: 15px; |
||||
} |
||||
|
||||
.icon { |
||||
margin-left: 10px; |
||||
font-size: 18px; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,560 @@ |
||||
<template> |
||||
<div> |
||||
<Breadcrumb :data="crumbs" /> |
||||
<div class="page"> |
||||
<div class="side"> |
||||
<div class="m-b-20"> |
||||
<el-radio-group v-model="isNotJoin" @change="typeChange"> |
||||
<div class="m-b-20"> |
||||
<el-radio :label="0">所有试题</el-radio> |
||||
</div> |
||||
<div> |
||||
<el-radio :label="1">未分配知识点的试题</el-radio> |
||||
</div> |
||||
</el-radio-group> |
||||
</div> |
||||
<el-divider></el-divider> |
||||
<div> |
||||
<div class="flex-between m-b-10"> |
||||
<h6 class="page-name" style="margin-bottom: 0">知识点框架</h6> |
||||
<el-button type="text" @click="toSet">设置</el-button> |
||||
</div> |
||||
<el-input class="m-b-10" placeholder="请输入知识点分类、知识点名称" prefix-icon="el-icon-search" size="small" |
||||
v-model="keyword" clearable></el-input> |
||||
<div style="height: 504px; max-height: 504px; overflow: auto"> |
||||
<el-tree :data="types" default-expand-all ref="typeTree" node-key="id" highlight-current |
||||
:expand-on-click-node="false" @node-click="handleNodeClick" :props="{ label: 'name', isLeaf: 'leaf' }"> |
||||
<span class="custom-tree-node" slot-scope="{ node, data }"> |
||||
<img v-if="data.type" class="m-r-5" src="@/assets/images/knowledge.svg" alt=""> |
||||
<span class="org-name">{{ data.name }}</span> |
||||
</span> |
||||
</el-tree> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="right"> |
||||
<h6 class="page-name">筛选</h6> |
||||
<div class="tool"> |
||||
<ul class="filter"> |
||||
<li> |
||||
<label>题目类型</label> |
||||
<el-select v-model="filter.questionTypes" clearable placeholder="请选择题目类型" multiple @change="initData"> |
||||
<el-option v-for="(item, i) in questionTypes" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>专业</label> |
||||
<el-select v-model="filter.specialtyIds" clearable placeholder="请选择专业" multiple @change="initData"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>年份</label> |
||||
<el-date-picker v-model="givenYears" type="year" placeholder="请选择年份" format="yyyy" value-format="yyyy" |
||||
multiple @change="initData"> |
||||
</el-date-picker> |
||||
</li> |
||||
<li> |
||||
<label>试题难度</label> |
||||
<el-select v-model="filter.difficultys" clearable placeholder="请选择试题难度" multiple @change="initData"> |
||||
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>知识点</label> |
||||
<el-cascader :disabled="isNotJoin !== 0" placeholder="请选择知识点" v-model="knowledgePointIds" |
||||
:options="knowledges" :props="{ value: 'id', label: 'name', multiple: true }" clearable collapse-tags |
||||
@change="initData"></el-cascader> |
||||
</li> |
||||
<li> |
||||
<label>正确率</label> |
||||
<el-input style="width: 90px;" placeholder="请输入" v-model="filter.correctRateStart" clearable /> |
||||
<span style="margin: 0 10px;">% -- </span> |
||||
<el-input style="width: 90px;" placeholder="请输入" v-model="filter.correctRateEnd" clearable /> |
||||
<span style="margin-left: 10px;">%</span> |
||||
</li> |
||||
<li> |
||||
<label>状态</label> |
||||
<el-select v-model="filter.status" clearable placeholder="请选择状态" @change="initData"> |
||||
<el-option v-for="(item, i) in status" :key="i" :label="item.name" :value="item.id"></el-option> |
||||
</el-select> |
||||
</li> |
||||
<li> |
||||
<label>搜索</label> |
||||
<el-input style="width: 250px;" placeholder="请输入题干" prefix-icon="el-icon-search" v-model="filter.keyword" |
||||
clearable /> |
||||
</li> |
||||
<div style="margin-bottom: 15px;"> |
||||
<el-button type="primary" @click="add">新增试题</el-button> |
||||
<el-button type="primary" @click="batchImport">批量导入</el-button> |
||||
<!-- <el-button type="primary" @click="add">批量转移</el-button> --> |
||||
<el-button type="primary" @click="add">批量移除 </el-button> |
||||
<el-button type="primary" @click="add">批量删除</el-button> |
||||
</div> |
||||
</ul> |
||||
</div> |
||||
|
||||
<el-table :data="list" class="table" ref="table" stripe header-align="center" |
||||
@selection-change="handleSelectionChange" row-key="id"> |
||||
<el-table-column type="selection" width="45" align="center" :reserve-selection="true"></el-table-column> |
||||
<el-table-column type="index" width="50" label="序号" align="center"></el-table-column> |
||||
<el-table-column prop="stem" label="题干" align="center" min-width="120" show-overflow-tooltip></el-table-column> |
||||
<el-table-column prop="account" label="题型" align="center" width="100"> |
||||
<template slot-scope="scope">{{ questionTypes.find(e => e.id === scope.row.questionType) ? |
||||
questionTypes.find(e => e.id === scope.row.questionType).name : '' }}</template> |
||||
</el-table-column> |
||||
<el-table-column prop="professionalName" label="专业" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="knowledgePointName" label="知识点" align="center" min-width="120"></el-table-column> |
||||
<el-table-column prop="givenYear" label="年份" align="center" width="50"></el-table-column> |
||||
<el-table-column prop="difficulty" label="难度" align="center" width="50"> |
||||
<template slot-scope="scope">{{ difficults.find(e => e.id === scope.row.difficulty) ? difficults.find(e => |
||||
e.id === scope.row.difficulty).name : '' }}</template> |
||||
</el-table-column> |
||||
<el-table-column prop="correctRate" label="正确率" align="center" width="60"></el-table-column> |
||||
<el-table-column prop="updateTime" label="更新时间" align="center" width="140"></el-table-column> |
||||
<el-table-column prop="lastEditor" label="最近编辑人" align="center" width="90"></el-table-column> |
||||
<el-table-column prop="referenceCount" label="已引用试卷(套)" align="center" width="100"></el-table-column> |
||||
<el-table-column label="操作" align="center" width="300"> |
||||
<template slot-scope="scope"> |
||||
<el-button type="text" @click="copy(scope.row)">复制</el-button> |
||||
<el-button type="text" @click="toDetail(scope.row, 1)">查看</el-button> |
||||
<el-button type="text" @click="toDetail(scope.row)">编辑</el-button> |
||||
<el-button type="text" @click="del(scope.row)">移除</el-button> |
||||
<el-button type="text" @click="del(scope.row)">删除</el-button> |
||||
<el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0" style="margin: 0 10px 0 5px" |
||||
:active-text="scope.row.status ? '开' : '关'" |
||||
@change="switchOff($event, scope.row, scope.$index)"></el-switch> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
<div class="pagination"> |
||||
<el-pagination background @current-change="currentChange" :current-page="page" |
||||
layout="total, prev, pager, next" :total="total"></el-pagination> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<Detail :visible.sync="quesVisible" :row.sync="curRow" :readonly.sync="readonly" /> |
||||
|
||||
<el-dialog title="批量导入试题" :visible.sync="importVisible" width="520px" :close-on-click-modal="false" |
||||
:modal-append-to-body="false"> |
||||
<el-form label-width="110px"> |
||||
<el-form-item prop="userName" label="题库分类"> |
||||
<el-select style="width: 100%" v-model="form.provinceId" placeholder="请选择题库分类"> |
||||
<el-option v-for="(item, i) in types" :key="i" :label="item.provinceName" |
||||
:value="item.provinceId"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="当前题库"> |
||||
<el-input placeholder="请输入题库名称" v-model="form.name" disabled></el-input> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="模板文件"> |
||||
<el-button type="primary" @click="download">模板下载<i class="el-icon-download el-icon--right"></i></el-button> |
||||
</el-form-item> |
||||
<el-form-item prop="userName" label="选择文件上传"> |
||||
<el-upload name="file" accept=".xls,.xlsx" ref="upload" class="import-file" drag :before-upload="beforeUpload" |
||||
:on-remove="handleRemove" :on-error="uploadError" :on-success="uploadSuccess" :before-remove="beforeRemove" |
||||
:limit="1" :data="{ |
||||
// competitionId: id, |
||||
platformId: 2 |
||||
}" :disabled="uploading" :on-exceed="handleExceed" :action="this.api.batchImportPersonalData" |
||||
:file-list="uploadList" :headers="headers"> |
||||
<i class="el-icon-upload"></i> |
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
||||
<div class="el-upload__tip" slot="tip" style="line-height: 1.8;"> |
||||
<p>上传说明:</p> |
||||
<p>1.请按照模板要求,正确填写后上传</p> |
||||
<p>2.上传文件大小限制50M</p> |
||||
<p>3.仅支持上传.xls、 .xlsx文件格式</p> |
||||
</div> |
||||
</el-upload> |
||||
</el-form-item> |
||||
</el-form> |
||||
<span slot="footer" class="dialog-footer"> |
||||
<el-button @click="importVisible = false">关闭</el-button> |
||||
</span> |
||||
</el-dialog> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import Util from '@/libs/util' |
||||
import Setting from '@/setting' |
||||
import Ueditor from '@/components/ueditor' |
||||
import Breadcrumb from '@/components/breadcrumb' |
||||
import Detail from '../detail' |
||||
import Const from '@/const/ques' |
||||
export default { |
||||
components: { Ueditor, Breadcrumb, Detail }, |
||||
data () { |
||||
return { |
||||
crumbs: [ |
||||
{ |
||||
name: this.$route.query.questionBankName || '题库管理', |
||||
route: '/quesBank' |
||||
}, |
||||
{ |
||||
name: '试题管理' |
||||
}, |
||||
], |
||||
difficults: Const.difficults, |
||||
questionTypes: Const.questionTypes, |
||||
typeId: this.$route.query.id, |
||||
loading: false, |
||||
isNotJoin: 0, |
||||
createSource: 1, |
||||
keyword: '', |
||||
type: 1, |
||||
types: [], |
||||
status: [ |
||||
{ |
||||
id: 1, |
||||
name: '启用' |
||||
}, |
||||
{ |
||||
id: 0, |
||||
name: '禁用' |
||||
}, |
||||
], |
||||
knowledges: [], |
||||
givenYears: '', |
||||
knowledgePointIds: [], |
||||
filter: { |
||||
questionTypes: [], |
||||
correctRateEnd: '', |
||||
correctRateStart: '', |
||||
difficultys: [], |
||||
specialtyIds: [], |
||||
status: '', |
||||
keyword: '', |
||||
}, |
||||
list: [], |
||||
page: 1, |
||||
pageSize: 10, |
||||
total: 0, |
||||
multipleSelection: [], |
||||
|
||||
quesVisible: false, |
||||
curRow: {}, |
||||
readonly: false, |
||||
|
||||
form: {}, |
||||
importVisible: false, |
||||
uploadList: [], |
||||
uploadFaild: false, |
||||
uploadTips: '', |
||||
exportCode: '', |
||||
headers: { |
||||
token: Util.local.get(Setting.tokenKey) |
||||
}, |
||||
uploading: false, |
||||
}; |
||||
}, |
||||
watch: { |
||||
keyword: function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(this.getType, 500); |
||||
}, |
||||
'filter.keyword': function (val) { |
||||
clearTimeout(this.searchTimer); |
||||
this.searchTimer = setTimeout(this.initData, 500); |
||||
}, |
||||
quesVisible () { |
||||
this.quesVisible || this.getList() |
||||
} |
||||
}, |
||||
mounted () { |
||||
this.getType() |
||||
this.getKnowledge() |
||||
}, |
||||
methods: { |
||||
// 获取知识点 |
||||
async getType () { |
||||
try { |
||||
this.loading = true |
||||
const { data } = await this.$post(this.api.TreeStructure, { |
||||
createSource: 1, |
||||
questionBankId: this.typeId, |
||||
keyword: this.keyword, |
||||
}) |
||||
this.types = data |
||||
this.getList() |
||||
} finally { |
||||
this.loading = false |
||||
} |
||||
}, |
||||
// 前往知识点 |
||||
toSet () { |
||||
this.$router.push(`/knowledge?id=${this.typeId}`) |
||||
}, |
||||
// 类型回调 |
||||
typeChange () { |
||||
this.$refs.typeTree.setCurrentKey(null) |
||||
this.initData() |
||||
}, |
||||
// 点击树节点查询列表数据 |
||||
handleNodeClick () { |
||||
this.isNotJoin = '' |
||||
this.initData() |
||||
this.$refs.table.clearSelection() |
||||
}, |
||||
// 处理树形 |
||||
handleType (list) { |
||||
list.map(e => { |
||||
if (e.children && e.children.length) { |
||||
this.handleType(e.children) |
||||
} else { |
||||
delete e.children |
||||
} |
||||
}) |
||||
}, |
||||
// 获取知识点 |
||||
async getKnowledge () { |
||||
try { |
||||
const { data } = await this.$post(this.api.TreeStructure, { |
||||
createSource: 1, |
||||
questionBankId: this.typeId, |
||||
keyword: '' |
||||
}) |
||||
this.handleType(data) |
||||
this.knowledges = data |
||||
} catch (e) { } |
||||
}, |
||||
// 列表 |
||||
async getList () { |
||||
let type = this.$refs.typeTree.getCurrentKey() |
||||
const k = this.knowledgePointIds |
||||
if (k.length) { // 右边筛选里的知识点 |
||||
type = k.map(e => { |
||||
return e[e.length - 1] |
||||
}) |
||||
} else if (type) { |
||||
type = [type] |
||||
} |
||||
const { message } = await this.$post(this.api.listQuestion, { |
||||
...this.filter, |
||||
givenYears: this.givenYears ? [this.givenYears] : [], |
||||
isNotJoin: this.isNotJoin || '', |
||||
pageNum: this.page, |
||||
pageSize: this.pageSize, |
||||
questionBankId: this.typeId, |
||||
knowledgePointIds: type || [], |
||||
}) |
||||
this.list = Util.removeTag(message.records) |
||||
this.total = message.total |
||||
}, |
||||
// 切换页码 |
||||
currentChange (val) { |
||||
this.page = val |
||||
this.getList() |
||||
}, |
||||
handleSelectionChange (val) { // 多选 |
||||
this.multipleSelection = val |
||||
}, |
||||
initData () { |
||||
this.$refs.table.clearSelection() |
||||
this.page = 1 |
||||
this.getList() |
||||
}, |
||||
|
||||
// 添加 |
||||
add () { |
||||
this.quesVisible = true |
||||
this.curRow = {} |
||||
this.readonly = false |
||||
}, |
||||
// 复制 |
||||
copy (row) { |
||||
|
||||
}, |
||||
// 编辑/查看 |
||||
toDetail (row, readonly = false) { |
||||
this.quesVisible = true |
||||
this.curRow = row |
||||
this.readonly = readonly |
||||
}, |
||||
// 删除 |
||||
del (row) { |
||||
this.$confirm("确定要删除吗?", "提示", { |
||||
type: "warning" |
||||
}).then(() => { |
||||
this.$post(`${this.api.delPartnerAccount}?accountId=${row.accountId}`).then(res => { |
||||
Util.successMsg("删除成功") |
||||
this.getList() |
||||
}).catch(res => { }) |
||||
}).catch(() => { }) |
||||
}, |
||||
async switchOff (val, row) { |
||||
this.$post(this.api.disabledEventsCompetition, { |
||||
competitionId: row.id, |
||||
isOpen: val, |
||||
type: 0 // 禁用平台来源(0中台,1职站) |
||||
}).then(res => { |
||||
Util.successMsg(val == 1 ? '禁用成功' : '启用成功') |
||||
}).catch(err => { }) |
||||
|
||||
await this.$post(`${this.api.refreshPageNotification}?content=1`) |
||||
}, |
||||
|
||||
|
||||
// 批量导入 |
||||
batchImport () { |
||||
this.importVisible = true |
||||
this.uploadList = [] |
||||
this.uploadFaild = false |
||||
}, |
||||
// 模板下载 |
||||
download () { |
||||
location.href = this.api[this.info.completeCompetitionSetup.competitionType ? 'competionTeamTemplate' : 'competionPersonTemplate'] |
||||
}, |
||||
// 上传文件 |
||||
handleExceed (files, fileList) { |
||||
Util.warningMsg( |
||||
`当前限制选择 1 个文件,如需更换,请删除上一个文件再重新选择!` |
||||
) |
||||
}, |
||||
// 下载失败文件 |
||||
showFaild () { |
||||
axios.get(`${this.api.TeamDataExportFailure}?exportCode=${this.exportCode}&platformId=2&type=${this.info.completeCompetitionSetup.competitionType ? 1 : 2}`, { |
||||
headers: this.headers, |
||||
responseType: 'blob' |
||||
}).then((res) => { |
||||
const name = res.headers['content-disposition'] |
||||
Util.downloadFileDirect(name ? decodeURI(name) : '批量导入报名人员失败数据导出.xlsx', new Blob([res.data])) |
||||
}).catch(res => { }) |
||||
}, |
||||
uploadSuccess ({ data, status }) { |
||||
this.uploading = false |
||||
this.uploadFaild = false |
||||
this.uploadTips = '' |
||||
if (status === 200) { |
||||
this.init() |
||||
const { tip } = data |
||||
if (data.exportCode) { |
||||
this.exportCode = data.exportCode |
||||
this.uploadFaild = true |
||||
this.uploadTips = tip |
||||
} else { |
||||
Util[tip.includes('5000') ? 'errorMsg' : 'successMsg'](tip, 3000) |
||||
this.importVisible = false |
||||
} |
||||
} else { |
||||
Util.errorMsg(res.message || '上传失败,请检查数据', 3000) |
||||
} |
||||
}, |
||||
uploadError (err, file, fileList) { |
||||
this.uploading = false |
||||
this.$message({ |
||||
message: "上传出错,请重试!", |
||||
type: "error", |
||||
center: true |
||||
}) |
||||
}, |
||||
beforeUpload (file) { |
||||
this.uploading = true |
||||
}, |
||||
beforeRemove (file, fileList) { |
||||
return this.$confirm(`确定移除 ${file.name}?`) |
||||
}, |
||||
handleRemove (file, fileList) { |
||||
this.uploadList = fileList |
||||
this.uploadFaild = false |
||||
}, |
||||
cancelUpload () { |
||||
this.uploading = false |
||||
this.$refs.upload.abort() |
||||
this.keyword = '' |
||||
this.init() |
||||
this.importVisible = false |
||||
}, |
||||
// 后台上传 |
||||
backstageUpload () { |
||||
this.isBackstage = 1 |
||||
this.importVisible = false |
||||
}, |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.page { |
||||
display: flex; |
||||
padding: 0 24px; |
||||
|
||||
.side { |
||||
width: 300px; |
||||
padding: 24px 10px 24px 0; |
||||
margin-right: 24px; |
||||
border-right: 1px solid rgba(0, 0, 0, 0.06); |
||||
} |
||||
|
||||
.right { |
||||
width: calc(100% - 324px); |
||||
padding: 24px 0; |
||||
} |
||||
} |
||||
|
||||
.tool { |
||||
margin-bottom: 0; |
||||
|
||||
.filter { |
||||
flex-wrap: wrap; |
||||
justify-content: space-between; |
||||
|
||||
li { |
||||
margin-bottom: 15px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/deep/.opts { |
||||
.line { |
||||
display: flex; |
||||
align-items: center; |
||||
margin-bottom: 15px; |
||||
} |
||||
|
||||
.el-radio { |
||||
margin-right: 15px; |
||||
} |
||||
|
||||
.icon { |
||||
margin-left: 10px; |
||||
font-size: 18px; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
|
||||
/deep/.fill-blanks { |
||||
.fills { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
} |
||||
|
||||
.fill-item { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
margin-right: 10px; |
||||
|
||||
.el-input { |
||||
width: 100px; |
||||
margin-right: 10px; |
||||
} |
||||
} |
||||
|
||||
.add-fill { |
||||
margin-left: 10px; |
||||
} |
||||
|
||||
.score-wrap { |
||||
display: inline-flex; |
||||
align-items: center; |
||||
|
||||
.el-input { |
||||
width: 80px; |
||||
margin: 0 10px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
Loading…
Reference in new issue