yujialong 4 months ago
parent 1af3178ea3
commit 87b03ed8b6
  1. 2
      public/static/ueditorPlus/ueditor.config.js
  2. 62
      src/api/index.js
  3. 3
      src/components/ueditor/index.vue
  4. 22
      src/pages/ques/detail/index.vue
  5. 9
      src/pages/ques/list/index.vue
  6. 1
      src/pages/testPaper/detail/auto.vue
  7. 233
      src/pages/testPaper/detail/index.vue
  8. 8
      src/pages/testPaper/detail/manual.vue
  9. 10
      src/pages/testPaper/list/index.vue

@ -50,7 +50,7 @@
// 服务器统一请求接口路径
serverUrl: "http://121.37.12.51/exam/exam/upload/configAndUpload",
serverUrl: "http://192.168.31.51:9000/exam/exam/upload/configAndUpload",
imageActionName: "imgUpload",
imageAllowFiles: [
".png",

@ -5,26 +5,26 @@ export default {
encrypt: `/nakadai/data/encrypt`,
queryProfessional: `/exam/exam/professional/queryProfessional`,
categoriesDel: `/exam/question/bank/categories/batchDeletion`,
categoriesFind: `/exam/question/bank/categories/findById`,
getAllQuestionBankCategories: `/exam/question/bank/categories/getAllQuestionBankCategories`,
categoriesSave: `/exam/question/bank/categories/saveOrUpdate`,
categoriesDisable: `/exam/question/bank/categories/updateStatus`,
categoriesDel: `/exam/exam/question/bank/categories/batchDeletion`,
categoriesFind: `/exam/exam/question/bank/categories/findById`,
getAllQuestionBankCategories: `/exam/exam/question/bank/categories/getAllQuestionBankCategories`,
categoriesSave: `/exam/exam/question/bank/categories/saveOrUpdate`,
categoriesDisable: `/exam/exam/question/bank/categories/updateStatus`,
questionBankDel: `/exam/questionBank/batchDeletion`,
questionBankFind: `/exam/questionBank/findById`,
questionBankList: `/exam/questionBank/pagingQuery`,
questionBankSave: `/exam/questionBank/saveOrUpdate`,
questionBankDisable: `/exam/questionBank/updateStatus`,
copyQuestionBank: `/exam/questionBank/copyQuestionBank`,
questionBankStructureLevel: `/exam/question/bank/categories/questionBankStructureLevel`,
questionBankDel: `/exam/exam/questionBank/batchDeletion`,
questionBankFind: `/exam/exam/questionBank/findById`,
questionBankList: `/exam/exam/questionBank/pagingQuery`,
questionBankSave: `/exam/exam/questionBank/saveOrUpdate`,
questionBankDisable: `/exam/exam/questionBank/updateStatus`,
copyQuestionBank: `/exam/exam/questionBank/copyQuestionBank`,
questionBankStructureLevel: `/exam/exam/question/bank/categories/questionBankStructureLevel`,
TreeStructure: `/exam/knowledgeHierarchy/TreeStructure`,
classificationTreeStructure: `/exam/knowledgeHierarchy/classificationTreeStructure`,
knowledgeHierarchyDel: `/exam/knowledgeHierarchy/batchDeletion`,
knowledgeHierarchyFind: `/exam/knowledgeHierarchy/findById`,
knowledgeHierarchySave: `/exam/knowledgeHierarchy/saveOrUpdate`,
knowledgeHierarchyList: `/exam/knowledgeHierarchy/pagingQuery`,
TreeStructure: `/exam/exam/knowledgeHierarchy/TreeStructure`,
classificationTreeStructure: `/exam/exam/knowledgeHierarchy/classificationTreeStructure`,
knowledgeHierarchyDel: `/exam/exam/knowledgeHierarchy/batchDeletion`,
knowledgeHierarchyFind: `/exam/exam/knowledgeHierarchy/findById`,
knowledgeHierarchySave: `/exam/exam/knowledgeHierarchy/saveOrUpdate`,
knowledgeHierarchyList: `/exam/exam/knowledgeHierarchy/pagingQuery`,
libraryClassificationDel: `/exam/exam/libraryClassification/delete`,
libraryClassificationSave: `/exam/exam/libraryClassification/save`,
@ -57,17 +57,17 @@ export default {
saveExamPaperTemplate: `/exam/exam/paperTemplate/saveExamPaperTemplate`,
templateDetails: `/exam/exam/paperTemplate/templateDetails`,
addQuestion: `/exam/questions/addQuestion`,
findQuestion: `/exam/questions/findById`,
listQuestion: `/exam/questions/pagingQuery`,
updateQuestion: `/exam/questions/updateQuestion`,
batchImportQuestions: `${host}/exam/questions/batchImportQuestions`,
checkQuestion: `/exam/questions/checkQuestion`,
delQuestion: `/exam/questions/batchDeletion`,
checkQuestionIsUse: `/exam/questions/checkQuestionIsUse`,
copyQuestion: `/exam/questions/copyQuestion`,
createNewVersion: `/exam/questions/createNewVersion`,
disableOrEnableQuestion: `/exam/questions/disableOrEnableQuestion`,
findAllByQuestionBank: `/exam/questions/findAllByQuestionBank`,
selectQuestionsByTypeAndDifficulty: `/exam/questions/selectQuestionsByTypeAndDifficulty`,
addQuestion: `/exam/exam/questions/addQuestion`,
findQuestion: `/exam/exam/questions/findById`,
listQuestion: `/exam/exam/questions/pagingQuery`,
updateQuestion: `/exam/exam/questions/updateQuestion`,
batchImportQuestions: `${host}/exam/exam/questions/batchImportQuestions`,
checkQuestion: `/exam/exam/questions/checkQuestion`,
delQuestion: `/exam/exam/questions/batchDeletion`,
checkQuestionIsUse: `/exam/exam/questions/checkQuestionIsUse`,
copyQuestion: `/exam/exam/questions/copyQuestion`,
createNewVersion: `/exam/exam/questions/createNewVersion`,
disableOrEnableQuestion: `/exam/exam/questions/disableOrEnableQuestion`,
findAllByQuestionBank: `/exam/exam/questions/findAllByQuestionBank`,
selectQuestionsByTypeAndDifficulty: `/exam/exam/questions/selectQuestionsByTypeAndDifficulty`,
}

@ -5,6 +5,7 @@
</template>
<script>
import Setting from '@/setting'
export default {
name: 'UE',
props: {
@ -45,7 +46,7 @@ export default {
this.$nextTick(() => {
// eslint-disable-next-line no-undef
this.instance = UE.getEditor(this.randomId, {
UEDITOR_HOME_URL: '/static/ueditorPlus/',
UEDITOR_HOME_URL: Setting.isDev ? '/static/ueditorPlus/' : '/examination/static/ueditorPlus/',
serverUrl: "http://121.37.12.51/exam/exam/upload/configAndUpload",
plugins: 'gapfilling'
})

@ -231,15 +231,7 @@ export default {
},
answerAnalysis: '',
originFillBlank: {},
fillBlanks: [
// {
// serial: 1,
// fills: [{
// val: ''
// }],
// scoreProportion: ''
// }
],
fillBlanks: [],
uploadList: [],
form: {
difficulty: '',
@ -511,22 +503,26 @@ export default {
this.richEditor.dialogVisible = false
}
},
// 线
questionItemReset (content) {
let spanRegex = new RegExp('<span class="gapfilling-span" (.*?)>(.*?)______(.*?)<\\/span>', 'g')
let newFormItem = []
let gapfillingItems = content.match(spanRegex)
if (gapfillingItems !== null) {
gapfillingItems.forEach(function (span, index) {
const pairRegex = /<span class="gapfilling-span (.*?)">(.*?)<\/span>/
const pairRegex = /<span class="gapfilling-span" (.*?)">(.*?)______(.*?)<\/span>/
pairRegex.test(span)
newFormItem.push({ fills: [{ val: '' }], uuid: RegExp.$1, scoreProportion: '0' })
})
newFormItem.forEach(e => {
if (!this.fillBlanks.some(n => n.uuid === e.uuid)) {
this.fillBlanks.push(e)
}
!this.fillBlanks.some(n => n.uuid === e.uuid) && this.fillBlanks.push(e)
})
this.fillBlanks.map((e, i) => {
!newFormItem.some(n => n.uuid === e.uuid) && this.fillBlanks.splice(i, 1)
})
} else {
this.fillBlanks = []
}
},
//

@ -1,7 +1,7 @@
<template>
<div>
<Breadcrumb :data="crumbs" />
<div class="page">
<div class="page">
<Breadcrumb style="margin-bottom: 0;" :data="crumbs" />
<div class="wrap">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="isNotJoin" @change="typeChange">
@ -565,9 +565,8 @@ export default {
</script>
<style lang="scss" scoped>
.page {
.wrap {
display: flex;
padding: 0 24px;
.side {
width: 300px;

@ -288,7 +288,6 @@ export default {
//
difficultChange (val) {
// Decimal(e.score).add(Decimal(score))
const difficultyWeights = [0.2, 0.4, 0.6, 0.8]
const names = ['basicDifficulty', 'normalDifficulty', 'hardDifficulty', 'veryHardDifficulty']
//

@ -133,16 +133,16 @@
<el-checkbox v-model="ques.check"></el-checkbox>
<div :class="['ques-info', { disabled: !ques.status, del: ques.isDel, repeat: ques.isRepeat }]">
<div class="top-line">
<span class="label">{{ j + 1 }} / 10</span>
<span class="label">{{ j + 1 }} / {{ item.examQuestions.length }}</span>
<span class="label">{{ questionTypes.find(e => e.id === item.questionType).name }}</span>
<div v-html="ques.stem"></div>
<p v-if="ques.questionType !== 'fill_blank'"><el-input class="score" placeholder="请输入"
<div :id="'stem' + ques.questionVersionId" v-html="getQuesStem(ques)"></div>
<p v-if="item.questionType !== 'fill_blank'"><el-input class="score" placeholder="请输入"
v-model="ques.score" /></p>
</div>
<!-- 单选多选判断的选项 -->
<template
v-if="ques.questionType !== 'fill_blank' && ques.questionType !== 'essay' && ques.questionAnswerVersionsList">
v-if="item.questionType !== 'fill_blank' && item.questionType !== 'essay' && ques.questionAnswerVersionsList">
<div v-for="(opt, j) in ques.questionAnswerVersionsList" :key="j" class="opt">
<span>{{ numToLetter(j) }}.&nbsp;</span>
<div v-html="opt.optionText"></div>
@ -151,7 +151,7 @@
<div class="bottom-line">
<div class="correct">
{{ ques.questionType === 'essay' ? '参考答案' : '正确答案' }}
{{ item.questionType === 'essay' ? '参考答案' : '正确答案' }}
<div v-html="getCorrectAnswer(ques)"></div>
</div>
<div class="actions">
@ -197,6 +197,7 @@ import Template from './template'
import Manual from './manual'
import Auto from './auto'
import Detail from '@/pages/ques/detail'
import Decimal from 'decimal.js'
export default {
components: { Ueditor, Breadcrumb, Template, Manual, Auto, Detail },
@ -229,7 +230,7 @@ export default {
name: '',
paperMethod: '',
paperType: '',
particularYear: '',
particularYear: new Date(),
professionalId: '',
remarks: '',
score: '',
@ -322,6 +323,60 @@ export default {
}
},
mounted () {
function distributeScores (objects, totalScore) {
const numObjects = objects.length;
//
const baseScore = totalScore / numObjects;
const hasFraction = baseScore % 1 !== 0; //
//
for (let i = 0; i < numObjects; i++) {
objects[i].score = Math.floor(baseScore);
}
//
let fractionalPartSum = 0;
if (hasFraction) {
for (let i = 0; i < numObjects; i++) {
fractionalPartSum += baseScore % 1;
}
}
//
let remainingObjects = numObjects;
while (fractionalPartSum > 0) {
objects[--remainingObjects].score += 1;
fractionalPartSum -= 1;
}
//
if (totalScore < numObjects) {
//
const fractionalDistribution = Math.ceil(fractionalPartSum);
for (let i = 0; i < fractionalDistribution; i++) {
objects[i].score += 1;
}
}
return objects;
}
//
const objects = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 }
];
const totalScore = 3; //
const result = distributeScores(objects, totalScore);
console.log(result);
this.crumbs = [
{
name: '试卷管理',
@ -358,8 +413,6 @@ export default {
})
if (r.particularYear) r.particularYear = r.particularYear + ''
this.form = r
// this.answerAnalysis = opts[0].answerAnalysis
}
} catch (e) { }
},
@ -436,12 +489,65 @@ export default {
})
})
if (data && data.avgValueList && data.avgValueList.length) {
const fillBlanks = []
data.avgValueList.map((e, i) => {
paper[i].questionType === 'fill_blank' && fillBlanks.push(...paper[i].examQuestions)
// scores-1
e.scores.includes(-1) || e.scores.map((n, j) => {
this.$set(paper[i].examQuestions[j], 'score', n)
})
})
fillBlanks.length && this.fillBlankAllocation(fillBlanks) //
}
},
//
async allocation (item) {
const { data } = await this.$post(this.api.avgValues, {
avgValueList: [{
questionNum: item.examQuestions.length,
targetScore: +item.targetScore
}]
})
if (data && data.avgValueList && data.avgValueList.length) {
const { scores } = data.avgValueList[0]
scores.includes(-1) || item.examQuestions.forEach((e, i) => {
this.$set(e, 'score', scores[i])
})
}
item.questionType === 'fill_blank' && this.fillBlankAllocation(item.examQuestions) //
},
//
async fillBlankAllocation (list) {
const param = list.map(e => {
let { answerData } = e.questionAnswerVersionsList[0]
if (answerData) {
answerData = JSON.parse(answerData)
return {
questionNum: answerData.length,
targetScore: e.score,
questionId: e.questionVersionId
}
}
})
const { data } = await this.$post(this.api.avgValues, {
avgValueList: param
})
if (data && data.avgValueList && data.avgValueList.length) {
data.avgValueList.map((e, i) => {
// scores-1
if (!e.scores.includes(-1)) {
const stem = document.querySelector(`#stem` + e.questionId)
if (stem) {
const inputs = stem.querySelectorAll('.fill-input')
if (inputs) {
for (const j in e.scores) {
const item = inputs[j]
inputs[j].value = e.scores[j]
}
}
}
}
})
}
},
@ -493,6 +599,29 @@ export default {
return correct ? (e.questionType === 'judgement' ? correct[0].optionText : correct.map(e => Util.numToLetter(e.optionNumber - 1)).join('')) : '' // ABC
}
},
//
getQuesStem (ques) {
let { stem } = ques
if (ques.questionType === 'fill_blank') { //
let { jsonText } = ques
if (jsonText) jsonText = JSON.parse(jsonText)
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="${jsonText && jsonText.scores ? jsonText.scores[index] : ''}">`
result = result.replace(match[0], newInput)
index++
}
return result
} else {
return stem
}
},
//
toQues (item, i, ques) {
this.curType = item
@ -537,25 +666,6 @@ export default {
}
} catch (e) { }
},
//
allocation (item) {
const total = +item.targetScore
const len = item.examQuestions.length
const quotient = Math.floor(total / len) //
let remainder = total % len //
//
item.examQuestions.forEach(e => {
e.score = quotient
})
//
while (remainder > 0) {
for (let i = 0; i < len && remainder > 0; i++) {
item.examQuestions[i].score += 1
remainder -= 1
}
}
},
//
delQues (item, i) {
item.examQuestions.splice(i, 1)
@ -588,16 +698,38 @@ export default {
invalid = 1
break
}
const chineseNum = this.arabicToChinese(+i + 1)
//
if (+e.questionNum !== e.examQuestions.length) {
Util.warningMsg(`${this.arabicToChinese(i + 1)}大题的小题总数跟目标题数不一致,请重新修改`)
Util.warningMsg(`${chineseNum}大题的小题总数跟目标题数不一致,请重新修改`)
invalid = 1
break
}
//
if (+e.targetScore !== e.examQuestions.reduce((e, j) => (e += +j.score), 0)) {
Util.warningMsg(`${this.arabicToChinese(i + 1)}大题的小题总分跟目标分值不一致,请重新修改`)
//
if (e.questionType === 'fill_blank') {
let totalScore = 0
e.examQuestions.map(n => {
const stem = document.querySelector(`#stem` + n.questionVersionId)
if (stem) {
const inputs = stem.querySelectorAll('.fill-input')
if (inputs) {
for (const e of inputs) {
totalScore = Decimal(totalScore).add(e.value || 0).toNumber()
}
}
}
})
if (+e.targetScore !== totalScore) {
Util.warningMsg(`${chineseNum}大题的小题总分跟目标分值不一致,请重新修改`)
invalid = 1
break
}
} else if (+e.targetScore !== e.examQuestions.reduce((e, j) => (e += +j.score), 0)) {
//
Util.warningMsg(`${chineseNum}大题的小题总分跟目标分值不一致,请重新修改`)
invalid = 1
break
}
@ -609,7 +741,6 @@ export default {
break
}
}
// debugger
if (invalid) return false
this.submiting = true
@ -627,11 +758,30 @@ export default {
e.outlineId = ''
}
e.targetScore = +e.targetScore
e.examQuestions = e.examQuestions.map(n => {
e.examQuestions = e.examQuestions.map((n, j) => {
//
if (n.questionType === 'fill_blank') {
const stem = document.querySelector(`#stem` + n.questionVersionId)
const scores = []
if (stem) {
const inputs = stem.querySelectorAll('.fill-input')
if (inputs) {
for (const e of inputs) {
scores.push(e.value)
}
}
}
n.jsonText = JSON.stringify({
questionVersionId: n.questionVersionId,
scores
})
}
return {
questionVersionId: n.questionVersionId,
serialNumber: n.serialNumber,
score: +n.score,
jsonText: n.jsonText,
paperId: !isCopy && this.paperId || '',
outlineId: !isCopy && e.outlineId || '',
}
@ -641,6 +791,7 @@ export default {
form.questionType = [...new Set(paper.map(e => e.questionType))].join('、') //
form.createSource = 1
if (isCopy) form.paperId = ''
// debugger
try {
await this.$post(this.api.saveExamPaper, form)
Util.successMsg('保存成功')
@ -774,6 +925,22 @@ export default {
}
}
/deep/.fill-input {
width: 100px;
height: 28px;
padding: 0 15px;
margin: 0 10px;
font-size: 13px;
line-height: 28px;
color: #606266;
border: 1px solid #DCDEE0;
border-radius: 2px;
&:focus {
outline: none;
}
}
.opt {
display: flex;
flex-wrap: wrap;

@ -39,7 +39,7 @@
<el-checkbox v-model="item.check" :disabled="item.disabled"
@change="val => quesChange(val, item)"></el-checkbox>
<span class="serial">{{ i + 1 }}</span>
<span>{{ item.stem }}</span>
<span>{{ item.stemText }}</span>
</div>
</div>
</div>
@ -47,7 +47,7 @@
<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.stem"></div>
<div v-html="$parent.curQues.stemText"></div>
</div>
<div class="flex j-between a-center">
@ -66,7 +66,7 @@
<div class="check-left">
<el-checkbox v-model="item.check"></el-checkbox>
<span class="serial">{{ i + 1 }}</span>
<div v-html="item.stem"></div>
<div v-html="item.stemText"></div>
</div>
<i class="el-icon-delete action-icon" @click="delChecked(item)"></i>
</div>
@ -212,7 +212,7 @@ export default {
data.map(e => {
const el = document.createElement('div')
el.innerHTML = e.stem
e.stem = el.innerText
e.stemText = el.innerText
e.check = !!this.checked.find(n => n.questionId === e.questionId)
e.disabled = !!checked.find(n => n.questionVersionId === e.questionId)
})

@ -1,7 +1,7 @@
<template>
<div>
<Breadcrumb :data="crumbs" />
<div class="page">
<div class="page">
<Breadcrumb style="margin-bottom: 0;" :data="crumbs" />
<div class="wrap">
<div class="side">
<div class="m-b-20">
<el-radio-group v-model="isNotJoin" @change="changeType">
@ -510,11 +510,9 @@ export default {
margin-right: 20px;
}
.page {
.wrap {
display: flex;
min-height: 100%;
margin-top: 20px;
padding: 0 24px;
.side {
width: 300px;

Loading…
Cancel
Save