yujialong 5 months ago
parent d79c0d0cbb
commit b015e22c1a
  1. 4
      src/api/index.js
  2. 715
      src/pages/allocationReview/detail/auto.vue
  3. 1360
      src/pages/allocationReview/detail/index.vue
  4. 610
      src/pages/allocationReview/detail/manual.vue
  5. 119
      src/pages/allocationReview/detail/repeatQues.vue
  6. 329
      src/pages/allocationReview/detail/template.vue
  7. 6
      src/pages/allocationReview/list/index.vue
  8. 6
      src/pages/allocationReview/list/progress.vue
  9. 8
      src/pages/allocationReview/list/progressDetail.vue
  10. 706
      src/pages/allocationReview/preview/index.vue
  11. 262
      src/pages/allocationReview/records/allocation.vue
  12. 336
      src/pages/allocationReview/records/index.vue
  13. 351
      src/pages/allocationReview/records/people.vue
  14. 4
      src/pages/myReview/records/index.vue
  15. 10
      src/router/modules/allocationReview.js

@ -7,7 +7,9 @@ export default {
queryProvince: `/nakadai/nakadai/province/queryProvince`,
queryCity: `/nakadai/nakadai/city/queryCity`,
querySchool: `/nakadai/nakadai/school/querySchool`,
treeListArch: `/nakadai/nakadai/staffAccountArchitecture/treeList`,
staffList: `/nakadai/nakadai/backstageStaff/staffList`,
querySchoolByReadAndAppraise: `/nakadai/nakadai/school/querySchoolByReadAndAppraise`,
getDetailedExamScores: `/exam/exam/paper/getDetailedExamScores`,
reviewSettingsList: `/competition/competition/readAndAppraise/reviewSettingsList`,

@ -1,715 +0,0 @@
<template>
<div>
<el-drawer title="自动选题" :visible.sync="quesVisible" size="1200px" :close-on-click-modal="false"
custom-class="ques-dia" @closed="closeDia">
<div class="overflow">
<h6 class="page-name">难度设置</h6>
<div class="tool">
<ul class="filter">
<li style="margin-right: 10px">
<label>试卷难度</label>
<el-select v-model="difficult" placeholder="请选择试卷难度" @change="difficultChange">
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
<el-tooltip placement="top">
<div class="diff-text" slot="content">
<p>基础题难度系数0.2</p>
<p>普通题难度系数0.4</p>
<p>较难题难度系数0.6</p>
<p>困难题难度系数0.8</p>
<p>1<span class="em">题型难度系数</span>=对应题型所有试题的难度系数之和/总试题数</p>
<p>2<span class="em">试卷总难度系数</span>=所有试题的难度系数之和/总试题数</p>
<p>3<span class="em">难度系数评价</span></p>
<div class="coe">
<p>简单系数 &lt;=0.3</p>
<p>普通0.3&lt;系数&lt;=0.4</p>
<p>较难0.4&lt;系数&lt;0.5</p>
<p>困难:系数&gt;=0.5</p>
</div>
</div>
<i class="el-icon-question" style="font-size: 16px;color: #8f8f8f;cursor: pointer;"></i>
</el-tooltip>
</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>
<ul class="filter">
<li class="m-b-10">
<label>题库分类</label>
<el-cascader style="width: 240px;" placeholder="请选择题库分类" v-model="quesBankTypeVal"
:options="quesBankTypes" :props="{ value: 'id', label: 'name', checkStrictly: true }" clearable
@change="initQuesBank"></el-cascader>
</li>
<li>
<el-input placeholder="请输入题库名称" prefix-icon="el-icon-search" v-model="quesBankKeyword" clearable />
</li>
</ul>
<template v-if="quesBanks.length">
<div class="line">
<span class="serial first">序号</span>
<span>题库名称</span>
</div>
<div class="able-check lines">
<div v-for="(item, i) in quesBanks" :key="i" :class="['line', { active: curQuesBank.id === item.id }]"
@click="questionBankClick(item)">
<span class="serial first">{{ i + 1 }}</span>
<p class="stem" :title="item.questionBankName">{{ item.questionBankName }}</p>
</div>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</div>
<!-- 知识点 -->
<div class="item">
<p class="total m-b-10">知识点</p>
<ul class="filter">
<li class="m-b-10">
<label>知识点框架</label>
<el-cascader style="width: 240px;" placeholder="请选择知识点分类" v-model="knowledgeTypeVal"
:options="knowledgeTypes" :props="{ value: 'id', label: 'name', checkStrictly: true }" clearable
@change="getKnowledge"></el-cascader>
</li>
<li>
<el-input placeholder="请输入知识点名称" prefix-icon="el-icon-search" v-model="knowledgeKeyword" clearable />
</li>
</ul>
<template v-if="knowledges.length">
<div class="line">
<el-checkbox v-model="knowledgeCheck" @change="knowledgeAllCheckChange"></el-checkbox>
<span class="serial">序号</span>
<span>知识点名称</span>
</div>
<div class="lines">
<div v-for="(item, i) in knowledges" :key="i" class="line">
<el-checkbox v-model="item.check" :disabled="item.disabled"
@change="val => knowledgeChange(val, item)"></el-checkbox>
<span class="serial">{{ i + 1 }}</span>
<p class="stem" :title="item.name">{{ item.name }}</p>
</div>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</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>
<template v-for="(item, i) in checked">
<div :key="i" class="j-between m-b-10">
<div class="flex a-center">
题库{{ item.quesBank.questionBankName }}
<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-8 m-b-8" closable
@close="delKnowledge(i, j, item, tag)">{{ tag.name }}</el-tag>
</div>
</div>
</template>
</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>
</div>
<div class="btns">
<el-button @click="quesVisible = false">取消</el-button>
<el-button type="primary" :loading="submiting" @click="submit">自动选题</el-button>
</div>
</el-drawer>
</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: '',
searchTimer: null,
curQuesBank: {},
quesBankTypeVal: [],
quesBankTypes: [],
quesBankKeyword: '',
quesBanks: [],
pageQuesBank: 1,
pageSizeQuesBank: 10,
totalQuesBank: 0,
knowledgeKeyword: '',
knowledgeTypeVal: [],
knowledgeTypes: [],
knowledgeCheck: false,
knowledges: [],
pageKn: 1,
pageSizeKn: 10,
totalKn: 0,
checkedKeyword: '',
checked: [],
list: [],
years: ['暂无年份', '2024', '2023', '2022', '2021', '2020', '2019', '2018', '2017', '2016', '更早'],
yearAll: true,
yearCheck: [],
submiting: false,
loaded: 0,
};
},
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.initQuesBank, 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.handleQuesList()
if (!this.loaded) {
this.loaded = 1
this.yearCheck = this.years
this.getQuesBankType()
this.initQuesBank()
this.difficult = this.$parent.form.difficult
this.difficult && this.difficultChange(this.difficult)
}
},
//
async getQuesBankType () {
try {
const { data } = await this.$post(this.api.getAllQuestionBankCategories, {
createSource: 1,
status: 1,
})
this.handleList(data)
this.quesBankTypes = data
} catch (e) { }
},
//
async getQuesBank () {
try {
const type = this.quesBankTypeVal
const res = await this.$post(this.api.questionBankList, {
status: 1,
pageNum: 1,
pageSize: 1000,
questionCategoryId: type.length ? type[type.length - 1] : '',
name: this.quesBankKeyword
})
this.quesBanks = res.message.records
this.totalQuesBank = res.message.total
} catch (e) { }
},
initQuesBank () {
this.curQuesBank = {}
this.pageQuesBank = 1
this.getQuesBank()
},
//
currentChangeQuesBank (val) {
this.pageQuesBank = val
this.getQuesBank()
},
//
questionBankClick (item) {
this.curQuesBank = item
this.knowledgeCheck = false
this.getKnowledgeType()
this.getKnowledge()
},
//
handleList (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleList(e.children)
} else {
delete e.children
}
})
},
//
async getKnowledgeType () {
try {
const { data } = await this.$post(this.api.classificationTreeStructure, {
createSource: 1,
questionBankId: this.curQuesBank.id,
})
this.handleList(data)
this.knowledgeTypes = data
} catch (e) { }
},
//
async getKnowledge () {
try {
const { id } = this.curQuesBank
if (id) {
const type = this.knowledgeTypeVal
const res = await this.$post(this.api.knowledgeHierarchyList, {
pageNum: 1,
pageSize: 1000,
questionBankId: id,
knowledgePointCategoryId: type.length ? type[type.length - 1] : '',
name: this.knowledgeKeyword,
})
const list = res.message.records
const { allKnowledges } = this
list.map(e => {
e.check = !!allKnowledges.find(n => n.id === e.id)
})
this.knowledges = list
}
} catch (e) { }
},
//
currentChangeKn (val) {
this.pageKn = val
this.getKnowledge()
},
//
knowledgeAllCheckChange (val) {
this.knowledges.map(e => {
e.check = val
this.knowledgeChange(val, e)
})
},
//
knowledgeChange (checked, data) {
const checkQues = this.curQuesBank
const index = this.checked.findIndex(e => e.quesBank.id === checkQues.id)
//
if (index !== -1) {
const ques = this.checked[index]
const i = ques.knowledges.findIndex(e => e.id === data.id)
if (checked && i === -1) {
ques.knowledges.push(data)
} else if (!checked && i >= 0) {
ques.knowledges.splice(i, 1)
}
ques.knowledges.length || this.checked.splice(index, 1)
} else {
this.checked.push({
quesBank: checkQues,
knowledges: [data]
})
}
},
//
handleQuesList () {
this.list = _.cloneDeep(this.$parent.form.paperOutline)
},
//
async clearChecked () {
try {
await this.$confirm(`确认要清空吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
})
this.knowledges.map(e => e.check = false)
this.checked = []
this.knowledgeCheck = false
} catch (e) { }
},
//
async delQuesBank (i) {
try {
await this.$confirm(`确认要移除吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
})
const k = this.knowledges
this.checked[i].knowledges.map(e => {
const cur = k.findIndex(n => n.id === e.id)
if (cur !== -1) k[cur].check = false
})
this.checked.splice(i, 1)
this.knowledgeCheck = false
} catch (e) { }
},
//
delKnowledge (i, j, item, k) {
const cur = this.knowledges.findIndex(e => e.id === k.id)
if (cur !== -1) this.knowledges[cur].check = false
item.knowledges.splice(j, 1)
item.knowledges.length || this.checked.splice(i, 1) //
this.knowledgeCheck = false
},
//
difficultChange (val) {
const difficultyWeights = [0.2, 0.4, 0.6, 0.8]
const names = ['basicDifficulty', 'normalDifficulty', 'hardDifficulty', 'veryHardDifficulty']
//
this.list.forEach(e => {
const total = e.questionNum
let already = 0 //
if (val === 1) {
this.$set(e, 'basicDifficulty', Math.floor(total * 0.7))
this.$set(e, 'normalDifficulty', Math.floor(total * 0.3))
this.$set(e, 'hardDifficulty', 0)
this.$set(e, 'veryHardDifficulty', 0)
} else if (val === 2) {
this.$set(e, 'basicDifficulty', Math.floor(total * 0.45))
this.$set(e, 'normalDifficulty', Math.floor(total * 0.55))
this.$set(e, 'hardDifficulty', 0)
this.$set(e, 'veryHardDifficulty', 0)
} else if (val === 3) {
this.$set(e, 'basicDifficulty', Math.floor(total * 0.3))
this.$set(e, 'normalDifficulty', Math.floor(total * 0.3))
this.$set(e, 'hardDifficulty', Math.floor(total * 0.4))
this.$set(e, 'veryHardDifficulty', 0)
} else if (val === 4) {
this.$set(e, 'basicDifficulty', Math.floor(total * 0.1))
this.$set(e, 'normalDifficulty', Math.floor(total * 0.1))
this.$set(e, 'hardDifficulty', Math.floor(total * 0.3))
this.$set(e, 'veryHardDifficulty', Math.floor(total * 0.5))
}
already = Decimal(already).add(e.basicDifficulty).add(e.normalDifficulty).add(e.hardDifficulty).add(e.veryHardDifficulty).toNumber()
//
while (total > already) {
e[names[val - 1]]++
already++
}
this.$set(e, 'randomDifficulty', 0)
})
},
//
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
let totalCount = 0
for (const i in list) {
const e = list[i]
const name = `${Util.arabicToChinese(+i + 1)}大题`
if (!e.questionType) {
Util.warningMsg(`${name}请先选择题型`)
invalid = 1
break
}
if (!e.questionNum || isNaN(e.questionNum) || e.questionNum <= 0) {
Util.warningMsg(`${name}的目标题数请输入正整数`)
invalid = 1
break
}
let total = Decimal(e.basicDifficulty || 0).add(e.normalDifficulty || 0).add(e.hardDifficulty || 0).add(e.veryHardDifficulty || 0).toNumber() // 4
if (total) { // 41
this.$set(e, 'randomDifficulty', 0)
} else {
total = +e.randomDifficulty || 0
}
if (total > e.questionNum) {
Util.warningMsg(`${name}的小题总数大于目标题数,请重新输入`)
invalid = 1
break
}
e.count = total
totalCount = Decimal(totalCount).add(total).toNumber()
}
if (invalid) return false
if (!totalCount) return Util.warningMsg(`请填写难度题数`)
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.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) => {
if (+e.count !== res.list[i].questions.length) invalid = 1
if (e.examQuestions.length) hasQues = 1
e.score = 0
})
// 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) => {
res.list[i].questions.map((e, i) => {
e.questionId = e.id
e.serialNumber = i + 1
e.originSort = i + 1
this.$parent.handleQuesInfo(e)
})
this.$parent.form.paperOutline[i].examQuestions = res.list[i].questions
})
this.quesVisible = false
this.$parent.calcDifficult()
this.submiting = false
} catch (e) {
this.submiting = false
}
},
//
closeDia () {
this.$emit('update:visible', false)
}
}
};
</script>
<style lang="scss" scoped>
/deep/.ques-dia {
.el-drawer__header {
margin-bottom: 20px;
}
.overflow {
height: calc(100vh - 147px);
padding: 0 20px;
overflow: auto;
}
.wrap {
display: flex;
margin-top: 20px;
border: 1px solid #eee;
.filter {
margin-bottom: 15px;
li {
display: flex;
align-items: center;
}
label {
margin-right: 10px;
font-size: 14px;
color: #333;
white-space: nowrap;
}
}
.item {
width: 30%;
padding: 15px;
border-right: 1px solid #eee;
&: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;
}
.lines {
height: calc(100vh - 392px);
overflow: auto;
}
.line {
display: flex;
padding: 5px 0;
color: #333;
}
.able-check {
.line {
cursor: pointer;
&:hover {
background-color: #f5f5f5;
}
&.active {
background-color: #e5e5e5;
}
}
}
.serial {
width: 32px;
margin: 0 12px;
text-align: center;
white-space: nowrap;
&.first {
margin-left: 0;
}
}
.stem {
max-width: calc(100% - 71px);
@include ellipsis;
}
.checked-stem {
max-width: 165px;
@include ellipsis;
}
.check-left {
display: inline-flex;
align-items: center;
}
.action-icon {
font-size: 14px;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

@ -1,610 +0,0 @@
<template>
<div>
<el-drawer :title="diaTitle" :visible.sync="selectQuesVisible" size="1200px" :close-on-click-modal="false"
custom-class="ques-dia" @closed="closeDia">
<div class="wrap">
<!-- 题库 -->
<div class="item">
<p class="total m-b-10">题库</p>
<ul class="filter">
<li class="m-b-10">
<label>题库分类</label>
<el-cascader style="width: 240px;" placeholder="请选择题库分类" v-model="quesBankTypeVal"
:options="quesBankTypes" :props="{ value: 'id', label: 'name', checkStrictly: true }" clearable
@change="initQuesBank"></el-cascader>
</li>
<li>
<el-input placeholder="请输入题库名称" prefix-icon="el-icon-search" v-model="quesBankKeyword" clearable />
</li>
</ul>
<template v-if="quesBanks.length">
<div class="line">
<span class="serial">序号</span>
<span>题库名称</span>
</div>
<div class="able-check lines">
<div v-for="(item, i) in quesBanks" :key="i" :class="['line', { active: curQuesBank.id === item.id }]"
@click="questionBankClick(item)">
<span class="serial">{{ i + 1 }}</span>
<p class="quesBank" :title="item.questionBankName">{{ item.questionBankName }}</p>
</div>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</div>
<!-- 题目 -->
<div class="item">
<p class="total m-b-10">{{ questionTypeName }}{{ ques.length }}道题</p>
<ul class="filter">
<li class="m-b-10">
<label>知识点</label>
<el-cascader style="width: 240px;" placeholder="请选择知识点" v-model="knowledgeVal" :options="knowledges"
:props="{ value: 'id', label: 'name', multiple: true }" clearable @change="getQues"></el-cascader>
</li>
<li>
<el-input placeholder="请输入题干" prefix-icon="el-icon-search" v-model="knowledgeKeyword" clearable />
</li>
</ul>
<template v-if="ques.length">
<div class="line">
<el-checkbox v-model="quesAllCheck" @change="quesAllCheckChange"></el-checkbox>
<span class="serial">序号</span>
<span class="stem">题干</span>
<span class="kl">知识点</span>
</div>
<div class="lines">
<div v-for="(item, i) in ques" :key="i" class="line">
<el-checkbox v-model="item.check" :disabled="item.disabled"
@change="val => quesChange(val, item)"></el-checkbox>
<span class="serial">{{ i + 1 }}</span>
<el-tooltip effect="dark" :content="item.stemText" placement="top-start">
<p class="stem cursor-pointer" @click="toShowQues(item)">{{ item.stemText }}</p>
</el-tooltip>
<el-tooltip effect="dark" :content="item.knowledgePointName" placement="top-start">
<p class="kl">{{ item.knowledgePointName }}</p>
</el-tooltip>
</div>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</div>
<!-- 已选试题 -->
<div class="item">
<div v-if="$parent.curQues" class="m-b-20">
<p class="total m-b-10">原试题共1道题</p>
<div v-html="$parent.curQues.stemText"></div>
</div>
<div class="flex j-between a-center">
<p v-if="$parent.curQues" class="total">更换试题{{ checked.length }}道题</p>
<p v-else class="total">已选试题{{ checkedLen }}道题</p>
<el-button type="text" @click="batchDelChecked">批量移除</el-button>
</div>
<el-input class="m-t-10 m-b-10" placeholder="请输入题干/知识点" prefix-icon="el-icon-search" v-model="checkedKeyword"
clearable />
<template v-if="checked.length">
<div class="ques">
<div class="line">
<el-checkbox v-model="checkedAllCheck" @change="checkedAllCheckChange"></el-checkbox>
<span class="serial">序号</span>
<span class="stem">题干</span>
<span class="kl">知识点</span>
</div>
<div :class="['lines', { switch: $parent.curQues }]">
<template v-for="(item, i) in checked">
<div v-if="item.stemText.includes(checkedKeyword) || item.knowledgePointName.includes(checkedKeyword)"
:key="i" class="line">
<div class="check-left">
<el-checkbox v-model="item.check"></el-checkbox>
<span class="serial">{{ i + 1 }}</span>
<el-tooltip effect="dark" :content="item.stemText" placement="top-start">
<p class="checked-stem">{{ item.stemText }}</p>
</el-tooltip>
<el-tooltip effect="dark" :content="item.knowledgePointName" placement="top-start">
<p class="kl checked-kl">{{ item.knowledgePointName }}</p>
</el-tooltip>
</div>
<i class="el-icon-delete action-icon" @click="delChecked(item)"></i>
</div>
</template>
</div>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</div>
</div>
<div class="flex j-between p-l-20 p-r-20">
<p>未找到试题<a class="link" @click="toAddQues">去新增</a></p>
<p>已选题数/目标题数{{ checkedLen }}/{{ $parent.curType.questionNum }}
</p>
</div>
<div class="btns">
<el-button @click="selectQuesVisible = false">取消</el-button>
<el-button type="primary" :loading="submiting" @click="submit">确定</el-button>
</div>
</el-drawer>
<el-drawer title="新增试题" :visible.sync="addQuesVisible" size="1200px" :close-on-click-modal="false"
custom-class="add-dia">
<QuesDetail :key="quesKey" :paperType.sync="paperType" :curQues.sync="curRow" @closeAdd="closeAdd" />
</el-drawer>
</div>
</template>
<script>
import Setting from '@/setting'
import Util from '@/libs/util'
import _ from 'lodash'
import QuesConst from '@/const/ques'
import QuesDetail from '@/pages/ques/detail'
export default {
props: ['visible', 'questionType'],
components: { QuesDetail },
data () {
return {
selectQuesVisible: false,
searchTimer: null,
quesBankKeyword: '',
curQuesBank: {},
quesBankTypeVal: [],
quesBankTypes: [],
quesBanks: [],
pageQuesBank: 1,
pageSizeQuesBank: 10,
totalQuesBank: 0,
knowledgeKeyword: '',
key: 1,
knowledgeVal: [],
knowledges: [],
quesAllCheck: false,
ques: [],
checkedAllCheck: false,
checked: [],
curCheckQues: [],
checkedKeyword: '',
submiting: false,
quesVisible: false,
curRow: {},
addQuesVisible: false,
quesKey: 1,
paperType: 1,
};
},
computed: {
// +
checkedLen () {
let len = this.curCheckQues.length + this.checked.length
if (this.$parent.curQues) len -= 1
return len
},
// name
questionTypeName () {
return this.questionType ? QuesConst.questionTypes.find(e => e.id === this.questionType).name : ''
},
//
diaTitle () {
const { curQuesIndex, curQues } = this.$parent
return curQues ?
'更换试题' :
typeof curQuesIndex === 'number' ?
'添加试题' :
this.questionType ? `批量添加${QuesConst.questionTypes.find(e => e.id === this.questionType).name}` : ''
},
},
watch: {
'quesBankKeyword': function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.initQuesBank, 500)
},
'knowledgeKeyword': function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getQues, 500)
},
visible () {
this.selectQuesVisible = this.visible
this.visible && this.init()
}
},
mounted () {
},
methods: {
init () {
//
this.key++
this.knowledges = []
this.ques = []
this.checked = []
this.quesAllCheck = false
this.checkedAllCheck = false
this.quesBankKeyword = ''
this.knowledgeKeyword = ''
//
const { curType, curQues } = this.$parent
if (curQues) curQues.stemText = Util.delTag(curQues.stem)
this.curCheckQues = curType.examQuestions
this.getQuesBankType()
this.initQuesBank()
},
//
async getQuesBankType () {
try {
const { data } = await this.$post(this.api.getAllQuestionBankCategories, {
createSource: 1,
status: 1,
})
this.handleList(data)
this.quesBankTypes = data
} catch (e) { }
},
//
async getQuesBank () {
try {
const type = this.quesBankTypeVal
const res = await this.$post(this.api.questionBankList, {
status: 1,
pageNum: 1,
pageSize: 1000,
questionCategoryId: type.length ? type[type.length - 1] : '',
name: this.quesBankKeyword
})
const { records } = res.message
this.quesBanks = records
this.totalQuesBank = res.message.total
records.length && this.questionBankClick(records[0])
} catch (e) { }
},
initQuesBank () {
this.curQuesBank = {}
this.pageQuesBank = 1
this.getQuesBank()
},
//
currentChangeQuesBank (val) {
this.pageQuesBank = val
this.getQuesBank()
},
//
questionBankClick (item) {
this.curQuesBank = item
this.knowledgeCheck = false
this.getKnowledge()
this.getQues()
this.quesAllCheck = false
},
//
handleList (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleList(e.children)
} else {
delete e.children
}
})
},
//
async getKnowledge () {
try {
const { id } = this.curQuesBank
if (id) {
const { data } = await this.$post(this.api.TreeStructure, {
createSource: 1,
questionBankId: id,
keyword: '',
})
this.handleList(data)
this.knowledges = data
}
} catch (e) { }
},
//
async getQues () {
const { id } = this.curQuesBank
let k = this.knowledgeVal //
k = k.map(e => {
return e[e.length - 1]
})
if (id) {
const { list } = await this.$post(this.api.findAllByQuestionBank, {
status: 1,
questionBankIds: [id],
knowledgePointIds: k,
questionTypes: this.questionType ? [this.questionType] : [],
keyword: this.knowledgeKeyword,
})
const data = list
const { curCheckQues, checked } = this
data.map(e => {
e.stemText = Util.delTag(e.stem)
const quesChecked = !!curCheckQues.find(n => n.questionVersionId === e.questionVersionId)
e.disabled = quesChecked
e.check = !!checked.find(n => n.questionVersionId === e.questionVersionId) || quesChecked
})
this.ques = data
}
},
//
knowledgeCheck () {
},
//
quesAllCheckChange (val) {
this.ques.map(e => {
if (!e.disabled) {
e.check = val
this.quesChange(val, e)
}
})
},
//
quesChange (val, item) {
const cur = this.checked.findIndex(e => e.questionVersionId === item.questionVersionId)
//
if (val) {
if (cur === -1) {
const e = _.cloneDeep(item)
e.check = false
this.checked.push(e)
}
} else {
//
cur >= 0 && this.checked.splice(cur, 1)
}
},
//
checkedAllCheckChange (val) {
this.checked.map(e => e.check = val)
},
//
async batchDelChecked (val) {
try {
const checked = this.checked.filter(e => e.check)
if (checked.length) {
checked.map(e => {
const cur = this.ques.find(n => n.questionVersionId === e.questionVersionId)
if (cur) {
cur.check = false
}
})
this.quesAllCheck = false
this.checkedAllCheck = false
this.checked = this.checked.filter(e => !e.check)
} else {
Util.warningMsg('请选择数据')
}
} catch (e) { }
},
//
async delChecked (item) {
try {
const cur = this.ques.find(e => e.questionVersionId === item.questionVersionId)
if (cur) cur.check = false
this.checked.splice(this.checked.findIndex(e => e.questionVersionId === item.questionVersionId), 1)
} catch (e) { }
},
//
toAddQues () {
this.quesKey++
this.paperType = 1
this.addQuesVisible = true
},
//
toShowQues (ques) {
this.quesKey++
this.curRow = ques
this.paperType = 3
this.addQuesVisible = true
},
//
closeAdd () {
this.addQuesVisible = false
},
//
async submit () {
if (this.submiting) return false
const checked = _.cloneDeep(this.checked)
if (!checked.length) return Util.warningMsg('请选择试题')
const { curType, curQuesIndex, curQues } = this.$parent
if (this.checkedLen > +curType.questionNum) return Util.warningMsg(`目标题数为${curType.questionNum},已选题数不得大于目标题数`)
try {
checked.map((e, i) => {
this.$set(e, 'check', false)
this.$set(e, 'sort', i + 1)
this.$set(e, 'originSort', i + 1)
this.$set(e, 'score', '')
this.$parent.handleQuesInfo(e)
})
if (curQues) {
// curQues
this.curCheckQues.splice(curQuesIndex, 1, ...checked)
} else {
// curQuesIndex
typeof curQuesIndex === 'number' ?
this.curCheckQues.splice(curQuesIndex + 1, 0, ...checked) :
this.curCheckQues.push(...checked)
}
//
this.curCheckQues.map((e, i) => {
this.$set(e, 'serialNumber', i + 1)
})
this.$parent.calcDifficult()
this.selectQuesVisible = false
this.submiting = false
} catch (e) {
this.submiting = false
}
},
//
closeDia () {
this.$emit('update:visible', false)
}
}
};
</script>
<style lang="scss" scoped>
/deep/.ques-dia {
.el-drawer__header {
margin-bottom: 20px;
}
.wrap {
display: flex;
margin-bottom: 10px;
border: 1px solid #eee;
.filter {
margin-bottom: 15px;
li {
display: flex;
align-items: center;
}
label {
margin-right: 10px;
font-size: 14px;
color: #333;
white-space: nowrap;
}
}
.item {
width: 38%;
padding: 15px;
border-right: 1px solid #eee;
&:first-child {
width: 24%;
}
}
.total {
font-size: 16px;
color: #333;
}
.lines {
height: calc(100vh - 358px);
overflow: auto;
}
.ques {
.lines {
height: calc(100vh - 328px);
overflow: auto;
&.switch {
height: calc(100vh - 394px);
}
}
}
.line {
display: flex;
padding: 5px 0;
color: #333;
}
.able-check {
.line {
cursor: pointer;
&:hover {
background-color: #f5f5f5;
}
&.active {
background-color: #e5e5e5;
}
}
}
.serial {
width: 32px;
margin: 0 12px;
text-align: center;
white-space: nowrap;
}
.quesBank {
width: calc(100% - 71px);
@include ellipsis;
}
.stem {
width: calc(100% - 210px);
margin-right: 20px;
@include ellipsis;
&:hover {
opacity: .9;
}
}
.kl {
width: 120px;
@include ellipsis;
&.checked-kl {
width: 100px;
margin-right: 10px;
}
}
.checked-stem {
width: 190px;
margin-right: 20px;
@include ellipsis;
}
.check-left {
display: inline-flex;
align-items: center;
}
.action-icon {
font-size: 14px;
}
}
.link {
color: $main-color;
cursor: pointer;
}
}
/deep/.add-dia {
.el-drawer__header {
margin-bottom: 0;
}
}
</style>

@ -1,119 +0,0 @@
<template>
<el-drawer title="提示" :visible.sync="listVisible" size="800px" :close-on-press-escape="false" :wrapperClosable="false"
:show-close="false" custom-class="ques-dia" @closed="closeDia">
<div class="wrap p-20">
<el-alert title="以下试题在试卷中疑似出现重复,是否要继续发布!" type="warning" effect="dark" :closable="false" />
<el-table class="m-t-10" :data="data" stripe header-align="center" row-key="uuid">
<el-table-column prop="outlineName" label="大题名称" align="center" width="90"></el-table-column>
<el-table-column prop="serialNumber" label="题号" align="center" width="60"></el-table-column>
<el-table-column prop="stem" label="题干" align="center" min-width="120">
<template slot-scope="scope">
<div v-html="scope.row.stem"></div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="140">
<template slot-scope="scope">
<el-button type="text" @click="toQues(scope.row)">详情</el-button>
<el-button type="text" @click="delQues(scope.row, scope.$index)">移除</el-button>
<!-- <el-button type="text" @click="switchQues(scope.row, scope.$index)">替换</el-button> -->
</template>
</el-table-column>
</el-table>
</div>
<div class="btns">
<el-button type="primary" @click="check">检查一下</el-button>
<el-button :loading="submiting" @click="submit">继续发布</el-button>
</div>
</el-drawer>
</template>
<script>
import _ from 'lodash'
export default {
props: ['visible', 'list'],
data () {
return {
listVisible: false,
data: [],
submiting: false,
};
},
watch: {
visible () {
this.listVisible = this.visible
this.visible && this.init()
}
},
mounted () {
},
methods: {
init () {
this.data = this.list
},
//
toQues (row) {
const paper = this.$parent.form.paperOutline
this.$parent.toQues(paper[row.paperIndex], row.quesIndex, paper[row.paperIndex].examQuestions[row.quesIndex], 3)
},
//
async delQues (row, i) {
try {
await this.$confirm(`确认要移除吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
})
this.$parent.delQues(this.$parent.form.paperOutline[row.paperIndex], row.quesIndex, 1)
const { data } = this
data.splice(i, 1)
data.map(e => e.repeat = false)
this.data = this.$parent.hasRepeatQues(data)
} catch (e) { }
},
//
switchQues (row) {
const paper = this.$parent.form.paperOutline
this.$parent.showManualDia(paper[row.paperIndex], row.quesIndex, paper[row.paperIndex].examQuestions[row.quesIndex])
this.listVisible = false
},
//
async check () {
const { data } = this
this.$parent.form.paperOutline.map(e => {
e.examQuestions.map(n => {
this.$set(n, 'repeat', !!data.find(m => m.questionVersionId === n.questionVersionId))
})
})
this.$parent.submiting = false
this.listVisible = false
},
//
async submit () {
if (this.submiting) return false
this.submiting = true
await this.$parent.saveTestPaper()
this.submiting = false
},
//
closeDia () {
this.$parent.submiting = false
this.$emit('update:visible', false)
}
}
};
</script>
<style lang="scss" scoped>
/deep/.ques-dia {
.el-drawer__header {
margin-bottom: 0;
}
.wrap {
max-height: calc(100vh - 110px);
overflow: auto;
}
}
</style>

@ -1,329 +0,0 @@
<template>
<div>
<el-dialog title="选择试卷大纲模板" :visible.sync="listVisible" width="1200px" :close-on-click-modal="false"
@closed="closeDia">
<div class="tool">
<ul class="filter">
<li>
<label>题型</label>
<el-select v-model="questionType" multiple clearable placeholder="请选择题目类型" @change="initData">
<el-option v-for="(item, i) in questionTypes" :key="i" :value="item.id" :label="item.name"></el-option>
</el-select>
</li>
<li>
<label>搜索</label>
<el-input style="width: 250px;" placeholder="请输入模板名称" prefix-icon="el-icon-search" v-model="templateName"
clearable />
</li>
</ul>
<div>
<el-button type="primary" @click="add">新增模板</el-button>
</div>
</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 prop="templateName" label="模板名称" align="center" min-width="100"></el-table-column>
<el-table-column prop="questionTypeName" label="题型" align="center" min-width="140"></el-table-column>
<el-table-column prop="outlineNum" label="大题数" align="center" width="60"></el-table-column>
<el-table-column prop="questionNum" label="小题总数" align="center" width="80"></el-table-column>
<el-table-column prop="totalScore" label="总分" align="center" width="60"></el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center" width="160"></el-table-column>
<el-table-column prop="createUser" label="创建人" align="center" width="80"></el-table-column>
<el-table-column label="操作" align="center" width="150">
<template slot-scope="scope">
<el-button type="text" @click="useTemplate(scope.row, 0)">使用模板</el-button>
<el-button type="text" @click="edit(scope.row, 1)">编辑</el-button>
<el-button type="text" @click="del(scope.row)">删除</el-button>
</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>
<span slot="footer" class="dialog-footer">
<el-button @click="listVisible = false">关闭</el-button>
</span>
</el-dialog>
<el-dialog title="新增模板" :visible.sync="detailVisible" width="800px" :close-on-click-modal="false">
<el-form :model="form" :rules="rules" label-width="100px">
<el-form-item prop="templateName" label="模板名称">
<el-input placeholder="请输入模板名称" v-model="form.templateName" />
</el-form-item>
</el-form>
<el-table :data="form.paperOutline" stripe header-align="center" row-key="id">
<el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
<el-table-column prop="outlineName" label="大题" align="center" min-width="120">
<template slot-scope="scope">{{ arabicToChinese(scope.$index + 1) }}大题</template>
</el-table-column>
<el-table-column prop="name" label="题型" align="center" min-width="120">
<template slot-scope="scope">
<el-select v-model="scope.row.questionType" placeholder="请选择题型">
<el-option v-for="(item, i) in questionTypes" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="name" label="目标题数" align="center" min-width="120">
<template slot-scope="scope">
<el-input placeholder="请输入目标题数" v-model="scope.row.questionNum" type="number" />
</template>
</el-table-column>
<el-table-column prop="name" label="目标分值" align="center" min-width="120">
<template slot-scope="scope">
<el-input placeholder="请输入目标分值" v-model="scope.row.targetScore" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="120">
<template slot-scope="scope">
<i class="el-icon-circle-plus-outline action-icon m-r-10" @click="addLine(scope.$index)"></i>
<i v-if="form.paperOutline.length > 1" class="el-icon-remove-outline action-icon"
@click="delLine(scope.$index)"></i>
</template>
</el-table-column>
</el-table>
<p class="m-t-10 text-right">目标总题数{{ questionNum }}目标总分{{ totalScore }}</p>
<span slot="footer" class="dialog-footer">
<el-button @click="detailVisible = false">取消</el-button>
<el-button type="primary" v-loading="submiting" @click="submit">保存模板</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Setting from '@/setting'
import Util from '@/libs/util'
import _ from 'lodash'
import QuesConst from '@/const/ques'
export default {
props: ['visible'],
data () {
return {
arabicToChinese: Util.arabicToChinese,
questionTypes: QuesConst.questionTypes,
listVisible: false,
searchTimer: null,
templateName: '',
questionType: [],
list: [],
page: 1,
pageSize: 10,
total: 0,
detailVisible: false,
originForm: {},
form: {
templateName: '',
paperOutline: [
{
examQuestions: [],
outlineName: '单选题',
questionNum: '',
questionType: 'single_choice',
targetScore: '',
},
{
examQuestions: [],
outlineName: '多选题',
questionNum: '',
questionType: 'multiple_choice',
targetScore: '',
},
{
examQuestions: [],
outlineName: '判断题',
questionNum: '',
questionType: 'judgement',
targetScore: '',
},
{
examQuestions: [],
outlineName: '填空题',
questionNum: '',
questionType: 'fill_blank',
targetScore: '',
},
{
examQuestions: [],
outlineName: '问答题',
questionNum: '',
questionType: 'essay',
targetScore: '',
},
],
},
rules: {
templateName: [
{ required: true, message: '请输入模板名称', trigger: 'blur' }
],
},
submiting: false,
};
},
computed: {
questionNum () {
return this.form.paperOutline.reduce((e, j) => (e += +j.questionNum), 0)
},
totalScore () {
return this.form.paperOutline.reduce((e, j) => (e += +j.targetScore), 0)
}
},
watch: {
templateName: function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.initData, 500)
},
visible () {
this.listVisible = this.visible
this.visible && this.getList()
}
},
mounted () {
this.originForm = _.cloneDeep(this.form)
},
methods: {
//
async getList () {
try {
const res = await this.$post(this.api.examPaperTemplateList, {
pageNum: this.page,
pageSize: this.pageSize,
questionType: this.questionType.join(),
templateName: this.templateName
})
const list = res.pageList.records
const types = QuesConst.questionTypes
list.map(e => {
const names = []
e.questionType.split('、').map(n => {
const item = types.find(m => m.id === n)
item && names.push(item.name)
})
if (names.length) e.questionTypeName = names.join('、')
})
this.list = list
this.total = res.pageList.total
} catch (e) { }
},
//
currentChange (val) {
this.page = val
this.getList()
},
initData () {
this.page = 1
this.getList()
},
//
add () {
this.form = _.cloneDeep(this.originForm)
this.detailVisible = true
},
//
addLine (i) {
this.form.paperOutline.splice(i + 1, 0, {
examQuestions: [],
outlineName: '',
questionNum: '',
questionType: '',
targetScore: '',
})
},
//
delLine (i) {
this.form.paperOutline.length > 1 && this.form.paperOutline.splice(i, 1)
},
// 使
async useTemplate (row) {
const data = await this.getDetail(row.templateId)
data.paperOutline.map(e => {
e.shrink = false
e.checkAll = false
e.examQuestions = []
})
this.$parent.form.paperOutline = data.paperOutline
this.$parent.templateName = data.templateName
this.listVisible = false
},
//
async getDetail (id) {
const res = await this.$get(this.api.templateDetails, {
id
})
return res.template
},
//
async edit (row) {
this.detailVisible = true
const data = await this.getDetail(row.templateId)
this.form = data
},
//
async del (row) {
try {
await this.$confirm(`确认要删除【${row.templateName}】吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
})
await this.$post(this.api.deleteTemplate, {
ids: [row.templateId]
})
Util.successMsg('删除成功')
this.getList()
} catch (e) { }
},
//
async submit () {
if (this.submiting) return false
const { form } = this
if (!form.templateName) return Util.warningMsg('请输入模板名称')
let invalid = 0
for (const e of form.paperOutline) {
if (!e.questionType) {
Util.warningMsg('请选择题型')
invalid = 1
break
}
if (!e.questionNum) {
Util.warningMsg('请输入目标题数')
invalid = 1
break
}
if (!e.targetScore) {
Util.warningMsg('请输入目标分值')
invalid = 1
break
}
}
if (invalid) return false
this.submiting = true
form.createSource = 1
form.questionNum = this.questionNum
form.totalScore = this.totalScore
form.outlineNum = form.paperOutline.length
form.questionType = [...new Set(form.paperOutline.map(e => e.questionType))].join('、')
try {
await this.$post(this.api.saveExamPaperTemplate, form)
Util.successMsg('保存成功')
this.detailVisible = false
this.submiting = false
this.getList()
} catch (e) {
this.submiting = false
}
},
//
closeDia () {
this.$emit('update:visible', false)
}
}
};
</script>
<style lang="scss" scoped></style>

@ -61,8 +61,8 @@
</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>
<el-pagination background :page-sizes="[10, 30, 50, 100, 200]" @current-change="currentChange"
:current-page="page" layout="total, prev, pager, next, sizes" :total="total"></el-pagination>
</div>
<Setup :visible.sync="setupVisible" />
@ -243,7 +243,7 @@ export default {
},
//
toTask (row) {
this.$router.push(`task`)
this.$router.push(`records`)
},
}
};

@ -12,7 +12,7 @@
<ul class="filter">
<li>
<label>评阅情况</label>
<el-select v-model="filter.difficult" placeholder="请选择评阅情况" @change="difficultChange">
<el-select v-model="filter.difficult" placeholder="请选择评阅情况" @change="initData">
<el-option v-for="(item, i) in difficults" :key="i" :label="item.name" :value="item.id"></el-option>
</el-select>
</li>
@ -93,7 +93,7 @@ export default {
methods: {
//
init () {
this.initList()
this.initData()
},
// tab
async tabChange () {
@ -114,7 +114,7 @@ export default {
this.totalQuesBank = res.message.total
} catch (e) { }
},
initList () {
initData () {
this.page = 1
this.getList()
},

@ -29,7 +29,7 @@
<label>学校</label>
<el-select v-model="filter.schoolId" clearable filterable placeholder="请选择学校" :disabled="!filter.cityId"
@change="initData">
<el-option v-for="(item, index) in schools" :key="index" :label="item.schoolName"
<el-option v-for="(item, i) in schools" :key="i" :label="item.schoolName"
:value="item.schoolId"></el-option>
</el-select>
</li>
@ -104,7 +104,7 @@ export default {
//
init () {
this.getProvince()
this.initList()
this.initData()
},
// tab
async tabChange () {
@ -125,7 +125,7 @@ export default {
this.totalQuesBank = res.message.total
} catch (e) { }
},
initList () {
initData () {
this.page = 1
this.getList()
},
@ -172,7 +172,7 @@ export default {
},
//
async getSchool () {
const { list } = await this.$get(this.api.querySchool, {
const { list } = await this.$get(this.api.querySchoolByReadAndAppraise, {
provinceId: this.filter.provinceId,
cityId: this.filter.cityId,
})

@ -1,706 +0,0 @@
<template>
<div class="index">
<div class="top">
<p class="names">{{ form.name }}</p>
<div class="count m-r-30">
用时
<span>{{ timeSum.day }}</span>
<span>{{ timeSum.hour }}</span>小时
<span>{{ timeSum.minutes }}</span>
<span>{{ timeSum.seconds }}</span>
</div>
<img class="exit" src="@/assets/images/exit.svg" alt="" @click="close">
</div>
<div class="wrap">
<div class="left">
<h6 class="title">答题卡</h6>
<div class="progress">
<p class="fs-14">答题进度</p>
<el-progress class="m-t-5 m-b-5" :percentage="progress" :format="progressFormat"></el-progress>
<p>{{ form.questionCount }}满分{{ form.score }}</p>
</div>
<div v-if="form.paperOutline" class="type-wrap">
<div v-for="(item, i) in form.paperOutline" :key="i" class="type">
<h6 class="stem">{{ arabicToChinese(i + 1) }}{{ item.outlineName }}本题共{{ item.questionNum }}小题{{
item.targetScore }}</h6>
<ul class="serials">
<template v-for="(ques, j) in item.examQuestions">
<li
v-if="!sheetStatus || (sheetStatus === 1 && !ques.answered) || (sheetStatus === 2 && ques.answered) || (sheetStatus === 3 && ques.partAnswer) || (sheetStatus === 4 && ques.sign)"
:key="j" :class="{ answered: ques.answered, partAnswer: ques.partAnswer }"
@click="scrollToQues(ques, item)">
<img v-if="ques.sign" class="tag" src="@/assets/images/tag-active.svg" alt="">
{{ j + 1 }}
</li>
</template>
</ul>
</div>
</div>
<ul class="status-filter">
<li :class="{ active: sheetStatus === 1 }" @click="filterStatus(1)">未作答</li>
<li :class="{ active: sheetStatus === 2 }" @click="filterStatus(2)">已作答</li>
<li :class="{ active: sheetStatus === 3 }" @click="filterStatus(3)">部分已作答</li>
<li :class="{ active: sheetStatus === 4 }" @click="filterStatus(4)"><img class="tag"
src="@/assets/images/tag-active.svg" alt=""> 已标记</li>
</ul>
</div>
<ul v-if="form.paperOutline" class="ques-wrap" id="quesWrap">
<li v-for="(item, i) in form.paperOutline" :key="i">
<div class="outline">
{{ arabicToChinese(i + 1) }}{{ item.outlineName }}本题共{{ item.questionNum }}小题{{
item.targetScore }}
<img :class="['shrink', { active: item.shrink }]" src="@/assets/images/shrink.svg" alt=""
@click="item.shrink = !item.shrink">
</div>
<div :class="['ques', { hide: item.shrink }]">
<div v-for="(ques, j) in item.examQuestions" :key="j"
:class="['item', { disabled: !ques.status, del: ques.isDel, repeat: ques.repeat }]"
:id="'ques' + ques.id">
<div class="stem-wrap">
<span class="label">{{ j + 1 }} / {{ item.questionNum }}</span>
<span class="label">{{ item.questionTypeName }}</span>
<div class="stem html-parse" :id="'stem' + ques.id" v-html="getQuesStem(ques)"></div>
<p v-if="item.questionType !== 'fill_blank'">{{ ques.score }}</p>
<img class="tag" :src="require('@/assets/images/' + (ques.sign ? 'tag-active' : 'tag') + '.svg')" alt=""
@click="ques.sign = ques.sign ? 0 : 1">
</div>
<!-- 单选多选判断的选项 -->
<template
v-if="item.questionType !== 'fill_blank' && item.questionType !== 'essay' && ques.questionAnswerVersionsList">
<div v-for="(opt, j) in ques.questionAnswerVersionsList" :key="j" class="opt">
<el-checkbox v-if="item.questionType === 'multiple_choice'" v-model="opt.answer" :true-label="1"
@change="mulChange(ques)"></el-checkbox>
<el-radio v-else v-model="opt.answer" :true-label="1" :label="1"
@change="singleChange(ques, j)"></el-radio>
<span>{{ numToLetter(j) }}.&nbsp;</span>
<div class="text html-parse" v-html="opt.optionText"></div>
</div>
</template>
<!-- 简答题需要展示题干文件及富文本 -->
<template v-if="item.questionType === 'essay'">
<div v-if="ques.stemAttachment" class="m-b-20">
<el-link class="m-r-10" type="primary" @click="preview(ques.stemAttachment)">{{ ques.fileName
|| ques.stemAttachment
}}</el-link>
<el-button type="primary" size="mini" round
@click="download(ques.fileName || ques.stemAttachment, ques.stemAttachment)">下载</el-button>
</div>
<UeditorPlus :ref="'essayAnswer' + ques.id" v-model="ques.answer"
@ready="editor => essayAnswerReady(editor, ques)" />
<div v-if="ques.allowAttachment" class="m-t-20">
<div v-if="ques.uploadInstructions" class="flex m-b-10 fs-12">
<span>上传要求说明</span>
<div class="html-parse" v-html="ques.uploadInstructions"></div>
</div>
<el-upload action="#">
<el-button size="small" type="primary">上传文件</el-button>
</el-upload>
</div>
</template>
</div>
</div>
</li>
</ul>
</div>
<el-dialog title="图片预览" :visible.sync="previewImgVisible" width="800px" :close-on-click-modal="false">
<el-image style="max-width: 100px; max-height: 100px" :src="previewImg" :preview-src-list="[previewImg]">
</el-image>
</el-dialog>
<PdfDia :key="pdfVisible" :visible.sync="pdfVisible" :src.sync="pdfSrc" />
</div>
</template>
<script>
import Util from '@/libs/util'
import Setting from "@/setting"
import QuesConst from '@/const/ques'
import TestPaperConst from '@/const/testPaper'
import _ from 'lodash'
import Oss from '@/components/upload/upload.js'
import Upload from '@/components/upload'
import UeditorPlus from '@/components/ueditorPlus'
import PdfDia from '@/components/pdf'
export default {
components: {
Upload, UeditorPlus, PdfDia
},
data () {
return {
questionTypes: QuesConst.questionTypes,
numToLetter: Util.numToLetter,
arabicToChinese: Util.arabicToChinese,
id: +this.$route.query.id,
entryTime: '',
counterTimer: null, // setInterval
timeSumVal: 0,
//
timeSum: {
day: 0,
seconds: 0,
minutes: 0,
hour: 0,
},
totalAnswered: 0,
progress: 0,
sheetStatus: '',
form: {
questionCount: 0,
},
previewImgVisible: false,
previewImg: '',
pdfVisible: false,
pdfSrc: '',
};
},
mounted () {
this.$once('hook:beforeDestroy', function () {
clearInterval(this.counterTimer)
})
this.getPaper()
},
methods: {
//
async getPaper (now) {
try {
this.entryTime = await Util.getNow()
const { id } = this
if (id) {
//
const { examPaper } = await this.$get(this.api.examPaperDetails, { id })
this.startCount()
const r = examPaper
const paper = r.paperOutline
const types = this.questionTypes
paper.map(e => {
const type = e.questionType
e.questionTypeName = types.find(n => n.id === type).name
e.shrink = false
e.examQuestions.map(n => {
Object.assign(n, n.question)
n.sign = 0
const opts = n.questionAnswerVersionsList
if (type !== 'fill_blank' && type !== 'essay' && opts) { //
opts.map(m => {
m.answer = 0
})
} else { //
n.answer = ''
//
n.uploadList = []
}
})
})
this.form = r
// input
this.$nextTick(() => {
paper.map(e => {
e.examQuestions.map(n => {
if (e.questionType === 'fill_blank') {
const stem = document.querySelector(`#stem` + n.id)
if (stem) {
const inputs = stem.querySelectorAll('.fill-input')
if (inputs) {
for (const e of inputs) {
e.addEventListener('input', () => {
const answers = []
for (const e of inputs) {
e.value && answers.push(e.value)
}
n.answered = answers.length === inputs.length ? 1 : 0
n.partAnswer = answers.length && answers.length !== inputs.length ? 1 : 0
})
}
}
}
}
})
})
this.calcProgress()
})
}
} catch (e) { }
},
//
handleCounter (counterTime, isCount) {
let leave1 = counterTime % (24 * 3600) //
let leave2 = leave1 % 3600 //
let leave3 = leave2 % 60 //
let day = Math.floor(counterTime / (24 * 3600)) //
let hour = Math.floor(leave1 / 3600) //
let minutes = Math.floor(leave2 / 60) //
let seconds = Math.round(leave3) //
day = this.timeFormat(day)
hour = this.timeFormat(hour)
minutes = this.timeFormat(minutes)
seconds = this.timeFormat(seconds)
const count = this[isCount ? 'counterVal' : 'timeSum']
count.day = day
count.hour = hour
count.minutes = minutes
count.seconds = seconds
},
//
startCount () {
clearInterval(this.counterTimer)
this.counterTimer = setInterval(() => {
this.timeSumVal >= 0 && this.handleCounter(this.timeSumVal++)
}, 1000)
},
timeFormat (param) {
return param < 10 ? '0' + param : param
},
//
calcProgress () {
let answered = 0
this.form.paperOutline.map(e => {
answered += e.examQuestions.filter(n => n.answered).length
})
this.totalAnswered = answered
this.progress = +(answered / this.form.questionCount * 100).toFixed(1)
},
//
progressFormat (e) {
return this.totalAnswered + '/' + this.form.questionCount
},
scrollToSmooth (position, duration) {
let startTime = Date.now()
function scroll () {
let now = Date.now()
let progress = Math.min(1, (now - startTime) / duration)
document.querySelector('#quesWrap').scrollTo(0, position * progress)
if (progress < 1) {
window.requestAnimationFrame(scroll)
}
}
window.requestAnimationFrame(scroll)
},
//
scrollToQues (e, item) {
item.shrink = false
const el = document.querySelector('#ques' + e.id)
this.$nextTick(() => {
el && this.scrollToSmooth(el.offsetTop - document.querySelector('#quesWrap').offsetTop, 200)
})
},
//
filterStatus (e) {
this.sheetStatus = this.sheetStatus === e ? '' : e
},
//
getQuesStem (ques) {
let { stem } = ques
if (ques.questionType === 'fill_blank') { //
let { fills } = ques
const regex = /<span class="gapfilling-span" data-id="(.*?)">______<\/span>/g
let match
let index = 0 //
let result = stem
while ((match = regex.exec(stem)) !== null) {
const newInput = `<input type="text" class="fill-input" value="${fills && fills.length ? fills[index] : ''}">`
result = result.replace(match[0], newInput)
index++
}
return result
} else {
return stem
}
},
//
singleChange (ques, j) {
ques.questionAnswerVersionsList.map(e => {
e.answer = 0
})
ques.questionAnswerVersionsList[j].answer = 1
ques.answered = 1
this.calcProgress()
},
//
mulChange (ques) {
ques.answered = ques.questionAnswerVersionsList.some(e => e.answer)
this.calcProgress()
},
//
essayAnswerReady (editor, ques) {
editor.ques = ques
editor.addListener('contentChange', () => {
ques.answered = editor.getContent() ? 1 : 0
this.calcProgress()
})
ques.answer && editor.setContent(ques.answer)
},
//
preview (url) {
const ext = url.split('.').pop()
if (Util.isDoc(ext)) {
window.open('https://view.officeapps.live.com/op/view.aspx?src=' + url)
} else if (Util.isImg(ext)) {
this.previewImgVisible = true
this.previewImg = url
} else if (ext === 'pdf') {
this.pdfVisible = true
this.pdfSrc = url
}
},
//
download (name, url) {
Util.downloadFile(name, url)
},
handleRemove (ques) {
Oss.del(ques.attachmentUrl)
ques.attachmentName = ''
ques.attachmentUrl = ''
},
uploadSuccess (file, ques) {
ques.attachmentName = file.name
ques.attachmentUrl = file.url
},
//
answerAnalysisReady (editor) {
this.answerAnalysis && editor.setContent(this.answerAnalysis)
},
close () {
window.close()
}
}
};
</script>
<style lang="scss" scoped>
.top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
color: #fff;
background-color: #5786fc;
.item {
display: inline-flex;
align-items: center;
}
.names {
font-size: 18px;
font-weight: 600;
}
.submit {
width: 106px;
font-size: 15px;
}
.exit {
margin-left: 20px;
cursor: pointer;
&:hover {
opacity: .9;
}
}
}
/deep/.wrap {
display: flex;
padding: 15px;
.left {
width: 300px;
margin-right: 15px;
background-color: #fff;
.title {
padding: 10px 0;
font-size: 16px;
text-align: center;
color: #333;
}
.progress {
padding: 10px;
color: #5a5a5a;
background-color: #d4e9ff;
}
.type-wrap {
max-height: calc(100vh - 248px);
padding: 10px;
overflow: auto;
.type {
margin-bottom: 20px;
}
.stem {
font-size: 15px;
color: #333;
}
}
.serials {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
li {
position: relative;
width: 35px;
margin: 7px 9px;
font-size: 13px;
text-align: center;
line-height: 35px;
color: #505050;
border: 1px solid #d3d3d3;
cursor: pointer;
&:hover {
opacity: .9;
}
&.answered {
color: #fff;
background-color: #66b2ff;
border-color: #66b2ff;
}
&.partAnswer {
border-color: #66b2ff;
}
}
.tag {
position: absolute;
top: -2px;
left: -4px;
}
}
.status-filter {
display: flex;
justify-content: space-between;
padding: 10px;
border-top: 1px solid #e5e5e5;
li {
display: inline-flex;
align-items: center;
padding: 0 3px;
font-size: 12px;
color: #333;
cursor: pointer;
border: 1px solid transparent;
&:not(:last-child):before {
content: '';
width: 13px;
height: 13px;
margin-right: 5px;
border: 1px solid #ccc;
}
&:nth-child(2):before {
background-color: #56aaff;
border: 0;
}
&:nth-child(3):before {
border-color: #56aaff;
}
&.active {
font-weight: 600;
color: #007eff;
border-color: #007eff;
&:last-child {
color: #d81e06;
border-color: #d81e06;
}
}
}
}
}
.ques-wrap {
width: calc(100% - 315px);
height: calc(100vh - 80px);
background-color: #fff;
overflow: auto;
&>li {
margin-bottom: 15px;
}
.outline {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
font-size: 15px;
font-weight: 600;
color: #333;
background-color: #e8f0ff;
}
.shrink {
cursor: pointer;
transition: .5s;
&.active {
transform: rotate(180deg);
}
}
.ques {
max-height: none;
padding: 15px;
margin-bottom: 15px;
transition: all 1.5s;
overflow: hidden;
&.hide {
max-height: 10px;
}
}
.item {
position: relative;
overflow: hidden;
&:not(:last-child) {
padding-bottom: 15px;
margin-bottom: 15px;
border-bottom: 1px dashed #e1e1e1;
}
&.disabled,
&.del,
&.repeat {
border-color: #f00;
&:after {
content: '已 禁 用';
position: absolute;
top: 17px;
right: -33px;
padding: 5px 36px;
font-size: 14px;
color: #fff;
background-color: #f00;
transform: rotate(45deg);
opacity: .6;
}
}
&.del {
&:after {
content: '已 删 除';
}
}
&.repeat {
border-color: #ff962a;
&:after {
content: '存在重复题';
background-color: #ff962a;
}
}
}
.stem-wrap {
display: flex;
align-items: baseline;
margin-bottom: 10px;
}
.tag {
margin-left: 10px;
cursor: pointer;
&:hover {
opacity: .9;
}
}
.label {
padding: 3px 5px;
margin-right: 10px;
font-size: 12px;
line-height: 1;
color: $main-color;
white-space: nowrap;
border: 1px solid;
border-radius: 2px;
}
.stem {
max-width: calc(100% - 191px);
}
img {
max-width: 100%;
}
.fill-input {
width: 100px;
height: 28px;
padding: 0 15px;
margin: 0 10px;
font-size: 13px;
line-height: 28px;
color: #606266;
border: 1px solid #DCDEE0;
border-radius: 2px;
&:focus {
outline: none;
}
}
.opt {
display: flex;
flex-wrap: wrap;
align-items: baseline;
padding-left: 10px;
margin-bottom: 5px;
font-size: 14px;
color: #707070;
line-height: 1.6;
.el-radio,
.el-checkbox {
margin-right: 15px;
}
.el-radio__label {
display: none;
}
.text {
max-width: calc(100% - 48px);
}
}
}
}
</style>

@ -0,0 +1,262 @@
<template>
<div>
<el-drawer title="分配评阅人员" :visible.sync="allocationVisible" size="1200px" :close-on-click-modal="false"
custom-class="allo-dia" @closed="closeDia">
<div class="overflow">
<div class="tool">
<ul class="filter">
<li style="align-items: flex-start;">
<label>分配方式</label>
<div>
<el-radio v-model="radio" label="1">按整卷分配</el-radio>
<p class="tips m-b-20">每份答卷将从以下已选的评阅人员中按照评阅设置的每题评阅人数随机挑选评阅人员对整卷进行评阅且以下已选的每位评阅人员分配到的答卷数量基本平均</p>
<el-radio v-model="radio" label="2">按每道人工判分题分配</el-radio>
<p class="tips">每份答卷的每道人工判分题将从以下题目已选的评阅人员中按照评阅设置的每题评阅人数随机挑选评阅人员对该题进行评阅且以下已选的每位评阅人员分配到的该题答卷数量基本平均</p>
</div>
</li>
</ul>
</div>
<!-- <People /> -->
<div>
<div class="flex a-center m-b-10">
<h6 class="page-name m-r-10" style="margin-bottom: 0">选择评阅人员</h6>
<el-button type="primary" size="mini" @click="batchAlloc">批量分配</el-button>
</div>
<el-table :data="ques" class="table" ref="table" stripe header-align="center" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" 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"></el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<i class="el-icon-edit-outline"></i>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="btns">
<el-button @click="allocationVisible = false">取消</el-button>
<el-button type="primary" :loading="submiting" @click="submit">确定</el-button>
</div>
</el-drawer>
<el-drawer title="分配评阅人员" :visible.sync="peopleVisible" :with-header="false" size="1000px"
:close-on-click-modal="false" custom-class="allo-dia">
<div class="p-l-20 p-r-20">
<People />
</div>
<div class="btns">
<el-button @click="peopleVisible = false">取消</el-button>
<el-button type="primary" :loading="submiting" @click="peopleSubmit">确定</el-button>
</div>
</el-drawer>
</div>
</template>
<script>
import People from './people'
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 {
components: { People },
props: ['visible'],
data () {
return {
radio: '',
allocationVisible: false,
searchTimer: null,
userType: '',
ques: [],
multipleSelection: [],
submiting: false,
peopleVisible: false,
};
},
watch: {
visible () {
this.allocationVisible = this.visible
this.visible && this.init()
}
},
mounted () {
},
methods: {
//
init () {
this.handleQuesList()
},
//
async getQuesBankType () {
try {
const { data } = await this.$post(this.api.getAllQuestionBankCategories, {
createSource: 1,
status: 1,
})
this.handleList(data)
this.quesBankTypes = data
} catch (e) { }
},
handleSelectionChange (val) {
this.multipleSelection = val
},
//
async batchAlloc () {
try {
this.peopleVisible = true
return
const checked = this.multipleSelection
if (checked.length) {
this.peopleVisible = true
} else {
Util.warningMsg('请选择数据')
}
} catch (e) { }
},
//
alloc () {
this.peopleVisible = true
},
//
peopleSubmit () {
},
//
async submit () {
if (this.submiting) return false
const { list } = this
let invalid = 0
let totalCount = 0
for (const i in list) {
const e = list[i]
const name = `${Util.arabicToChinese(+i + 1)}大题`
if (!e.questionType) {
Util.warningMsg(`${name}请先选择题型`)
invalid = 1
break
}
if (!e.questionNum || isNaN(e.questionNum) || e.questionNum <= 0) {
Util.warningMsg(`${name}的目标题数请输入正整数`)
invalid = 1
break
}
let total = Decimal(e.basicDifficulty || 0).add(e.normalDifficulty || 0).add(e.hardDifficulty || 0).add(e.veryHardDifficulty || 0).toNumber() // 4
if (total) { // 41
this.$set(e, 'randomDifficulty', 0)
} else {
total = +e.randomDifficulty || 0
}
if (total > e.questionNum) {
Util.warningMsg(`${name}的小题总数大于目标题数,请重新输入`)
invalid = 1
break
}
e.count = total
totalCount = Decimal(totalCount).add(total).toNumber()
}
if (invalid) return false
if (!totalCount) return Util.warningMsg(`请填写难度题数`)
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.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) => {
if (+e.count !== res.list[i].questions.length) invalid = 1
if (e.examQuestions.length) hasQues = 1
e.score = 0
})
// 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) => {
res.list[i].questions.map((e, i) => {
e.questionId = e.id
e.serialNumber = i + 1
e.originSort = i + 1
this.$parent.handleQuesInfo(e)
})
this.$parent.form.paperOutline[i].examQuestions = res.list[i].questions
})
this.allocationVisible = false
this.$parent.calcDifficult()
this.submiting = false
} catch (e) {
this.submiting = false
}
},
//
closeDia () {
this.$emit('update:visible', false)
}
}
};
</script>
<style lang="scss" scoped>
/deep/.allo-dia {
.el-drawer__header {
margin-bottom: 20px;
}
.overflow {
height: calc(100vh - 147px);
padding: 0 20px;
overflow: auto;
}
.tips {
margin-top: 3px;
font-size: 12px;
color: #585858;
}
}
</style>

@ -0,0 +1,336 @@
<template>
<div class="page">
<Breadcrumb :data="crumbs" />
<h6 class="page-name">筛选</h6>
<div class="tool">
<ul class="filter">
<li>
<label>省份</label>
<el-select v-model="filter.provinceId" clearable placeholder="请选择省份" @change="provinceChange"
@clear="clearprovince">
<el-option v-for="(item, i) in provinces" :key="i" :label="item.provinceName"
:value="item.provinceId"></el-option>
</el-select>
</li>
<li>
<label>城市</label>
<el-select v-model="filter.cityId" clearable placeholder="请选择城市" :disabled="!filter.provinceId"
@clear="clearcity" @change="getSchool">
<el-option v-for="(item, i) in cities" :key="i" :label="item.cityName" :value="item.cityId"></el-option>
</el-select>
</li>
<li>
<label>学校</label>
<el-select v-model="filter.schoolId" clearable filterable placeholder="请选择学校" :disabled="!filter.cityId"
@change="initData">
<el-option v-for="(item, i) in schools" :key="i" :label="item.schoolName"
:value="item.schoolId"></el-option>
</el-select>
</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-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: 400px;" placeholder="请输入学生姓名、学生学号、团队名称、答卷ID、提交名称" prefix-icon="el-icon-search"
v-model="filter.keyword" clearable />
</li>
</ul>
<div>
<el-button type="primary" @click="batchReview">修改评阅设置</el-button>
<!-- <el-button type="primary">批量导出评分表</el-button> -->
<el-button type="primary">批量导出列表</el-button>
</div>
</div>
<el-table :data="list" class="table" ref="table" stripe header-align="center" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" 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"></el-table-column>
<el-table-column prop="professionalName" label="城市" align="center" min-width="100"></el-table-column>
<el-table-column prop="knowledgePointName" label="学生所在学校" align="center" min-width="100"></el-table-column>
<el-table-column prop="lastEditor" label="团队名称" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="学生姓名" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="学号" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="答卷ID" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="用时" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="提交时间" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="提交名称" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="是否完成分配" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="评阅人员" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="评阅人数" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="评阅状态" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="成绩" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="最新分配时间" align="center" width="90"></el-table-column>
<el-table-column prop="lastEditor" label="最新分配人" align="center" width="90"></el-table-column>
<el-table-column label="操作" align="center" width="100" fixed="right">
<template slot-scope="scope">
<el-button type="text" @click="allocation(scope.row)">分配评阅人员</el-button>
<!-- <el-button type="text" @click="toScore(scope.row)">查看评分表</el-button>
<el-button type="text" @click="exportScore(scope.row)">导出评分表</el-button> -->
</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>
<Allocation :visible.sync="allocationVisible" />
</div>
</template>
<script>
import Allocation from './allocation'
import Breadcrumb from '@/components/breadcrumb'
import Util from '@/libs/util'
import Setting from '@/setting'
import Const from '@/const/ques'
import Qs from 'qs'
import dayjs from 'dayjs'
export default {
components: { Allocation, Breadcrumb },
data () {
return {
crumbs: [],
paperName: this.$route.query.paperName,
difficults: Const.difficults,
questionTypes: Const.questionTypes,
loading: false,
provinces: [],
cities: [],
schools: [],
status: [
{
id: 1,
name: '启用'
},
{
id: 0,
name: '禁用'
},
],
date: [],
filter: {
month: '',
startTime: null,
endTime: null,
status: '',
keyword: '',
},
list: [{}],
page: +this.$route.query.page || 1,
pageSize: 10,
total: 0,
multipleSelection: [],
allocationVisible: false,
};
},
watch: {
'filter.month': function (val) {
if (val) {
let unit = 24 * 60 * 60 * 1000
this.date = [dayjs(new Date(Date.now() - unit * 30 * val)).format('YYYY-MM-DD'), dayjs(new Date(Date.now() + unit)).format('YYYY-MM-DD')]
} else {
this.date = []
}
},
date: function (val) {
if (val) {
this.filter.startTime = val[0];
this.filter.endTime = val[1];
} else {
this.filter.startTime = ''
this.filter.endTime = ''
}
// this.initData();
},
'filter.keyword': function () {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.initData, 500)
},
},
mounted () {
this.crumbs = [
{
name: '分配评阅任务',
route: '/allocationReview'
},
{
name: '任务分配'
},
]
const { query } = this.$route
if (query.page) {
const { questionTypes, correctRateEnd, correctRateStart, difficultys, specialtyIds, status, keyword, questionTypeSort, givenYearSort, difficultySort, correctRateSort, updateTimeSort, referenceCountSort, givenYears, knowledgePointIds, questionBankId, questionBankName, questionBankCategory } = query
this.filter = {
questionTypes: questionTypes ? questionTypes.split(',') : [],
correctRateEnd: correctRateEnd || '',
correctRateStart: correctRateStart || '',
difficultys: difficultys ? difficultys.split(',') : [],
specialtyIds: specialtyIds ? specialtyIds.split(',').map(e => +e) : [],
status: status ? +status : '',
keyword: keyword || '',
questionTypeSort: questionTypeSort || '',
givenYearSort: givenYearSort || '',
difficultySort: difficultySort || '',
correctRateSort: correctRateSort || '',
updateTimeSort: updateTimeSort || '',
referenceCountSort: referenceCountSort || '',
}
this.givenYears = givenYears || ''
this.knowledgePointIds = knowledgePointIds ? JSON.parse(knowledgePointIds) : []
this.$router.push(`/myReview?questionBankId=${questionBankId}&questionBankName=${questionBankName}&questionBankCategory=${questionBankCategory}`).catch(() => { })
}
this.getProvince()
// this.getProfessional()
// this.getKnowledge()
},
methods: {
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.questionBankId,
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()
},
//
async getProvince () {
const { list } = await this.$get(this.api.queryProvince)
this.provinces = list
},
//
clearprovince () {
this.filter.cityId = '',
this.filter.schoolId = ''
},
//
provinceChange () {
this.clearprovince()
this.getCity()
this.initData()
},
//
async getCity () {
const { list } = await this.$get(this.api.queryCity, {
provinceId: this.filter.provinceId
})
this.cities = list
},
//
clearcity () {
this.filter.schoolId = ''
},
//
cityChange () {
this.filter.schoolId = ''
this.getSchool()
this.initData()
},
//
async getSchool () {
const { list } = await this.$get(this.api.querySchoolByReadAndAppraise, {
provinceId: this.filter.provinceId,
cityId: this.filter.cityId,
})
this.schools = list
},
//
async batchReview () {
const list = this.multipleSelection
if (list.length) {
try {
await this.$confirm(`确定要删除已选定的${list.length}份试卷吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
})
await this.$post(this.api.paperDel, {
delete: false,
ids: list.map(e => e.paperId)
})
Util.successMsg('删除成功')
this.multipleSelection = []
this.$refs.table.clearSelection()
this.getList()
} catch (e) { }
} else {
Util.warningMsg('请选择数据')
}
},
//
allocation (row) {
this.allocationVisible = true
},
//
toScore (row) {
},
//
exportScore (row) {
},
}
};
</script>
<style lang="scss" scoped>
.tool {
margin-bottom: 0;
.filter {
flex-wrap: wrap;
li {
margin-bottom: 15px;
}
}
}
</style>

@ -0,0 +1,351 @@
<template>
<div>
<h6 class="page-name m-t-20">选择评阅人员</h6>
<div class="wrap">
<div class="item">
<el-radio-group class="m-b-10" v-model="userType" size="small">
<el-radio-button label="平台用户"></el-radio-button>
<el-radio-button label="专家"></el-radio-button>
</el-radio-group>
<el-tree :data="nakadais" default-expand-all ref="nakadais" node-key="id" highlight-current
:expand-on-click-node="false" @node-click="getNakadaiUser"
:props="{ children: 'children', label: 'organizationName', isLeaf: 'leaf' }"></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="userKeyword"
clearable />
<template v-if="users.length">
<div class="line">
<el-checkbox v-model="userCheck" @change="userAllCheckChange"></el-checkbox>
<span class="username">姓名</span>
<!-- <span>现所在单位</span>
<span>职务</span> -->
</div>
<div class="lines">
<div v-for="(item, i) in users" :key="i" class="line">
<el-checkbox v-model="item.check" :disabled="item.disabled"
@change="val => userChange(val, item)"></el-checkbox>
<p class="username" :title="item.userName">{{ item.userName }}</p>
</div>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</div>
<div class="item">
<div class="flex j-between a-center">
<p class="total">已选人</p>
<el-button type="text" @click="batchDelChecked">批量移除</el-button>
</div>
<el-input class="m-b-10" placeholder="请输入姓名、现所在单位" prefix-icon="el-icon-search" v-model="checkedKeyword"
clearable />
<template v-if="checked.length">
<div class="line">
<el-checkbox v-model="checkedAllCheck" @change="checkedAllCheckChange"></el-checkbox>
<span class="username">姓名</span>
</div>
<div class="lines">
<template v-for="(item, i) in checked">
<div v-if="item.userName.includes(checkedKeyword)" :key="i" class="line">
<div class="check-left">
<el-checkbox v-model="item.check"></el-checkbox>
<p class="username" :title="item.userName">{{ item.userName }}</p>
</div>
<i class="el-icon-delete action-icon" @click="delChecked(item)"></i>
</div>
</template>
</div>
</template>
<div v-else class="empty">
<img class="icon" src="@/assets/images/empty.svg" alt="">
<p>暂无数据</p>
</div>
</div>
</div>
</div>
</template>
<script>
import Setting from '@/setting'
import Util from '@/libs/util'
import _ from 'lodash'
import Decimal from 'decimal.js'
export default {
data () {
return {
nakadais: [],
searchTimer: null,
userType: '',
userCheck: false,
users: [],
userKeyword: '',
checkedKeyword: '',
checkedAllCheck: false,
checked: [],
submiting: false,
};
},
watch: {
'quesBankKeyword': function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.initQuesBank, 500)
},
'userKeyword': function (val) {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(this.getKnowledge, 500)
},
},
mounted () {
this.getNakadais()
},
methods: {
//
async getNakadais () {
const res = await this.$post(this.api.treeListArch)
const list = res.treeList
this.handleList(list)
this.nakadais = list
},
//
handleList (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleList(e.children)
} else {
delete e.children
}
})
},
async getNakadaiUser (data) {
console.log(11, data)
const { page } = await this.$post(this.api.staffList, {
type: 1,
staffArchitectureId: data.id || '',
keyWord: this.userKeyword,
pageNum: 1,
pageSize: 1000
})
this.users = page.records
},
nakadaiClick () {
},
//
async getQuesBank () {
try {
const type = this.quesBankTypeVal
const res = await this.$post(this.api.questionBankList, {
status: 1,
pageNum: 1,
pageSize: 1000,
questionCategoryId: type.length ? type[type.length - 1] : '',
name: this.quesBankKeyword
})
this.quesBanks = res.message.records
this.totalQuesBank = res.message.total
} catch (e) { }
},
//
questionBankClick (item) {
this.curQuesBank = item
this.userCheck = false
this.getKnowledgeType()
this.getKnowledge()
},
//
handleList (list) {
list.map(e => {
if (e.children && e.children.length) {
this.handleList(e.children)
} else {
delete e.children
}
})
},
//
userAllCheckChange (val) {
this.users.map(e => {
e.check = val
this.userChange(val, e)
})
},
//
userChange (val, item) {
const cur = this.checked.findIndex(e => e.userId === item.userId)
//
if (val) {
if (cur === -1) {
const e = _.cloneDeep(item)
e.check = false
this.checked.push(e)
}
} else {
//
cur >= 0 && this.checked.splice(cur, 1)
}
},
//
handleQuesList () {
this.list = _.cloneDeep(this.$parent.form.paperOutline)
},
//
checkedAllCheckChange (val) {
this.checked.map(e => e.check = val)
},
//
async batchDelChecked (val) {
try {
const checked = this.checked.filter(e => e.check)
if (checked.length) {
checked.map(e => {
const cur = this.users.find(n => n.userId === e.userId)
if (cur) {
cur.check = false
}
})
this.userCheck = false
this.checkedAllCheck = false
this.checked = this.checked.filter(e => !e.check)
} else {
Util.warningMsg('请选择数据')
}
} catch (e) { }
},
//
async delChecked (item) {
try {
const cur = this.users.find(e => e.userId === item.userId)
if (cur) cur.check = false
this.checked.splice(this.checked.findIndex(e => e.userId === item.userId), 1)
} catch (e) { }
},
//
async submit () {
if (this.submiting) return false
this.submiting = true
try {
const res = await this.$post(this.api.selectQuestionsByTypeAndDifficulty, list)
let invalid = 0
let hasQues = 0
list.map((e, i) => {
if (+e.count !== res.list[i].questions.length) invalid = 1
if (e.examQuestions.length) hasQues = 1
e.score = 0
})
// 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) => {
res.list[i].questions.map((e, i) => {
e.questionId = e.id
e.serialNumber = i + 1
e.originSort = i + 1
this.$parent.handleQuesInfo(e)
})
this.$parent.form.paperOutline[i].examQuestions = res.list[i].questions
})
this.allocationVisible = false
this.$parent.calcDifficult()
this.submiting = false
} catch (e) {
this.submiting = false
}
},
//
closeDia () {
this.$emit('update:visible', false)
}
}
};
</script>
<style lang="scss" scoped>
/deep/.wrap {
display: flex;
margin-top: 20px;
border: 1px solid #eee;
.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled) {
box-shadow: none;
}
.item {
width: 30%;
padding: 15px;
border-right: 1px solid #eee;
&:last-child {
width: 40%;
border-right: 0;
}
}
.total {
font-size: 16px;
color: #333;
}
.users {
padding-left: 44px;
margin-top: 10px;
}
.lines {
height: calc(100vh - 392px);
overflow: auto;
}
.line {
display: flex;
align-items: center;
padding: 5px 0;
color: #333;
.username {
margin: 0 12px;
}
}
.check-left {
display: inline-flex;
align-items: center;
width: calc(100% - 30px);
}
.action-icon {
font-size: 14px;
}
}
</style>

@ -23,7 +23,7 @@
<label>学校</label>
<el-select v-model="filter.schoolId" clearable filterable placeholder="请选择学校" :disabled="!filter.cityId"
@change="initData">
<el-option v-for="(item, index) in schools" :key="index" :label="item.schoolName"
<el-option v-for="(item, i) in schools" :key="i" :label="item.schoolName"
:value="item.schoolId"></el-option>
</el-select>
</li>
@ -253,7 +253,7 @@ export default {
},
//
async getSchool () {
const { list } = await this.$get(this.api.querySchool, {
const { list } = await this.$get(this.api.querySchoolByReadAndAppraise, {
provinceId: this.filter.provinceId,
cityId: this.filter.cityId,
})

@ -15,10 +15,10 @@ export default {
component: () => import('@/pages/allocationReview/list'),
meta: { title: '分配评阅任务' }
},
// {
// path: 'detail',
// component: () => import('@/pages/testPaper/detail'),
// meta: { title: '试卷管理' }
// },
{
path: 'records',
component: () => import('@/pages/allocationReview/records'),
meta: { title: '任务分配' }
},
]
};

Loading…
Cancel
Save