parent
10b6532744
commit
9ded1da513
9 changed files with 575 additions and 72 deletions
@ -0,0 +1,443 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-dialog title="自动选题" :visible.sync="quesVisible" width="1200px" :close-on-click-modal="false" @closed="closeDia"> |
||||||
|
<h6 class="page-name">难度设置</h6> |
||||||
|
<div class="tool"> |
||||||
|
<ul class="filter"> |
||||||
|
<li> |
||||||
|
<label>试卷难度</label> |
||||||
|
<el-select v-model="difficult" placeholder="请选择试卷难度" @change="difficultData"> |
||||||
|
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option> |
||||||
|
</el-select> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
|
||||||
|
<el-table :data="list" stripe header-align="center" row-key="libraryId"> |
||||||
|
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column> |
||||||
|
<el-table-column label="大题" align="center" min-width="100"> |
||||||
|
<template slot-scope="scope">第{{ arabicToChinese(scope.$index + 1) }}大题</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column prop="name" label="题型" align="center" min-width="90"> |
||||||
|
<template slot-scope="scope"> |
||||||
|
<p v-if="scope.row.questionType">{{ questionTypes.find(e => e.id === scope.row.questionType).name }}</p> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column prop="questionNum" label="目标题数" align="center" min-width="80"></el-table-column> |
||||||
|
<el-table-column label="基础(道题)" align="center" width="90"> |
||||||
|
<template slot-scope="scope"> |
||||||
|
<el-input v-model.number="scope.row.basicDifficulty" type="number" /> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="普通(道题)" align="center" width="90"> |
||||||
|
<template slot-scope="scope"> |
||||||
|
<el-input v-model.number="scope.row.normalDifficulty" type="number" /> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="较难(道题)" align="center" width="90"> |
||||||
|
<template slot-scope="scope"> |
||||||
|
<el-input v-model.number="scope.row.hardDifficulty" type="number" /> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="难(道题)" align="center" width="90"> |
||||||
|
<template slot-scope="scope"> |
||||||
|
<el-input v-model.number="scope.row.veryHardDifficulty" type="number" /> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="难度随机(道题)" align="center" width="100"> |
||||||
|
<template slot-scope="scope"> |
||||||
|
<el-input v-model.number="scope.row.randomDifficulty" type="number" /> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
</el-table> |
||||||
|
|
||||||
|
<h6 class="page-name m-t-20">知识点设置</h6> |
||||||
|
<div class="wrap"> |
||||||
|
<!-- 题库 --> |
||||||
|
<div class="item"> |
||||||
|
<p class="total m-b-10">题库</p> |
||||||
|
<el-input class="m-b-10" placeholder="请输入题库分类/题库名称" prefix-icon="el-icon-search" v-model="quesBankKeyword" |
||||||
|
clearable /> |
||||||
|
<el-tree :key="key" node-key="id" default-expand-all highlight-current ref="quesBank" :data="quesBanks" |
||||||
|
:props="{ label: 'name' }" @node-click="getKnowledge" @check-change="quesBankCheck"></el-tree> |
||||||
|
</div> |
||||||
|
<!-- 知识点 --> |
||||||
|
<div class="item"> |
||||||
|
<p class="total m-b-10">知识点框架</p> |
||||||
|
<el-input class="m-b-10" placeholder="请输入知识点分类/知识点名称" prefix-icon="el-icon-search" v-model="knowledgeKeyword" |
||||||
|
clearable /> |
||||||
|
<el-tree :data="knowledges" default-expand-all ref="knowledge" node-key="id" highlight-current |
||||||
|
:expand-on-click-node="false" show-checkbox @check-change="knowledgeCheck" :props="{ label: 'name' }"> |
||||||
|
<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 class="item"> |
||||||
|
<div class="flex j-between a-center m-b-20"> |
||||||
|
<p class="total m-b-10">已选知识点({{ allKnowledges.length }}个)</p> |
||||||
|
<p class="clear" @click="clearChecked"> |
||||||
|
<i class="el-icon-delete m-r-5"></i> |
||||||
|
清空 |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div v-for="(item, i) in checked" :key="i" class="line j-between"> |
||||||
|
<div class="flex a-center"> |
||||||
|
题库:{{ item.quesBank.name }} |
||||||
|
<i class="el-icon-delete action-icon m-l-10" @click="delQuesBank(i)"></i> |
||||||
|
</div> |
||||||
|
<div class="knowledges"> |
||||||
|
<el-tag v-for="(tag, j) in item.knowledges" :key="tag.name" class="m-r-10" closable |
||||||
|
@close="delKnowledge(i, j, item)"> |
||||||
|
{{ tag.name }} |
||||||
|
</el-tag> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<h6 class="page-name m-t-20">年份设置</h6> |
||||||
|
<div class="years flex"> |
||||||
|
<el-checkbox style="margin-right: 20px" v-model="yearAll" @change="yearAllChange">全选</el-checkbox> |
||||||
|
<el-checkbox-group v-model="yearCheck" @change="yearChange"> |
||||||
|
<el-checkbox v-for="(item, i) in years" :key="i" :label="item"></el-checkbox> |
||||||
|
</el-checkbox-group> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
<span slot="footer" class="dialog-footer"> |
||||||
|
<el-button @click="quesVisible = false">取消</el-button> |
||||||
|
<el-button type="primary" :loading="submiting" @click="submit">自动选题</el-button> |
||||||
|
</span> |
||||||
|
</el-dialog> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script> |
||||||
|
import Setting from '@/setting' |
||||||
|
import Util from '@/libs/util' |
||||||
|
import QuesConst from '@/const/ques' |
||||||
|
import TestPaperConst from '@/const/testPaper' |
||||||
|
import _ from 'lodash' |
||||||
|
// import Decimal from 'decimal.js' |
||||||
|
export default { |
||||||
|
props: ['visible'], |
||||||
|
data () { |
||||||
|
return { |
||||||
|
arabicToChinese: Util.arabicToChinese, |
||||||
|
difficults: TestPaperConst.difficults, |
||||||
|
questionTypes: QuesConst.questionTypes, |
||||||
|
quesVisible: false, |
||||||
|
difficult: '', |
||||||
|
|
||||||
|
quesBankKeyword: '', |
||||||
|
knowledgeKeyword: '', |
||||||
|
searchTimer: null, |
||||||
|
key: 1, |
||||||
|
quesBanks: [], |
||||||
|
knowledges: [], |
||||||
|
checked: [], |
||||||
|
|
||||||
|
list: [], |
||||||
|
years: ['暂无年份', '2024', '2023', '2022', '2021', '2020', '2019', '2018', '2017', '2016', '更早'], |
||||||
|
yearAll: true, |
||||||
|
yearCheck: [], |
||||||
|
submiting: false, |
||||||
|
}; |
||||||
|
}, |
||||||
|
computed: { |
||||||
|
allKnowledges () { |
||||||
|
const result = [] |
||||||
|
this.checked.map(e => { |
||||||
|
result.push(...e.knowledges) |
||||||
|
}) |
||||||
|
return result |
||||||
|
}, |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'quesBankKeyword': function (val) { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(this.getQuesBank, 500) |
||||||
|
}, |
||||||
|
'knowledgeKeyword': function (val) { |
||||||
|
clearTimeout(this.searchTimer) |
||||||
|
this.searchTimer = setTimeout(this.getKnowledge, 500) |
||||||
|
}, |
||||||
|
visible () { |
||||||
|
this.quesVisible = this.visible |
||||||
|
this.visible && this.init() |
||||||
|
} |
||||||
|
}, |
||||||
|
mounted () { |
||||||
|
|
||||||
|
}, |
||||||
|
methods: { |
||||||
|
// 初始化 |
||||||
|
init () { |
||||||
|
this.yearCheck = this.years |
||||||
|
this.handleQuesList() |
||||||
|
this.getQuesBank() |
||||||
|
}, |
||||||
|
// 获取题库 |
||||||
|
async getQuesBank () { |
||||||
|
try { |
||||||
|
const { list } = await this.$post(this.api.questionBankStructureLevel, { |
||||||
|
keyword: this.quesBankKeyword, |
||||||
|
createSource: 1, |
||||||
|
}) |
||||||
|
this.quesBanks = list |
||||||
|
} catch (e) { } |
||||||
|
}, |
||||||
|
// 获取知识点 |
||||||
|
async getKnowledge () { |
||||||
|
try { |
||||||
|
const id = this.$refs.quesBank.getCurrentKey() |
||||||
|
if (id) { |
||||||
|
const { data } = await this.$post(this.api.TreeStructure, { |
||||||
|
createSource: 1, |
||||||
|
questionBankId: id, |
||||||
|
keyword: this.knowledgeKeyword, |
||||||
|
}) |
||||||
|
this.knowledges = data |
||||||
|
} |
||||||
|
} catch (e) { } |
||||||
|
}, |
||||||
|
// 题库勾选回调 |
||||||
|
quesBankCheck (data, checked) { |
||||||
|
// debugger |
||||||
|
if (checked) { |
||||||
|
// this.$refs.quesBank.setCurrentKey(data.id) |
||||||
|
this.getKnowledge() |
||||||
|
} |
||||||
|
this.$refs.knowledge.setCheckedNodes(checked ? this.knowledges : []) |
||||||
|
}, |
||||||
|
// 知识点勾选回调 |
||||||
|
knowledgeCheck (data, checked) { |
||||||
|
// 选中的是知识点才需要显示在最右边 |
||||||
|
if (data.type) { |
||||||
|
const checkQues = this.$refs.quesBank.getCurrentNode() |
||||||
|
const ques = this.checked.find(e => e.quesBank.id === checkQues.id) |
||||||
|
// 已选中的题库数组里有该题库,则往该题库的知识点数组里 |
||||||
|
if (ques) { |
||||||
|
const i = ques.knowledges.findIndex(e => e === data.id) |
||||||
|
if (checked && i === -1) { |
||||||
|
ques.knowledges.push(data) |
||||||
|
} else if (!checked && i >= 0) { |
||||||
|
ques.knowledges.splice(i, 1) |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.checked.push({ |
||||||
|
quesBank: checkQues, |
||||||
|
knowledges: [data] |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
// 处理大纲列表 |
||||||
|
handleQuesList () { |
||||||
|
const list = _.cloneDeep(this.$parent.form.paperOutline) |
||||||
|
this.list = list |
||||||
|
}, |
||||||
|
// 清空已选 |
||||||
|
async clearChecked () { |
||||||
|
try { |
||||||
|
await this.$confirm(`确认要清空吗?`, '提示', { |
||||||
|
confirmButtonText: '确定', |
||||||
|
cancelButtonText: '取消', |
||||||
|
type: 'warning', |
||||||
|
closeOnClickModal: false, |
||||||
|
}) |
||||||
|
this.checked = [] |
||||||
|
} catch (e) { } |
||||||
|
}, |
||||||
|
// 删除题库 |
||||||
|
delQuesBank (i) { |
||||||
|
this.checked.splice(i, 1) |
||||||
|
}, |
||||||
|
// 删除知识点 |
||||||
|
delKnowledge (i, j, item) { |
||||||
|
item.knowledges.splice(j, 1) |
||||||
|
item.knowledges.length || this.checked.splice(i, 1) // 知识点清空了则把该题库删除 |
||||||
|
}, |
||||||
|
// 获取模板列表 |
||||||
|
async getList () { |
||||||
|
try { |
||||||
|
const res = await this.$post(this.api.examPaperTemplateList, { |
||||||
|
pageNum: this.page, |
||||||
|
pageSize: this.pageSize, |
||||||
|
...this.filter |
||||||
|
}) |
||||||
|
this.list = res.pageList.records |
||||||
|
this.total = res.pageList.total |
||||||
|
} catch (e) { } |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
calculateQuestionNumbers (list, target) { |
||||||
|
// Decimal(e.score).add(Decimal(score)) |
||||||
|
const difficultyWeights = [0.2, 0.4, 0.6, 0.8] |
||||||
|
const names = ['basicDifficulty', 'normalDifficulty', 'hardDifficulty', 'veryHardDifficulty'] |
||||||
|
// 遍历题型数组 |
||||||
|
list.forEach(e => { |
||||||
|
const total = e.questionNum |
||||||
|
const nums = { |
||||||
|
basicDifficulty: 0, |
||||||
|
normalDifficulty: 0, |
||||||
|
hardDifficulty: 0, |
||||||
|
veryHardDifficulty: 0, |
||||||
|
} |
||||||
|
|
||||||
|
// 初始化题目数量 |
||||||
|
for (let i = 0; i < 4; i++) { |
||||||
|
nums[names[i]] = 0 |
||||||
|
} |
||||||
|
|
||||||
|
// 初始分配题目数量 |
||||||
|
let totalWeight = total * target |
||||||
|
const maxCount = Math.ceil(total / 4) |
||||||
|
for (let i = 0; i < 4; i++) { |
||||||
|
console.log("🚀 ~ calculateQuestionNumbers ~ totalWeight:", totalWeight) |
||||||
|
if (totalWeight > 0) { |
||||||
|
const random = Math.floor(Math.random() * (maxCount)) + 1 |
||||||
|
const weight = difficultyWeights[i] |
||||||
|
totalWeight -= weight * random |
||||||
|
e[names[i]] = totalWeight > 0 ? random : 0 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// e.nums = nums |
||||||
|
}); |
||||||
|
|
||||||
|
return list |
||||||
|
}, |
||||||
|
// 试卷难度选择回调 |
||||||
|
difficultData (val) { |
||||||
|
// debugger |
||||||
|
console.log(111, this.calculateQuestionNumbers(this.list, 0.3)) |
||||||
|
}, |
||||||
|
// 年份全选回调 |
||||||
|
yearAllChange (val) { |
||||||
|
this.yearCheck = val ? this.years : [] |
||||||
|
}, |
||||||
|
// 年份选择回调 |
||||||
|
yearChange (val) { |
||||||
|
this.yearAll = val.length === 11 |
||||||
|
}, |
||||||
|
// 提交 |
||||||
|
async submit () { |
||||||
|
if (this.submiting) return false |
||||||
|
const { list } = this |
||||||
|
// let invalid = 0 |
||||||
|
// for (const e of list) { |
||||||
|
// if (!e.questionType) { |
||||||
|
// Util.warningMsg('请选择题型') |
||||||
|
// invalid = 1 |
||||||
|
// break |
||||||
|
// } |
||||||
|
// } |
||||||
|
// if (invalid) return false |
||||||
|
this.submiting = true |
||||||
|
const k = this.allKnowledges.map(e => e.id) |
||||||
|
|
||||||
|
const years = [] |
||||||
|
this.yearCheck.map(e => { |
||||||
|
if (e === '暂无年份') { |
||||||
|
years.push('') |
||||||
|
} else if (e === '更早') { |
||||||
|
// 选的是更早则直接传1990~2005所有年份 |
||||||
|
for (let i = 1990; i < 2006; i++) { |
||||||
|
years.push(i) |
||||||
|
} |
||||||
|
} else { |
||||||
|
years.push(+e) |
||||||
|
} |
||||||
|
}) |
||||||
|
list.map(e => { |
||||||
|
e.randomDifficulty = 0 |
||||||
|
e.givenYears = years |
||||||
|
e.knowledgePointsIds = k |
||||||
|
}) |
||||||
|
try { |
||||||
|
const res = await this.$post(this.api.selectQuestionsByTypeAndDifficulty, list) |
||||||
|
|
||||||
|
let invalid = 0 |
||||||
|
let hasQues = 0 |
||||||
|
list.map((e, i) => { |
||||||
|
console.log("🚀 ~ submit ~ e:", e) |
||||||
|
if (e.questionNum !== res.list[i].questions.length) invalid = 1 |
||||||
|
if (e.examQuestions.length) hasQues = 1 |
||||||
|
}) |
||||||
|
|
||||||
|
// 3种情况提示不一样 |
||||||
|
const tips = invalid && hasQues ? |
||||||
|
'此操作会清空当前试卷已添加的试题,并且满足自动选题设置的试题数量不足,确定要继续自动选题吗?' : |
||||||
|
invalid && !hasQues ? |
||||||
|
'满足自动选题设置的试题数量不足,确认要继续自动选题吗?' : |
||||||
|
!invalid && hasQues ? '此操作会清空当前试卷已添加的试题,是否确定要继续自动选题吗?' : |
||||||
|
'' |
||||||
|
|
||||||
|
if (tips) { |
||||||
|
await this.$confirm(tips, '提示', { |
||||||
|
confirmButtonText: '确定', |
||||||
|
cancelButtonText: '取消', |
||||||
|
type: 'warning', |
||||||
|
closeOnClickModal: false, |
||||||
|
}) |
||||||
|
} |
||||||
|
list.map((e, i) => { |
||||||
|
this.$parent.form.paperOutline[i].examQuestions = res.list[i].questions |
||||||
|
}) |
||||||
|
this.quesVisible = false |
||||||
|
this.submiting = false |
||||||
|
} catch (e) { |
||||||
|
this.submiting = false |
||||||
|
} |
||||||
|
}, |
||||||
|
// 弹框关闭回调 |
||||||
|
closeDia () { |
||||||
|
this.$emit('update:visible', false) |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.wrap { |
||||||
|
display: flex; |
||||||
|
margin-top: 20px; |
||||||
|
border: 1px solid #eee; |
||||||
|
|
||||||
|
.item { |
||||||
|
width: 30%; |
||||||
|
max-height: calc(100vh - 190px); |
||||||
|
padding: 15px; |
||||||
|
border-right: 1px solid #eee; |
||||||
|
overflow: auto; |
||||||
|
|
||||||
|
&:last-child { |
||||||
|
width: 40%; |
||||||
|
border-right: 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.total { |
||||||
|
font-size: 16px; |
||||||
|
color: #333; |
||||||
|
} |
||||||
|
|
||||||
|
.clear { |
||||||
|
display: inline-flex; |
||||||
|
align-items: center; |
||||||
|
font-size: 14px; |
||||||
|
color: #8b8b8b; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
.knowledges { |
||||||
|
padding-left: 44px; |
||||||
|
margin-top: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue