@zykjcommon/questions 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.browserslistrc +3 -0
- package/.env +7 -0
- package/.env.buildTest +9 -0
- package/.env.development +9 -0
- package/.env.production +13 -0
- package/.env.test +12 -0
- package/@types/global.d.ts +33 -0
- package/@types/shims-vue.d.ts +6 -0
- package/@types/shims-vuex.d.ts +15 -0
- package/auto-imports.d.ts +6 -0
- package/babel.config.js +5 -0
- package/components.d.ts +23 -0
- package/design/App.vue +60 -0
- package/design/main.js +23 -0
- package/design/views/dialog/contentDialog.vue +18 -0
- package/design/views/dialog/contentDialog2.vue +18 -0
- package/design/views/dialog/contentDialog3.vue +19 -0
- package/design/views/exam/analysis.vue +208 -0
- package/design/views/exam/exam.vue +355 -0
- package/design/views/home/illustrate.vue +45 -0
- package/design/views/home/login.vue +43 -0
- package/design/vueMapper.js +8 -0
- package/design/vueMapperTree.js +2 -0
- package/dist/demo.html +1 -0
- package/dist/zykjcommon-questions.common.js +12817 -0
- package/dist/zykjcommon-questions.css +1 -0
- package/dist/zykjcommon-questions.umd.js +12836 -0
- package/dist/zykjcommon-questions.umd.min.js +18 -0
- package/index.js +10 -0
- package/package.json +61 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +19 -0
- package/public/static/js/jquery.html2json.js +169 -0
- package/public/static/js/jquery.json2html.js +137 -0
- package/public/static/js/jquery.min.js +2 -0
- package/public/static/js/json2html.js +447 -0
- package/readme +8 -0
- package/src/App.vue +37 -0
- package/src/assets/img/afei.jpg +0 -0
- package/src/assets/img/audio-ico.gif +0 -0
- package/src/assets/img/audio-ico.png +0 -0
- package/src/assets/img/bc-type-bg.png +0 -0
- package/src/assets/img/big-close.png +0 -0
- package/src/assets/img/big-next.png +0 -0
- package/src/assets/img/big-pre.png +0 -0
- package/src/assets/img/book-bg.png +0 -0
- package/src/assets/img/checkbox-cur.png +0 -0
- package/src/assets/img/checkbox.png +0 -0
- package/src/assets/img/cpp-bg.png +0 -0
- package/src/assets/img/deer-logo.png +0 -0
- package/src/assets/img/header-bg-2.png +0 -0
- package/src/assets/img/header-bg.png +0 -0
- package/src/assets/img/illustrate-bg.png +0 -0
- package/src/assets/img/loading.gif +0 -0
- package/src/assets/img/login-bg.png +0 -0
- package/src/assets/img/login-box-bg.png +0 -0
- package/src/assets/img/login-box-logo.png +0 -0
- package/src/assets/img/logo.png +0 -0
- package/src/assets/img/logoByText.png +0 -0
- package/src/assets/img/py-bg.png +0 -0
- package/src/assets/img/pygame-bg.png +0 -0
- package/src/assets/img/radio-cur.png +0 -0
- package/src/assets/img/radio.png +0 -0
- package/src/assets/img/return-top-hover.png +0 -0
- package/src/assets/img/return-top.png +0 -0
- package/src/assets/img/sb3-bg.png +0 -0
- package/src/assets/img/star-ico.png +0 -0
- package/src/assets/img/tab-mark.png +0 -0
- package/src/assets/img/video-play-btn.png +0 -0
- package/src/assets/js/arms.js +16 -0
- package/src/assets/js/bus.js +14 -0
- package/src/assets/js/fun.js +883 -0
- package/src/assets/js/helper.js +575 -0
- package/src/assets/js/http.js +219 -0
- package/src/assets/js/md5.js +260 -0
- package/src/assets/js/rem.js +33 -0
- package/src/assets/js/validation.js +216 -0
- package/src/assets/js/zykjcommon-questions.umd.min.js +18 -0
- package/src/assets/logo.png +0 -0
- package/src/assets/scss/dialog/dialog.scss +144 -0
- package/src/assets/scss/exam/exam.scss +256 -0
- package/src/assets/scss/home/home.scss +222 -0
- package/src/assets/scss/index.scss +80 -0
- package/src/assets/scss/questions/index.scss +345 -0
- package/src/common/const.ts +15 -0
- package/src/components/common/ContentDialog.vue +172 -0
- package/src/components/common/IframeComponent.vue +101 -0
- package/src/components/common/Loading.vue +45 -0
- package/src/components/common/MediaLooker.vue +171 -0
- package/src/components/common/TextAreaEditor.vue +121 -0
- package/src/components/exam/QuestionCard.vue +494 -0
- package/src/components/exam/QuestionHeader.vue +87 -0
- package/src/components/exam/TimeCounter.vue +107 -0
- package/src/components/questions/QuestionReader.js +20 -0
- package/src/components/questions/Question_SingleChoice.vue +208 -0
- package/src/components/questions/buildEntry.js +12 -0
- package/src/components/questions/developmentEntry.js +11 -0
- package/src/components/questions/mixin.js +64 -0
- package/src/main.ts +176 -0
- package/src/router/exam.ts +50 -0
- package/src/router/index.ts +33 -0
- package/src/store/exam.ts +199 -0
- package/src/store/index.ts +22 -0
- package/src/types/common/index.ts +4 -0
- package/src/types/exam/exam.ts +10 -0
- package/src/views/exam/Analysis.vue +516 -0
- package/src/views/exam/Default.vue +28 -0
- package/src/views/exam/Exam.vue +594 -0
- package/src/views/exam/ReviewPaper.vue +178 -0
- package/src/views/exam/ReviewQuestion.vue +167 -0
- package/tasks/vueMapper.js +37 -0
- package/tasks/vueMapperTree.js +42 -0
- package/tsconfig.json +46 -0
- package/tslint.json +19 -0
- package/vue.config.js +107 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="question-car-box">
|
|
3
|
+
<div class="question-car-tit">答题卡</div>
|
|
4
|
+
<ul class="question-car-list clear">
|
|
5
|
+
<li :class="{'current':item.completed == true,'right':item.isCorrect == true,'err':item.isCorrect == false}"
|
|
6
|
+
@click="jump(index)"
|
|
7
|
+
:key="index"
|
|
8
|
+
v-for="(item,index) in responsiveObj.questionList">{{item.questionIndex}}</li>
|
|
9
|
+
</ul>
|
|
10
|
+
<div class="question-car-btngroud">
|
|
11
|
+
<button class="submit" @click="btnSubmit" v-if="route.name !== 'analysis'">提交</button>
|
|
12
|
+
<!-- <button class="quit" @click="btnQuit">退出</button>-->
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="submitVisible"
|
|
16
|
+
:cancelText="'再检查一下'"
|
|
17
|
+
:confirmText="'提交'"
|
|
18
|
+
@confirm="submitQuestion">
|
|
19
|
+
<template #content>
|
|
20
|
+
<div class="con-text-1">提交后,将无法修改。<br>请确认是否继续提交?</div>
|
|
21
|
+
</template>
|
|
22
|
+
</ContentDialog>
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="quitVisible"
|
|
26
|
+
:cancelText="'退出'"
|
|
27
|
+
:confirmText="'继续测评'"
|
|
28
|
+
@cancel="submitQuestion(1,true,false)">
|
|
29
|
+
<template #content>
|
|
30
|
+
<div class="con-text-1" style="margin-top: 0.2rem">测评还未结束,确定退出?</div>
|
|
31
|
+
</template>
|
|
32
|
+
</ContentDialog>
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="noCompleteVisible"
|
|
36
|
+
:hide-cancel="true"
|
|
37
|
+
:confirmText="'我知道了'">
|
|
38
|
+
<template #content>
|
|
39
|
+
<div class="con-text-1">你还有题目未作答<br>请全部作答后,再提交。</div>
|
|
40
|
+
</template>
|
|
41
|
+
</ContentDialog>
|
|
42
|
+
|
|
43
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="timeoverVisible"
|
|
44
|
+
@confirm="quitQuestion"
|
|
45
|
+
:hide-cancel="true"
|
|
46
|
+
:confirmText="'我知道了'">
|
|
47
|
+
<template #content>
|
|
48
|
+
<div class="con-text-1" style="font-size: 14px;line-height: 22px"><span style="font-size: 20px;font-weight: bold;display: inline-block;margin-bottom: 15px;">测评时间到!</span><br>
|
|
49
|
+
测评结束,试卷已自动提交,如有疑问请联系招聘老师。
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
</ContentDialog>
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="initTimeoverVisible"
|
|
57
|
+
:hide-cancel="true"
|
|
58
|
+
:confirmText="'我知道了'">
|
|
59
|
+
<template #content>
|
|
60
|
+
<div class="con-text-1" style="font-size: 14px;line-height: 22px"><span style="font-size: 20px;font-weight: bold;display: inline-block;margin-bottom: 15px;">测评已结束</span><br>
|
|
61
|
+
如有疑问,请联系招聘老师。
|
|
62
|
+
</div>
|
|
63
|
+
</template>
|
|
64
|
+
</ContentDialog>
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="nearTimeoverVisible"
|
|
68
|
+
:hide-cancel="true"
|
|
69
|
+
:confirmText="'我知道了'">
|
|
70
|
+
<template #content>
|
|
71
|
+
<div class="con-text-1" style="font-size: 14px;line-height: 22px"><span style="font-size: 20px;font-weight: bold;display: inline-block;margin-bottom: 15px;">测评即将结束</span><br>
|
|
72
|
+
离自动交卷还有10分钟,请把握好时间!
|
|
73
|
+
</div>
|
|
74
|
+
</template>
|
|
75
|
+
</ContentDialog>
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
<ContentDialog v-if="route.name === 'examIndex'" v-model:visible="warnVisible"
|
|
79
|
+
:hide-cancel="true"
|
|
80
|
+
:confirmText="'我知道了'"
|
|
81
|
+
@confirm="quitQuestion">
|
|
82
|
+
<template #content>
|
|
83
|
+
<div class="con-text-1" style="font-size: 14px;line-height: 22px"><span style="font-size: 20px;font-weight: bold;display: inline-block;margin-bottom: 15px;">答题失败</span><br>
|
|
84
|
+
该试卷已提交,请勿重复答题,如有疑<br>问请联系老师。
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
</ContentDialog>
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
<ContentDialog v-model:visible="completeVisible"
|
|
91
|
+
unit="px"
|
|
92
|
+
:width="396"
|
|
93
|
+
:height="195"
|
|
94
|
+
:hide-cancel="true">
|
|
95
|
+
<template #content>
|
|
96
|
+
<div class="con-text-1" style="font-size: 14px;line-height: 22px"><span style="font-size: 20px;font-weight: bold;display: inline-block;margin-bottom: 20px;">试卷提交成功!</span><br>
|
|
97
|
+
测评结果请咨询招聘老师。
|
|
98
|
+
</div>
|
|
99
|
+
</template>
|
|
100
|
+
</ContentDialog>
|
|
101
|
+
|
|
102
|
+
<Loading :loading="loading"></Loading>
|
|
103
|
+
</template>
|
|
104
|
+
|
|
105
|
+
<script lang="ts">
|
|
106
|
+
import {
|
|
107
|
+
defineComponent,
|
|
108
|
+
ref,
|
|
109
|
+
toRef,
|
|
110
|
+
toRefs,
|
|
111
|
+
reactive,
|
|
112
|
+
onMounted,
|
|
113
|
+
watch,
|
|
114
|
+
nextTick,
|
|
115
|
+
getCurrentInstance,
|
|
116
|
+
computed
|
|
117
|
+
} from 'vue'
|
|
118
|
+
import fun from '@src/assets/js/fun.js'
|
|
119
|
+
import bus from "@/assets/js/bus";
|
|
120
|
+
import {useRouter,useRoute} from 'vue-router'
|
|
121
|
+
import {createNamespacedHelpers} from "vuex-composition-helpers";
|
|
122
|
+
interface dataInterface{
|
|
123
|
+
completeVisible:boolean,
|
|
124
|
+
submitVisible:boolean,
|
|
125
|
+
warnVisible:boolean,
|
|
126
|
+
quitVisible:boolean,
|
|
127
|
+
noCompleteVisible:boolean,
|
|
128
|
+
nearTimeoverVisible:boolean,
|
|
129
|
+
initTimeoverVisible:boolean,
|
|
130
|
+
timeoverVisible:boolean,
|
|
131
|
+
loading:boolean,
|
|
132
|
+
autoSubmitTimer:any,
|
|
133
|
+
route:any,
|
|
134
|
+
examInfo:any,
|
|
135
|
+
uploadCodingFileSuccess:boolean
|
|
136
|
+
}
|
|
137
|
+
interface responsiveData{
|
|
138
|
+
questionList:Array<any>
|
|
139
|
+
}
|
|
140
|
+
export default defineComponent({
|
|
141
|
+
props: {
|
|
142
|
+
questionList: {
|
|
143
|
+
type: Array,
|
|
144
|
+
default:[]
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
components:{
|
|
148
|
+
},
|
|
149
|
+
setup(props, context) {
|
|
150
|
+
|
|
151
|
+
const {useActions,useState} = createNamespacedHelpers('exam'); // specific module name
|
|
152
|
+
const {saveAnswersActions,submitExamActions} = useActions(['saveAnswersActions','submitExamActions'])
|
|
153
|
+
const {hasError,examInfo} = useState(['hasError','examInfo'])
|
|
154
|
+
let route = useRoute()
|
|
155
|
+
const currentInstance:any = getCurrentInstance()
|
|
156
|
+
let _this = currentInstance.proxy
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
let data:dataInterface = reactive({
|
|
160
|
+
completeVisible:false,
|
|
161
|
+
submitVisible:false,
|
|
162
|
+
warnVisible:false,
|
|
163
|
+
quitVisible:false,
|
|
164
|
+
noCompleteVisible:false,
|
|
165
|
+
nearTimeoverVisible:false,
|
|
166
|
+
initTimeoverVisible:false,
|
|
167
|
+
timeoverVisible:false,
|
|
168
|
+
loading:false,
|
|
169
|
+
autoSubmitTimer:null,
|
|
170
|
+
uploadCodingFileSuccess:false,
|
|
171
|
+
route:route,
|
|
172
|
+
examInfo
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
//需要响应式放里面
|
|
176
|
+
let responsiveObj:{value:responsiveData} = ref({
|
|
177
|
+
questionList:[]
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
onMounted(()=>{
|
|
181
|
+
watch(() => props.questionList, (nv) => {
|
|
182
|
+
if(nv && nv.length){
|
|
183
|
+
responsiveObj.value.questionList = fun.copyDeepObject(nv) as Array<any>
|
|
184
|
+
//考试路由才有自动提交
|
|
185
|
+
if(route.name === 'examIndex'){
|
|
186
|
+
intervalAutoSubmit()
|
|
187
|
+
}else if(route.name === 'analysis'){
|
|
188
|
+
_this.$nextTick(()=>{
|
|
189
|
+
let parentRefs = _this.$parent.$refs
|
|
190
|
+
responsiveObj.value.questionList.forEach((item,index)=>{
|
|
191
|
+
let questionComponent = parentRefs[`question${index}`][0]
|
|
192
|
+
let isCorrect = questionComponent.isCorrect ? questionComponent.isCorrect() : false
|
|
193
|
+
item.isCorrect = isCorrect
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
},{immediate:true,deep:true})
|
|
201
|
+
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
// questionIndex:questionInfo.questionIndex - 1,
|
|
207
|
+
// answered
|
|
208
|
+
bus.$on('questionCardChange',(obj:any)=>{
|
|
209
|
+
let questionIndex = obj.questionIndex
|
|
210
|
+
if(route.name === 'examIndex'){
|
|
211
|
+
let answered = obj.answered
|
|
212
|
+
// if(responsiveObj.value.questionList && responsiveObj.value.questionList.length){
|
|
213
|
+
responsiveObj.value.questionList[questionIndex].completed = answered
|
|
214
|
+
// }
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
// 考试剩下10分钟提示
|
|
220
|
+
bus.$on('examNearEnd',(obj:any)=>{
|
|
221
|
+
//关掉所有弹窗
|
|
222
|
+
fun.closeAllContentDialog()
|
|
223
|
+
data.nearTimeoverVisible = true
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
//考试倒计时结束视为手动提交,关闭所有弹窗,超时弹窗优先级最高
|
|
229
|
+
bus.$on('examEnd',(isInitTimeOut:any)=>{
|
|
230
|
+
bus.$emit('showBlur')
|
|
231
|
+
if(isInitTimeOut){
|
|
232
|
+
fun.closeAllContentDialog()
|
|
233
|
+
data.initTimeoverVisible = true
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
//关掉所有弹窗
|
|
237
|
+
fun.closeAllContentDialog()
|
|
238
|
+
data.timeoverVisible = true
|
|
239
|
+
let parentRefs = _this.$parent.$refs
|
|
240
|
+
let keys = Object.keys(parentRefs)
|
|
241
|
+
let codeQuestionKeys = keys.filter((key)=>{
|
|
242
|
+
return parentRefs[key][0].questionInfo.question_type == 16
|
|
243
|
+
})
|
|
244
|
+
let codeQuestionComponent = null
|
|
245
|
+
for(let i=0;i<codeQuestionKeys.length;i++){
|
|
246
|
+
let codeQuestionKey = codeQuestionKeys[i]
|
|
247
|
+
if(codeQuestionKey){
|
|
248
|
+
let codeQuestion = parentRefs[codeQuestionKey][0]
|
|
249
|
+
if(codeQuestion.showFrame){
|
|
250
|
+
codeQuestionComponent = codeQuestion
|
|
251
|
+
break
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if(codeQuestionComponent){
|
|
257
|
+
codeQuestionComponent.submitCodeQuestionByTimeover()
|
|
258
|
+
}else{
|
|
259
|
+
submitQuestion(0,false)
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
//时间到并且开着编程题的时候,保存编程题后的回调
|
|
265
|
+
bus.$on('uploadCodingFileSuccess',()=>{
|
|
266
|
+
data.uploadCodingFileSuccess = true
|
|
267
|
+
submitQuestion(0,false)
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
bus.$on('submitQuestion',(obj: any )=>{
|
|
271
|
+
submitQuestion(obj.saveType,obj.submitRequestAutoQuit,obj.needSubmitRequest)
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
function clearAutoTimer(){
|
|
276
|
+
data.autoSubmitTimer && clearInterval(data.autoSubmitTimer)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function intervalAutoSubmit(){
|
|
280
|
+
let t = 1000 * 60
|
|
281
|
+
// let t = 1000 * 2
|
|
282
|
+
clearAutoTimer()
|
|
283
|
+
data.autoSubmitTimer = setInterval(()=>{
|
|
284
|
+
submitQuestion(0)
|
|
285
|
+
},t)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function btnQuit(){
|
|
289
|
+
if(hasError && hasError.value){
|
|
290
|
+
fun.postMessageByType('close')
|
|
291
|
+
console.log('系统异常');
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
if(data.loading){
|
|
295
|
+
fun.postMessageByType('close')
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
if(data.route.name === 'reviewPaper'){
|
|
299
|
+
fun.postMessageByType('close')
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if(data.route.name === 'analysis'){
|
|
303
|
+
fun.postMessageByType('close')
|
|
304
|
+
}else{
|
|
305
|
+
data.quitVisible = true
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
function btnSubmit(){
|
|
311
|
+
if(data.route.name !== 'examIndex'){
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if(data.loading){
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
let noComplete = false
|
|
318
|
+
let parentRefs = _this.$parent.$refs
|
|
319
|
+
let keys = Object.keys(parentRefs)
|
|
320
|
+
//是否完成答题校验
|
|
321
|
+
for(let i=0;i<keys.length;i++){
|
|
322
|
+
let questionItemScope = parentRefs[keys[i]][0]
|
|
323
|
+
// console.log(questionItemScope.isAnswered(),456);
|
|
324
|
+
if(!questionItemScope.isAnswered()){
|
|
325
|
+
noComplete = true
|
|
326
|
+
break
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if(noComplete){
|
|
330
|
+
data.noCompleteVisible = true
|
|
331
|
+
return
|
|
332
|
+
}
|
|
333
|
+
data.submitVisible = true
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
interface examAnswerMapItemInterF{
|
|
338
|
+
question_id:number|string,
|
|
339
|
+
a:boolean,
|
|
340
|
+
b:number
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
interface submitExamInterF{
|
|
344
|
+
save_type:number,
|
|
345
|
+
exam_id:number|string,
|
|
346
|
+
exam_answer_map:{
|
|
347
|
+
[propName:string]:examAnswerMapItemInterF
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
//submitRequestAutoQuit:true 真正手动触发提交需要请求成功后退出iframe false: 考试超时提交点我知道了退出iframe
|
|
351
|
+
function submitQuestion(save_type:number|undefined,submitRequestAutoQuit:boolean|undefined = true,needSubmitRequest:boolean = true){
|
|
352
|
+
if(data.loading){
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
let parentRefs = _this.$parent.$refs
|
|
356
|
+
let keys = Object.keys(parentRefs)
|
|
357
|
+
//save_type 0.自动 1.手动
|
|
358
|
+
// let examId = route.query.examId as string | number
|
|
359
|
+
let examId = data.examInfo.id
|
|
360
|
+
let params:submitExamInterF = {
|
|
361
|
+
save_type:save_type===undefined?1:save_type,
|
|
362
|
+
exam_id:examId,
|
|
363
|
+
exam_answer_map:{}
|
|
364
|
+
}
|
|
365
|
+
for(let i=0;i<keys.length;i++){
|
|
366
|
+
let questionItemScope = parentRefs[keys[i]][0]
|
|
367
|
+
// console.log(questionItemScope,'questionItemScope');
|
|
368
|
+
if(!questionItemScope){
|
|
369
|
+
let msg = `可能报错但难以复现的错误:keys---${JSON.stringify(keys)},questionList---${JSON.stringify(responsiveObj.value.questionList)}`;
|
|
370
|
+
(fun as any).fbError(msg,window.location.href,0,0,'可能报错但难以复现的错误')
|
|
371
|
+
console.log(msg);
|
|
372
|
+
}
|
|
373
|
+
let question_type = responsiveObj.value.questionList[i].question_type
|
|
374
|
+
//阅读理解题打平小题提交
|
|
375
|
+
let answered = questionItemScope.isAnswered()
|
|
376
|
+
if(answered){
|
|
377
|
+
if(question_type == 11){
|
|
378
|
+
let answerList = questionItemScope.getAnswer()
|
|
379
|
+
answerList.forEach((item:any)=>{
|
|
380
|
+
let answer = item.answer
|
|
381
|
+
params.exam_answer_map[item.question_id] = {
|
|
382
|
+
question_id:item.question_id,
|
|
383
|
+
...answer
|
|
384
|
+
}
|
|
385
|
+
})
|
|
386
|
+
}else{
|
|
387
|
+
let question_id = responsiveObj.value.questionList[i].question_id
|
|
388
|
+
let answer = questionItemScope.getAnswer()
|
|
389
|
+
params.exam_answer_map[question_id] = {
|
|
390
|
+
question_id,
|
|
391
|
+
...answer
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
}
|
|
397
|
+
//一题都没做不需要调保存接口
|
|
398
|
+
let paramsKeys = Object.keys(params.exam_answer_map)
|
|
399
|
+
if(!paramsKeys.length){
|
|
400
|
+
//一题都没做,并且是 考试时间到视为手动提交,不需要调保存直接提交
|
|
401
|
+
if(params.save_type == 1 || data.timeoverVisible){
|
|
402
|
+
clearAutoTimer()
|
|
403
|
+
//手动提交需要停止倒计时
|
|
404
|
+
bus.$emit('stopTimeCounter')
|
|
405
|
+
//时间到了需要提交请求
|
|
406
|
+
if(needSubmitRequest){
|
|
407
|
+
submitRequest(examId,submitRequestAutoQuit as boolean)
|
|
408
|
+
}else{
|
|
409
|
+
//什么都没做点退出,并且还有剩余时间的情况下
|
|
410
|
+
submitRequestAutoQuit && quitQuestion()
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return
|
|
414
|
+
}else{
|
|
415
|
+
if((params.save_type == 1 && submitRequestAutoQuit) || data.timeoverVisible){
|
|
416
|
+
//手动提交并且需要自动退出才需要清理自动提交定时器和倒计时定时器
|
|
417
|
+
clearAutoTimer()
|
|
418
|
+
bus.$emit('stopTimeCounter')
|
|
419
|
+
}
|
|
420
|
+
data.loading = true
|
|
421
|
+
saveAnswersActions(params).then((res:any) => {
|
|
422
|
+
data.loading = false
|
|
423
|
+
let {error_code} = res;
|
|
424
|
+
if (!error_code) {
|
|
425
|
+
if(params.save_type == 1 || data.timeoverVisible){
|
|
426
|
+
if(needSubmitRequest){
|
|
427
|
+
submitRequest(examId,submitRequestAutoQuit as boolean)
|
|
428
|
+
}else{
|
|
429
|
+
submitRequestAutoQuit && quitQuestion()
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}else{
|
|
433
|
+
if(error_code === 39002){
|
|
434
|
+
data.warnVisible = true
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
},()=>{
|
|
438
|
+
data.loading = false
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function submitRequest(examId:string | number,submitRequestAutoQuit:boolean){
|
|
444
|
+
data.loading = true
|
|
445
|
+
submitExamActions({exam_id:examId}).then((res:any)=>{
|
|
446
|
+
data.loading = false
|
|
447
|
+
let {error_code} = res;
|
|
448
|
+
if (!error_code){
|
|
449
|
+
//时间到了就不弹完成弹窗
|
|
450
|
+
if(!data.timeoverVisible){
|
|
451
|
+
fun.closeAllContentDialog()
|
|
452
|
+
data.completeVisible = true
|
|
453
|
+
}
|
|
454
|
+
bus.$emit('showBlur')
|
|
455
|
+
// console.log(submitRequestAutoQuit,888888888888);
|
|
456
|
+
submitRequestAutoQuit && quitQuestion()
|
|
457
|
+
}
|
|
458
|
+
},()=>{
|
|
459
|
+
data.loading = false
|
|
460
|
+
})
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
function quitQuestion(){
|
|
465
|
+
clearAutoTimer()
|
|
466
|
+
fun.postMessageByType('close')
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
function jump(index:number){
|
|
471
|
+
let idStr = `question${index}`
|
|
472
|
+
let jumpTarget = document.getElementById(idStr)
|
|
473
|
+
let header = document.querySelector('.header')
|
|
474
|
+
let oft = fun.offset(jumpTarget,'top')
|
|
475
|
+
let headerH = (header as HTMLElement).clientHeight
|
|
476
|
+
let scrollDistance = oft - headerH
|
|
477
|
+
let scrollMain:any = document.querySelector('.content-outter')
|
|
478
|
+
scrollMain.scrollTop = scrollDistance
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
...toRefs(data),
|
|
483
|
+
btnSubmit,
|
|
484
|
+
btnQuit,
|
|
485
|
+
submitQuestion,
|
|
486
|
+
quitQuestion,
|
|
487
|
+
jump,
|
|
488
|
+
responsiveObj
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
})
|
|
492
|
+
</script>
|
|
493
|
+
|
|
494
|
+
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="header" :class="{'fixed':enterCode && routeName === 'examIndex'}">
|
|
3
|
+
<div class="header-main">
|
|
4
|
+
<div class="header-left">
|
|
5
|
+
<div class="header-left-top">姓名:<span v-if="responsiveObj.resData.applicant_simple_info">{{ responsiveObj.resData.applicant_simple_info.applicant_name }}</span></div>
|
|
6
|
+
<div class="header-left-bottom">手机号:<span v-if="responsiveObj.resData.applicant_simple_info">{{ responsiveObj.resData.applicant_simple_info.phone }}</span></div>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="header-title">{{responsiveObj.resData.online_exam_name}}</div>
|
|
9
|
+
|
|
10
|
+
<div class="header-right"
|
|
11
|
+
v-if="routeName === 'examIndex' || routeName === 'reviewPaper'">
|
|
12
|
+
<span>测评剩余时间</span>
|
|
13
|
+
<TimeCounter :time="responsiveObj.resData.remain_second"></TimeCounter>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="header-right" v-if="routeName === 'analysis'">
|
|
16
|
+
<span>测评成绩</span>
|
|
17
|
+
<span class="score">{{responsiveObj.resData.user_total_score}}<span>分</span></span>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
import {defineComponent, ref, toRefs, reactive, watch, onMounted} from 'vue'
|
|
25
|
+
import TimeCounter from '@src/components/exam/TimeCounter.vue'
|
|
26
|
+
import {useRoute} from 'vue-router'
|
|
27
|
+
import bus from "@/assets/js/bus";
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
interface dataInterface{
|
|
31
|
+
enterCode:boolean,
|
|
32
|
+
routeName:string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface responsiveData{
|
|
36
|
+
resData:any
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
export default defineComponent({
|
|
41
|
+
props: {
|
|
42
|
+
resData: {
|
|
43
|
+
type: Object,
|
|
44
|
+
default:{}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
components: {
|
|
48
|
+
TimeCounter
|
|
49
|
+
},
|
|
50
|
+
setup(props,context) {
|
|
51
|
+
let route = useRoute()
|
|
52
|
+
//不需要响应式或者写死的数据放里面
|
|
53
|
+
let data:dataInterface = reactive({
|
|
54
|
+
enterCode:false,
|
|
55
|
+
routeName:route.name as string
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
//需要响应式放里面
|
|
59
|
+
let responsiveObj:{value:responsiveData} = ref({
|
|
60
|
+
resData:{}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
onMounted(()=>{
|
|
65
|
+
bus.$on('enterCode',(bol)=>{
|
|
66
|
+
data.enterCode = bol as boolean
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
watch(() => props.resData, (nv) => {
|
|
72
|
+
if(nv){
|
|
73
|
+
responsiveObj.value.resData = nv
|
|
74
|
+
}
|
|
75
|
+
},{immediate:true})
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
...toRefs(data),
|
|
80
|
+
responsiveObj
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
</script>
|
|
85
|
+
<style lang="scss" scoped>
|
|
86
|
+
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="time">{{responsiveObj.examTimeStr}}</span>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import {defineComponent, ref, toRef, toRefs, reactive, onMounted, watch, nextTick, getCurrentInstance} from 'vue'
|
|
7
|
+
import bus from "@/assets/js/bus";
|
|
8
|
+
import {useRoute} from "vue-router";
|
|
9
|
+
interface dataInterface{
|
|
10
|
+
timer:any
|
|
11
|
+
}
|
|
12
|
+
interface responsiveData{
|
|
13
|
+
examTime:number,
|
|
14
|
+
examTimeStr:string
|
|
15
|
+
}
|
|
16
|
+
export default defineComponent({
|
|
17
|
+
props: {
|
|
18
|
+
time: {
|
|
19
|
+
type: Number
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
components:{
|
|
23
|
+
|
|
24
|
+
},
|
|
25
|
+
setup(props, context) {
|
|
26
|
+
let route = useRoute()
|
|
27
|
+
let data:dataInterface = reactive({
|
|
28
|
+
timer:null
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
//需要响应式放里面
|
|
32
|
+
let responsiveObj:{value:responsiveData} = ref({
|
|
33
|
+
examTime:0,
|
|
34
|
+
examTimeStr:''
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if(props.time === undefined || props.time === null){
|
|
39
|
+
responsiveObj.value.examTimeStr = getExamTimeStr(0)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
watch(() => props.time, (nv) => {
|
|
44
|
+
responsiveObj.value.examTime = nv ? (nv < 0 ? 0: nv) : 0
|
|
45
|
+
// responsiveObj.value.examTime = 3000
|
|
46
|
+
responsiveObj.value.examTimeStr = getExamTimeStr(responsiveObj.value.examTime)
|
|
47
|
+
route.name === 'examIndex' && intervalGetExamTimeStr()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
bus.$on('stopTimeCounter',()=>{
|
|
51
|
+
clearInterval(data.timer)
|
|
52
|
+
data.timer = null
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/*function getExamTimeStr(examTime:number){
|
|
57
|
+
let hours = `${Math.floor(examTime / 3600000)}`
|
|
58
|
+
let min = `${Math.floor((examTime % 3600000) / 60000)}`
|
|
59
|
+
let s = `${Math.floor((examTime % 3600000 % 60000) / 1000 )}`
|
|
60
|
+
hours = Number(hours) < 10 ? `0${hours}` : hours
|
|
61
|
+
min = Number(min) < 10 ? `0${min}` : min
|
|
62
|
+
s = Number(s) < 10 ? `0${s}` : s
|
|
63
|
+
return `${hours}:${min}:${s}`
|
|
64
|
+
}*/
|
|
65
|
+
function getExamTimeStr(examTime:number){
|
|
66
|
+
let min = `${Math.floor(examTime / 60000)}`
|
|
67
|
+
let s = `${Math.floor((examTime % 60000) / 1000 )}`
|
|
68
|
+
min = Number(min) < 10 ? `0${min}` : min
|
|
69
|
+
s = Number(s) < 10 ? `0${s}` : s
|
|
70
|
+
return `${min}:${s}`
|
|
71
|
+
}
|
|
72
|
+
function intervalGetExamTimeStr(){
|
|
73
|
+
//一进来就没时间了和自然走到没时间要区分
|
|
74
|
+
if((props as any).time < 1000){
|
|
75
|
+
bus.$emit('examEnd',true)//true为是否初始化就是没时间
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
data.timer = setInterval(()=>{
|
|
79
|
+
// console.log(data.examTime);
|
|
80
|
+
if(responsiveObj.value.examTime < 1000){
|
|
81
|
+
responsiveObj.value.examTime = 0
|
|
82
|
+
clearInterval(data.timer)
|
|
83
|
+
data.timer = null
|
|
84
|
+
bus.$emit('examEnd')
|
|
85
|
+
}else{
|
|
86
|
+
let tenMin = 1000 * 60 * 10
|
|
87
|
+
if(responsiveObj.value.examTime <= tenMin && responsiveObj.value.examTime > tenMin - 1000){
|
|
88
|
+
bus.$emit('examNearEnd')
|
|
89
|
+
}
|
|
90
|
+
responsiveObj.value.examTime -= 1000
|
|
91
|
+
}
|
|
92
|
+
responsiveObj.value.examTimeStr = getExamTimeStr(responsiveObj.value.examTime)
|
|
93
|
+
},1000)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
...toRefs(data),
|
|
98
|
+
responsiveObj
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
105
|
+
<style scoped lang="scss">
|
|
106
|
+
|
|
107
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Created by Allen Liu on 2022/4/1.
|
|
3
|
+
*/
|
|
4
|
+
import Question_SingleChoice from '@src/components/questions/Question_SingleChoice.vue'
|
|
5
|
+
import Question_MultipleChoice from '@src/components/questions/Question_MultipleChoice.vue'
|
|
6
|
+
import Question_Programming from '@src/components/questions/Question_Programming.vue'
|
|
7
|
+
import Question_BriefAnswer from '@src/components/questions/Question_BriefAnswer.vue'
|
|
8
|
+
import Question_Reading from '@src/components/questions/Question_Reading.vue'
|
|
9
|
+
import Question_FillBlank from '@src/components/questions/Question_FillBlank.vue'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export default {
|
|
14
|
+
Question_SingleChoice,
|
|
15
|
+
Question_MultipleChoice,
|
|
16
|
+
Question_Programming,
|
|
17
|
+
Question_BriefAnswer,
|
|
18
|
+
Question_Reading,
|
|
19
|
+
Question_FillBlank
|
|
20
|
+
}
|