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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 758 | \ No newline at end of file |