|
|
|
@ -2,27 +2,28 @@ |
|
|
|
|
<div class="index"> |
|
|
|
|
<div class="top"> |
|
|
|
|
<div class="item"> |
|
|
|
|
<p class="names">{{ curStage.stageName }}:{{ curStage.paperName }}</p> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="count"> |
|
|
|
|
<div class="count m-l-30"> |
|
|
|
|
阶段剩余时间 |
|
|
|
|
<span>{{ day }}</span>天 |
|
|
|
|
<span>{{ hour }}</span>小时 |
|
|
|
|
<span>{{ minutes }}</span>分 |
|
|
|
|
<span>{{ seconds }}</span>秒 |
|
|
|
|
<span>{{ counterVal.day }}</span>天 |
|
|
|
|
<span>{{ counterVal.hour }}</span>小时 |
|
|
|
|
<span>{{ counterVal.minutes }}</span>分 |
|
|
|
|
<span>{{ counterVal.seconds }}</span>秒 |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="item"> |
|
|
|
|
<div class="count m-r-30"> |
|
|
|
|
用时 |
|
|
|
|
<span>{{ day }}</span>天 |
|
|
|
|
<span>{{ hour }}</span>小时 |
|
|
|
|
<span>{{ minutes }}</span>分 |
|
|
|
|
<span>{{ seconds }}</span>秒 |
|
|
|
|
<span>{{ timeSum.day }}</span>天 |
|
|
|
|
<span>{{ timeSum.hour }}</span>小时 |
|
|
|
|
<span>{{ timeSum.minutes }}</span>分 |
|
|
|
|
<span>{{ timeSum.seconds }}</span>秒 |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<el-button class="submit" @click="submit">提交</el-button> |
|
|
|
|
<el-button class="submit" :loading="submiting" @click="confirmSubmit">提交</el-button> |
|
|
|
|
<img class="exit" src="@/assets/img/exit.svg" alt="" @click="$router.back()"> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
@ -39,15 +40,23 @@ |
|
|
|
|
<h6 class="stem">{{ arabicToChinese(i + 1) }}、{{ item.questionTypeName }}(本题共{{ item.questionNum }}小题,共{{ |
|
|
|
|
item.targetScore }}分)</h6> |
|
|
|
|
<ul class="serials"> |
|
|
|
|
<li v-for="(ques, j) in item.examQuestions" :key="j">{{ j + 1 }}</li> |
|
|
|
|
<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 }"> |
|
|
|
|
<img v-if="ques.sign" class="tag" src="@/assets/img/tag-active.svg" alt=""> |
|
|
|
|
{{ j + 1 }} |
|
|
|
|
</li> |
|
|
|
|
</template> |
|
|
|
|
</ul> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
<ul class="status-filter"> |
|
|
|
|
<li>未作答</li> |
|
|
|
|
<li>已作答</li> |
|
|
|
|
<li>部分已作答</li> |
|
|
|
|
<li>已标记</li> |
|
|
|
|
<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/img/tag-active.svg" alt=""> 已标记</li> |
|
|
|
|
</ul> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
@ -64,18 +73,20 @@ |
|
|
|
|
<div class="stem-wrap"> |
|
|
|
|
<span class="label">{{ j + 1 }} / {{ item.questionNum }}</span> |
|
|
|
|
<span class="label">{{ item.questionTypeName }}</span> |
|
|
|
|
<div :id="'stem' + ques.questionVersionId" v-html="getQuesStem(ques)"></div> |
|
|
|
|
<div :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/img/' + (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="item.answerIsCorrect" |
|
|
|
|
:true-label="1"></el-checkbox> |
|
|
|
|
<el-radio v-else v-model="item.answerIsCorrect" :true-label="1" :label="1" |
|
|
|
|
@change="correctChange(i)"></el-radio> |
|
|
|
|
<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) }}. </span> |
|
|
|
|
<div class="text" v-html="opt.optionText"></div> |
|
|
|
@ -87,17 +98,25 @@ |
|
|
|
|
<el-link class="m-r-10" type="primary">{{ ques.stemAttachment }}</el-link> |
|
|
|
|
<el-button type="primary" size="mini" round @click="download(ques.stemAttachment)">下载</el-button> |
|
|
|
|
</div> |
|
|
|
|
<UeditorPlus ref="answerAnalysis" @ready="answerAnalysisReady" v-model="form.answerAnalysis" /> |
|
|
|
|
<Upload v-if="ques.allowAttachment" class="m-t-20" |
|
|
|
|
accept=".csv,.xlsx,.xls,.docx,.doc,.pdf,.jpg,.png,.zip,.rar,.7z" :max-size="50" |
|
|
|
|
:file-list="uploadList" :on-remove="handleRemove" @onSuccess="uploadSuccess"> |
|
|
|
|
<div slot="trigger"> |
|
|
|
|
<el-button type="primary">上传附件</el-button> |
|
|
|
|
<UeditorPlus :ref="'essayAnswer' + ques.id" v-model="ques.answer" |
|
|
|
|
@ready="editor => essayAnswerReady(editor, ques)" /> |
|
|
|
|
<!-- v-if="ques.allowAttachment" --> |
|
|
|
|
<div class="m-t-20"> |
|
|
|
|
<div v-if="form.uploadInstructions" class="flex m-b-10 fs-12"> |
|
|
|
|
<span>上传附件:</span> |
|
|
|
|
<div v-html="form.uploadInstructions"></div> |
|
|
|
|
</div> |
|
|
|
|
<template slot="tip"> |
|
|
|
|
<p>上传说明内容,支持.csv;.xlsx; .docx; .pdf; .jpg; .zip 等常见文件格式;上传文件大小不能超过50MB</p> |
|
|
|
|
</template> |
|
|
|
|
</Upload> |
|
|
|
|
<Upload style="max-width: 700px;" accept=".csv,.xlsx,.xls,.docx,.doc,.pdf,.jpg,.png,.zip,.rar,.7z" |
|
|
|
|
:max-size="50" :file-list="ques.uploadList" :on-remove="e => handleRemove(ques)" |
|
|
|
|
@onSuccess="e => uploadSuccess(e, ques)"> |
|
|
|
|
<div slot="trigger"> |
|
|
|
|
<el-button type="primary" plain>上传文件</el-button> |
|
|
|
|
</div> |
|
|
|
|
<template slot="tip"> |
|
|
|
|
<p></p> |
|
|
|
|
</template> |
|
|
|
|
</Upload> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
@ -112,9 +131,11 @@ 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' |
|
|
|
|
|
|
|
|
|
export default { |
|
|
|
|
components: { |
|
|
|
|
Upload, UeditorPlus |
|
|
|
@ -122,6 +143,7 @@ export default { |
|
|
|
|
data () { |
|
|
|
|
return { |
|
|
|
|
routes: [], |
|
|
|
|
per: 2, // 项目权限(0、练习 1、考核 2、竞赛) |
|
|
|
|
questionTypes: QuesConst.questionTypes, |
|
|
|
|
numToLetter: Util.numToLetter, |
|
|
|
|
arabicToChinese: Util.arabicToChinese, |
|
|
|
@ -129,59 +151,228 @@ export default { |
|
|
|
|
token: Util.local.get(Setting.tokenKey) |
|
|
|
|
}, |
|
|
|
|
token: Util.local.get(Setting.tokenKey), |
|
|
|
|
// id: +this.$route.query.id, |
|
|
|
|
id: 43, |
|
|
|
|
id: +this.$route.query.id, // 赛事id |
|
|
|
|
stageId: +this.$route.query.stageId, |
|
|
|
|
entryTime: '', |
|
|
|
|
curStage: { |
|
|
|
|
stageName: '', |
|
|
|
|
paperName: '', |
|
|
|
|
}, |
|
|
|
|
counterTimer: null, // 获取setInterval对象值 |
|
|
|
|
day: 0, // 天数 |
|
|
|
|
seconds: 0, // 秒数 |
|
|
|
|
minutes: 0, // 分钟数 |
|
|
|
|
hour: 0, // 小时数 |
|
|
|
|
countVal: 0, |
|
|
|
|
// 倒计时 |
|
|
|
|
counterVal: { |
|
|
|
|
day: 0, |
|
|
|
|
seconds: 0, |
|
|
|
|
minutes: 0, |
|
|
|
|
hour: 0, |
|
|
|
|
}, |
|
|
|
|
timeSumVal: 0, |
|
|
|
|
// 用时 |
|
|
|
|
timeSum: { |
|
|
|
|
day: 0, |
|
|
|
|
seconds: 0, |
|
|
|
|
minutes: 0, |
|
|
|
|
hour: 0, |
|
|
|
|
}, |
|
|
|
|
sheetStatus: '', |
|
|
|
|
form: {}, |
|
|
|
|
uploadList: [], |
|
|
|
|
submiting: false, |
|
|
|
|
warned: 0, |
|
|
|
|
}; |
|
|
|
|
}, |
|
|
|
|
mounted () { |
|
|
|
|
this.$once('hook:beforeDestroy', function () { |
|
|
|
|
clearInterval(this.timer) |
|
|
|
|
this.timerList.forEach(n => { |
|
|
|
|
clearTimeout(n) |
|
|
|
|
}) |
|
|
|
|
this.timerList = [] |
|
|
|
|
clearInterval(this.counterTimer) |
|
|
|
|
this.submiting || this.submit(0) |
|
|
|
|
}) |
|
|
|
|
this.getDetail() |
|
|
|
|
|
|
|
|
|
// this.initOss() |
|
|
|
|
this.getCompetition() |
|
|
|
|
}, |
|
|
|
|
methods: { |
|
|
|
|
// 获取竞赛信息 |
|
|
|
|
async getCompetition () { |
|
|
|
|
// clearInterval(this.timer) |
|
|
|
|
const { competition } = await this.$post(`${this.api.getCompetition}?competitionId=${this.id}`) |
|
|
|
|
const stages = competition.contentList |
|
|
|
|
if (stages) { |
|
|
|
|
const stage = stages.find(e => e.stageId === this.stageId) |
|
|
|
|
const item = competition.competitionStage.find(e => e.stageId === this.stageId) |
|
|
|
|
if (item) { |
|
|
|
|
stage.stageName = item.stageName |
|
|
|
|
stage.resultAnnouncementTime = item.resultAnnouncementTime |
|
|
|
|
} |
|
|
|
|
this.curStage = stage |
|
|
|
|
const endTime = new Date(stage.endTime) |
|
|
|
|
const now = await Util.getNow() |
|
|
|
|
// 如果已经结束 |
|
|
|
|
if (now >= endTime) { |
|
|
|
|
this.$alert('竞赛时间已到,系统已自动交卷', '提示', { |
|
|
|
|
confirmButtonText: '确定' |
|
|
|
|
}) |
|
|
|
|
this.submit(1) |
|
|
|
|
} else { // 没结束,则显示倒计时 |
|
|
|
|
this.countVal = (endTime - now) / 1000 |
|
|
|
|
this.getPaper(now) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 获取试卷详情 |
|
|
|
|
async getDetail () { |
|
|
|
|
async getPaper (now) { |
|
|
|
|
try { |
|
|
|
|
const { id } = this |
|
|
|
|
if (id) { |
|
|
|
|
const res = await this.$get(this.api.examPaperDetails, { |
|
|
|
|
id |
|
|
|
|
const { paperId, stageId } = this.curStage |
|
|
|
|
if (paperId) { |
|
|
|
|
// 试卷详情 |
|
|
|
|
const { examPaper } = await this.$get(this.api.examPaperDetails, { id: paperId }) |
|
|
|
|
|
|
|
|
|
// 缓存,如果有,则全部回显到页面上 |
|
|
|
|
const res = await this.$post(this.api.getExamPaperCache, { |
|
|
|
|
competitionId: this.id, |
|
|
|
|
paperId, |
|
|
|
|
stageId |
|
|
|
|
}) |
|
|
|
|
const r = res.examPaper |
|
|
|
|
const cache = res.examSubmitReq |
|
|
|
|
let cacheQues = [] |
|
|
|
|
if (cache) { |
|
|
|
|
this.entryTime = new Date(cache.startTime) |
|
|
|
|
this.timeSumVal = (now - new Date(cache.startTime)) / 1000 |
|
|
|
|
cacheQues = cache.examSubmitJudgeList |
|
|
|
|
} else { |
|
|
|
|
this.entryTime = now |
|
|
|
|
} |
|
|
|
|
this.startCount() |
|
|
|
|
|
|
|
|
|
const r = examPaper |
|
|
|
|
const paper = r.paperOutline |
|
|
|
|
const types = this.questionTypes |
|
|
|
|
paper.map(e => { |
|
|
|
|
e.questionTypeName = types.find(n => n.id === e.questionType).name |
|
|
|
|
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) |
|
|
|
|
const curQues = cacheQues.find(m => m.outlineId === e.outlineId && m.questionVersionId === n.questionVersionId) // 缓存里的试题 |
|
|
|
|
n.sign = curQues ? curQues.sign : 0 |
|
|
|
|
|
|
|
|
|
if (type !== 'fill_blank' && type !== 'essay' && n.questionAnswerVersionsList) { // 选择题 |
|
|
|
|
n.questionAnswerVersionsList.map(m => { |
|
|
|
|
m.answer = curQues && curQues.answer && curQues.answer.length && curQues.answer.some(n => n == m.optionNumber) ? 1 : 0 |
|
|
|
|
}) |
|
|
|
|
if (n.questionAnswerVersionsList.some(m => m.answer)) n.answered = 1 |
|
|
|
|
} else if (type === 'fill_blank') { // 填空题 |
|
|
|
|
n.fills = curQues && curQues.answer && curQues.answer.length ? curQues.answer : '' |
|
|
|
|
if (n.fills) n.answered = 1 |
|
|
|
|
} else { // 简答题 |
|
|
|
|
n.answer = type === 'essay' && curQues ? curQues.answerContent : '' |
|
|
|
|
n.attachmentName = curQues ? curQues.attachmentName : '' |
|
|
|
|
n.attachmentUrl = curQues ? curQues.attachmentUrl : '' |
|
|
|
|
// 附件 |
|
|
|
|
const url = n.attachmentUrl |
|
|
|
|
if (url) { |
|
|
|
|
n.uploadList = [{ |
|
|
|
|
name: n.attachmentName || url, |
|
|
|
|
url |
|
|
|
|
}] |
|
|
|
|
} |
|
|
|
|
if (n.answer || url) n.answered = 1 |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
}) |
|
|
|
|
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 |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
console.log("🚀 ~ getPaper ~ r:", r) |
|
|
|
|
} |
|
|
|
|
} 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 |
|
|
|
|
}, |
|
|
|
|
// 计时前的判断 |
|
|
|
|
counter (counterTime) { |
|
|
|
|
if (counterTime <= 0) { |
|
|
|
|
if (this.per) { // 竞赛/考核 |
|
|
|
|
clearInterval(this.counterTimer) |
|
|
|
|
this.$alert(`${this.per == 2 ? '竞赛' : '考核'}时间已到,系统已自动交卷`, '提示', { |
|
|
|
|
confirmButtonText: '确定', |
|
|
|
|
type: 'warning' |
|
|
|
|
}) |
|
|
|
|
this.submit(1) |
|
|
|
|
} else { |
|
|
|
|
this.handleCounter(counterTime, 1) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// 剩15分钟时要提示 |
|
|
|
|
if (counterTime <= 900) { |
|
|
|
|
this.warned || this.$alert(`请注意,${this.per == 2 ? '比赛' : '考核'}还剩15分钟,请尽快完成答题并提交试卷。`, '提示', { |
|
|
|
|
confirmButtonText: '确定', |
|
|
|
|
type: 'warning' |
|
|
|
|
}) |
|
|
|
|
this.warned = 1 |
|
|
|
|
} |
|
|
|
|
this.handleCounter(counterTime, 1) |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 启动倒计时 |
|
|
|
|
startCount () { |
|
|
|
|
clearInterval(this.counterTimer) |
|
|
|
|
this.counterTimer = setInterval(() => { |
|
|
|
|
this.counter(this.per ? this.countVal-- : this.countVal++) |
|
|
|
|
this.timeSumVal >= 0 && this.handleCounter(this.timeSumVal++) |
|
|
|
|
}, 1000) |
|
|
|
|
}, |
|
|
|
|
timeFormat (param) { |
|
|
|
|
return param < 10 ? '0' + param : param |
|
|
|
|
}, |
|
|
|
|
// 答题卡筛选 |
|
|
|
|
filterStatus (e) { |
|
|
|
|
this.sheetStatus = this.sheetStatus === e ? '' : e |
|
|
|
|
}, |
|
|
|
|
// 处理题干显示 |
|
|
|
|
getQuesStem (ques) { |
|
|
|
|
let { stem } = ques |
|
|
|
|
if (ques.questionType === 'fill_blank') { // 填空题 |
|
|
|
|
let { jsonText } = ques |
|
|
|
|
if (jsonText) jsonText = JSON.parse(jsonText) |
|
|
|
|
let { fills } = ques |
|
|
|
|
|
|
|
|
|
const regex = /<span class="gapfilling-span" data-id="(.*?)">______<\/span>/g |
|
|
|
|
let match |
|
|
|
@ -189,7 +380,7 @@ export default { |
|
|
|
|
let result = stem |
|
|
|
|
|
|
|
|
|
while ((match = regex.exec(stem)) !== null) { |
|
|
|
|
const newInput = `<input type="text" class="fill-input">` |
|
|
|
|
const newInput = `<input type="text" class="fill-input" value="${fills && fills.length ? fills[index] : ''}">` |
|
|
|
|
result = result.replace(match[0], newInput) |
|
|
|
|
index++ |
|
|
|
|
} |
|
|
|
@ -198,34 +389,147 @@ export default { |
|
|
|
|
return stem |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
// 单选题回调 |
|
|
|
|
singleChange (ques, j) { |
|
|
|
|
ques.questionAnswerVersionsList.map(e => { |
|
|
|
|
e.answer = 0 |
|
|
|
|
}) |
|
|
|
|
ques.questionAnswerVersionsList[j].answer = 1 |
|
|
|
|
|
|
|
|
|
ques.answered = 1 |
|
|
|
|
}, |
|
|
|
|
// 多选题回调 |
|
|
|
|
mulChange (ques) { |
|
|
|
|
ques.answered = ques.questionAnswerVersionsList.some(e => e.answer) |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 简答题富文本加载完毕回调 |
|
|
|
|
essayAnswerReady (editor, ques) { |
|
|
|
|
editor.ques = ques |
|
|
|
|
editor.addListener('contentChange', () => { |
|
|
|
|
ques.answered = editor.getContent() ? 1 : 0 |
|
|
|
|
}) |
|
|
|
|
ques.answer && editor.setContent(ques.answer) |
|
|
|
|
}, |
|
|
|
|
// 下载附件 |
|
|
|
|
download (url) { |
|
|
|
|
Util.downloadFile(url, url) |
|
|
|
|
}, |
|
|
|
|
handleRemove () { |
|
|
|
|
Oss.del(this.form.stemAttachment) |
|
|
|
|
this.form.stemAttachment = '' |
|
|
|
|
handleRemove (ques) { |
|
|
|
|
Oss.del(ques.attachmentUrl) |
|
|
|
|
ques.attachmentName = '' |
|
|
|
|
ques.attachmentUrl = '' |
|
|
|
|
}, |
|
|
|
|
uploadSuccess (file) { |
|
|
|
|
this.form.stemAttachment = file.url |
|
|
|
|
uploadSuccess (file, ques) { |
|
|
|
|
ques.attachmentName = file.name |
|
|
|
|
ques.attachmentUrl = file.url |
|
|
|
|
}, |
|
|
|
|
// 解析富文本加载完毕回调 |
|
|
|
|
answerAnalysisReady (editor) { |
|
|
|
|
this.answerAnalysis && editor.setContent(this.answerAnalysis) |
|
|
|
|
}, |
|
|
|
|
// 提交 |
|
|
|
|
async submit () { |
|
|
|
|
// 提交询问 |
|
|
|
|
async confirmSubmit () { |
|
|
|
|
if (this.submiting) return false |
|
|
|
|
let msg = '此操作将视为结束答题,确认要提交吗?' |
|
|
|
|
// if (!isVscode) msg = '实验报告未填写,实验成绩为零,是否确认提交?' |
|
|
|
|
|
|
|
|
|
for (const e of this.form.paperOutline) { |
|
|
|
|
if (e.examQuestions.some(n => !n.answered)) { |
|
|
|
|
msg = '还有试题未答完,确认要提交吗?' |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
try { |
|
|
|
|
await this.$confirm(msg, '提示', { |
|
|
|
|
confirmButtonText: '确定', |
|
|
|
|
cancelButtonText: '取消', |
|
|
|
|
// confirmButtonText: '确定', |
|
|
|
|
// cancelButtonText: '取消', |
|
|
|
|
type: 'warning', |
|
|
|
|
closeOnClickModal: false |
|
|
|
|
}) |
|
|
|
|
this.submit(1) |
|
|
|
|
} catch (e) { } |
|
|
|
|
}, |
|
|
|
|
// 提交 |
|
|
|
|
async submit (isSubmit) { |
|
|
|
|
if (this.submiting) return false |
|
|
|
|
try { |
|
|
|
|
this.submiting = true |
|
|
|
|
const form = _.cloneDeep(this.form) |
|
|
|
|
const now = await Util.getNow() |
|
|
|
|
const { entryTime, curStage } = this |
|
|
|
|
const ques = [] |
|
|
|
|
form.paperOutline.map(e => { |
|
|
|
|
const type = e.questionType |
|
|
|
|
e.examQuestions.map(n => { |
|
|
|
|
let answer = [] |
|
|
|
|
let answerContent = '' |
|
|
|
|
if (type !== 'fill_blank' && type !== 'essay') { // 选择题 |
|
|
|
|
answer = n.questionAnswerVersionsList.filter(m => m.answer).map(m => m.optionNumber) |
|
|
|
|
} else if (type === 'essay') { // 简答题 |
|
|
|
|
const editor = this.$refs['essayAnswer' + n.id] |
|
|
|
|
// console.log("🚀 ~ submit ~ editor:", n.id, editor, this.$refs) |
|
|
|
|
if (editor && editor.length) answerContent = editor[0].getUEContent() |
|
|
|
|
} else { // 填空题 |
|
|
|
|
const stem = document.querySelector(`#stem` + n.id) |
|
|
|
|
if (stem) { |
|
|
|
|
const inputs = stem.querySelectorAll('.fill-input') |
|
|
|
|
console.log("🚀 ~ submit ~ editor333:", stem, inputs) |
|
|
|
|
if (inputs) { |
|
|
|
|
for (const e of inputs) { |
|
|
|
|
answer.push(e.value) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ques.push({ |
|
|
|
|
answer, |
|
|
|
|
answerContent, |
|
|
|
|
attachmentName: n.attachmentName, |
|
|
|
|
attachmentUrl: n.attachmentUrl, |
|
|
|
|
outlineId: e.outlineId, |
|
|
|
|
questionType: type, |
|
|
|
|
questionVersionId: n.questionVersionId, |
|
|
|
|
serialNumber: n.serialNumber, |
|
|
|
|
setScore: n.score, |
|
|
|
|
sign: n.sign, |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
const timeSum = Math.ceil((now - entryTime) / 60000) // 计算实验用时(分钟),向上取整 |
|
|
|
|
const submitTime = Util.formatDate('yyyy-MM-dd hh:mm:ss', now) |
|
|
|
|
// debugger |
|
|
|
|
// 缓存跟提交接口的参数一样 |
|
|
|
|
const res = await this.$post(this.api[isSubmit ? 'submitTheExamPaper' : 'examPaperRecordCache'], { |
|
|
|
|
competitionId: this.id, |
|
|
|
|
stageId: curStage.stageId, |
|
|
|
|
startTime: Util.formatDate('yyyy-MM-dd hh:mm:ss', entryTime), // 取页面进入的时间 |
|
|
|
|
endTime: this.per ? curStage.endTime : submitTime, // 结束时间(考核:直接从职站取考核的结束时间;练习:取提交时间) |
|
|
|
|
submitTime, // 提交时间,即当前时间(这3个时间都是传完整的日期时间格式) |
|
|
|
|
timeSum, |
|
|
|
|
totalScore: form.score, |
|
|
|
|
paperId: curStage.paperId, |
|
|
|
|
examSubmitJudgeList: ques, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 如果是竞赛,并且勾选了公布成绩详情的选项,则弹框提示 |
|
|
|
|
if (this.id) { |
|
|
|
|
const time = curStage.resultAnnouncementTime |
|
|
|
|
const msg = |
|
|
|
|
time === '0' ? '提交成功!成绩将在比赛结束后公布,请前往参赛信息模块查看' : time > 0 ? `提交成功!成绩将在比赛结束后${time}小时公布,请前往参赛信息模块查看` : '提交成功'; |
|
|
|
|
this.$alert(msg, '提示', { |
|
|
|
|
confirmButtonText: '确定', |
|
|
|
|
type: 'success', |
|
|
|
|
callback: () => { |
|
|
|
|
this.$router.back() |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
this.$message.success('提交成功!') |
|
|
|
|
} |
|
|
|
|
} catch (e) { |
|
|
|
|
this.submiting = false |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
</script> |
|
|
|
@ -235,7 +539,7 @@ export default { |
|
|
|
|
display: flex; |
|
|
|
|
justify-content: space-between; |
|
|
|
|
align-items: center; |
|
|
|
|
padding: 10px; |
|
|
|
|
padding: 10px 20px; |
|
|
|
|
color: #fff; |
|
|
|
|
background-color: #5786fc; |
|
|
|
|
|
|
|
|
@ -244,10 +548,24 @@ export default { |
|
|
|
|
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 { |
|
|
|
@ -293,13 +611,30 @@ export default { |
|
|
|
|
margin-top: 5px; |
|
|
|
|
|
|
|
|
|
li { |
|
|
|
|
position: relative; |
|
|
|
|
width: 35px; |
|
|
|
|
margin: 7px 9px; |
|
|
|
|
font-size: 13px; |
|
|
|
|
text-align: center; |
|
|
|
|
line-height: 35px; |
|
|
|
|
color: #fff; |
|
|
|
|
background-color: #66b2ff; |
|
|
|
|
color: #505050; |
|
|
|
|
border: 1px solid #d3d3d3; |
|
|
|
|
|
|
|
|
|
&.answered { |
|
|
|
|
color: #fff; |
|
|
|
|
background-color: #66b2ff; |
|
|
|
|
border-color: #66b2ff; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&.partAnswer { |
|
|
|
|
border-color: #66b2ff; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.tag { |
|
|
|
|
position: absolute; |
|
|
|
|
top: -2px; |
|
|
|
|
left: -4px; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -312,11 +647,13 @@ export default { |
|
|
|
|
li { |
|
|
|
|
display: inline-flex; |
|
|
|
|
align-items: center; |
|
|
|
|
padding: 0 3px; |
|
|
|
|
font-size: 12px; |
|
|
|
|
color: #333; |
|
|
|
|
cursor: pointer; |
|
|
|
|
border: 1px solid transparent; |
|
|
|
|
|
|
|
|
|
&:before { |
|
|
|
|
&:not(:last-child):before { |
|
|
|
|
content: ''; |
|
|
|
|
width: 13px; |
|
|
|
|
height: 13px; |
|
|
|
@ -333,9 +670,15 @@ export default { |
|
|
|
|
border-color: #56aaff; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&:last-child:before { |
|
|
|
|
// background-color: #54b6ff; |
|
|
|
|
// border: 0; |
|
|
|
|
&.active { |
|
|
|
|
font-weight: 600; |
|
|
|
|
color: #007eff; |
|
|
|
|
border-color: #007eff; |
|
|
|
|
|
|
|
|
|
&:last-child { |
|
|
|
|
color: #d81e06; |
|
|
|
|
border-color: #d81e06; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -395,6 +738,15 @@ export default { |
|
|
|
|
margin-bottom: 10px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.tag { |
|
|
|
|
margin-left: 10px; |
|
|
|
|
cursor: pointer; |
|
|
|
|
|
|
|
|
|
&:hover { |
|
|
|
|
opacity: .9; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.label { |
|
|
|
|
padding: 3px 5px; |
|
|
|
|
margin-right: 10px; |
|
|
|
|