|
|
|
@ -4,8 +4,8 @@ |
|
|
|
|
<p class="paper-name">{{ paperName }}</p> |
|
|
|
|
|
|
|
|
|
<div class="actions"> |
|
|
|
|
<el-button class="btn" @click="prev">上一个</el-button> |
|
|
|
|
<el-button class="btn" @click="prev">下一个</el-button> |
|
|
|
|
<el-button v-if="curIndex > 0" class="btn" @click="prev">上一个</el-button> |
|
|
|
|
<el-button v-if="recordTotal - 1 > curIndex" class="btn" @click="next">下一个</el-button> |
|
|
|
|
<el-button class="btn" @click="saveAll">一键保存分数</el-button> |
|
|
|
|
<img class="exit" src="@/assets/images/exit.svg" alt="" @click="close"> |
|
|
|
|
</div> |
|
|
|
@ -14,7 +14,7 @@ |
|
|
|
|
<div class="report" v-loading="loading"> |
|
|
|
|
<div class="left"> |
|
|
|
|
<h6 class="title">答题卡</h6> |
|
|
|
|
<ul class="review-type"> |
|
|
|
|
<ul v-if="hasManualScoreType" class="review-type"> |
|
|
|
|
<li v-for="(item, i) in reviews" :key="i" :class="{ active: curReview === item.id }" |
|
|
|
|
@click="reviewClick(item)"> |
|
|
|
|
{{ item.name }}</li> |
|
|
|
@ -85,18 +85,18 @@ |
|
|
|
|
@click="download(ques.fileName || ques.stemAttachment, ques.stemAttachment)">下载</el-button> |
|
|
|
|
</div> |
|
|
|
|
<div v-if="ques.uploadInstructions" class="line m-b-10"> |
|
|
|
|
<span>考生上传附件说明:</span> |
|
|
|
|
<span class="line-label">考生上传附件说明:</span> |
|
|
|
|
<div v-html="ques.uploadInstructions" class="html-parse"></div> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
<div v-if="ques.knowledgePointList && ques.knowledgePointList.length" class="m-b-10"> |
|
|
|
|
<span>【知识点】</span> |
|
|
|
|
<span class="line-label">【知识点】</span> |
|
|
|
|
<el-tag v-for="(kp, k) in ques.knowledgePointList" :key="k" class="m-r-5" type="info">{{ kp.name |
|
|
|
|
}}</el-tag> |
|
|
|
|
</div> |
|
|
|
|
<div class="flex m-b-10"> |
|
|
|
|
<span>【解析】</span> |
|
|
|
|
<span class="line-label">【解析】</span> |
|
|
|
|
<div |
|
|
|
|
v-if="ques.questionAnswerVersionsList.length && ques.questionAnswerVersionsList[0].answerAnalysis" |
|
|
|
|
v-html="ques.questionAnswerVersionsList[0].answerAnalysis" class="html-parse"></div> |
|
|
|
@ -139,15 +139,17 @@ |
|
|
|
|
|
|
|
|
|
<div class="line">题目分值:{{ ques.questionScore }}分</div> |
|
|
|
|
<div class="line"> |
|
|
|
|
考生得分:<el-input class="score-input" size="small" :value="ques.userScore" />分  |
|
|
|
|
考生得分:<el-input class="score-input hide-spin" type="number" placeholder="请输入分数" size="small" |
|
|
|
|
v-model.number="ques.userScore" />分  |
|
|
|
|
<el-button type="primary" size="mini" @click="saveScore(ques)">保存分数</el-button> |
|
|
|
|
<el-popover class="m-l-10" placement="bottom" width="400" trigger="click"> |
|
|
|
|
<el-input type="textarea" :rows="3" autosize placeholder="请输入" /> |
|
|
|
|
<el-input type="textarea" :rows="3" autosize resize="none" placeholder="请输入" |
|
|
|
|
v-model="ques.comments" /> |
|
|
|
|
<div class="m-t-10 text-right"> |
|
|
|
|
<el-button type="primary" size="mini" @click="saveComment(ques)">保存</el-button> |
|
|
|
|
</div> |
|
|
|
|
<div slot="reference"> |
|
|
|
|
<el-button type="primary" size="mini" @click="showComment(ques)">评语</el-button> |
|
|
|
|
<el-button type="primary" size="mini">评语</el-button> |
|
|
|
|
</div> |
|
|
|
|
</el-popover> |
|
|
|
|
</div> |
|
|
|
@ -155,7 +157,7 @@ |
|
|
|
|
评语: |
|
|
|
|
<div> |
|
|
|
|
<span>2024-12-12</span> |
|
|
|
|
<i class="el-icon-delete-solid del-comment"></i> |
|
|
|
|
<i class="el-icon-delete-solid del-comment" @click="delComment(ques)"></i> |
|
|
|
|
<div class="comment">xxx</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
@ -168,14 +170,16 @@ |
|
|
|
|
<div class="right"> |
|
|
|
|
<h6>基本信息</h6> |
|
|
|
|
<div class="lines"> |
|
|
|
|
<p>考生所在院校:xx</p> |
|
|
|
|
<p>团队名称:xx</p> |
|
|
|
|
<p>考生班级:xx</p> |
|
|
|
|
<p>考生姓名:xx</p> |
|
|
|
|
<p>考生学号:xx</p> |
|
|
|
|
<p>答卷ID:xx</p> |
|
|
|
|
<p>提交时间:xx</p> |
|
|
|
|
<p>用时:xx</p> |
|
|
|
|
<template v-if="showUserInfo"> |
|
|
|
|
<p>考生所在院校:{{ info.realSchool }}</p> |
|
|
|
|
<p>团队名称:{{ info.teamName }}</p> |
|
|
|
|
<p>考生班级:{{ info.className }}</p> |
|
|
|
|
<p>考生姓名:{{ info.userName }}</p> |
|
|
|
|
<p>考生学号:{{ info.workNumber }}</p> |
|
|
|
|
</template> |
|
|
|
|
<p>答卷ID:{{ info.reportId }}</p> |
|
|
|
|
<p>提交时间:{{ info.submitTime }}</p> |
|
|
|
|
<p>用时:{{ info.timeSum }}min</p> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
@ -203,24 +207,28 @@ export default { |
|
|
|
|
return { |
|
|
|
|
numToLetter: Util.numToLetter, |
|
|
|
|
arabicToChinese: Util.arabicToChinese, |
|
|
|
|
// reportId: this.$route.query.reportId, |
|
|
|
|
reportId: '', |
|
|
|
|
competitionId: this.$route.query.c, |
|
|
|
|
stageId: this.$route.query.s, |
|
|
|
|
showUserInfo: +this.$route.query.u, // 是否展示学生信息 |
|
|
|
|
hasManualScoreType: +this.$route.query.m, // 是否有主观题 |
|
|
|
|
curIndex: 0, |
|
|
|
|
paperName: '', |
|
|
|
|
reportId: 3791, |
|
|
|
|
outline: [], |
|
|
|
|
editing: false, |
|
|
|
|
loading: false, |
|
|
|
|
curReview: 1, |
|
|
|
|
curReview: +this.$route.query.m ? 0 : '', |
|
|
|
|
reviews: [ |
|
|
|
|
{ |
|
|
|
|
id: '', |
|
|
|
|
name: '全部' |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
id: 1, |
|
|
|
|
id: 0, |
|
|
|
|
name: '待评阅' |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
id: 2, |
|
|
|
|
id: 1, |
|
|
|
|
name: '已评阅' |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
@ -243,9 +251,11 @@ export default { |
|
|
|
|
name: '待判分' |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
outlines: [], |
|
|
|
|
info: {}, |
|
|
|
|
paper: [], |
|
|
|
|
essayExist: 0, |
|
|
|
|
records: [], |
|
|
|
|
page: 1, |
|
|
|
|
recordTotal: 0, |
|
|
|
|
previewImgVisible: false, |
|
|
|
|
previewImg: '', |
|
|
|
|
pdfVisible: false, |
|
|
|
@ -253,94 +263,123 @@ export default { |
|
|
|
|
exporting: false, |
|
|
|
|
}; |
|
|
|
|
}, |
|
|
|
|
watch: { |
|
|
|
|
$route: { |
|
|
|
|
handler () { |
|
|
|
|
this.curIndex = +this.$route.query.i |
|
|
|
|
this.reportId = this.$route.query.id |
|
|
|
|
this.getData() |
|
|
|
|
}, |
|
|
|
|
immediate: true |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
mounted () { |
|
|
|
|
this.getData() |
|
|
|
|
this.getRecords() |
|
|
|
|
}, |
|
|
|
|
methods: { |
|
|
|
|
async getData () { |
|
|
|
|
this.loading = true |
|
|
|
|
try { |
|
|
|
|
const { userAnswers: outline, report, paper } = await this.$get(`${this.api.getDetailedExamScores}?reportId=${this.reportId}`) |
|
|
|
|
this.form = report |
|
|
|
|
const { userAnswers: outline, report } = await this.$get(`${this.api.reviewTheDetailsReport}?reportId=${this.reportId}&status=${this.curReview}`) |
|
|
|
|
this.info = report |
|
|
|
|
|
|
|
|
|
// 处理试题信息 |
|
|
|
|
const { questionTypes: types, difficults } = QuesConst |
|
|
|
|
const { numToLetter } = Util |
|
|
|
|
const paper = [] |
|
|
|
|
outline.map(e => { |
|
|
|
|
e.shrink = false |
|
|
|
|
const type = e.questionType |
|
|
|
|
e.questionTypeName = types.find(n => n.id === type).name |
|
|
|
|
e.userAnswerList && e.userAnswerList.map(n => { |
|
|
|
|
if (n.difficulty) { |
|
|
|
|
const curDiff = difficults.find(m => m.id === n.difficulty) |
|
|
|
|
if (curDiff) { |
|
|
|
|
n.difficult = curDiff.name |
|
|
|
|
n.difficultTheme = curDiff.theme |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const opts = n.questionAnswerVersionsList |
|
|
|
|
if (type !== 'fill_blank' && type !== 'essay') { // 选择题 |
|
|
|
|
if (!n.userScore) n.userScore = 0 |
|
|
|
|
n.isCorrect = n.userScore && n.userScore === n.questionScore ? 1 : 2 |
|
|
|
|
|
|
|
|
|
// 用户选择结果 |
|
|
|
|
let { userAnswer } = n |
|
|
|
|
if (userAnswer) { |
|
|
|
|
userAnswer = JSON.parse(userAnswer) |
|
|
|
|
n.userAnswerStr = userAnswer.length ? (type === 'judgement' ? opts[+userAnswer[0] - 1].optionText : userAnswer.map(m => numToLetter(+m - 1)).join('')) : '未作答' |
|
|
|
|
} else { |
|
|
|
|
userAnswer = [] |
|
|
|
|
if (e.userAnswerList && e.userAnswerList.length) { |
|
|
|
|
e.shrink = false |
|
|
|
|
const type = e.questionType |
|
|
|
|
e.questionTypeName = types.find(n => n.id === type).name |
|
|
|
|
e.userAnswerList.map(n => { |
|
|
|
|
if (n.difficulty) { |
|
|
|
|
const curDiff = difficults.find(m => m.id === n.difficulty) |
|
|
|
|
if (curDiff) { |
|
|
|
|
n.difficult = curDiff.name |
|
|
|
|
n.difficultTheme = curDiff.theme |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!n.comments) n.comments = '' |
|
|
|
|
|
|
|
|
|
const opts = n.questionAnswerVersionsList |
|
|
|
|
if (type !== 'fill_blank' && type !== 'essay') { // 选择题 |
|
|
|
|
if (!n.userScore) n.userScore = 0 |
|
|
|
|
n.isCorrect = n.userScore && n.userScore === n.questionScore ? 1 : 2 |
|
|
|
|
|
|
|
|
|
// 用户选择结果 |
|
|
|
|
let { userAnswer } = n |
|
|
|
|
if (userAnswer) { |
|
|
|
|
userAnswer = JSON.parse(userAnswer) |
|
|
|
|
n.userAnswerStr = userAnswer.length ? (type === 'judgement' ? opts[+userAnswer[0] - 1].optionText : userAnswer.map(m => numToLetter(+m - 1)).join('')) : '未作答' |
|
|
|
|
} else { |
|
|
|
|
userAnswer = [] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const quesAnswer = [] |
|
|
|
|
opts && opts.map((m, j) => { |
|
|
|
|
const selected = userAnswer.includes(m.optionNumber) |
|
|
|
|
m.optCorrect = m.answerIsCorrect ? 1 : (selected ? 0 : -1) // 用户选择的结果跟正确答案是否匹配(1正确,0错误,-1未选择) |
|
|
|
|
m.answerIsCorrect && quesAnswer.push(type === 'judgement' ? m.optionText : numToLetter(j)) |
|
|
|
|
}) |
|
|
|
|
n.quesAnswer = quesAnswer.join('') |
|
|
|
|
|
|
|
|
|
} else if (type === 'fill_blank') { // 填空题 |
|
|
|
|
// 学生做的填空题答案及分数 |
|
|
|
|
let { jsonText } = n |
|
|
|
|
if (jsonText) { |
|
|
|
|
n.userAnswerFill = JSON.parse(jsonText) |
|
|
|
|
} |
|
|
|
|
const quesAnswer = [] |
|
|
|
|
opts && opts.map((m, j) => { |
|
|
|
|
const selected = userAnswer.includes(m.optionNumber) |
|
|
|
|
m.optCorrect = m.answerIsCorrect ? 1 : (selected ? 0 : -1) // 用户选择的结果跟正确答案是否匹配(1正确,0错误,-1未选择) |
|
|
|
|
m.answerIsCorrect && quesAnswer.push(type === 'judgement' ? m.optionText : numToLetter(j)) |
|
|
|
|
}) |
|
|
|
|
n.quesAnswer = quesAnswer.join('') |
|
|
|
|
|
|
|
|
|
} else if (type === 'fill_blank') { // 填空题 |
|
|
|
|
// 学生做的填空题答案及分数 |
|
|
|
|
let { jsonText } = n |
|
|
|
|
if (jsonText) { |
|
|
|
|
n.userAnswerFill = JSON.parse(jsonText) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 正确答案 |
|
|
|
|
if (opts && opts.length) { |
|
|
|
|
let { answerData } = opts[0] |
|
|
|
|
if (answerData) { |
|
|
|
|
answerData = JSON.parse(answerData) |
|
|
|
|
let quesAnswer = '' |
|
|
|
|
answerData.map((m, j) => { |
|
|
|
|
if (m.fills) { |
|
|
|
|
quesAnswer += `填空${j + 1}:${m.fills.map(n => n.val).join(' ||| ')};` |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
n.quesAnswer = quesAnswer |
|
|
|
|
// 正确答案 |
|
|
|
|
if (opts && opts.length) { |
|
|
|
|
let { answerData } = opts[0] |
|
|
|
|
if (answerData) { |
|
|
|
|
answerData = JSON.parse(answerData) |
|
|
|
|
let quesAnswer = '' |
|
|
|
|
answerData.map((m, j) => { |
|
|
|
|
if (m.fills) { |
|
|
|
|
quesAnswer += `填空${j + 1}:${m.fills.map(n => n.val).join(' ||| ')};` |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
n.quesAnswer = quesAnswer |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!n.userScore) n.userScore = 0 |
|
|
|
|
// 填空题需要区分部分正确还是正确、错误 |
|
|
|
|
let rightLen = 0 |
|
|
|
|
if (n.userAnswerFill) rightLen = n.userAnswerFill.filter(m => m.correct).length // 正确的空的数量 |
|
|
|
|
n.isCorrect = n.userScore && n.questionScore === n.userScore ? 1 : (rightLen ? 3 : 2) |
|
|
|
|
} else if (type === 'essay') { // 简答题 |
|
|
|
|
n.isCorrect = 4 // 简答题显示待判分 |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
if (!n.userScore) n.userScore = 0 |
|
|
|
|
// 填空题需要区分部分正确还是正确、错误 |
|
|
|
|
let rightLen = 0 |
|
|
|
|
if (n.userAnswerFill) rightLen = n.userAnswerFill.filter(m => m.correct).length // 正确的空的数量 |
|
|
|
|
n.isCorrect = n.userScore && n.questionScore === n.userScore ? 1 : (rightLen ? 3 : 2) |
|
|
|
|
} else if (type === 'essay') { // 简答题 |
|
|
|
|
if (!n.userScore) n.userScore = '' |
|
|
|
|
n.isCorrect = 4 // 简答题显示待判分 |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
paper.push(e) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.paper = outline |
|
|
|
|
this.paper = paper |
|
|
|
|
|
|
|
|
|
this.loading = false |
|
|
|
|
} catch (e) { |
|
|
|
|
this.loading = false |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 查询批阅记录列表,用以上一页下一页切换 |
|
|
|
|
async getRecords () { |
|
|
|
|
this.page = Math.ceil(this.curIndex / 10) || 1 |
|
|
|
|
const { page } = await this.$post(this.api.myReviewTaskByReviewList, { |
|
|
|
|
pageNum: this.page, |
|
|
|
|
pageSize: 10, |
|
|
|
|
competitionId: this.competitionId, |
|
|
|
|
stageId: this.stageId, |
|
|
|
|
}) |
|
|
|
|
const list = page.records |
|
|
|
|
this.records = list |
|
|
|
|
this.recordTotal = page.total |
|
|
|
|
}, |
|
|
|
|
scrollToSmooth (position, duration) { |
|
|
|
|
let startTime = Date.now() |
|
|
|
|
|
|
|
|
@ -367,6 +406,7 @@ export default { |
|
|
|
|
// 左侧评阅切换 |
|
|
|
|
reviewClick (item) { |
|
|
|
|
this.curReview = item.id |
|
|
|
|
this.getData() |
|
|
|
|
}, |
|
|
|
|
// 答题卡筛选 |
|
|
|
|
filterStatus (e) { |
|
|
|
@ -390,16 +430,28 @@ export default { |
|
|
|
|
Util.downloadFile(name, url) |
|
|
|
|
}, |
|
|
|
|
// 保存分数 |
|
|
|
|
saveScore (ques) { |
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
// 展示评语弹框 |
|
|
|
|
showComment (ques) { |
|
|
|
|
|
|
|
|
|
async saveScore (ques) { |
|
|
|
|
await this.$post(this.api.reviewPaper, [{ |
|
|
|
|
assignmentDetailId: ques.assignmentDetailId, |
|
|
|
|
score: ques.userScore, |
|
|
|
|
}]) |
|
|
|
|
Util.successMsg('保存成功') |
|
|
|
|
}, |
|
|
|
|
// 保存评语 |
|
|
|
|
saveComment (ques) { |
|
|
|
|
|
|
|
|
|
async saveComment (ques) { |
|
|
|
|
await this.$post(this.api.setComments, { |
|
|
|
|
assignmentDetailId: ques.assignmentDetailId, |
|
|
|
|
comments: ques.comments, |
|
|
|
|
}) |
|
|
|
|
Util.successMsg('保存成功') |
|
|
|
|
}, |
|
|
|
|
// 删除评语 |
|
|
|
|
async delComment (ques) { |
|
|
|
|
await this.$post(this.api.reviewPaper, { |
|
|
|
|
assignmentDetailId: ques.assignmentDetailId, |
|
|
|
|
score: ques.userScore, |
|
|
|
|
}) |
|
|
|
|
Util.successMsg('删除成功') |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 上一个 |
|
|
|
@ -417,29 +469,31 @@ export default { |
|
|
|
|
}, |
|
|
|
|
// 下一个 |
|
|
|
|
async next () { |
|
|
|
|
this.exporting = true |
|
|
|
|
const res = await axios.get(`${this.api.exportExamPaperReport}?reportId=${this.reportId}`, { |
|
|
|
|
headers: { |
|
|
|
|
token: this.token |
|
|
|
|
}, |
|
|
|
|
responseType: 'blob' |
|
|
|
|
}) |
|
|
|
|
const name = res.headers['content-disposition'] |
|
|
|
|
Util.downloadFileDirect(name ? decodeURI(name) : '标准成绩报告.docx', new Blob([res.data])) |
|
|
|
|
this.exporting = false |
|
|
|
|
const i = this.curIndex + 1 |
|
|
|
|
const newPage = Math.ceil(i / 10) || 1 |
|
|
|
|
// debugger |
|
|
|
|
if (newPage > this.page) { |
|
|
|
|
await this.getRecords() |
|
|
|
|
} |
|
|
|
|
if (this.records[i % 10 - 1]) { |
|
|
|
|
let reportId = this.records[i % 10 - 1].reportId |
|
|
|
|
this.$router.push(`/theoryReview?id=${reportId}&u=${this.showUserInfo}&c=${this.competitionId}&s=${this.stageId}&i=${i}`) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 一键保存分数 |
|
|
|
|
async saveAll () { |
|
|
|
|
this.exporting = true |
|
|
|
|
const res = await axios.get(`${this.api.exportExamPaperReport}?reportId=${this.reportId}`, { |
|
|
|
|
headers: { |
|
|
|
|
token: this.token |
|
|
|
|
}, |
|
|
|
|
responseType: 'blob' |
|
|
|
|
const { paper } = this |
|
|
|
|
const params = [] |
|
|
|
|
paper.forEach(e => { |
|
|
|
|
e.userAnswerList.forEach(n => { |
|
|
|
|
n.userScore !== '' && params.push({ |
|
|
|
|
assignmentDetailId: n.assignmentDetailId, |
|
|
|
|
score: n.userScore, |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
const name = res.headers['content-disposition'] |
|
|
|
|
Util.downloadFileDirect(name ? decodeURI(name) : '标准成绩报告.docx', new Blob([res.data])) |
|
|
|
|
this.exporting = false |
|
|
|
|
await this.$post(this.api.reviewPaper, params) |
|
|
|
|
Util.successMsg('保存成功') |
|
|
|
|
}, |
|
|
|
|
close () { |
|
|
|
|
window.close() |
|
|
|
@ -527,10 +581,14 @@ export default { |
|
|
|
|
background-color: $main-color; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&+.type-wrap { |
|
|
|
|
height: calc(100vh - 185px); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.type-wrap { |
|
|
|
|
height: calc(100vh - 185px); |
|
|
|
|
height: calc(100vh - 137px); |
|
|
|
|
padding: 10px 0; |
|
|
|
|
overflow: auto; |
|
|
|
|
|
|
|
|
|