dev_202412
yujialong 8 months ago
parent 3ea12dca58
commit 838a5b9ed7
  1. 8
      src/libs/util.js
  2. 2
      src/pages/match/details/index.vue
  3. 2
      src/pages/match/list/index.vue
  4. 206
      src/pages/match/theoryExam/index.vue

@ -1,10 +1,10 @@
import cookies from "./util.cookies"; import cookies from "./util.cookies";
import { _local, _session } from "./util.db"; import { _local, _session } from "./util.db";
import { Message } from "element-ui"; import { Message } from "element-ui";
import store from "@/store"; import store from '@/store'
import axios from "axios"; import axios from 'axios'
import api from "@/api"; import api from '@/api'
import Setting from "@/setting"; import Setting from '@/setting'
let logout = false; let logout = false;
// 文件后缀集合 // 文件后缀集合

@ -1645,7 +1645,7 @@ export default {
// //
if (method === 1) { if (method === 1) {
this.$router.push(`theoryExam?id=${form.id}&stageId=${stageId}`) this.$router.push(`/match/theoryExam?id=${form.id}&stageId=${stageId}&teamId=${teamId}`)
} else { } else {
let token = Util.local.get(Setting.tokenKey); let token = Util.local.get(Setting.tokenKey);
if (systemId == 11) { if (systemId == 11) {

@ -973,7 +973,7 @@ export default {
// //
if (method === 1) { if (method === 1) {
this.$router.push(`theoryExam?id=${form.id}&stageId=${stageId}`) this.$router.push(`/match/theoryExam?id=${form.id}&stageId=${stageId}&teamId=${teamId}`)
} else { } else {
let token = Util.local.get(Setting.tokenKey) let token = Util.local.get(Setting.tokenKey)
if (systemId == 11) { if (systemId == 11) {

@ -1,5 +1,5 @@
<template> <template>
<div class="index"> <div class="index" v-loading="loading || submiting">
<div class="top"> <div class="top">
<div class="item"> <div class="item">
<p class="names">{{ curStage.stageName }}{{ curStage.paperName }}</p> <p class="names">{{ curStage.stageName }}{{ curStage.paperName }}</p>
@ -22,7 +22,7 @@
<span>{{ timeSum.seconds }}</span> <span>{{ timeSum.seconds }}</span>
</div> </div>
<el-button class="submit" :loading="submiting" @click="confirmSubmit">提交</el-button> <el-button class="submit" :loading="submiting" :disabled="submited" @click="confirmSubmit">提交</el-button>
<img class="exit" src="@/assets/img/exit.svg" alt="" @click="$router.back()"> <img class="exit" src="@/assets/img/exit.svg" alt="" @click="$router.back()">
</div> </div>
</div> </div>
@ -32,24 +32,29 @@
<h6 class="title">答题卡</h6> <h6 class="title">答题卡</h6>
<div class="progress"> <div class="progress">
<p class="fs-14">答题进度</p> <p class="fs-14">答题进度</p>
<el-progress class="m-t-5 m-b-5" :percentage="50"></el-progress> <el-progress class="m-t-5 m-b-5" :percentage="progress" :format="progressFormat"></el-progress>
<p>{{ form.questionCount }}满分{{ form.score }}</p> <p>{{ form.questionCount }}满分{{ form.score }}</p>
</div> </div>
<div v-if="form.paperOutline" class="type-wrap"> <div v-if="form.paperOutline" class="type-wrap">
<div v-for="(item, i) in form.paperOutline" :key="i" class="type"> <template v-for="(item, i) in form.paperOutline">
<h6 class="stem">{{ arabicToChinese(i + 1) }}{{ item.questionTypeName }}本题共{{ item.questionNum }}小题{{ <div
item.targetScore }}</h6> v-if="item.examQuestions.length && (!sheetStatus || item.examQuestions.some(e => (sheetStatus === 1 && !e.answered) || (sheetStatus === 2 && e.answered) || (sheetStatus === 3 && e.partAnswer) || (sheetStatus === 4 && e.sign)))"
<ul class="serials"> :key="i" class="type">
<template v-for="(ques, j) in item.examQuestions"> <h6 class="stem">{{ arabicToChinese(i + 1) }}{{ item.questionTypeName }}本题共{{ item.questionNum }}小题{{
<li item.targetScore }}</h6>
v-if="!sheetStatus || (sheetStatus === 1 && !ques.answered) || (sheetStatus === 2 && ques.answered) || (sheetStatus === 3 && ques.partAnswer) || (sheetStatus === 4 && ques.sign)" <ul class="serials">
:key="j" :class="{ answered: ques.answered, partAnswer: ques.partAnswer }"> <template v-for="(ques, j) in item.examQuestions">
<img v-if="ques.sign" class="tag" src="@/assets/img/tag-active.svg" alt=""> <li
{{ j + 1 }} v-if="!sheetStatus || (sheetStatus === 1 && !ques.answered) || (sheetStatus === 2 && ques.answered) || (sheetStatus === 3 && ques.partAnswer) || (sheetStatus === 4 && ques.sign)"
</li> :key="j" :class="{ answered: ques.answered, partAnswer: ques.partAnswer }"
</template> @click="scrollToQues(ques)">
</ul> <img v-if="ques.sign" class="tag" src="@/assets/img/tag-active.svg" alt="">
</div> {{ j + 1 }}
</li>
</template>
</ul>
</div>
</template>
</div> </div>
<ul class="status-filter"> <ul class="status-filter">
<li :class="{ active: sheetStatus === 1 }" @click="filterStatus(1)">未作答</li> <li :class="{ active: sheetStatus === 1 }" @click="filterStatus(1)">未作答</li>
@ -60,7 +65,7 @@
</ul> </ul>
</div> </div>
<ul v-if="form.paperOutline" class="ques-wrap"> <ul v-if="form.paperOutline" class="ques-wrap" id="quesWrap">
<li v-for="(item, i) in form.paperOutline" :key="i"> <li v-for="(item, i) in form.paperOutline" :key="i">
<div class="outline"> <div class="outline">
{{ arabicToChinese(i + 1) }}{{ item.questionTypeName }}本题共{{ item.questionNum }}小题{{ {{ arabicToChinese(i + 1) }}{{ item.questionTypeName }}本题共{{ item.questionNum }}小题{{
@ -69,12 +74,14 @@
@click="item.shrink = !item.shrink"> @click="item.shrink = !item.shrink">
</div> </div>
<div :class="['ques', { hide: item.shrink }]"> <div :class="['ques', { hide: item.shrink }]">
<div v-for="(ques, j) in item.examQuestions" :key="j" class="item"> <div v-for="(ques, j) in item.examQuestions" :key="j" class="item" :id="'ques' + ques.id">
<div class="stem-wrap"> <div class="stem-wrap">
<span class="label">{{ j + 1 }} / {{ item.questionNum }}</span> <div class="labels">
<span class="label">{{ item.questionTypeName }}</span> <span class="label">{{ j + 1 }} / {{ item.questionNum }}</span>
<div :id="'stem' + ques.id" v-html="getQuesStem(ques)"></div> <span class="label">{{ item.questionTypeName }}</span>
<p v-if="item.questionType !== 'fill_blank'">{{ ques.score }}</p> </div>
<div class="stem" :id="'stem' + ques.id" v-html="getQuesStem(ques)"></div>
<p>{{ ques.score }}</p>
<img class="tag" :src="require('@/assets/img/' + (ques.sign ? 'tag-active' : 'tag') + '.svg')" alt="" <img class="tag" :src="require('@/assets/img/' + (ques.sign ? 'tag-active' : 'tag') + '.svg')" alt=""
@click="ques.sign = ques.sign ? 0 : 1"> @click="ques.sign = ques.sign ? 0 : 1">
</div> </div>
@ -100,11 +107,10 @@
</div> </div>
<UeditorPlus :ref="'essayAnswer' + ques.id" v-model="ques.answer" <UeditorPlus :ref="'essayAnswer' + ques.id" v-model="ques.answer"
@ready="editor => essayAnswerReady(editor, ques)" /> @ready="editor => essayAnswerReady(editor, ques)" />
<!-- v-if="ques.allowAttachment" --> <div v-if="ques.allowAttachment" class="m-t-20">
<div class="m-t-20"> <div v-if="ques.uploadInstructions" class="flex m-b-10 fs-12">
<div v-if="form.uploadInstructions" class="flex m-b-10 fs-12">
<span>上传附件</span> <span>上传附件</span>
<div v-html="form.uploadInstructions"></div> <div v-html="ques.uploadInstructions"></div>
</div> </div>
<Upload style="max-width: 700px;" accept=".csv,.xlsx,.xls,.docx,.doc,.pdf,.jpg,.png,.zip,.rar,.7z" <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)" :max-size="50" :file-list="ques.uploadList" :on-remove="e => handleRemove(ques)"
@ -142,7 +148,7 @@ export default {
}, },
data () { data () {
return { return {
routes: [], loading: false,
per: 2, // (0 1 2) per: 2, // (0 1 2)
questionTypes: QuesConst.questionTypes, questionTypes: QuesConst.questionTypes,
numToLetter: Util.numToLetter, numToLetter: Util.numToLetter,
@ -153,12 +159,13 @@ export default {
token: Util.local.get(Setting.tokenKey), token: Util.local.get(Setting.tokenKey),
id: +this.$route.query.id, // id id: +this.$route.query.id, // id
stageId: +this.$route.query.stageId, stageId: +this.$route.query.stageId,
teamId: this.$route.query.teamId || '',
entryTime: '', entryTime: '',
curStage: { curStage: {
stageName: '', stageName: '',
paperName: '', paperName: '',
}, },
counterTimer: null, // setInterval counterTimer: null,
countVal: 0, countVal: 0,
// //
counterVal: { counterVal: {
@ -175,16 +182,21 @@ export default {
minutes: 0, minutes: 0,
hour: 0, hour: 0,
}, },
totalAnswered: 0,
progress: 0,
sheetStatus: '', sheetStatus: '',
form: {}, form: {
questionCount: 0,
},
submiting: false, submiting: false,
submited: false,
warned: 0, warned: 0,
}; };
}, },
mounted () { mounted () {
this.$once('hook:beforeDestroy', function () { this.$once('hook:beforeDestroy', function () {
clearInterval(this.counterTimer) clearInterval(this.counterTimer)
this.submiting || this.submit(0) this.submited || this.submit(0)
}) })
this.getCompetition() this.getCompetition()
@ -192,7 +204,7 @@ export default {
methods: { methods: {
// //
async getCompetition () { async getCompetition () {
// clearInterval(this.timer) this.loading = true
const { competition } = await this.$post(`${this.api.getCompetition}?competitionId=${this.id}`) const { competition } = await this.$post(`${this.api.getCompetition}?competitionId=${this.id}`)
const stages = competition.contentList const stages = competition.contentList
if (stages) { if (stages) {
@ -207,6 +219,7 @@ export default {
const now = await Util.getNow() const now = await Util.getNow()
// //
if (now >= endTime) { if (now >= endTime) {
this.loading = false
this.$alert('竞赛时间已到,系统已自动交卷', '提示', { this.$alert('竞赛时间已到,系统已自动交卷', '提示', {
confirmButtonText: '确定' confirmButtonText: '确定'
}) })
@ -226,12 +239,11 @@ export default {
const { examPaper } = await this.$get(this.api.examPaperDetails, { id: paperId }) const { examPaper } = await this.$get(this.api.examPaperDetails, { id: paperId })
// //
const res = await this.$post(this.api.getExamPaperCache, { const { examSubmitReq: cache } = await this.$post(this.api.getExamPaperCache, {
competitionId: this.id, competitionId: this.id,
paperId, paperId,
stageId stageId
}) })
const cache = res.examSubmitReq
let cacheQues = [] let cacheQues = []
if (cache) { if (cache) {
this.entryTime = new Date(cache.startTime) this.entryTime = new Date(cache.startTime)
@ -253,16 +265,19 @@ export default {
Object.assign(n, n.question) Object.assign(n, n.question)
const curQues = cacheQues.find(m => m.outlineId === e.outlineId && m.questionVersionId === n.questionVersionId) // const curQues = cacheQues.find(m => m.outlineId === e.outlineId && m.questionVersionId === n.questionVersionId) //
n.sign = curQues ? curQues.sign : 0 n.sign = curQues ? curQues.sign : 0
const opts = n.questionAnswerVersionsList
if (type !== 'fill_blank' && type !== 'essay' && n.questionAnswerVersionsList) { // if (type !== 'fill_blank' && type !== 'essay' && opts) { //
n.questionAnswerVersionsList.map(m => { opts.map(m => {
m.answer = curQues && curQues.answer && curQues.answer.length && curQues.answer.some(n => n == m.optionNumber) ? 1 : 0 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 if (opts.some(m => m.answer)) n.answered = 1
} else if (type === 'fill_blank') { // } else if (type === 'fill_blank') { //
n.fills = curQues && curQues.answer && curQues.answer.length ? curQues.answer : '' n.fills = curQues && curQues.answer && curQues.answer.length && curQues.answer.some(m => m) ? curQues.answer : ''
if (n.fills) n.answered = 1 let { answerData } = opts[0]
} else { // if (answerData) answerData = JSON.parse(answerData)
n.answered = n.fills && answerData && answerData.length === n.fills.filter(m => m).length ? 1 : 0
n.partAnswer = n.fills && answerData && answerData.length !== n.fills.filter(m => m).length ? 1 : 0
} else if (type === 'essay') { //
n.answer = type === 'essay' && curQues ? curQues.answerContent : '' n.answer = type === 'essay' && curQues ? curQues.answerContent : ''
n.attachmentName = curQues ? curQues.attachmentName : '' n.attachmentName = curQues ? curQues.attachmentName : ''
n.attachmentUrl = curQues ? curQues.attachmentUrl : '' n.attachmentUrl = curQues ? curQues.attachmentUrl : ''
@ -279,6 +294,7 @@ export default {
}) })
}) })
this.form = r this.form = r
this.loading = false
// input // input
this.$nextTick(() => { this.$nextTick(() => {
@ -304,10 +320,13 @@ export default {
} }
}) })
}) })
this.calcProgress()
}) })
console.log("🚀 ~ getPaper ~ r:", r) console.log("🚀 ~ getPaper ~ r:", r)
} }
} catch (e) { } } catch (e) {
this.loading = false
}
}, },
// //
handleCounter (counterTime, isCount) { handleCounter (counterTime, isCount) {
@ -364,6 +383,39 @@ export default {
timeFormat (param) { timeFormat (param) {
return param < 10 ? '0' + param : 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) {
const el = document.querySelector('#ques' + e.id)
el && this.scrollToSmooth(el.offsetTop - document.querySelector('#quesWrap').offsetTop, 200)
},
// //
filterStatus (e) { filterStatus (e) {
this.sheetStatus = this.sheetStatus === e ? '' : e this.sheetStatus = this.sheetStatus === e ? '' : e
@ -397,17 +449,20 @@ export default {
ques.questionAnswerVersionsList[j].answer = 1 ques.questionAnswerVersionsList[j].answer = 1
ques.answered = 1 ques.answered = 1
this.calcProgress()
}, },
// //
mulChange (ques) { mulChange (ques) {
ques.answered = ques.questionAnswerVersionsList.some(e => e.answer) ques.answered = ques.questionAnswerVersionsList.some(e => e.answer)
this.calcProgress()
}, },
// //
essayAnswerReady (editor, ques) { essayAnswerReady (editor, ques) {
editor.ques = ques editor.ques = ques
editor.addListener('contentChange', () => { editor.addListener('contentChange', () => {
ques.answered = editor.getContent() ? 1 : 0 ques.answered = editor.hasContents() ? 1 : 0
this.calcProgress()
}) })
ques.answer && editor.setContent(ques.answer) ques.answer && editor.setContent(ques.answer)
}, },
@ -473,7 +528,6 @@ export default {
const stem = document.querySelector(`#stem` + n.id) const stem = document.querySelector(`#stem` + n.id)
if (stem) { if (stem) {
const inputs = stem.querySelectorAll('.fill-input') const inputs = stem.querySelectorAll('.fill-input')
console.log("🚀 ~ submit ~ editor333:", stem, inputs)
if (inputs) { if (inputs) {
for (const e of inputs) { for (const e of inputs) {
answer.push(e.value) answer.push(e.value)
@ -497,11 +551,12 @@ export default {
}) })
const timeSum = Math.ceil((now - entryTime) / 60000) // const timeSum = Math.ceil((now - entryTime) / 60000) //
const submitTime = Util.formatDate('yyyy-MM-dd hh:mm:ss', now) const submitTime = Util.formatDate('yyyy-MM-dd hh:mm:ss', now)
// debugger
// //
const res = await this.$post(this.api[isSubmit ? 'submitTheExamPaper' : 'examPaperRecordCache'], { await this.$post(this.api[isSubmit ? 'submitTheExamPaper' : 'examPaperRecordCache'], {
competitionId: this.id, competitionId: this.id,
stageId: curStage.stageId, stageId: curStage.stageId,
teamId: this.teamId,
startTime: Util.formatDate('yyyy-MM-dd hh:mm:ss', entryTime), // startTime: Util.formatDate('yyyy-MM-dd hh:mm:ss', entryTime), //
endTime: this.per ? curStage.endTime : submitTime, // endTime: this.per ? curStage.endTime : submitTime, //
submitTime, // 3 submitTime, // 3
@ -511,20 +566,25 @@ export default {
examSubmitJudgeList: ques, examSubmitJudgeList: ques,
}) })
// clearInterval(this.counterTimer)
if (this.id) { this.submiting = false
const time = curStage.resultAnnouncementTime this.submited = true
const msg = if (isSubmit) {
time === '0' ? '提交成功!成绩将在比赛结束后公布,请前往参赛信息模块查看' : time > 0 ? `提交成功!成绩将在比赛结束后${time}小时公布,请前往参赛信息模块查看` : '提交成功'; //
this.$alert(msg, '提示', { if (this.id) {
confirmButtonText: '确定', const time = curStage.resultAnnouncementTime
type: 'success', const msg =
callback: () => { time === '0' ? '提交成功!成绩将在比赛结束后公布,请前往参赛信息模块查看' : time > 0 ? `提交成功!成绩将在比赛结束后${time}小时公布,请前往参赛信息模块查看` : '提交成功';
this.$router.back() this.$alert(msg, '提示', {
} confirmButtonText: '确定',
}) type: 'success',
} else { callback: () => {
this.$message.success('提交成功!') this.$router.back()
}
})
} else {
this.$message.success('提交成功!')
}
} }
} catch (e) { } catch (e) {
this.submiting = false this.submiting = false
@ -573,7 +633,7 @@ export default {
padding: 15px; padding: 15px;
.left { .left {
width: 300px; width: 293px;
margin-right: 15px; margin-right: 15px;
background-color: #fff; background-color: #fff;
@ -612,13 +672,18 @@ export default {
li { li {
position: relative; position: relative;
width: 35px; width: 30px;
margin: 7px 9px; margin: 7px 9px;
font-size: 13px; font-size: 13px;
text-align: center; text-align: center;
line-height: 35px; line-height: 30px;
color: #505050; color: #505050;
border: 1px solid #d3d3d3; border: 1px solid #d3d3d3;
cursor: pointer;
&:hover {
opacity: .9;
}
&.answered { &.answered {
color: #fff; color: #fff;
@ -685,10 +750,11 @@ export default {
} }
.ques-wrap { .ques-wrap {
width: calc(100% - 315px); width: calc(100% - 308px);
height: calc(100vh - 192px); height: calc(100vh - 192px);
background-color: #fff; background-color: #fff;
overflow: auto; overflow: auto;
outline: none;
&>li { &>li {
margin-bottom: 15px; margin-bottom: 15px;
@ -734,7 +800,7 @@ export default {
.stem-wrap { .stem-wrap {
display: flex; display: flex;
align-items: center; align-items: baseline;
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -747,16 +813,26 @@ export default {
} }
} }
.labels {
display: inline-flex;
align-items: center;
}
.label { .label {
padding: 3px 5px; padding: 3px 5px;
margin-right: 10px; margin-right: 10px;
font-size: 12px; font-size: 12px;
line-height: 1; line-height: 1;
color: $main-color; color: $main-color;
white-space: nowrap;
border: 1px solid; border: 1px solid;
border-radius: 2px; border-radius: 2px;
} }
.stem {
max-width: calc(100% - 191px);
}
.fill-input { .fill-input {
width: 100px; width: 100px;
height: 28px; height: 28px;

Loading…
Cancel
Save