Commit 86201e49a31aabcf2ceea94015f500b285e76a2a
1 parent
53300a7b
即时测模块
Showing
5 changed files
with
1954 additions
and
0 deletions
src/views/basic/test/components/contrast.vue
0 → 100644
1 | +<template> | |
2 | + <div ref="main" class="page-container"> | |
3 | + <div class="page-content"> | |
4 | + <div class="content-header"> | |
5 | + <div class="tab-box"> | |
6 | + <span v-for="(item, index) in tabList" :key="item" class="tab-item" :class="type == index ? 'active' : ''" | |
7 | + @click="setType(index)">{{ item }}</span> | |
8 | + </div> | |
9 | + <el-button class="setMinScore" @click="openDia" round size="small">对比成绩等级设置</el-button> | |
10 | + </div> | |
11 | + <div id="print-content" class="table-box" v-loading="loading"> | |
12 | + <el-table :max-height="tableMaxHeight" v-show="type == 0" :data="tableData" border style="width: 100%"> | |
13 | + <el-table-column type="index" label="序号" fixed align="center" width="60"></el-table-column> | |
14 | + <el-table-column prop="className" label="班级" align="center" fixed></el-table-column> | |
15 | + <el-table-column label="测验人数/班级人数" align="center" width="84"> | |
16 | + <template slot-scope="scope"> | |
17 | + <p v-for="(item, index) in scope.row.count.split('/')"> | |
18 | + {{ item }}{{ index == 0 ? "/" : "" }} | |
19 | + </p> | |
20 | + </template> | |
21 | + </el-table-column> | |
22 | + <el-table-column prop="percent" label="参与度" align="center"></el-table-column> | |
23 | + <el-table-column prop="avg" label="班平均分" align="center"></el-table-column> | |
24 | + <el-table-column prop="max" label="班最高分" sortable align="center"></el-table-column> | |
25 | + <el-table-column prop="min" label="班最低分" sortable align="center"></el-table-column> | |
26 | + | |
27 | + <el-table-column v-for="(item, index) in defaultLevels.levels" :label="item[0] + '数(率)'" | |
28 | + align="center"><template slot-scope="scoped"> | |
29 | + <p class="p1">{{ scoped.row.levels[index].people }}</p> | |
30 | + <p class="p1">({{ scoped.row.levels[index].percent }})</p> | |
31 | + </template></el-table-column> | |
32 | + </el-table> | |
33 | + <el-table v-show="type == 1" :max-height="tableMaxHeight" :data="tableData2" border style="width: 100%"> | |
34 | + <el-table-column prop="rank" label="排名" sortable align="center"></el-table-column> | |
35 | + <el-table-column prop="name" label="姓名" align="center"></el-table-column> | |
36 | + <el-table-column prop="className" label="班级" align="center"></el-table-column> | |
37 | + <el-table-column prop="score" label="总分" sortable align="center"></el-table-column> | |
38 | + <el-table-column prop="levelName" label="成绩等级" align="center"></el-table-column> | |
39 | + </el-table> | |
40 | + </div> | |
41 | + <div class="down"> | |
42 | + <div> | |
43 | + <el-button v-loading="exportLoading" @click="exportData" type="primary" plain round | |
44 | + icon="fa fa-cloud-download">导出报表</el-button> | |
45 | + <el-button v-if="!this.$store.getters.code" @click="print" type="primary" plain round | |
46 | + icon="el-icon-printer">打印</el-button> | |
47 | + </div> | |
48 | + </div> | |
49 | + | |
50 | + <el-dialog :close-on-click-modal="false" title="等级设置" :visible.sync="diaLogBox" width="800px" @closed="closeDia"> | |
51 | + <el-form class="use-form"> | |
52 | + <el-form-item class="use-form-item-box"> | |
53 | + <el-form-item label="等级名称:" class="use-form-item"> | |
54 | + <el-select size="small" v-model="fromData.type" @change="changeType"> | |
55 | + <el-option label="优良合格不合格" :value="0"></el-option> | |
56 | + <el-option label="ABCD" :value="1"></el-option> | |
57 | + <el-option label="自定义" :value="2"></el-option> | |
58 | + </el-select> | |
59 | + </el-form-item> | |
60 | + <el-form-item label="等级设置模式:" class="use-form-item"> | |
61 | + <el-select size="small" v-model="fromData.levelType"> | |
62 | + <el-option label="按分数比例" :value="0"></el-option> | |
63 | + <el-option label="按已考人数比例" :value="1"></el-option> | |
64 | + </el-select> | |
65 | + </el-form-item> | |
66 | + </el-form-item> | |
67 | + <el-form-item> | |
68 | + <div class="dia-tab-box"> | |
69 | + <p class="dia-tab-tit"> | |
70 | + <span class="item1">编号</span> | |
71 | + <span class="item2"><i>*</i>等级名称</span> | |
72 | + <span class="item3"><i>*</i>等级最高</span> | |
73 | + <span class="item3"><i>*</i>等级最低</span> | |
74 | + <span class="item"></span> | |
75 | + </p> | |
76 | + <div class="dia-tab-item" v-for="(item, index) in fromData.levels"> | |
77 | + <span class="item1">{{ index + 1 }}</span> | |
78 | + <p class="item2"> | |
79 | + <el-input class="score-ipt" v-model="item[0]" :maxlength="12" | |
80 | + @keydown.native="keydownRange($event)"></el-input> | |
81 | + </p> | |
82 | + <p class="item3"> | |
83 | + <el-input class="score-ipt" type="number" v-model="item[1]" :min="item[2]" | |
84 | + :max="index == 0 ? 100 : fromData.levels[index - 1][2]" | |
85 | + @keydown.native="keydownRange($event)"></el-input> | |
86 | + % | |
87 | + <template v-if="fromData.levelType == 0"> | |
88 | + ({{ index != 0 ? "不含" : "" | |
89 | + }}{{ | |
90 | + Number(((item[1] / 100) * examPaperScore).toFixed(1)) | |
91 | +}}分) | |
92 | + </template> | |
93 | + <template v-else>{{ index != 0 ? "不含" : "" }}</template> | |
94 | + </p> | |
95 | + <p>~</p> | |
96 | + <p class="item3"> | |
97 | + <el-input class="score-ipt" type="number" v-model="item[2]" :min="0" :max="item[1]" | |
98 | + @keydown.native="keydownRange($event)"></el-input> | |
99 | + % | |
100 | + <template v-if="fromData.levelType == 0"> | |
101 | + ({{ | |
102 | + Number(((item[2] / 100) * examPaperScore).toFixed(1)) | |
103 | + }}分) | |
104 | + </template> | |
105 | + </p> | |
106 | + <p class="item"> | |
107 | + <el-link type="danger" :underline="false" @click="fromData.levels.splice(index, 1)">删除</el-link> | |
108 | + </p> | |
109 | + </div> | |
110 | + <div class="add"> | |
111 | + <p @click="fromData.levels.push(['', '', ''])"> | |
112 | + <el-button size="mini" icon="el-icon-plus" circle type="primary"></el-button>添加一行 | |
113 | + </p> | |
114 | + </div> | |
115 | + </div> | |
116 | + </el-form-item> | |
117 | + </el-form> | |
118 | + | |
119 | + <div class="dialog-footer" slot="footer" align="center"> | |
120 | + <el-button type="danger" @click="savefrom">保存</el-button> | |
121 | + <el-button @click="diaLogBox = false">取 消</el-button> | |
122 | + </div> | |
123 | + </el-dialog> | |
124 | + </div> | |
125 | + </div> | |
126 | +</template> | |
127 | + | |
128 | +<script> | |
129 | +import { downloadFile, tablePrint } from "@/utils"; | |
130 | +export default { | |
131 | + props: { | |
132 | + role: "", | |
133 | + ids: Array, | |
134 | + classId: String, | |
135 | + subjectName: String, | |
136 | + title: String, | |
137 | + }, | |
138 | + data() { | |
139 | + return { | |
140 | + tabList: ["班级对比情况", "学生成绩排名"], | |
141 | + type: 0, | |
142 | + loading: false, | |
143 | + exportLoading: false, | |
144 | + diaLogBox: false, | |
145 | + fromData: { | |
146 | + type: 0, | |
147 | + levelType: 0, | |
148 | + levels: [ | |
149 | + ["优秀", 100, 90], | |
150 | + ["良好", 89.9, 70], | |
151 | + ["合格", 69.9, 60], | |
152 | + ["不合格", 59.9, 0], | |
153 | + ], | |
154 | + }, | |
155 | + defaultLevels: { | |
156 | + levelType: 0, | |
157 | + levels: [], | |
158 | + }, | |
159 | + tableMaxHeight: 600, | |
160 | + tableData: [], | |
161 | + tableData2: [], | |
162 | + examPaperScore: 100, //卷面最高分 | |
163 | + }; | |
164 | + }, | |
165 | + async created() { | |
166 | + await this._QueryData(); | |
167 | + await this._QueryDefaultLevels(); | |
168 | + }, | |
169 | + destroyed() { | |
170 | + sessionStorage.setItem("levelFromData", ""); | |
171 | + }, | |
172 | + methods: { | |
173 | + // 禁止输入负数 | |
174 | + keydownRange(event) { | |
175 | + if (event.key == "-" || event.key == "e") { | |
176 | + event.returnValue = ""; | |
177 | + } | |
178 | + }, | |
179 | + print() { | |
180 | + tablePrint( | |
181 | + "print-content", | |
182 | + `多班_${this.subjectName}_${this.title}_测练成绩对比分析` | |
183 | + ); | |
184 | + }, | |
185 | + setType(type) { | |
186 | + console.log(this.$refs.main.offsetHeight - 50); | |
187 | + this.tableMaxHeight = this.$refs.main.offsetHeight; | |
188 | + this.type = type; | |
189 | + }, | |
190 | + openDia() { | |
191 | + this.diaLogBox = true; | |
192 | + }, | |
193 | + closeDia() { | |
194 | + let levelFromData = sessionStorage.getItem("levelFromData"); | |
195 | + if (levelFromData) { | |
196 | + levelFromData = JSON.parse(levelFromData); | |
197 | + this.fromData.type = levelFromData.type; | |
198 | + this.fromData.levelType = levelFromData.levelType; | |
199 | + this.fromData.levels = [...levelFromData.levels]; | |
200 | + } else { | |
201 | + this.fromData.type = 0; | |
202 | + this.fromData.levelType = this.defaultLevels.levelType; | |
203 | + this.fromData.levels = [...this.defaultLevels.levels]; | |
204 | + } | |
205 | + }, | |
206 | + changeType(val) { | |
207 | + if (val == this.defaultLevels.type) { | |
208 | + this.fromData.levels = [...this.defaultLevels.levels]; | |
209 | + } else { | |
210 | + this.fromData.levels = this.fromData.levels.splice(0, 4); | |
211 | + if (val == 0) { | |
212 | + this.fromData.levels = this.fromData.levels.map((item, index) => { | |
213 | + let arrTxt = ["优秀", "良好", "合格", "不合格"]; | |
214 | + return [arrTxt[index], item[1], item[2]]; | |
215 | + }); | |
216 | + } else if (val == 1) { | |
217 | + this.fromData.levels = this.fromData.levels.map((item, index) => { | |
218 | + let arrTxt = ["A", "B", "C", "D"]; | |
219 | + return [arrTxt[index], item[1], item[2]]; | |
220 | + }); | |
221 | + } else { | |
222 | + this.fromData.levels = this.fromData.levels.map((item, index) => { | |
223 | + return ["", item[1], item[2]]; | |
224 | + }); | |
225 | + } | |
226 | + } | |
227 | + }, | |
228 | + savefrom() { | |
229 | + for (let i = 0; i < this.fromData.levels.length; i++) { | |
230 | + if (this.fromData.levels[i].includes("")) { | |
231 | + this.$message.warning("请补全编号" + (i + 1) + "设置信息!"); | |
232 | + return; | |
233 | + } | |
234 | + } | |
235 | + if (this.fromData.levels.length == 0) { | |
236 | + this.$message.warning("请添加等级设置!"); | |
237 | + return; | |
238 | + } | |
239 | + let nums = []; | |
240 | + let ERR_OK = false; | |
241 | + this.fromData.levels.map((item) => { | |
242 | + nums.push(Number(item[1])); | |
243 | + nums.push(Number(item[2])); | |
244 | + }); | |
245 | + for (let i = 0; i < nums.length; i++) { | |
246 | + if (nums[i + 1] && nums[i + 1] > nums[i]) { | |
247 | + ERR_OK = true; | |
248 | + this.$message.warning("高等级比例不能低于低等级比例!请检查"); | |
249 | + break; | |
250 | + } | |
251 | + } | |
252 | + if (ERR_OK) return; | |
253 | + this.tableData = []; | |
254 | + this.tableData2 = []; | |
255 | + this.defaultLevels.type = this.fromData.type; | |
256 | + this.defaultLevels.levelType = this.fromData.levelType; | |
257 | + this.defaultLevels.levels = [...this.fromData.levels]; | |
258 | + sessionStorage.setItem("levelFromData", JSON.stringify(this.fromData)); | |
259 | + this.diaLogBox = false; | |
260 | + this._QueryData({ | |
261 | + levelType: this.fromData.levelType, | |
262 | + levels: this.fromData.levels, | |
263 | + }); | |
264 | + }, | |
265 | + | |
266 | + async _QueryDefaultLevels() { | |
267 | + const { data, info, status } = await this.$request.defaultLevels(); | |
268 | + if (status === 0) { | |
269 | + this.defaultLevels = { ...data } || { | |
270 | + levelType: 0, | |
271 | + levels: [ | |
272 | + ["优秀", 100, 90], | |
273 | + ["良好", 89.9, 70], | |
274 | + ["合格", 69.9, 60], | |
275 | + ["不合格", 59.9, 0], | |
276 | + ], | |
277 | + }; | |
278 | + this.defaultLevels.type = 0 | |
279 | + this.fromData.levelType = this.defaultLevels.levelType; | |
280 | + this.fromData.levels = [...this.defaultLevels.levels]; | |
281 | + sessionStorage.setItem( | |
282 | + "levelFromData", | |
283 | + JSON.stringify(this.defaultLevels) | |
284 | + ); | |
285 | + } else { | |
286 | + this.$message.error(info); | |
287 | + } | |
288 | + }, | |
289 | + async _QueryData(params) { | |
290 | + let query = {}; | |
291 | + if (params) { | |
292 | + let paramObj = JSON.parse(JSON.stringify(params)) | |
293 | + if (paramObj.levelType == 0) { | |
294 | + paramObj.levels = paramObj.levels.map((item) => { | |
295 | + item[1] = ((item[1] / 100) * this.examPaperScore).toFixed(1); | |
296 | + item[2] = ((item[2] / 100) * this.examPaperScore).toFixed(1); | |
297 | + return item; | |
298 | + }); | |
299 | + } | |
300 | + query = { ...paramObj }; | |
301 | + } | |
302 | + const { data, info, status } = await this.$request.examMultiClassReport({ | |
303 | + examIds: this.ids, | |
304 | + ...query, | |
305 | + }); | |
306 | + if (status === 0) { | |
307 | + this.examPaperScore = data.examPaperScore || 100; | |
308 | + this.tableData = data.classes || []; | |
309 | + this.tableData2 = | |
310 | + data.students.map((item) => { | |
311 | + item.score = Number(item.score); | |
312 | + return item; | |
313 | + }) || []; | |
314 | + } else { | |
315 | + this.$message.error(info); | |
316 | + } | |
317 | + }, | |
318 | + | |
319 | + //导出 | |
320 | + async exportData() { | |
321 | + if (this.exportLoading == true) return; | |
322 | + this.exportLoading = true; | |
323 | + let params = { ...this.fromData }; | |
324 | + if (params.levelType == 0) { | |
325 | + params.levels = params.levels.map((item) => { | |
326 | + console.log(item); | |
327 | + item[1] = ((item[1] / 100) * this.examPaperScore).toFixed(1); | |
328 | + item[2] = ((item[2] / 100) * this.examPaperScore).toFixed(1); | |
329 | + return item; | |
330 | + }); | |
331 | + } | |
332 | + const data = await this.$request.exportExamMultiReport({ | |
333 | + examIds: this.ids, | |
334 | + levels: params.levels, | |
335 | + levelType: params.levelType, | |
336 | + }); | |
337 | + this.exportLoading = false; | |
338 | + if (data) { | |
339 | + let blob = new Blob([data], { | |
340 | + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | |
341 | + }); | |
342 | + downloadFile( | |
343 | + `多班_${this.subjectNames}_${this.title}_测练成绩对比分析`, | |
344 | + blob | |
345 | + ); | |
346 | + } else { | |
347 | + this.$message.error("下载失败"); | |
348 | + } | |
349 | + }, | |
350 | + }, | |
351 | +}; | |
352 | +</script> | |
353 | + | |
354 | +<style lang="scss" scoped> | |
355 | +.page-container { | |
356 | + position: relative; | |
357 | + height: 100%; | |
358 | + | |
359 | + .table-box { | |
360 | + min-height: 100%; | |
361 | + } | |
362 | + | |
363 | + &.active { | |
364 | + overflow: hidden; | |
365 | + } | |
366 | + | |
367 | + .content-header { | |
368 | + width: 100%; | |
369 | + position: relative; | |
370 | + | |
371 | + .setMinScore { | |
372 | + position: absolute; | |
373 | + bottom: 0; | |
374 | + right: 0; | |
375 | + } | |
376 | + } | |
377 | + | |
378 | + .page-content { | |
379 | + padding: 20px 20px 0; | |
380 | + } | |
381 | +} | |
382 | + | |
383 | +.tab-box { | |
384 | + width: 400px; | |
385 | + margin: 0 auto 12px; | |
386 | + background: #f8f8f8; | |
387 | + border-radius: 20px; | |
388 | + display: flex; | |
389 | + user-select: none; | |
390 | + | |
391 | + .tab-item { | |
392 | + flex: 1; | |
393 | + height: 40px; | |
394 | + line-height: 40px; | |
395 | + text-align: center; | |
396 | + font-size: 16px; | |
397 | + color: #666; | |
398 | + font-weight: 500; | |
399 | + background: transparent; | |
400 | + border-radius: 20px; | |
401 | + cursor: pointer; | |
402 | + | |
403 | + &.active { | |
404 | + background: #667ffd; | |
405 | + color: #fff; | |
406 | + } | |
407 | + } | |
408 | +} | |
409 | + | |
410 | +.down { | |
411 | + padding-top: 20px; | |
412 | + width: 100%; | |
413 | + display: flex; | |
414 | + justify-content: space-between; | |
415 | +} | |
416 | + | |
417 | +.use-form { | |
418 | + padding: 0 12px; | |
419 | + | |
420 | + .use-form-item-box { | |
421 | + :deep(.el-form-item__content) { | |
422 | + display: flex; | |
423 | + } | |
424 | + | |
425 | + .use-form-item { | |
426 | + width: 40%; | |
427 | + margin-right: 20px; | |
428 | + } | |
429 | + } | |
430 | +} | |
431 | + | |
432 | +.dia-tab-box { | |
433 | + | |
434 | + .dia-tab-tit, | |
435 | + .dia-tab-item { | |
436 | + margin-bottom: 10px; | |
437 | + | |
438 | + i { | |
439 | + color: #f30; | |
440 | + padding-right: 5px; | |
441 | + } | |
442 | + | |
443 | + display: flex; | |
444 | + | |
445 | + .item { | |
446 | + width: 40px; | |
447 | + } | |
448 | + | |
449 | + .item1 { | |
450 | + padding-left: 10px; | |
451 | + width: 10%; | |
452 | + } | |
453 | + | |
454 | + .item2 { | |
455 | + width: 18%; | |
456 | + } | |
457 | + | |
458 | + .item3 { | |
459 | + padding-left: 12px; | |
460 | + flex: 1; | |
461 | + } | |
462 | + | |
463 | + .score-ipt { | |
464 | + width: 100px; | |
465 | + } | |
466 | + } | |
467 | + | |
468 | + .dia-tab-tit { | |
469 | + background: rgba(243, 243, 243, 1); | |
470 | + } | |
471 | + | |
472 | + .add { | |
473 | + display: flex; | |
474 | + justify-content: center; | |
475 | + margin: 0 auto; | |
476 | + | |
477 | + p { | |
478 | + cursor: pointer; | |
479 | + } | |
480 | + | |
481 | + .el-button { | |
482 | + margin-right: 6px; | |
483 | + } | |
484 | + } | |
485 | +} | |
486 | + | |
487 | +.p1 { | |
488 | + line-height: 18px; | |
489 | +} | |
490 | +</style> | |
0 | 491 | \ No newline at end of file | ... | ... |
src/views/basic/test/components/multipleSubTest.vue
0 → 100644
1 | +<template> | |
2 | + <div class="table-box" ref="main" v-loading="loading"> | |
3 | + <div id="print-content"> | |
4 | + <!-- 多科多卷 --> | |
5 | + <el-table :data="tableData" :max-height="tableMaxHeight" border style="width: 100%"> | |
6 | + <el-table-column prop="studentCode" label="学号" align="center" fixed></el-table-column> | |
7 | + | |
8 | + <el-table-column prop="studentName" label="姓名" fixed align="center"> | |
9 | + <template slot-scope="scoped"><span class="click-b" @click="toPortrait(scoped.row)"> | |
10 | + {{ scoped.row.studentName }} | |
11 | + </span></template> | |
12 | + </el-table-column> | |
13 | + <el-table-column align="center" v-for="(item, index) in answerList" :key="index" :label="item"> | |
14 | + <el-table-column :prop="'examCount' + item" label="测练数" align="center" | |
15 | + :class-name="index % 2 == 0 ? 'bg' : ''"></el-table-column> | |
16 | + <el-table-column :prop="'participationCount' + item" label="参与数" align="center" | |
17 | + :class-name="index % 2 == 0 ? 'bg' : ''"></el-table-column> | |
18 | + <el-table-column :prop="'score' + item" label="总分" align="center" | |
19 | + :class-name="index % 2 == 0 ? 'bg' : ''"></el-table-column> | |
20 | + <el-table-column :prop="'classRank' + item" label="班名" align="center" | |
21 | + :class-name="index % 2 == 0 ? 'bg' : ''"></el-table-column> | |
22 | + </el-table-column> | |
23 | + <el-table-column label="查看折线图" align="center"> | |
24 | + <template slot-scope="scoped"> | |
25 | + <el-button @click="openChart(scoped.row)" type="primary" size="mini" circle | |
26 | + icon="el-icon-arrow-right"></el-button> | |
27 | + </template> | |
28 | + </el-table-column> | |
29 | + </el-table> | |
30 | + </div> | |
31 | + <div class="down"> | |
32 | + <el-button @click="exportData" type="primary" plain round icon="fa fa-cloud-download">导出报表</el-button> | |
33 | + <el-button v-if="!this.$store.getters.code" @click="print" type="primary" plain round | |
34 | + icon="el-icon-printer">打印</el-button> | |
35 | + </div> | |
36 | + <el-dialog class="chart-dia" :visible.sync="chartDia" :title="chartTitle" width="800"> | |
37 | + <div class="chart-box"> | |
38 | + <RadarChart id="radarChart" :params="chartData" /> | |
39 | + </div> | |
40 | + </el-dialog> | |
41 | + </div> | |
42 | +</template> | |
43 | +<script> | |
44 | +import RadarChart from "@/components/charts/radarChart" | |
45 | + | |
46 | +import { downloadFile, tablePrint } from "@/utils"; | |
47 | +export default { | |
48 | + components: { | |
49 | + RadarChart | |
50 | + }, | |
51 | + props: { | |
52 | + role: "", | |
53 | + ids: Array, | |
54 | + classId: String, | |
55 | + subjectName: String, | |
56 | + }, | |
57 | + data() { | |
58 | + return { | |
59 | + tableMaxHeight: null, | |
60 | + answerList: [], //设置多卷内容供tableStage表格数据用 | |
61 | + tableData: [], | |
62 | + loading: false, | |
63 | + exportLoading: false, | |
64 | + chartData: { | |
65 | + indicator: [ | |
66 | + { | |
67 | + name: '', max: 100, | |
68 | + axisLabel: { | |
69 | + show: true, | |
70 | + showMaxLabel: true, | |
71 | + formatter: '{value}%' | |
72 | + }, | |
73 | + }, | |
74 | + ], | |
75 | + seriesData: [] | |
76 | + }, | |
77 | + chartDia: false, | |
78 | + chartTitle: "", | |
79 | + } | |
80 | + }, | |
81 | + computed: { | |
82 | + subjectList: function () { | |
83 | + return this.subjectName?.split(",") | |
84 | + } | |
85 | + }, | |
86 | + created() { | |
87 | + this.phaseExamReport() | |
88 | + }, | |
89 | + mounted() { | |
90 | + this.tableMaxHeight = this.$refs.main.offsetHeight; | |
91 | + }, | |
92 | + methods: { | |
93 | + print() { | |
94 | + tablePrint("print-content", this.title + this.tabList[this.type]); | |
95 | + }, | |
96 | + toPortrait(obj) { | |
97 | + //暂时不上线 | |
98 | + return; | |
99 | + if (this.$store.getters.code) { | |
100 | + return; | |
101 | + } | |
102 | + let subjectNames = []; | |
103 | + subjectNames = | |
104 | + this.role == "ROLE_BANZHUREN" | |
105 | + ? [...this.query["subjectNames"]] | |
106 | + : [this.query["subjectNames"]]; | |
107 | + if ( | |
108 | + this.query["subjectNames"] && | |
109 | + this.query["subjectNames"]?.length == 1 && | |
110 | + this.query["subjectNames"][0] == "全部" | |
111 | + ) { | |
112 | + subjectNames = this.subjectList.map((item) => { | |
113 | + return item.value; | |
114 | + }); | |
115 | + subjectNames?.shift(); | |
116 | + } | |
117 | + //去学生画像 | |
118 | + this.$router.push({ | |
119 | + path: "/portraitDetail", | |
120 | + query: { | |
121 | + id: obj.studentId, | |
122 | + classId: this.query.classId, | |
123 | + subjectNames: subjectNames.join(","), | |
124 | + studentName: obj.studentName, | |
125 | + studentCode: obj.studentCode, | |
126 | + startDay: this.query.startDay, | |
127 | + endDay: this.query.endDay, | |
128 | + date: this.date, | |
129 | + }, | |
130 | + }); | |
131 | + }, | |
132 | + //查看折线图 | |
133 | + openChart(obj) { | |
134 | + this.chartTitle = obj.studentName + '-多科-多课时作答表现图' | |
135 | + let subjectList = obj.dataList.map(item => item.subjectName) | |
136 | + subjectList.map((item, index) => { | |
137 | + if (index < 1) { | |
138 | + this.chartData.indicator[index].name = item | |
139 | + } else { | |
140 | + this.chartData.indicator.push({ name: item, max: 100 }) | |
141 | + } | |
142 | + }) | |
143 | + if (this.chartData.indicator.length < 3) { | |
144 | + let num = this.chartData.indicator.length | |
145 | + for (let i = 0; i < 6; i++) { | |
146 | + if (i >= num) { | |
147 | + this.chartData.indicator.push({ name: "", max: 100 }) | |
148 | + } | |
149 | + } | |
150 | + } | |
151 | + this.chartData.seriesData = [ | |
152 | + { | |
153 | + value: obj.dataList.map(item => item.participationRate), | |
154 | + name: '参与度' | |
155 | + }, | |
156 | + { | |
157 | + value: obj.dataList.map(item => item.correctRate), | |
158 | + name: '正确率' | |
159 | + }, | |
160 | + ] | |
161 | + this.chartDia = true | |
162 | + | |
163 | + | |
164 | + }, | |
165 | + async phaseExamReport() { | |
166 | + this.loading = true; | |
167 | + const { data, status, info } = await this.$request.cTPhaseExamReport({ | |
168 | + classId: this.classId, | |
169 | + examIds: this.ids, | |
170 | + subjectNames: this.subjectList, | |
171 | + }); | |
172 | + this.loading = false; | |
173 | + if (status === 0) { | |
174 | + this.total = data.count; | |
175 | + let subjectName = []; | |
176 | + this.tableData = data?.list.map((item) => { | |
177 | + let params = {}; | |
178 | + item.dataList.map((items, index) => { | |
179 | + if (!subjectName.includes(items.subjectName)) { | |
180 | + subjectName.push(items.subjectName); | |
181 | + } | |
182 | + params["examCount" + items.subjectName] = items.examCount; | |
183 | + params["participationCount" + items.subjectName] = | |
184 | + items.participationCount; | |
185 | + params["score" + items.subjectName] = items.score; | |
186 | + params["classRank" + items.subjectName] = items.classRank; | |
187 | + }); | |
188 | + return { | |
189 | + ...item, | |
190 | + ...params, | |
191 | + }; | |
192 | + }); | |
193 | + this.answerList = [...subjectName]; | |
194 | + } else { | |
195 | + this.$message.error(info); | |
196 | + } | |
197 | + }, | |
198 | + //导出 | |
199 | + async exportData() { | |
200 | + if (this.exportLoading == true) return; | |
201 | + this.exportLoading = true; | |
202 | + const data = await this.$request.exportExamReport({ | |
203 | + examId: this.ids, | |
204 | + }); | |
205 | + this.exportLoading = false; | |
206 | + if (data) { | |
207 | + let blob = new Blob([data], { | |
208 | + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | |
209 | + }); | |
210 | + downloadFile( | |
211 | + this.status | |
212 | + ? "即时测-已归档单卷测练报表.xlsx" | |
213 | + : "即时测-单卷测练报表.xlsx", | |
214 | + blob | |
215 | + ); | |
216 | + } else { | |
217 | + this.$message.error("下载失败"); | |
218 | + } | |
219 | + }, | |
220 | + } | |
221 | +}; | |
222 | +</script> | |
223 | +<style lang="scss" scoped> | |
224 | +.table-box { | |
225 | + padding: 20px; | |
226 | +} | |
227 | + | |
228 | +.down { | |
229 | + padding-top: 20px; | |
230 | + width: 100%; | |
231 | + display: flex; | |
232 | + justify-content: space-between; | |
233 | +} | |
234 | + | |
235 | +.chart-dia { | |
236 | + .chart-box { | |
237 | + width: 100%; | |
238 | + height: 400px; | |
239 | + } | |
240 | + | |
241 | + :deep(.el-dialog__body) { | |
242 | + padding: 0 0 20px 0; | |
243 | + } | |
244 | +} | |
245 | +</style> | ... | ... |
src/views/basic/test/components/multipleTest.vue
0 → 100644
1 | +<template> | |
2 | + <div class="table-box" ref="main" v-loading="loading"> | |
3 | + <div id="print-content"> | |
4 | + <el-table :max-height="tableMaxHeight" :data="tableData" border style="width: 100%"> | |
5 | + <el-table-column prop="studentCode" label="学号" align="center" fixed></el-table-column> | |
6 | + <el-table-column prop="studentName" label="姓名" fixed align="center"> | |
7 | + <template slot-scope="scoped"><span class="click-b" @click="toPortrait(scoped.row)"> | |
8 | + {{ scoped.row.studentName }} | |
9 | + </span></template></el-table-column> | |
10 | + <el-table-column align="center" v-for="(item, index) in answerList" :key="index" :label="item.title"> | |
11 | + <el-table-column :prop="'score' + index" :label="index == 0 ? '总分' : '成绩'" align="center" | |
12 | + :class-name="index % 2 == 0 ? 'bg' : ''"></el-table-column> | |
13 | + <el-table-column :prop="'classRank' + index" label="班名" align="center" sortable | |
14 | + :class-name="index % 2 == 0 ? 'bg' : ''"></el-table-column> | |
15 | + </el-table-column> | |
16 | + <el-table-column label="查看折线图" align="center"> | |
17 | + <template slot-scope="scoped"> | |
18 | + <el-button @click="openChart(scoped.row)" type="primary" size="mini" circle | |
19 | + icon="el-icon-arrow-right"></el-button> | |
20 | + </template> | |
21 | + </el-table-column> | |
22 | + </el-table> | |
23 | + </div> | |
24 | + <div class="down"> | |
25 | + <el-button @click="exportData" type="primary" plain round icon="fa fa-cloud-download">导出报表</el-button> | |
26 | + <el-button v-if="!this.$store.getters.code" @click="print" type="primary" plain round | |
27 | + icon="el-icon-printer">打印</el-button> | |
28 | + </div> | |
29 | + <el-dialog class="chart-dia" :visible.sync="chartDia" :title="chartTitle" width="800"> | |
30 | + <div class="chart-box"> | |
31 | + <LineChart id="lineChart" :params="chartData" :xAxis="xAxis" /> | |
32 | + </div> | |
33 | + </el-dialog> | |
34 | + </div> | |
35 | + <!-- 单科多卷 --> | |
36 | +</template> | |
37 | +<script> | |
38 | +import LineChart from "@/components/charts/lineChart" | |
39 | +import { downloadFile, tablePrint } from "@/utils"; | |
40 | +export default { | |
41 | + components: { LineChart }, | |
42 | + props: { | |
43 | + role: "", | |
44 | + ids: Array, | |
45 | + classId: String, | |
46 | + subjectName: String, | |
47 | + }, | |
48 | + data() { | |
49 | + return { | |
50 | + tableMaxHeight: null, | |
51 | + answerList: [], //设置多卷内容供tableStage表格数据用 | |
52 | + tableData: [], | |
53 | + loading: false, | |
54 | + exportLoading: false, | |
55 | + chartDia: false, | |
56 | + studentName: "", | |
57 | + xAxis: [], | |
58 | + chartData: [], | |
59 | + } | |
60 | + }, | |
61 | + computed: { | |
62 | + chartTitle: function () { | |
63 | + return `${this.studentName}-${this.subjectName}-多课时作答表现图` | |
64 | + } | |
65 | + }, | |
66 | + created() { | |
67 | + this.phaseExamReport() | |
68 | + }, | |
69 | + mounted() { | |
70 | + this.tableMaxHeight = this.$refs.main.offsetHeight; | |
71 | + }, | |
72 | + methods: { | |
73 | + print() { | |
74 | + tablePrint("print-content", this.subjectName + '汇总报表'); | |
75 | + }, | |
76 | + toPortrait(obj) { | |
77 | + //暂时不上线 | |
78 | + return; | |
79 | + if (this.$store.getters.code) { | |
80 | + return; | |
81 | + } | |
82 | + let subjectNames = []; | |
83 | + subjectNames = | |
84 | + this.role == "ROLE_BANZHUREN" | |
85 | + ? [...this.query["subjectNames"]] | |
86 | + : [this.query["subjectNames"]]; | |
87 | + if ( | |
88 | + this.query["subjectNames"] && | |
89 | + this.query["subjectNames"]?.length == 1 && | |
90 | + this.query["subjectNames"][0] == "全部" | |
91 | + ) { | |
92 | + subjectNames = this.subjectList.map((item) => { | |
93 | + return item.value; | |
94 | + }); | |
95 | + subjectNames?.shift(); | |
96 | + } | |
97 | + //去学生画像 | |
98 | + this.$router.push({ | |
99 | + path: "/portraitDetail", | |
100 | + query: { | |
101 | + id: obj.studentId, | |
102 | + classId: this.query.classId, | |
103 | + subjectNames: subjectNames.join(","), | |
104 | + studentName: obj.studentName, | |
105 | + studentCode: obj.studentCode, | |
106 | + startDay: this.query.startDay, | |
107 | + endDay: this.query.endDay, | |
108 | + date: this.date, | |
109 | + }, | |
110 | + }); | |
111 | + }, | |
112 | + //查看折线图 | |
113 | + openChart(obj) { | |
114 | + this.studentName = obj.studentName | |
115 | + this.chartDia = true | |
116 | + let participationRate = [] | |
117 | + let correctRate = [] | |
118 | + let answerCorrectRate = [] | |
119 | + this.xAxis = obj.examList.map(item => { | |
120 | + participationRate.push(item.participationRate) | |
121 | + correctRate.push(item.correctRate) | |
122 | + answerCorrectRate.push(item.answerCorrectRate) | |
123 | + return item.title | |
124 | + }) | |
125 | + this.chartData = [ | |
126 | + { | |
127 | + name: "参与度", | |
128 | + value: participationRate | |
129 | + }, | |
130 | + { | |
131 | + name: "正确率", | |
132 | + value: correctRate | |
133 | + }, | |
134 | + { | |
135 | + name: "已答正确率", | |
136 | + value: answerCorrectRate | |
137 | + }, | |
138 | + ] | |
139 | + | |
140 | + }, | |
141 | + async phaseExamReport() { | |
142 | + this.loading = true; | |
143 | + const phaseExamReport = | |
144 | + this.role == "ROLE_PERSONAL" | |
145 | + ? this.$request.pPhaseExamReport | |
146 | + : this.$request.phaseExamReport; | |
147 | + const { data, status, info } = await phaseExamReport({ | |
148 | + classId: this.classId, | |
149 | + examIds: this.ids, | |
150 | + subjectName: this.subjectName | |
151 | + }); | |
152 | + this.loading = false; | |
153 | + if (status === 0) { | |
154 | + this.total = data.count; | |
155 | + let dataIdsList = [], | |
156 | + dataList = []; | |
157 | + data?.list.map((item) => { | |
158 | + item.examList.map((items) => { | |
159 | + if (!dataIdsList.includes(items.title)) { | |
160 | + dataIdsList.push(items.title); | |
161 | + dataList.push(items); | |
162 | + } | |
163 | + }); | |
164 | + }); | |
165 | + this.tableData = data?.list.map((item) => { | |
166 | + let params = {}; | |
167 | + dataIdsList.map((ids, index) => { | |
168 | + params["score" + index] = "--"; | |
169 | + params["classRank" + index] = "--"; | |
170 | + item.examList.map((items) => { | |
171 | + if (items.title == ids) { | |
172 | + params["score" + index] = items.score; | |
173 | + params["classRank" + index] = items.classRank; | |
174 | + } | |
175 | + }); | |
176 | + }); | |
177 | + return { | |
178 | + ...item, | |
179 | + ...params, | |
180 | + }; | |
181 | + }); | |
182 | + this.answerList = dataList; | |
183 | + } else { | |
184 | + this.$message.error(info); | |
185 | + } | |
186 | + }, | |
187 | + //导出 | |
188 | + async exportData() { | |
189 | + if (this.exportLoading == true) return; | |
190 | + this.exportLoading = true; | |
191 | + const exportPhaseExamReport = this.role == "ROLE_PERSONAL" | |
192 | + ? this.$request.pExportPhaseExamReport | |
193 | + : this.$request.exportPhaseExamReport; | |
194 | + const data = await exportPhaseExamReport({ | |
195 | + examId: this.ids, | |
196 | + }); | |
197 | + this.exportLoading = false; | |
198 | + if (data) { | |
199 | + let blob = new Blob([data], { | |
200 | + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | |
201 | + }); | |
202 | + downloadFile("即时测-单科多卷报表.xlsx", blob); | |
203 | + } else { | |
204 | + this.$message.error("下载失败"); | |
205 | + } | |
206 | + }, | |
207 | + } | |
208 | +}; | |
209 | +</script> | |
210 | +<style lang="scss" scoped> | |
211 | +.table-box { | |
212 | + padding: 20px; | |
213 | +} | |
214 | + | |
215 | +.down { | |
216 | + padding-top: 20px; | |
217 | + width: 100%; | |
218 | + display: flex; | |
219 | + justify-content: space-between; | |
220 | +} | |
221 | + | |
222 | + | |
223 | + | |
224 | +.chart-dia { | |
225 | + .chart-box { | |
226 | + width: 100%; | |
227 | + height: 300px; | |
228 | + } | |
229 | + | |
230 | + :deep(.el-dialog__body) { | |
231 | + padding: 0 0 20px 0; | |
232 | + } | |
233 | +} | |
234 | +</style> | ... | ... |
src/views/basic/test/components/scoreSet.vue
0 → 100644
1 | +<template> | |
2 | + <div class="set-container"> | |
3 | + <div class="back"> | |
4 | + <div class="back-l" @click="closeScoreSet"> | |
5 | + <i class="fa fa-mail-reply-all"></i> | |
6 | + <span>答卷录分</span> | |
7 | + </div> | |
8 | + </div> | |
9 | + <div class="set-content"> | |
10 | + <div class="test-title"> | |
11 | + <el-button class="import-btn" type="primary" round @click="diaUp = true">从excel文件导入</el-button> | |
12 | + <p class="p1">{{ title }}</p> | |
13 | + <p class="p2">卷面总分:{{ examScore }}分</p> | |
14 | + </div> | |
15 | + <el-table :data="tableData" border style="width: 100%"> | |
16 | + <el-table-column prop="studentCode" label="学号" align="center" fixed></el-table-column> | |
17 | + <el-table-column prop="studentName" label="学号" align="center" fixed></el-table-column> | |
18 | + <el-table-column label="总得分" align="center" fixed></el-table-column> | |
19 | + <el-table-column label="客观题分" align="center"></el-table-column> | |
20 | + <el-table-column label="主观题分" align="center"></el-table-column> | |
21 | + <el-table-column v-for="(item, index) in questionList" :key="index" :label="'第' + cNum[index] + '大题'" | |
22 | + align="center"> | |
23 | + <el-table-column prop="score" v-for="(question, indexs) in item.subQuestions" :label="'Q' + question.id" | |
24 | + align="center"> | |
25 | + <template slot-scope="scoped"> | |
26 | + <el-input type="number" :min="0" | |
27 | + v-model="scoped.row.questionList[index].subQuestions[indexs].score"></el-input> | |
28 | + </template> | |
29 | + </el-table-column> | |
30 | + </el-table-column> | |
31 | + </el-table> | |
32 | + <p class="btn-box"> | |
33 | + <el-button type="primary" :loading="loadingSave" @click="_SubmitScore">保存</el-button> | |
34 | + </p> | |
35 | + </div> | |
36 | + | |
37 | + <el-dialog :close-on-click-modal="false" :append-to-body="true" title="答卷录分" :visible.sync="diaUp" width="600px" | |
38 | + top="120px"> | |
39 | + <upload :url="url" :examId="id" @upSuccess="upSuccess" fileName="主观题分数" v-loading="loadingDown"> | |
40 | + <template slot="down"> | |
41 | + <p class="down-txt"> | |
42 | + 第一步:<el-link type="danger" @click="downExcel">下载模板</el-link>,并编辑完成学生分数。 | |
43 | + </p> | |
44 | + <p class="down-txt">第二步:上传完成编辑的模板文件并导入。</p> | |
45 | + </template> | |
46 | + </upload> | |
47 | + <div class="dialog-footer" slot="footer"> | |
48 | + <el-button @click="diaUp = false">取 消</el-button> | |
49 | + </div> | |
50 | + </el-dialog> | |
51 | + </div> | |
52 | +</template> | |
53 | +<script> | |
54 | +import { downloadFile, cNum } from "utils"; | |
55 | +export default { | |
56 | + props: { | |
57 | + title: String, | |
58 | + id: String, | |
59 | + role: String, | |
60 | + examScore: { | |
61 | + type: Number, | |
62 | + default: 0 | |
63 | + }, | |
64 | + }, | |
65 | + data() { | |
66 | + return { | |
67 | + diaUp: false, | |
68 | + loading: false, | |
69 | + loadingDown: false, | |
70 | + loadingSave: false, | |
71 | + url: "/api_html/teaching/importScore", | |
72 | + tableData: [], | |
73 | + questionList: [], | |
74 | + cNum: cNum | |
75 | + } | |
76 | + }, | |
77 | + watch: { | |
78 | + id: { | |
79 | + handler: function (nVal) { | |
80 | + if (nVal) { | |
81 | + this._QueryData() | |
82 | + } | |
83 | + }, | |
84 | + immediate: true | |
85 | + } | |
86 | + }, | |
87 | + methods: { | |
88 | + closeScoreSet() { | |
89 | + this.$emit('closeScoreSet') | |
90 | + }, | |
91 | + async _QueryData() { | |
92 | + this.loading = true; | |
93 | + const { data, status, info } = await this.$request.listStudentsAndQuestions({ | |
94 | + examId: this.id | |
95 | + }); | |
96 | + this.loading = false; | |
97 | + if (status === 0) { | |
98 | + this.tableData = data.students || [] | |
99 | + this.questionList = data?.students ? data?.students[0].questionList : [] | |
100 | + console.log(this.questionList) | |
101 | + } else { | |
102 | + this.$message.error(info); | |
103 | + } | |
104 | + }, | |
105 | + async _SubmitScore() { | |
106 | + this.loadingSave = true; | |
107 | + let list = this.tableData.map(item => { | |
108 | + let scores = {} | |
109 | + item.questionList.map(list => { | |
110 | + list.subQuestions.map(question => { | |
111 | + scores[question.id] = question.score | |
112 | + }) | |
113 | + }) | |
114 | + return { | |
115 | + studentCode: item.studentCode, | |
116 | + scores | |
117 | + } | |
118 | + }) | |
119 | + console.log(list) | |
120 | + const { data, status, info } = await this.$request.submitScore({ | |
121 | + examId: this.id, | |
122 | + list | |
123 | + }); | |
124 | + this.loadingSave = false; | |
125 | + if (status === 0) { | |
126 | + this.tableData = data.students | |
127 | + } else { | |
128 | + this.$message.error(info); | |
129 | + } | |
130 | + }, | |
131 | + | |
132 | + //导入成功 | |
133 | + upSuccess(res) { | |
134 | + this.$message.success("导入成功"); | |
135 | + this.diaUp = false; | |
136 | + this._QueryData() | |
137 | + }, | |
138 | + async downExcel() { | |
139 | + //模板下载 | |
140 | + this.loadingDown = true; | |
141 | + let data = await this.$request.scoreTemplate({ | |
142 | + examId: this.id, | |
143 | + }); | |
144 | + this.loadingDown = false; | |
145 | + if (data && !data.code) { | |
146 | + let blob = new Blob([data], { | |
147 | + type: "application/vnd.ms-excel;charset=utf-8", | |
148 | + }); | |
149 | + downloadFile(`答卷录分模版.xlsx`, blob); | |
150 | + } else { | |
151 | + this.$message.error(data.info); | |
152 | + } | |
153 | + }, | |
154 | + } | |
155 | +} | |
156 | +</script> | |
157 | + | |
158 | +<style lang="scss" scoped> | |
159 | +.set-container { | |
160 | + position: absolute; | |
161 | + left: 0; | |
162 | + top: 0; | |
163 | + width: 100%; | |
164 | + height: 100%; | |
165 | + background: #fff; | |
166 | + z-index: 2000; | |
167 | + overflow-y: auto; | |
168 | +} | |
169 | + | |
170 | +.back { | |
171 | + width: 100%; | |
172 | + height: 56px; | |
173 | + border-bottom: 1px solid #e2e2e2; | |
174 | + display: flex; | |
175 | + justify-content: space-between; | |
176 | + align-items: center; | |
177 | + padding: 0 20px; | |
178 | + box-sizing: border-box; | |
179 | + | |
180 | + .back-l { | |
181 | + display: flex; | |
182 | + align-items: center; | |
183 | + cursor: pointer; | |
184 | + flex-shrink: 0; | |
185 | + font-size: 18px; | |
186 | + font-weight: 500; | |
187 | + } | |
188 | + | |
189 | + .back-r { | |
190 | + flex: 1; | |
191 | + display: flex; | |
192 | + justify-content: flex-end; | |
193 | + } | |
194 | + | |
195 | + .fa-mail-reply-all { | |
196 | + font-size: 28px; | |
197 | + color: #b3b3b3; | |
198 | + margin-right: 12px; | |
199 | + } | |
200 | +} | |
201 | + | |
202 | +.set-content { | |
203 | + padding: 12px 20px; | |
204 | + | |
205 | + .test-title { | |
206 | + width: 100%; | |
207 | + text-align: center; | |
208 | + position: relative; | |
209 | + margin-bottom: 20px; | |
210 | + | |
211 | + .import-btn { | |
212 | + position: absolute; | |
213 | + right: 0; | |
214 | + top: 5px; | |
215 | + } | |
216 | + | |
217 | + .p1 { | |
218 | + font-size: 18px; | |
219 | + font-weight: 700; | |
220 | + } | |
221 | + } | |
222 | +} | |
223 | + | |
224 | +.btn-box { | |
225 | + padding-top: 12px; | |
226 | + text-align: right; | |
227 | +} | |
228 | +</style> | |
0 | 229 | \ No newline at end of file | ... | ... |
src/views/basic/test/components/test.vue
0 → 100644
1 | +<template> | |
2 | + <div ref="main"> | |
3 | + <div class="tips" v-if="paperModifyLog.modifiedTime && !status"> | |
4 | + <p class="tips-p"> | |
5 | + <i class="fa fa-bell-o"></i> | |
6 | + {{ | |
7 | + `${paperModifyLog.modifiedTime} ${paperModifyLog.realName}` | |
8 | + }}修改了答案,是否重新记分? | |
9 | + </p> | |
10 | + <div class="btn-box"> | |
11 | + <el-button type="danger" round @click="_ReScore" size="mini">重新计分</el-button> | |
12 | + <el-button type="danger" round plain size="mini" @click="paperModifyLog.modifiedTime = ''">暂时不计</el-button> | |
13 | + </div> | |
14 | + </div> | |
15 | + <div class="page-content"> | |
16 | + <div class="content-header"> | |
17 | + <div class="tab-box"> | |
18 | + <span v-for="(item, index) in tabList" :key="item" class="tab-item" :class="type == index ? 'active' : ''" | |
19 | + @click="setType(index)">{{ item }}</span> | |
20 | + </div> | |
21 | + <el-button v-if="!status" class="setMinScore" @click="diaMinScore = true" round size="small">设置低分值</el-button> | |
22 | + </div> | |
23 | + <div id="print-content" v-loading="loading"> | |
24 | + <div class="table-box"> | |
25 | + <el-table :max-height="tableMaxHeight" v-show="type == 0" :data="tableData" border style="width: 100%"> | |
26 | + <el-table-column prop="questionIndex" label="题号" align="center" fixed width="60"></el-table-column> | |
27 | + <el-table-column prop="questionType" label="题型" align="center" fixed width="100"><template | |
28 | + slot-scope="scope">{{ | |
29 | + setSubPro(scope.row.questionType) | |
30 | + }}</template></el-table-column> | |
31 | + <el-table-column prop="score" width="100" label="满分值" sortable align="center"></el-table-column> | |
32 | + <el-table-column width="110" prop="highestScore" label="班最高分" sortable align="center"></el-table-column> | |
33 | + <el-table-column width="110" prop="lowestScore" label="班最低分" sortable align="center"></el-table-column> | |
34 | + <el-table-column width="110" prop="avgScore" label="班平均分" sortable align="center"></el-table-column> | |
35 | + <el-table-column prop="classScoringRate" width="120" sortable label="班级得分率" align="center"><template | |
36 | + slot-scope="scoped">{{ scoped.row.classScoringRate }}%</template></el-table-column> | |
37 | + <el-table-column prop="correctAnswer" label="答案" align="center"><template slot-scope="scoped">{{ | |
38 | + scoped.row.correctAnswer == 1 | |
39 | + ? "✓" | |
40 | + : scoped.row.correctAnswer == 2 | |
41 | + ? "✗" | |
42 | + : scoped.row.correctAnswer | |
43 | + }}</template> | |
44 | + </el-table-column> | |
45 | + <el-table-column v-for="(item, index) in optionsList" :key="index" :label="item.title" :prop="'count' + index" | |
46 | + align="center" width="120"><template slot-scope="scope"> | |
47 | + <p class="persent"> | |
48 | + {{ | |
49 | + scope.row.questionType == "5" | |
50 | + ? "" | |
51 | + : scope.row["option" + index] | |
52 | + ? `${scope.row["option" + index]}(${scope.row["persent" + index] | |
53 | + })` | |
54 | + : "" | |
55 | + }} | |
56 | + </p> | |
57 | + </template> | |
58 | + </el-table-column> | |
59 | + </el-table> | |
60 | + <div id="print-table"> | |
61 | + <table class="hide"> | |
62 | + <thead> | |
63 | + <tr> | |
64 | + <th>题号</th> | |
65 | + <th>题型</th> | |
66 | + <th>满分值</th> | |
67 | + <th>班最高分</th> | |
68 | + <th>班最低分</th> | |
69 | + <th>班平均分</th> | |
70 | + <th>班级得分率</th> | |
71 | + <th>答案</th> | |
72 | + <th>选项1</th> | |
73 | + <th>选项2</th> | |
74 | + <th>选项3</th> | |
75 | + <th>选项4</th> | |
76 | + <th>未答</th> | |
77 | + </tr> | |
78 | + </thead> | |
79 | + <tbody> | |
80 | + <tr v-for="(tr, index) in tableData"> | |
81 | + <td width="60">{{ index + 1 }}</td> | |
82 | + <td width="100">{{ setSubPro(tr.questionType) }}</td> | |
83 | + <td width="100">{{ tr.sortable }}</td> | |
84 | + <td width="110">{{ tr.highestScore }}</td> | |
85 | + <td width="110">{{ tr.lowestScore }}</td> | |
86 | + <td width="110">{{ tr.avgScore }}</td> | |
87 | + <td width="120">{{ tr.classScoringRate }}%</td> | |
88 | + <td> | |
89 | + {{ | |
90 | + tr.correctAnswer == 1 | |
91 | + ? "✓" | |
92 | + : tr.correctAnswer == 2 | |
93 | + ? "✗" | |
94 | + : tr.correctAnswer | |
95 | + }} | |
96 | + </td> | |
97 | + <td v-for="(item, index) in optionsList" :key="index" width="120"> | |
98 | + <p class="persent"> | |
99 | + {{ | |
100 | + tr.questionType == "5" | |
101 | + ? "" | |
102 | + : tr["option" + index] | |
103 | + ? `${tr["option" + index]}(${tr["persent" + index]})` | |
104 | + : "" | |
105 | + }} | |
106 | + </p> | |
107 | + </td> | |
108 | + </tr> | |
109 | + </tbody> | |
110 | + </table> | |
111 | + <div class="hui-box" v-show="type == 0"> | |
112 | + <span class="s-txt">汇总</span> | |
113 | + <ul class="hui-ul"> | |
114 | + <li class="hui-li"> | |
115 | + <span class="hui-s s1">主观题</span> | |
116 | + <span class="hui-s s1">{{ examReport.subjectiveScore }}</span> | |
117 | + <span class="hui-s s2">{{ | |
118 | + examReport.subjectiveHighestScore | |
119 | + }}</span> | |
120 | + <span class="hui-s s2">{{ | |
121 | + examReport.subjectiveLowestScore | |
122 | + }}</span> | |
123 | + <span class="hui-s s2">{{ | |
124 | + examReport.subjectiveAvgScore | |
125 | + }}</span> | |
126 | + <span class="hui-s s3">{{ examReport.subjectiveClassScoringRate }}%</span> | |
127 | + </li> | |
128 | + <li class="hui-li"> | |
129 | + <span class="hui-s s1">客观题</span> | |
130 | + <span class="hui-s s1">{{ examReport.objectiveScore }}</span> | |
131 | + <span class="hui-s s2">{{ | |
132 | + examReport.objectiveHighestScore | |
133 | + }}</span> | |
134 | + <span class="hui-s s2">{{ | |
135 | + examReport.objectiveLowestScore | |
136 | + }}</span> | |
137 | + <span class="hui-s s2">{{ examReport.objectiveAvgScore }}</span> | |
138 | + <span class="hui-s s3">{{ examReport.objectiveClassScoringRate }}%</span> | |
139 | + </li> | |
140 | + <li class="hui-li"> | |
141 | + <span class="hui-s s1">整卷</span> | |
142 | + <span class="hui-s s1">{{ examReport.examPaperScore }}</span> | |
143 | + <span class="hui-s s2">{{ examReport.highestScore }}</span> | |
144 | + <span class="hui-s s2">{{ examReport.lowestScore }}</span> | |
145 | + <span class="hui-s s2">{{ examReport.avgScore }}</span> | |
146 | + <span class="hui-s s3">{{ examReport.classScoringRate }}%</span> | |
147 | + </li> | |
148 | + </ul> | |
149 | + </div> | |
150 | + </div> | |
151 | + <el-table v-show="type == 1" :max-height="tableMaxHeight" :data="tableData2" border style="width: 100%" | |
152 | + :default-sort="{ prop: 'dadui', order: 'descending' }"> | |
153 | + <el-table-column prop="studentCode" label="学号" align="center" fixed></el-table-column> | |
154 | + <el-table-column prop="studentName" label="姓名" fixed align="center"></el-table-column> | |
155 | + <el-table-column prop="examScore" label="总分" sortable align="center"></el-table-column> | |
156 | + <el-table-column prop="scoringRate" label="得分率" sortable align="center"><template slot-scope="scope">{{ | |
157 | + scope.row.scoringRate }}%</template></el-table-column> | |
158 | + <el-table-column prop="classRank" label="班名" sortable align="center"></el-table-column> | |
159 | + <el-table-column label="客观题" align="center"> | |
160 | + <el-table-column prop="objectiveExamScore" label="得分" align="center"></el-table-column> | |
161 | + <el-table-column prop="objectiveScoringRate" label="得分率" align="center"><template slot-scope="scope">{{ | |
162 | + scope.row.objectiveScoringRate }}%</template></el-table-column> | |
163 | + </el-table-column> | |
164 | + <el-table-column label="主观题" align="center"> | |
165 | + <el-table-column prop="subjectiveExamScore" label="得分" align="center"></el-table-column> | |
166 | + <el-table-column prop="subjectiveScoringRate" label="得分率" align="center"><template slot-scope="scope">{{ | |
167 | + scope.row.subjectiveScoringRate }}%</template></el-table-column> | |
168 | + </el-table-column> | |
169 | + </el-table> | |
170 | + <el-table v-show="type == 2" :max-height="tableMaxHeight" :data="tableData2" border style="width: 100%" | |
171 | + :default-sort="{ prop: '', order: 'descending' }"> | |
172 | + <el-table-column prop="studentCode" label="学号" fixed align="center" width="120"></el-table-column> | |
173 | + <el-table-column prop="studentName" label="姓名" fixed align="center"></el-table-column> | |
174 | + <el-table-column prop="examScore" label="总分" sortable align="center"></el-table-column> | |
175 | + <el-table-column label="分数组成" align="center"> | |
176 | + <el-table-column prop="objectiveExamScore" label="客观题分" align="center"></el-table-column> | |
177 | + <el-table-column prop="subjectiveExamScore" label="主观题分" align="center"></el-table-column> | |
178 | + </el-table-column> | |
179 | + <el-table-column align="center" v-for="(item, index) in questionList" :key="index" :label="'Q' + item.id" | |
180 | + :prop="'score' + item.id"> | |
181 | + </el-table-column> | |
182 | + </el-table> | |
183 | + <el-table :max-height="tableMaxHeight" v-show="type == 3" :data="tableData2" border style="width: 100%" | |
184 | + :default-sort="{ prop: '', order: 'descending' }"> | |
185 | + <el-table-column prop="studentCode" label="学号" fixed align="center"></el-table-column> | |
186 | + <el-table-column prop="studentName" label="姓名" fixed align="center"></el-table-column> | |
187 | + <el-table-column prop="className" label="班级" align="center"></el-table-column> | |
188 | + <el-table-column prop="examScore" label="总分" sortable align="center"></el-table-column> | |
189 | + <el-table-column align="center" v-for="(item, index) in questionList" :key="index" :label="'Q' + item.id"> | |
190 | + <template slot-scope="scope"> | |
191 | + <span v-if="tableData[index]?.questionType == 5">*</span> | |
192 | + <span v-else-if="scope.row['answer' + item.id]" :class="scope.row['isRight' + item.id] ? '' : 'error'"> | |
193 | + {{ scope.row["answer" + item.id] }} | |
194 | + </span> | |
195 | + <span v-else :class="scope.row['questionType' + item.id] == 5 ? '' : 'error'">-</span> | |
196 | + </template> | |
197 | + </el-table-column> | |
198 | + </el-table> | |
199 | + </div> | |
200 | + </div> | |
201 | + <div class="down"> | |
202 | + <div> | |
203 | + <el-button @click="exportData" type="primary" plain round icon="fa fa-cloud-download">导出报表</el-button> | |
204 | + <el-button v-if="!this.$store.getters.code" @click="print" type="primary" plain round | |
205 | + icon="el-icon-printer">打印</el-button> | |
206 | + </div> | |
207 | + <div v-if="!status"> | |
208 | + <el-button type="primary" round @click="openScoreSet">答卷录分</el-button> | |
209 | + | |
210 | + <template v-if="role != 'ROLE_BANZHUREN'"> | |
211 | + <el-button @click="edit" type="primary" v-if="examReport.subjectiveScore != examReport.examPaperScore" | |
212 | + round>查看题目</el-button></template> | |
213 | + </div> | |
214 | + </div> | |
215 | + <ScoreSet v-show="diaScoreSet" :role="role" :id="id" :title="title" :examScore="score" | |
216 | + @closeScoreSet="closeScoreSet" /> | |
217 | + <el-dialog :close-on-click-modal="false" title="低分区间设置" :visible.sync="diaMinScore" width="480px" | |
218 | + @closed="closeDiaMinScore"> | |
219 | + <el-form> | |
220 | + <el-form-item label="低分设置模式:"> | |
221 | + <el-select v-model="lowRange.type" @change="changeScore"> | |
222 | + <el-option label="按分数设置" :value="0"></el-option> | |
223 | + <el-option label="按已考人数比例" :value="1"></el-option> | |
224 | + <el-option label="按分数比例设置(按题目)" :value="2"></el-option> | |
225 | + </el-select> | |
226 | + </el-form-item> | |
227 | + <el-form-item label="低分区间:"> | |
228 | + <el-input class="score-ipt" type="number" v-model="lowRange.range[0]" :min="0" :max="100" | |
229 | + @input="lowRange.range[1] > 100 ? (lowRange.range[1] = 100) : ''" | |
230 | + @keydown.native="keydownRange($event)"></el-input>{{ lowRange.type != 0 ? "%" : "分" }}(含) | |
231 | + <el-input class="score-ipt" type="number" v-model="lowRange.range[1]" :min="0" :max="100" | |
232 | + @input="lowRange.range[1] > 100 ? (lowRange.range[1] = 100) : ''" | |
233 | + @keydown.native="keydownRange($event)"></el-input>{{ lowRange.type != 0 ? "%" : "分" }}(含) | |
234 | + </el-form-item> | |
235 | + </el-form> | |
236 | + | |
237 | + <div class="dialog-footer" slot="footer" align="center" v-loading="loadingTange"> | |
238 | + <el-button type="danger" @click="_SavelowRange">保存</el-button> | |
239 | + <el-button @click="diaMinScore = false">取 消</el-button> | |
240 | + </div> | |
241 | + </el-dialog> | |
242 | + </div> | |
243 | + </div> | |
244 | +</template> | |
245 | +<script> | |
246 | +import ScoreSet from "./scoreSet.vue" | |
247 | +import { downloadFile, tablePrint } from "@/utils"; | |
248 | +export default { | |
249 | + components: { | |
250 | + ScoreSet | |
251 | + }, | |
252 | + props: { | |
253 | + role: "", | |
254 | + id: "", | |
255 | + title: String, | |
256 | + classId: String, | |
257 | + subjectName: String, | |
258 | + score: { | |
259 | + type: Number, | |
260 | + default: 0 | |
261 | + }, | |
262 | + }, | |
263 | + data() { | |
264 | + return { | |
265 | + status: 0,// 1:已归档试卷 | |
266 | + tableMaxHeight: 600, | |
267 | + loading: false, | |
268 | + exportLoading: false, | |
269 | + tabList: ["试题分析", "成绩排名", "小题分报表", "作答明细表"], | |
270 | + type: 0, | |
271 | + paperModifyLog: { //修改信息 | |
272 | + realName: "", | |
273 | + modifiedTime: "", | |
274 | + }, | |
275 | + examReport: { | |
276 | + subjectiveScore: 0, | |
277 | + subjectiveHighestScore: "", | |
278 | + subjectiveLowestScore: "", | |
279 | + subjectiveAvgScore: "", | |
280 | + subjectiveClassScoringRate: "", | |
281 | + objectiveScore: "", | |
282 | + objectiveHighestScore: "", | |
283 | + objectiveLowestScore: "", | |
284 | + objectiveAvgScore: "", | |
285 | + objectiveClassScoringRate: "", | |
286 | + examPaperScore: "", | |
287 | + highestScore: "", | |
288 | + lowestScore: "", | |
289 | + avgScore: "", | |
290 | + classScoringRate: "", | |
291 | + }, | |
292 | + tableData: [], | |
293 | + optionsList: [], | |
294 | + tableData2: [], | |
295 | + questionList: [], | |
296 | + page: 1, | |
297 | + size: 20, | |
298 | + total: 0, | |
299 | + // 设置低分值 | |
300 | + loadingTange: false, | |
301 | + diaMinScore: false, | |
302 | + lowRange: { | |
303 | + type: 0, | |
304 | + range: [60, 0], | |
305 | + }, | |
306 | + defaultLowRange: { | |
307 | + type: 0, | |
308 | + range: [], | |
309 | + }, | |
310 | + //答题录分 | |
311 | + diaScoreSet: false | |
312 | + }; | |
313 | + }, | |
314 | + created() { | |
315 | + this.status = this.$route.query.status ? this.$route.query.status : 0; | |
316 | + this._QueryData(); | |
317 | + }, | |
318 | + methods: { | |
319 | + print() { | |
320 | + if (this.type == 0) { | |
321 | + tablePrint("print-table", this.title + this.tabList[this.type], true); | |
322 | + } else { | |
323 | + tablePrint("print-content", this.title + this.tabList[this.type]); | |
324 | + } | |
325 | + }, | |
326 | + //打开答卷录分 | |
327 | + openScoreSet() { | |
328 | + this.diaScoreSet = true; | |
329 | + }, | |
330 | + //关闭设置分数 | |
331 | + closeScoreSet() { | |
332 | + this.diaScoreSet = false | |
333 | + }, | |
334 | + setType(type) { | |
335 | + this.tableMaxHeight = this.$refs.main.offsetHeight; | |
336 | + this.type = type; | |
337 | + }, | |
338 | + setSubPro(type) { | |
339 | + let tit; | |
340 | + switch (type) { | |
341 | + case 2: | |
342 | + tit = "单选题"; | |
343 | + break; | |
344 | + case 3: | |
345 | + tit = "多选题"; | |
346 | + break; | |
347 | + case 4: | |
348 | + tit = "判断题"; | |
349 | + break; | |
350 | + case 5: | |
351 | + tit = "主观题"; | |
352 | + break; | |
353 | + } | |
354 | + return tit; | |
355 | + }, | |
356 | + edit() { | |
357 | + this.$router.push({ | |
358 | + path: "/examinationPaperEdit", | |
359 | + query: { | |
360 | + paperId: this.id, | |
361 | + title: this.title, | |
362 | + type: 2, | |
363 | + }, | |
364 | + }); | |
365 | + }, | |
366 | + changePage(page) { | |
367 | + this.page = page; | |
368 | + this.examQuestionReport(); | |
369 | + }, | |
370 | + // 切换低分设置类型设置默认分值 | |
371 | + changeScore() { | |
372 | + this.lowRange.range = [...this.defaultLowRange.range]; | |
373 | + }, | |
374 | + // 禁止输入负数 | |
375 | + keydownRange(event) { | |
376 | + if (event.key == "-" || event.key == "e") { | |
377 | + event.returnValue = ""; | |
378 | + } | |
379 | + }, | |
380 | + // 关闭低分设置 | |
381 | + closeDiaMinScore() { | |
382 | + this.lowRange.type = this.defaultLowRange.type; | |
383 | + this.lowRange.range = [...this.defaultLowRange.range]; | |
384 | + }, | |
385 | + // 保存低分设置 | |
386 | + async _SavelowRange() { | |
387 | + if (this.lowRange.range[0].trim() == "" || this.lowRange.range[1].trim() == "") { | |
388 | + this.$message.warning("请补全低分设置!"); | |
389 | + return | |
390 | + } | |
391 | + this.loadingTange = true; | |
392 | + let { data, status, info } = await this.$request.setLowRange({ | |
393 | + classId: this.classId, | |
394 | + subjectName: this.subjectName, | |
395 | + ...this.lowRange, | |
396 | + }); | |
397 | + this.loadingTange = false; | |
398 | + if (status === 0) { | |
399 | + this.$message.success(info); | |
400 | + this.diaMinScore = false; | |
401 | + this.examDetail(); | |
402 | + } else { | |
403 | + this.$message.error(info); | |
404 | + } | |
405 | + }, | |
406 | + async _QueryData() { | |
407 | + this.examDetail(); | |
408 | + this.examStudentReport(); | |
409 | + this.examQuestionReport(); | |
410 | + }, | |
411 | + async examDetail() { | |
412 | + //详情 | |
413 | + this.loading = true; | |
414 | + const examDetail = this.role == "ROLE_PERSONAL" ? | |
415 | + this.$request.pExamDetail | |
416 | + : this.$request.examDetail; | |
417 | + | |
418 | + let { data, info, status } = await examDetail({ | |
419 | + examId: this.id, | |
420 | + }); | |
421 | + this.loading = false; | |
422 | + if (status === 0) { | |
423 | + if (data.paperModifyLog) { | |
424 | + this.paperModifyLog = { ...data?.paperModifyLog }; | |
425 | + } | |
426 | + this.examReport = { ...data?.examReport }; | |
427 | + this.defaultLowRange = data.lowRange || { | |
428 | + type: 1, | |
429 | + range: [60, 0], | |
430 | + }; | |
431 | + this.lowRange.type = this.defaultLowRange.type; | |
432 | + this.lowRange.range = [...this.defaultLowRange.range]; | |
433 | + } else { | |
434 | + this.$message.error(info); | |
435 | + } | |
436 | + }, | |
437 | + async _ReScore() { | |
438 | + //重新记分 | |
439 | + this.loading = true; | |
440 | + let { data, info, status } = await this.$request.reScore({ | |
441 | + examId: this.id, | |
442 | + }); | |
443 | + this.loading = false; | |
444 | + if (status === 0) { | |
445 | + this.$message.success(info); | |
446 | + this._QueryData(); | |
447 | + this.paperModifyLog.modifiedTime = ""; | |
448 | + this.paperModifyLog.realName = ""; | |
449 | + } else { | |
450 | + this.$message.error(info); | |
451 | + } | |
452 | + }, | |
453 | + async examStudentReport() { | |
454 | + //成绩排名-小题分-作答明细 | |
455 | + this.loading = true; | |
456 | + const examStudentReport = this.role == "ROLE_PERSONAL" ? | |
457 | + this.$request.pExamStudentReport | |
458 | + : this.$request.examStudentReport; | |
459 | + let { data, info, status } = await examStudentReport({ | |
460 | + examId: this.id, | |
461 | + }); | |
462 | + this.loading = false; | |
463 | + if (status === 0) { | |
464 | + let optionsList = []; | |
465 | + this.tableData2 = data?.list.map((item) => { | |
466 | + let params = {}; | |
467 | + | |
468 | + const detail = JSON.parse(item.detail); | |
469 | + if (detail.length > optionsList.length) { | |
470 | + optionsList = [...detail]; | |
471 | + } | |
472 | + detail.map((items, index) => { | |
473 | + params["que" + items.id] = items.id; | |
474 | + params["score" + items.id] = String(items.score).includes(".") | |
475 | + ? Number(items.score) | |
476 | + : items.score; | |
477 | + params["answer" + items.id] = | |
478 | + items.answer == 1 ? "✓" : items.answer == 2 ? "✗" : items.answer; | |
479 | + params["isRight" + items.id] = items.isRight; | |
480 | + params["questionType" + items.id] = items.questionType; | |
481 | + }); | |
482 | + return { | |
483 | + ...item, | |
484 | + ...params, | |
485 | + }; | |
486 | + }); | |
487 | + console.log(); | |
488 | + this.questionList = optionsList.sort((a, b) => { | |
489 | + return a.id - b.id; | |
490 | + }); | |
491 | + } else { | |
492 | + this.$message.error(info); | |
493 | + } | |
494 | + }, | |
495 | + async examQuestionReport() { | |
496 | + //试题分析 | |
497 | + this.loading = true; | |
498 | + const examQuestionReport = this.role == "ROLE_PERSONAL" ? | |
499 | + this.$request.pExamQuestionReport | |
500 | + : this.$request.examQuestionReport; | |
501 | + | |
502 | + let { data, info, status } = await examQuestionReport({ | |
503 | + examId: this.id, | |
504 | + page: this.page, | |
505 | + // size: this.size, | |
506 | + size: 9999, | |
507 | + }); | |
508 | + this.loading = false; | |
509 | + if (status === 0) { | |
510 | + let optionsList = [{}, {}, {}, {}, {}]; | |
511 | + let tableData = data?.list.map((item) => { | |
512 | + let params = {}; | |
513 | + const detail = JSON.parse(item.detail); | |
514 | + let lastOPtion = detail?.find((item) => { | |
515 | + return item.option == "未答"; | |
516 | + }); | |
517 | + let defaultArr = detail?.filter((item) => { | |
518 | + return item.option != "未答"; | |
519 | + }); | |
520 | + | |
521 | + optionsList.map((items, index) => { | |
522 | + if (index != 4) { | |
523 | + params["count" + index] = | |
524 | + defaultArr[index]?.option != "未答" | |
525 | + ? defaultArr[index]?.count | |
526 | + : ""; | |
527 | + params["persent" + index] = | |
528 | + defaultArr[index]?.option != "未答" | |
529 | + ? defaultArr[index]?.persent | |
530 | + : ""; | |
531 | + params["option" + index] = | |
532 | + defaultArr[index]?.option != "未答" | |
533 | + ? defaultArr[index]?.option == 1 | |
534 | + ? "✓" | |
535 | + : defaultArr[index]?.option == 2 | |
536 | + ? "✗" | |
537 | + : defaultArr[index]?.option | |
538 | + : ""; | |
539 | + items["title"] = "选项" + (index + 1); | |
540 | + } else { | |
541 | + items["title"] = "未答"; | |
542 | + params["count" + index] = lastOPtion.count; | |
543 | + params["persent" + index] = lastOPtion.persent; | |
544 | + params["option" + index] = "?"; | |
545 | + } | |
546 | + }); | |
547 | + return { | |
548 | + ...item, | |
549 | + ...params, | |
550 | + }; | |
551 | + }); | |
552 | + this.tableData = tableData.sort((a, b) => { | |
553 | + return a.questionIndex - b.questionIndex; | |
554 | + }); | |
555 | + this.optionsList = [...optionsList]; | |
556 | + this.total = data.count; | |
557 | + this.setType(0); | |
558 | + } else { | |
559 | + this.$message.error(info); | |
560 | + } | |
561 | + }, | |
562 | + //导出 | |
563 | + async exportData() { | |
564 | + if (this.exportLoading == true) return; | |
565 | + this.exportLoading = true; | |
566 | + const data = await this.$request.exportExamReport({ | |
567 | + examId: this.id, | |
568 | + }); | |
569 | + this.exportLoading = false; | |
570 | + if (data) { | |
571 | + let blob = new Blob([data], { | |
572 | + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", | |
573 | + }); | |
574 | + downloadFile( | |
575 | + this.status | |
576 | + ? "即时测-已归档单卷测练报表.xlsx" | |
577 | + : "即时测-单卷测练报表.xlsx", | |
578 | + blob | |
579 | + ); | |
580 | + } else { | |
581 | + this.$message.error("下载失败"); | |
582 | + } | |
583 | + }, | |
584 | + }, | |
585 | +}; | |
586 | +</script> | |
587 | +<style> | |
588 | +div::-webkit-scrollbar { | |
589 | + width: 3px; | |
590 | + height: 10px; | |
591 | +} | |
592 | + | |
593 | +div::-webkit-scrollbar-thumb { | |
594 | + border-radius: 10px; | |
595 | + background-color: #ccc; | |
596 | +} | |
597 | +</style> | |
598 | +<style lang="scss" scoped> | |
599 | +.hide { | |
600 | + display: none; | |
601 | +} | |
602 | + | |
603 | +.page-container { | |
604 | + position: relative; | |
605 | + height: 100%; | |
606 | + padding: 20px; | |
607 | + | |
608 | + .table-box { | |
609 | + min-height: 100%; | |
610 | + } | |
611 | + | |
612 | + &.active { | |
613 | + overflow: hidden; | |
614 | + } | |
615 | + | |
616 | + .edit-dia { | |
617 | + position: absolute; | |
618 | + left: 0; | |
619 | + top: 0; | |
620 | + right: 0; | |
621 | + bottom: 0; | |
622 | + width: 100%; | |
623 | + height: calc(100vh - 70px); | |
624 | + background: #fff; | |
625 | + overflow-y: auto; | |
626 | + z-index: 10; | |
627 | + } | |
628 | +} | |
629 | + | |
630 | +.persent { | |
631 | + white-space: nowrap; | |
632 | +} | |
633 | + | |
634 | +.error { | |
635 | + color: #f30; | |
636 | +} | |
637 | + | |
638 | +.page-content { | |
639 | + padding: 20px 20px 0; | |
640 | +} | |
641 | + | |
642 | +.tips { | |
643 | + height: 48px; | |
644 | + box-sizing: border-box; | |
645 | + line-height: 48px; | |
646 | + padding: 0 16px; | |
647 | + border: 1px solid #fac7cc; | |
648 | + border-radius: 5px; | |
649 | + background-color: #ffebec; | |
650 | + font-size: 14px; | |
651 | + color: #fd9795; | |
652 | + margin: 10px 20px 0 20px; | |
653 | + display: flex; | |
654 | + | |
655 | + &-p { | |
656 | + flex: 1; | |
657 | + } | |
658 | + | |
659 | + .fa-bell-o { | |
660 | + font-size: 18px; | |
661 | + margin-right: 5px; | |
662 | + } | |
663 | +} | |
664 | + | |
665 | +.tab-box { | |
666 | + width: 800px; | |
667 | + margin: 0 auto 12px; | |
668 | + background: #f8f8f8; | |
669 | + border-radius: 20px; | |
670 | + display: flex; | |
671 | + user-select: none; | |
672 | + | |
673 | + .tab-item { | |
674 | + flex: 1; | |
675 | + height: 40px; | |
676 | + line-height: 40px; | |
677 | + text-align: center; | |
678 | + font-size: 16px; | |
679 | + color: #666; | |
680 | + font-weight: 500; | |
681 | + background: transparent; | |
682 | + border-radius: 20px; | |
683 | + cursor: pointer; | |
684 | + | |
685 | + &.active { | |
686 | + background: #667ffd; | |
687 | + color: #fff; | |
688 | + } | |
689 | + } | |
690 | +} | |
691 | + | |
692 | +.down { | |
693 | + padding-top: 20px; | |
694 | + width: 100%; | |
695 | + display: flex; | |
696 | + justify-content: space-between; | |
697 | +} | |
698 | + | |
699 | +.hui-box { | |
700 | + display: flex; | |
701 | + text-align: center; | |
702 | + | |
703 | + .s-txt { | |
704 | + width: 61px; | |
705 | + line-height: 144px; | |
706 | + background: #e2e2e2; | |
707 | + font-size: 16px; | |
708 | + color: #fff; | |
709 | + font-weight: 700; | |
710 | + } | |
711 | + | |
712 | + .hui-ul { | |
713 | + border-top: 1px solid #e2e2e2; | |
714 | + } | |
715 | + | |
716 | + .hui-li { | |
717 | + display: flex; | |
718 | + | |
719 | + .hui-s { | |
720 | + height: 48px; | |
721 | + line-height: 48px; | |
722 | + border-right: 1px solid #e2e2e2; | |
723 | + border-bottom: 1px solid #e2e2e2; | |
724 | + box-sizing: border-box; | |
725 | + } | |
726 | + | |
727 | + .s1 { | |
728 | + width: 100px; | |
729 | + } | |
730 | + | |
731 | + .s2 { | |
732 | + width: 110px; | |
733 | + } | |
734 | + | |
735 | + .s3 { | |
736 | + width: 120px; | |
737 | + } | |
738 | + } | |
739 | +} | |
740 | + | |
741 | +// 设置低分值 | |
742 | +.content-header { | |
743 | + width: 100%; | |
744 | + position: relative; | |
745 | + | |
746 | + .setMinScore { | |
747 | + position: absolute; | |
748 | + bottom: 0; | |
749 | + right: 0px; | |
750 | + } | |
751 | +} | |
752 | + | |
753 | +.score-ipt { | |
754 | + width: 80px; | |
755 | + margin: 0 5px; | |
756 | +} | |
757 | +</style> | |
0 | 758 | \ No newline at end of file | ... | ... |