Commit 4295ede6e2a45b2e7f0f15ccf369b9aff4cad07c

Authored by 梁保满
1 parent dc015b2d

即使测报表对比页面开发

src/api/apis/apis.js
... ... @@ -1562,4 +1562,38 @@ export default {
1562 1562 data
1563 1563 });
1564 1564 },
  1565 +
  1566 +
  1567 + // 删除即时测考试
  1568 + deleteReport(data) {
  1569 + return service({
  1570 + url: setUpUrls.deleteReport,
  1571 + method: "POST",
  1572 + data
  1573 + });
  1574 + },
  1575 + // 设置单班科目分析低分区间
  1576 + setLowRange(data) {
  1577 + return service({
  1578 + url: setUpUrls.setLowRange,
  1579 + method: "POST",
  1580 + data
  1581 + });
  1582 + },
  1583 + // 查询即时测多班对比情况详情
  1584 + examMultiClassReport(data) {
  1585 + return service({
  1586 + url: setUpUrls.examMultiClassReport,
  1587 + method: "POST",
  1588 + data
  1589 + });
  1590 + },
  1591 + // 查询即时测多班对比情况详情
  1592 + exportExamMultiReport(data) {
  1593 + return service({
  1594 + url: setUpUrls.exportExamMultiReport,
  1595 + method: "POST",
  1596 + data
  1597 + });
  1598 + },
1565 1599 };
... ...
src/api/urls/apis.js
... ... @@ -405,4 +405,14 @@ export default {
405 405  
406 406 // 删除班级信息
407 407 removeClass: "/api_html/school/manager/delClass",
  408 +
  409 +
  410 + //删除即时测考试
  411 + deleteReport: "/api_html/teaching/deleteReport",
  412 + //设置单班科目分析低分区间
  413 + setLowRange: "/api_html/teaching/setLowRange",
  414 + //查询即时测多班对比情况详情
  415 + examMultiClassReport: "/api_html/teaching/examMultiClassReport",
  416 + //导出即时测多班报表
  417 + exportExamMultiReport: "/api_html/teaching/exportExamMultiReport",
408 418 }
... ...
src/router/index.js
... ... @@ -69,6 +69,13 @@ const Archived = () => import("@/views/standard/setUp/archived")
69 69 const DeviceError = () => import("@/views/standard/device/error")
70 70  
71 71 /**
  72 + * v1.5
  73 + */
  74 +const TestContrast = () => import("@/views/standard/test/contrast")
  75 +
  76 +
  77 +
  78 +/**
72 79 * 重写路由的push方法
73 80 */
74 81 const routerPush = Router.prototype.push
... ... @@ -268,6 +275,15 @@ let addrouters = [
268 275 parent: "test",
269 276 hidden: true,
270 277 children: []
  278 + },
  279 + {
  280 + path: "/testContrast",
  281 + iconCls: "", // 图标样式class
  282 + name: "即时测报表对比",
  283 + component: TestContrast,
  284 + parent: "test",
  285 + hidden: true,
  286 + children: []
271 287 }
272 288  
273 289 ]
... ... @@ -586,6 +602,14 @@ let csAddrouters = [
586 602 component: TestAnalysis,
587 603 parent: "test",
588 604 children: []
  605 + },
  606 + {
  607 + path: "/testContrast",
  608 + iconCls: "", // 图标样式class
  609 + name: "即时测报表分析",
  610 + component: TestContrast,
  611 + parent: "test",
  612 + children: []
589 613 }
590 614  
591 615 ]
... ...
src/views/standard/test/analysis.vue
... ... @@ -27,14 +27,23 @@
27 27 </div>
28 28 </div>
29 29 <div class="page-content">
30   - <div class="tab-box">
31   - <span
32   - v-for="(item, index) in tabList"
33   - :key="item"
34   - class="tab-item"
35   - :class="type == index ? 'active' : ''"
36   - @click="setType(index)"
37   - >{{ item }}</span
  30 + <div class="content-header">
  31 + <div class="tab-box">
  32 + <span
  33 + v-for="(item, index) in tabList"
  34 + :key="item"
  35 + class="tab-item"
  36 + :class="type == index ? 'active' : ''"
  37 + @click="setType(index)"
  38 + >{{ item }}</span
  39 + >
  40 + </div>
  41 + <el-button
  42 + class="setMinScore"
  43 + @click="diaMinScore = true"
  44 + round
  45 + size="small"
  46 + >设置低分值</el-button
38 47 >
39 48 </div>
40 49 <div id="print-content" class="table-box" v-loading="loading">
... ... @@ -444,7 +453,12 @@
444 453 >
445 454 </div>
446 455 </div>
447   - <el-dialog :close-on-click-modal="false" title="导入主观题分数" :visible.sync="diaUp" width="600">
  456 + <el-dialog
  457 + :close-on-click-modal="false"
  458 + title="导入主观题分数"
  459 + :visible.sync="diaUp"
  460 + width="600"
  461 + >
448 462 <up-load :url="url" :examId="id" @upSuccess="upSuccess">
449 463 <template slot="down">
450 464 <p class="down-txt">
... ... @@ -458,6 +472,47 @@
458 472 <el-button @click="diaUp = false">取 消</el-button>
459 473 </div>
460 474 </el-dialog>
  475 + <el-dialog
  476 + :close-on-click-modal="false"
  477 + title="低分区间设置"
  478 + :visible.sync="diaMinScore"
  479 + width="480px"
  480 + @closed="closeDiaMinScore"
  481 + >
  482 + <el-form>
  483 + <el-form-item label="低分设置模式:">
  484 + <el-select v-model="lowRange.type" @change="changeScore">
  485 + <el-option label="按已考人数比例" :value="0"></el-option>
  486 + <el-option label="按分数设置" :value="1"></el-option>
  487 + </el-select>
  488 + </el-form-item>
  489 + <el-form-item label="低分区间:">
  490 + <el-input
  491 + class="score-ipt"
  492 + type="number"
  493 + v-model="lowRange.range[0]"
  494 + :min="0"
  495 + :max="100"
  496 + @input="lowRange.range[1] > 100 ? (lowRange.range[1] = 100) : ''"
  497 + ></el-input
  498 + >{{ lowRange.type == 0 ? "%" : "分" }}(含)
  499 + <el-input
  500 + class="score-ipt"
  501 + type="number"
  502 + v-model="lowRange.range[1]"
  503 + :min="0"
  504 + :max="100"
  505 + @input="lowRange.range[1] > 100 ? (lowRange.range[1] = 100) : ''"
  506 + ></el-input
  507 + >{{ lowRange.type == 0 ? "%" : "分" }}(含)
  508 + </el-form-item>
  509 + </el-form>
  510 +
  511 + <div class="dialog-footer" slot="footer" align="center" v-loading="loadingTange">
  512 + <el-button type="danger" @click="_SavelowRange">保存</el-button>
  513 + <el-button @click="diaMinScore = false">取 消</el-button>
  514 + </div>
  515 + </el-dialog>
461 516 </div>
462 517 </div>
463 518 </template>
... ... @@ -475,6 +530,8 @@ export default {
475 530 diaUp: false,
476 531 url: "/api_html/teaching/importSubjectiveScore",
477 532 id: "",
  533 + classId: "",
  534 + subjectName: "",
478 535 title: "",
479 536 score: "",
480 537 tabList: ["试题分析", "成绩排名", "小题分报表", "作答明细表"],
... ... @@ -507,6 +564,13 @@ export default {
507 564 page: 1,
508 565 size: 20,
509 566 total: 0,
  567 + // 设置低分值
  568 + loadingTange:false,
  569 + diaMinScore: false,
  570 + lowRange: {
  571 + type: 1,
  572 + range: [60, 0],
  573 + },
510 574 };
511 575 },
512 576 created() {
... ... @@ -516,6 +580,8 @@ export default {
516 580 this.id = this.$route.query.id;
517 581 this.status = this.$route.query.status ? this.$route.query.status : 0;
518 582 this.title = this.$route.query.title || "";
  583 + this.classId = this.$route.query.classId || "";
  584 + this.subjectName = this.$route.query.subjectName || "";
519 585 this._QueryData();
520 586 },
521 587 methods: {
... ... @@ -569,6 +635,30 @@ export default {
569 635 this.page = page;
570 636 this.examQuestionReport();
571 637 },
  638 + // 切换低分设置类型设置默认分值
  639 + changeScore() {
  640 + this.lowRange.range = [60, 0];
  641 + },
  642 + // 关闭低分设置
  643 + closeDiaMinScore() {
  644 + this.lowRange.type = 1;
  645 + this.lowRange.range = [60, 0];
  646 + },
  647 + // 保存低分设置
  648 + async _SavelowRange() {
  649 + this.loadingTange = true;
  650 + let data = await this.$request.setLowRange({
  651 + classId: this.classId,
  652 + subjectName: this.subjectName,
  653 + ...this.lowRange,
  654 + });
  655 + this.loadingTange = false;
  656 + if (data && !data.code) {
  657 + this.$message.success(data.info);
  658 + this.diaMinScore = false;
  659 + this.$message.error(data.info);
  660 + }
  661 + },
572 662 async _QueryData() {
573 663 this.examDetail();
574 664 this.examStudentReport();
... ... @@ -586,6 +676,10 @@ export default {
586 676 this.paperModifyLog = { ...data?.paperModifyLog };
587 677 }
588 678 this.examReport = { ...data?.examReport };
  679 + this.lowRange = data.lowRange || {
  680 + type: 1,
  681 + range: [60, 0],
  682 + };
589 683 } else {
590 684 this.$message.error(info);
591 685 }
... ... @@ -875,4 +969,19 @@ div::-webkit-scrollbar-thumb {
875 969 }
876 970 }
877 971 }
  972 +
  973 +// 设置低分值
  974 +.content-header {
  975 + width: 100%;
  976 + position: relative;
  977 + .setMinScore {
  978 + position: absolute;
  979 + bottom: 0;
  980 + right: 50px;
  981 + }
  982 +}
  983 +.score-ipt {
  984 + width: 80px;
  985 + margin: 0 5px;
  986 +}
878 987 </style>
879 988 \ No newline at end of file
... ...
src/views/standard/test/contrast.vue 0 → 100644
  1 +<template>
  2 + <div ref="main" class="page-container">
  3 + <back-box>
  4 + <template slot="title">
  5 + <span>多班分析_{{ subjectNames }}_{{ title }}_成绩对比分析</span>
  6 + </template>
  7 + </back-box>
  8 + <div class="page-content">
  9 + <div class="content-header">
  10 + <div class="tab-box">
  11 + <span
  12 + v-for="(item, index) in tabList"
  13 + :key="item"
  14 + class="tab-item"
  15 + :class="type == index ? 'active' : ''"
  16 + @click="setType(index)"
  17 + >{{ item }}</span
  18 + >
  19 + </div>
  20 + <el-button
  21 + class="setMinScore"
  22 + @click="diaLogBox = true"
  23 + round
  24 + size="small"
  25 + >对比成绩等级设置</el-button
  26 + >
  27 + </div>
  28 + <div id="print-content" class="table-box" v-loading="loading">
  29 + <el-table
  30 + :max-height="tableMaxHeight"
  31 + v-show="type == 0"
  32 + :data="tableData"
  33 + border
  34 + style="width: 100%"
  35 + >
  36 + <el-table-column
  37 + type="index"
  38 + label="序号"
  39 + align="center"
  40 + width="60"
  41 + ></el-table-column>
  42 + <el-table-column
  43 + prop="className"
  44 + label="班级"
  45 + align="center"
  46 + fixed
  47 + width="100"
  48 + ><</el-table-column
  49 + >
  50 + <el-table-column
  51 + prop="count"
  52 + width="100"
  53 + label="测验人数/班级人数"
  54 + align="center"
  55 + ></el-table-column>
  56 + <el-table-column
  57 + prop="percent"
  58 + width="110"
  59 + label="参与度"
  60 + align="center"
  61 + ></el-table-column>
  62 + <el-table-column
  63 + width="110"
  64 + prop="avg"
  65 + label="班平均分"
  66 + align="center"
  67 + ></el-table-column>
  68 + <el-table-column
  69 + width="110"
  70 + prop="max"
  71 + label="班最高分"
  72 + sortable
  73 + align="center"
  74 + ></el-table-column>
  75 + <el-table-column
  76 + width="110"
  77 + prop="min"
  78 + label="班最低分"
  79 + sortable
  80 + align="center"
  81 + ></el-table-column>
  82 +
  83 + <el-table-column
  84 + v-for="(item, index) in tableData[0].levels"
  85 + width="120"
  86 + sortable
  87 + :label="item.name"
  88 + align="center"
  89 + ><template slot-scope="scoped">{{
  90 + `${scoped.row.levels[index].people}(${scoped.row.levels[index].percent})`
  91 + }}</template></el-table-column
  92 + >
  93 + </el-table>
  94 + <el-table
  95 + v-show="type == 1"
  96 + :max-height="tableMaxHeight"
  97 + :data="tableData2"
  98 + border
  99 + style="width: 100%"
  100 + >
  101 + <el-table-column
  102 + prop="studentCode"
  103 + label="排名"
  104 + align="center"
  105 + ></el-table-column>
  106 + <el-table-column
  107 + prop="name"
  108 + label="姓名"
  109 + align="center"
  110 + ></el-table-column>
  111 + <el-table-column
  112 + prop="className"
  113 + label="班级"
  114 + sortable
  115 + align="center"
  116 + ></el-table-column>
  117 + <el-table-column
  118 + prop="score"
  119 + label="总分"
  120 + sortable
  121 + align="center"
  122 + ></el-table-column>
  123 + <el-table-column
  124 + prop="levelName"
  125 + label="成绩等级"
  126 + sortable
  127 + align="center"
  128 + ></el-table-column>
  129 + </el-table>
  130 + </div>
  131 + <div class="down">
  132 + <div>
  133 + <el-button
  134 + @click="exportData"
  135 + type="primary"
  136 + plain
  137 + round
  138 + icon="fa fa-cloud-download"
  139 + >导出报表</el-button
  140 + >
  141 + <el-button
  142 + v-if="!this.$store.getters.code"
  143 + @click="print"
  144 + type="primary"
  145 + plain
  146 + round
  147 + icon="el-icon-printer"
  148 + >打印</el-button
  149 + >
  150 + </div>
  151 + </div>
  152 +
  153 + <el-dialog
  154 + :close-on-click-modal="false"
  155 + title="等级设置"
  156 + :visible.sync="diaLogBox"
  157 + width="720px"
  158 + @closed="closeDia"
  159 + >
  160 + <el-form class="use-form">
  161 + <el-form-item class="use-form-item-box">
  162 + <el-form-item label="等级名称:" class="use-form-item">
  163 + <el-select
  164 + size="small"
  165 + v-model="fromData.type"
  166 + @change="changeType"
  167 + >
  168 + <el-option label="优良合格不合格" :value="1"></el-option>
  169 + <el-option label="ABCD" :value="2"></el-option>
  170 + <el-option label="自定义" :value="3"></el-option>
  171 + </el-select>
  172 + </el-form-item>
  173 + <el-form-item label="等级设置模式:" class="use-form-item">
  174 + <el-select
  175 + size="small"
  176 + v-model="fromData.levelType"
  177 + @change="changeLevelType"
  178 + >
  179 + <el-option label="按已考人数比例" :value="0"></el-option>
  180 + <el-option label="按分数比例" :value="1"></el-option>
  181 + </el-select>
  182 + </el-form-item>
  183 + </el-form-item>
  184 + <el-form-item>
  185 + <div class="dia-tab-box">
  186 + <p class="dia-tab-tit">
  187 + <span class="item1">编号</span>
  188 + <span class="item2"><i>*</i>等级名称</span>
  189 + <span class="item2"><i>*</i>等级最高</span>
  190 + <span class="item2"><i>*</i>等级最低</span>
  191 + <span class="item1"></span>
  192 + </p>
  193 + <div
  194 + class="dia-tab-item"
  195 + v-for="(item, index) in fromData.levels"
  196 + >
  197 + <span class="item1">{{ index + 1 }}</span>
  198 + <p class="item2">
  199 + <el-input
  200 + class="score-ipt"
  201 + v-model="item[0]"
  202 + :maxlength="12"
  203 + ></el-input>
  204 + </p>
  205 + <p class="item2">
  206 + <el-input
  207 + class="score-ipt"
  208 + type="number"
  209 + v-model="item[1]"
  210 + :min="item[2]"
  211 + :max="index == 0 ? 150 : fromData.levels[index - 1][2]"
  212 + ></el-input>
  213 + {{ fromData.levelType == 1 ? "%" : "分" }} -
  214 + </p>
  215 + <p class="item2">
  216 + <el-input
  217 + class="score-ipt"
  218 + type="number"
  219 + v-model="item[2]"
  220 + :min="0"
  221 + :max="item[1]"
  222 + ></el-input>
  223 + {{ fromData.levelType == 1 ? "%" : "分" }}
  224 + </p>
  225 + <p class="item1">
  226 + <el-link
  227 + type="danger"
  228 + :underline="false"
  229 + @click="fromData.levels.splice(index, 1)"
  230 + >删除</el-link
  231 + >
  232 + </p>
  233 + </div>
  234 + <div class="add">
  235 + <p @click="fromData.levels.push(['', '', ''])">
  236 + <el-button
  237 + size="mini"
  238 + icon="el-icon-plus"
  239 + circle
  240 + type="primary"
  241 + ></el-button
  242 + >添加一行
  243 + </p>
  244 + </div>
  245 + </div>
  246 + </el-form-item>
  247 + </el-form>
  248 +
  249 + <div class="dialog-footer" slot="footer" align="center">
  250 + <el-button type="danger" @click="savefrom">保存</el-button>
  251 + <el-button @click="diaLogBox = false">取 消</el-button>
  252 + </div>
  253 + </el-dialog>
  254 + </div>
  255 + </div>
  256 +</template>
  257 +
  258 +<script>
  259 +import { downloadFile, tablePrint } from "@/utils";
  260 +export default {
  261 + data() {
  262 + return {
  263 + ids: "",
  264 + title: "",
  265 + subjectNames: "",
  266 + tabList: ["班级对比情况", "学生成绩排名"],
  267 + type: 0,
  268 + loading: false,
  269 + diaLogBox: false,
  270 + fromData: {
  271 + type: 1,
  272 + levelType: 0,
  273 + levels: [
  274 + ["优秀", 100, 90],
  275 + ["良好", 89.9, 70],
  276 + ["合格", 69.9, 60],
  277 + ["不合格", 59.9, 0],
  278 + ],
  279 + },
  280 +
  281 + tableMaxHeight: 600,
  282 + tableData: [],
  283 + tableData2: [],
  284 + };
  285 + },
  286 + created() {
  287 + this.ids = this.$route.query.ids;
  288 + this.title = this.$route.query.title || "";
  289 + this.subjectNames = this.$route.query.subjectNames;
  290 + this._QueryData();
  291 + },
  292 + methods: {
  293 + print() {
  294 + tablePrint("print-content", this.title + "_成绩对比分析");
  295 + },
  296 + setType(type) {
  297 + console.log(this.$refs.main.offsetHeight - 50);
  298 + this.tableMaxHeight = this.$refs.main.offsetHeight;
  299 + this.type = type;
  300 + },
  301 + closeDia() {
  302 + this.fromData.type = 1;
  303 + this.fromData.levelType = 0;
  304 + this.fromData.levels = [
  305 + ["优秀", 100, 90],
  306 + ["良好", 89.9, 70],
  307 + ["合格", 69.9, 60],
  308 + ["不合格", 59.9, 0],
  309 + ];
  310 + },
  311 + changeType(val) {
  312 + if (val == 1) {
  313 + this.fromData.levels = [
  314 + ["优秀", 100, 90],
  315 + ["良好", 89.9, 70],
  316 + ["合格", 69.9, 60],
  317 + ["不合格", 59.9, 0],
  318 + ];
  319 + } else if (val == 2) {
  320 + this.fromData.levels = [
  321 + ["A", 100, 90],
  322 + ["B", 89.9, 70],
  323 + ["C", 69.9, 60],
  324 + ["D", 59.9, 0],
  325 + ];
  326 + } else {
  327 + this.fromData.levels = [
  328 + ["", 100, 90],
  329 + ["", 89.9, 70],
  330 + ["", 69.9, 60],
  331 + ["", 59.9, 0],
  332 + ];
  333 + }
  334 + },
  335 + changeLevelType() {},
  336 + savefrom() {
  337 + this.tableData = [];
  338 + this.tableData2 = [];
  339 +
  340 + for (let i = 0; i < this.fromData.levels.length; i++) {
  341 + if (this.fromData.levels[i].includes("")) {
  342 + this.$message.warning("请补全编号" + (i + 1) + "设置信息!");
  343 + return;
  344 + }
  345 + }
  346 + this._QueryData({
  347 + levelType: this.fromData.levelType,
  348 + levels: this.fromData.levels,
  349 + });
  350 + },
  351 +
  352 + async _QueryData(params) {
  353 + let query = {};
  354 + if (params) {
  355 + query = { ...params };
  356 + }
  357 + const { data, info, status } = await this.$request.examMultiClassReport({
  358 + examIds: this.ids,
  359 + ...query,
  360 + });
  361 + if (status == 200) {
  362 + this.tableData = data.classs || [];
  363 + this.tableData2 = data.students || [];
  364 + } else {
  365 + this.$message.error(info);
  366 + }
  367 + },
  368 +
  369 + //导出
  370 + async exportData() {
  371 + if (this.exportLoading == true) return;
  372 + this.exportLoading = true;
  373 + const data = await this.$request.exportExamMultiReport({
  374 + examId: this.id,
  375 + });
  376 + this.exportLoading = false;
  377 + if (data) {
  378 + let blob = new Blob([data], {
  379 + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  380 + });
  381 + downloadFile("即时测-单卷测练报表.xlsx", blob);
  382 + } else {
  383 + this.$message.error("下载失败");
  384 + }
  385 + },
  386 + },
  387 +};
  388 +</script>
  389 +
  390 +<style lang="scss" scoped>
  391 +.page-container {
  392 + position: relative;
  393 + height: 100%;
  394 + .table-box {
  395 + min-height: 100%;
  396 + }
  397 + &.active {
  398 + overflow: hidden;
  399 + }
  400 + .content-header {
  401 + width: 100%;
  402 + position: relative;
  403 + .setMinScore {
  404 + position: absolute;
  405 + bottom: 0;
  406 + right: 50px;
  407 + }
  408 + }
  409 + .page-content {
  410 + padding: 20px 20px 0;
  411 + }
  412 +}
  413 +.tab-box {
  414 + width: 800px;
  415 + margin: 0 auto 12px;
  416 + background: #f8f8f8;
  417 + border-radius: 20px;
  418 + display: flex;
  419 + user-select: none;
  420 + .tab-item {
  421 + flex: 1;
  422 + height: 40px;
  423 + line-height: 40px;
  424 + text-align: center;
  425 + font-size: 16px;
  426 + color: #666;
  427 + font-weight: 500;
  428 + background: transparent;
  429 + border-radius: 20px;
  430 + cursor: pointer;
  431 + &.active {
  432 + background: #667ffd;
  433 + color: #fff;
  434 + }
  435 + }
  436 +}
  437 +.down {
  438 + padding-top: 20px;
  439 + width: 100%;
  440 + display: flex;
  441 + justify-content: space-between;
  442 +}
  443 +.use-form {
  444 + padding: 0 12px;
  445 + .use-form-item-box {
  446 + :deep(.el-form-item__content) {
  447 + display: flex;
  448 + }
  449 + .use-form-item {
  450 + width: 40%;
  451 + margin-right: 20px;
  452 + }
  453 + }
  454 +}
  455 +.dia-tab-box {
  456 + .dia-tab-tit,
  457 + .dia-tab-item {
  458 + margin-bottom: 10px;
  459 + i {
  460 + color: #f30;
  461 + padding-right: 5px;
  462 + }
  463 + display: flex;
  464 + .item1 {
  465 + padding-left: 10px;
  466 + width: 15%;
  467 + }
  468 + .item2 {
  469 + flex: 1;
  470 + }
  471 + .score-ipt {
  472 + width: 100px;
  473 + }
  474 + }
  475 + .dia-tab-tit {
  476 + background: rgba(243, 243, 243, 1);
  477 + }
  478 + .add {
  479 + display: flex;
  480 + justify-content: center;
  481 + margin: 0 auto;
  482 + p {
  483 + cursor: pointer;
  484 + }
  485 + .el-button {
  486 + margin-right: 6px;
  487 + }
  488 + }
  489 +}
  490 +</style>
0 491 \ No newline at end of file
... ...
src/views/standard/test/index.vue
... ... @@ -26,9 +26,11 @@
26 26 <div class="sel-box">
27 27 <el-select
28 28 class="sel"
29   - v-model="query.classId"
  29 + v-model="query.classIds"
30 30 placeholder="选择班级"
31 31 @change="changeclass"
  32 + multiple
  33 + collapse-tags
32 34 >
33 35 <el-option
34 36 v-for="item in classList"
... ... @@ -40,7 +42,7 @@
40 42 </el-select>
41 43 <el-select
42 44 v-if="role == 'ROLE_BANZHUREN'"
43   - class="sel"
  45 + class="sel sel2"
44 46 multiple
45 47 v-model="query.subjectNames"
46 48 placeholder="选择科目"
... ... @@ -56,7 +58,7 @@
56 58 </el-select>
57 59 <el-select
58 60 v-else
59   - class="sel"
  61 + class="sel sel2"
60 62 v-model="query.subjectNames"
61 63 placeholder="选择科目"
62 64 >
... ... @@ -104,7 +106,7 @@
104 106 <el-button type="primary" round @click="_QueryData()">筛选</el-button>
105 107 </div>
106 108 </div>
107   - <div class="table-box">
  109 + <div v-show="query.classIds.length == 1" class="table-box">
108 110 <el-radio-group
109 111 v-model="tabIndex"
110 112 @change="changeTab"
... ... @@ -122,29 +124,51 @@
122 124 <div v-show="tabIndex == 1" v-loading="loading">
123 125 <el-table :data="tableData" border style="width: 100%">
124 126 <el-table-column
  127 + prop="subjectName"
  128 + label="科目"
  129 + align="center"
  130 + width="100"
  131 + ></el-table-column>
  132 + <el-table-column
125 133 prop="title"
126 134 label="试卷名称"
127   - fixed
128 135 align="center"
129 136 ></el-table-column>
130 137 <el-table-column
  138 + prop="clazz"
  139 + label="考试班级"
  140 + align="center"
  141 + width="100"
  142 + ></el-table-column>
  143 + <el-table-column
131 144 prop="examPaperScore"
132 145 label="卷面分"
133 146 align="center"
134 147 width="68"
135 148 ></el-table-column>
136   - <el-table-column prop="answeredNum" label="测验人数" align="center"
  149 + <el-table-column
  150 + width="80"
  151 + prop="answeredNum"
  152 + label="测验人数"
  153 + align="center"
137 154 ><template slot-scope="scoped">{{
138 155 `${scoped.row.answeredNum}/${scoped.row.classPersonNum}`
139 156 }}</template></el-table-column
140 157 >
141 158 <el-table-column
142 159 prop="examStartTime"
143   - label="测验时间"
144   - width="100"
  160 + label="测验开始时间"
  161 + width="160"
  162 + align="center"
  163 + ></el-table-column>
  164 + <el-table-column
  165 + prop="examEndTime"
  166 + label="测验结束时间"
  167 + width="160"
145 168 align="center"
146 169 ></el-table-column>
147   - <el-table-column prop="avgScore" label="班平均分" align="center"
  170 + <!-- 添加对比删除 -->
  171 + <!-- <el-table-column prop="avgScore" label="班平均分" align="center"
148 172 ><template slot-scope="scoped">{{
149 173 (scoped.row.subjectiveScore == scoped.row.examPaperScore ||
150 174 scoped.row.answerNum == 0) &&
... ... @@ -270,8 +294,8 @@
270 294 </p>
271 295 </template>
272 296 </template></el-table-column
273   - >
274   - <el-table-column label="操作" align="center">
  297 + > -->
  298 + <el-table-column label="操作" width="100" align="center">
275 299 <template slot-scope="scoped">
276 300 <el-tooltip
277 301 v-if="
... ... @@ -330,6 +354,19 @@
330 354 @click="uploadSJ(scoped.row)"
331 355 ></el-button>
332 356 </el-tooltip>
  357 + <el-popconfirm
  358 + title="确定删除吗?"
  359 + @confirm="removeReport(scoped.row, scoped.$index)"
  360 + >
  361 + <el-button
  362 + class="remove-test"
  363 + slot="reference"
  364 + type="danger"
  365 + circle
  366 + size="mini"
  367 + icon="el-icon-delete"
  368 + ></el-button>
  369 + </el-popconfirm>
333 370 </template>
334 371 </el-table-column>
335 372 </el-table>
... ... @@ -480,7 +517,91 @@
480 517 >
481 518 </p>
482 519 </div>
483   - <el-dialog :close-on-click-modal="false" title="导入主观题分数" :visible.sync="diaUp" width="600">
  520 + <div v-show="query.classIds.length > 1" class="table-box">
  521 + <el-empty
  522 + :imag-size="48"
  523 + v-if="!classTableLen && loading"
  524 + description="暂无数据"
  525 + ></el-empty>
  526 + <div class="head-box" v-if="classTableLen">
  527 + <div class="tit">
  528 + <p class="txt">已考试卷信息</p>
  529 + <p>
  530 + 共筛选出{{ classTableLen }}个班级的已考试卷,<em class="red"
  531 + >不同班级请选择同一份试卷进行对比</em
  532 + >
  533 + </p>
  534 + </div>
  535 + <el-input
  536 + placeholder="输入试卷名称"
  537 + v-model="examReportName"
  538 + class="input-with-select"
  539 + @keyup.enter.native="examReportList(examReportName)"
  540 + >
  541 + <el-button
  542 + slot="append"
  543 + icon="el-icon-search"
  544 + @click="examReportList(examReportName)"
  545 + ></el-button>
  546 + </el-input>
  547 + </div>
  548 + <ul class="tab-ul">
  549 + <template v-for="(item, index) in classTable">
  550 + <li class="tab-li" v-if="item.length">
  551 + <p class="tab-tit">{{ item[0].className }}</p>
  552 + <el-table :data="item" border style="width: 100%">
  553 + <el-table-column label="选择" align="center" width="60">
  554 + <template slot-scope="scope">
  555 + <el-checkbox
  556 + v-model="multipleSelection"
  557 + :label="scope.row.id"
  558 + :disabled="checkboxDisabled(scope.row)"
  559 + >
  560 + {{ ` ` }}</el-checkbox
  561 + >
  562 + </template>
  563 + </el-table-column>
  564 + <el-table-column
  565 + prop="title"
  566 + label="试卷名称"
  567 + align="center"
  568 + ></el-table-column>
  569 + <el-table-column
  570 + prop="classPersonNum"
  571 + label="测验人数"
  572 + align="center"
  573 + width="80"
  574 + ></el-table-column>
  575 + <el-table-column
  576 + prop="examStartTime"
  577 + label="测验开始时间"
  578 + width="120"
  579 + align="center"
  580 + ></el-table-column>
  581 + <el-table-column
  582 + prop="duration"
  583 + label="测验时长"
  584 + align="center"
  585 + width="80"
  586 + >
  587 + <template slot-scope="scope">{{
  588 + (scope.row.duration / 60).toFixed(2)
  589 + }}</template>
  590 + </el-table-column>
  591 + </el-table>
  592 + </li>
  593 + </template>
  594 + </ul>
  595 + <p class="btn-box" v-if="classTableLen">
  596 + <el-button @click="linkToContrast">生成对比报表</el-button>
  597 + </p>
  598 + </div>
  599 + <el-dialog
  600 + :close-on-click-modal="false"
  601 + title="导入主观题分数"
  602 + :visible.sync="diaUp"
  603 + width="600"
  604 + >
484 605 <up-load
485 606 :url="url"
486 607 :examId="examId"
... ... @@ -527,13 +648,14 @@ export default {
527 648 date: "", //今天-昨天-本周
528 649 query: {
529 650 //搜索条件
530   - classId: "",
  651 + classIds: [],
531 652 subjectNames: "",
532 653 startDay: "",
533 654 endDay: "",
534 655 day: "",
535 656 },
536   - tabList: ["单卷测练报表", "阶段测练报表"],
  657 + examReportName: "", //试卷名称
  658 + tabList: ["已考试卷信息", "阶段测练报表"],
537 659 classList: [], //班级
538 660 subjectList: [], //科目
539 661 tabIndex: 1, //选项卡
... ... @@ -542,8 +664,19 @@ export default {
542 664 page: 1,
543 665 size: 20,
544 666 total: 0,
  667 + multipleSelection: [], //选中的试卷ID
  668 + classTable: [[], []], //多班级数据
545 669 };
546 670 },
  671 + computed: {
  672 + classTableLen: function () {
  673 + let len = 0;
  674 + this.classTable.map((item) => {
  675 + item.length ? (len += 1) : "";
  676 + });
  677 + return len;
  678 + },
  679 + },
547 680 async created() {
548 681 this.code = localStorage.getItem("csCode") || "";
549 682 this.role =
... ... @@ -551,7 +684,7 @@ export default {
551 684 this.$store.getters.info.permissions[0].role;
552 685 this._QueryClassList2();
553 686 await this._QueryClassList();
554   - if (!this.query.classId) {
  687 + if (!this.query.classIds.length) {
555 688 return;
556 689 }
557 690 await this._QuerySubjectList();
... ... @@ -569,7 +702,7 @@ export default {
569 702 that.query.subjectNames = that.role == "ROLE_BANZHUREN" ? [] : "";
570 703 that._QueryClassList2();
571 704 await that._QueryClassList();
572   - if (!that.query.classId) {
  705 + if (!that.query.classIds.length) {
573 706 return;
574 707 }
575 708 await that._QuerySubjectList();
... ... @@ -583,11 +716,27 @@ export default {
583 716 });
584 717 },
585 718 methods: {
  719 + // 多班级选择同一试卷
  720 + checkboxDisabled(obj) {
  721 + let id = this.multipleSelection[0] || "";
  722 + if (id) {
  723 + let examPaperId;
  724 + for (let i = 0; i < this.tableData.length; i++) {
  725 + if (this.tableData[i].id == id) {
  726 + examPaperId = this.tableData[i].examPaperId;
  727 + break;
  728 + }
  729 + }
  730 + return obj.examPaperId == examPaperId ? false : true;
  731 + } else {
  732 + return false;
  733 + }
  734 + },
586 735 print() {
587 736 tablePrint("print-content", "即时测-" + this.tabList[this.tabIndex - 1]);
588 737 },
  738 + //科目改变触发事件
589 739 changeSub(val) {
590   - //科目改变触发事件
591 740 let sub;
592 741 if (val && val.length) {
593 742 let leng = val.length - 1;
... ... @@ -603,19 +752,43 @@ export default {
603 752 path: "/testArchiving",
604 753 });
605 754 },
  755 + //去详情
606 756 linkTo(obj) {
607   - //去详情
608 757 this.$router.push({
609 758 path: "/testAnalysis",
610 759 query: {
611 760 id: obj.id,
612 761 title: obj.title,
613 762 score: obj.examPaperScore,
  763 + classId: obj.classId,
  764 + subjectName: obj.subjectName,
  765 + },
  766 + });
  767 + },
  768 + //去报表对比
  769 + linkToContrast() {
  770 + if (this.multipleSelection.length < 2) {
  771 + this.$message.warning("请选择同一份试卷多个班级进行对比!");
  772 + return;
  773 + }
  774 + let title = "";
  775 + for (let i = 0; i < this.tableData.length; i++) {
  776 + if (this.tableData[i].id == this.multipleSelection[0]) {
  777 + title = this.tableData[i].title;
  778 + break;
  779 + }
  780 + }
  781 + this.$router.push({
  782 + path: "/testContrast",
  783 + query: {
  784 + ids: this.multipleSelection,
  785 + subjectNames: this.query.subjectNames,
  786 + title: title,
614 787 },
615 788 });
616 789 },
  790 + //暂时不上线
617 791 toPortrait(obj) {
618   - //暂时不上线
619 792 return;
620 793 if (this.$store.getters.code) {
621 794 return;
... ... @@ -650,11 +823,23 @@ export default {
650 823 },
651 824 });
652 825 },
  826 + //导入开关
653 827 uploadSJ(obj) {
654   - //导入开关
655 828 this.examId = obj.id;
656 829 this.diaUp = true;
657 830 },
  831 + //删除即时测考试
  832 + async removeReport(obj, index) {
  833 + const { data, status, info } = await this.$request.deleteReport({
  834 + id: obj.id,
  835 + });
  836 + if (status == 200) {
  837 + this.$message.success("删除成功!");
  838 + this.tableData = this.tableData.splice(index, 1);
  839 + } else {
  840 + this.$message.error(info);
  841 + }
  842 + },
658 843 setDate(index) {
659 844 const that = this;
660 845 this.date = index == this.date ? "" : index;
... ... @@ -744,23 +929,20 @@ export default {
744 929 this.page = 1;
745 930 this._QueryData();
746 931 },
  932 + //导入成功
747 933 upSuccess(res) {
748   - //导入成功
749 934 this.$message.success("导入成功");
750 935 this.diaUp = false;
751 936 this._QueryData();
752 937 },
  938 + //切换班级
753 939 async changeclass() {
754 940 await this._QuerySubjectList();
755 941 this.page = 1;
756 942 this._QueryData();
757 943 },
758   - async changClazz() {
759   - this.page = 1;
760   - await this._QuerySubjectList();
761   - await this._QueryData();
762   - },
763 944 async _QueryClassList2() {
  945 + if (this.code) return;
764 946 const fetchClassList =
765 947 this.role == "ROLE_BANZHUREN"
766 948 ? this.$request.cTClassList
... ... @@ -778,6 +960,7 @@ export default {
778 960 ? this.$request.cTClassList
779 961 : this.$request.tClassList;
780 962 const { data, status, info } = await fetchClassList();
  963 + this.query.classIds = [];
781 964 if (status === 0) {
782 965 this.classList = data.list.map((item) => {
783 966 return {
... ... @@ -785,20 +968,25 @@ export default {
785 968 label: item.className,
786 969 };
787 970 });
788   - this.query.classId = this.classList[0]?.value;
  971 + this.query.classIds.push(this.classList[0]?.value);
789 972 } else {
790 973 this.$message.error(info);
791 974 }
792 975 },
793 976 async _QuerySubjectList() {
  977 + let query = {};
  978 + if (!this.query.classIds.length) return;
  979 + if (this.query.classIds.length == 1) {
  980 + query.classId = this.query.classIds[0];
  981 + } else {
  982 + query.classIds = this.query.classIds;
  983 + }
794 984 const fetchSubjectList =
795 985 this.role == "ROLE_BANZHUREN"
796 986 ? this.$request.cTSubjectList
797 987 : this.$request.tSubjectList;
798 988  
799   - const { data, status, info } = await fetchSubjectList({
800   - classId: this.query.classId,
801   - });
  989 + const { data, status, info } = await fetchSubjectList({ ...query });
802 990 if (status === 0) {
803 991 this.subjectList =
804 992 data.subjectNames?.map((item) => {
... ... @@ -821,9 +1009,8 @@ export default {
821 1009 }
822 1010 },
823 1011 async _QueryData() {
824   - if (!this.query.classId) {
825   - return;
826   - }
  1012 + this.examReportName = "";
  1013 + if (!this.query.classIds.length) return;
827 1014 this.tableData = [];
828 1015 if (this.tabIndex == 1) {
829 1016 this.examReportList();
... ... @@ -832,7 +1019,7 @@ export default {
832 1019 }
833 1020 },
834 1021 //单卷测练
835   - async examReportList() {
  1022 + async examReportList(msg) {
836 1023 this.loading = true;
837 1024 let query = {};
838 1025 for (let key in this.query) {
... ... @@ -858,15 +1045,39 @@ export default {
858 1045 return;
859 1046 }
860 1047 }
  1048 + if (this.query.classIds.length == 1) {
  1049 + query.classId = query.classIds[0];
  1050 + query.page = this.page;
  1051 + query.size = this.size;
  1052 + delete query.classIds;
  1053 + }
  1054 + if (msg) {
  1055 + query.title = msg;
  1056 + }
861 1057 const { data, status, info } = await this.$request.examReportList({
862 1058 ...query,
863   - page: this.page,
864   - size: this.size,
865 1059 });
866 1060 this.loading = false;
867 1061 if (status === 0) {
868   - this.tableData = (data?.list && [...data?.list]) || [];
869   - this.total = data?.count || 0;
  1062 + if (query.classId) {
  1063 + //单班级
  1064 + this.tableData = (data?.list && [...data?.list]) || [];
  1065 + this.total = data?.count || 0;
  1066 + } else {
  1067 + //多班级
  1068 + this.classTable = [];
  1069 + let tableData = [];
  1070 + this.tableData = (data?.list && [...data?.list]) || [];
  1071 + data?.list.map((item) => {
  1072 + let idx = query.classIds.indexOf(item);
  1073 + if (tableData[idx]) {
  1074 + tableData[idx].push(item);
  1075 + } else {
  1076 + tableData[idx] = [item];
  1077 + }
  1078 + });
  1079 + this.classTable = [...tableData];
  1080 + }
870 1081 } else {
871 1082 this.$message.error(info);
872 1083 }
... ... @@ -896,6 +1107,10 @@ export default {
896 1107 query["subjectNames"]?.shift();
897 1108 }
898 1109 }
  1110 + if (this.query.classIds.length == 1) {
  1111 + query.classId = query.classIds[0];
  1112 + delete query.classIds;
  1113 + }
899 1114 const phaseExamReport =
900 1115 this.role == "ROLE_BANZHUREN"
901 1116 ? this.$request.cTPhaseExamReport
... ... @@ -961,8 +1176,8 @@ export default {
961 1176 this.$message.error(info);
962 1177 }
963 1178 },
  1179 + //报表导出
964 1180 async downExl() {
965   - //报表到处
966 1181 if (this.exportLoading == true) return;
967 1182 let query = {};
968 1183 for (let key in this.query) {
... ... @@ -1006,8 +1221,8 @@ export default {
1006 1221 this.$message.error(data.info);
1007 1222 }
1008 1223 },
  1224 + //模板下载
1009 1225 async downExcel() {
1010   - //模板下载
1011 1226 this.loadingDown = true;
1012 1227 let data = await this.$request.subjectiveScoreTemplate({
1013 1228 examId: this.examId,
... ... @@ -1064,4 +1279,85 @@ div::-webkit-scrollbar-thumb {
1064 1279 color: #409eff;
1065 1280 text-decoration: underline;
1066 1281 }
  1282 +.head-box {
  1283 + display: flex;
  1284 + justify-content: space-between;
  1285 + font-size: 12px;
  1286 + color: #999;
  1287 + .txt {
  1288 + font-size: 16px;
  1289 + color: #333;
  1290 + line-height: 20px;
  1291 + position: relative;
  1292 + margin-bottom: 6px;
  1293 + &:after {
  1294 + content: "";
  1295 + position: absolute;
  1296 + top: 0;
  1297 + left: -16px;
  1298 + width: 4px;
  1299 + height: 100%;
  1300 + background: #409eff;
  1301 + }
  1302 + }
  1303 + .red {
  1304 + font-style: normal;
  1305 + color: #f30;
  1306 + }
  1307 + .sel {
  1308 + width: 200px;
  1309 + :deep(.el-input__inner) {
  1310 + border-radius: 20px;
  1311 + }
  1312 + }
  1313 +}
  1314 +.tab-ul {
  1315 + display: flex;
  1316 + flex-wrap: wrap;
  1317 + .tab-li {
  1318 + width: 50%;
  1319 + flex: 1;
  1320 + margin: 0 12px 12px 0;
  1321 + &:nth-child(2n) {
  1322 + margin-right: 0;
  1323 + }
  1324 + .tab-tit {
  1325 + width: 100%;
  1326 + line-height: 40px;
  1327 + border: 1px solid #ebeef5;
  1328 + }
  1329 + }
  1330 +}
  1331 +.btn-box {
  1332 + padding-top: 12px;
  1333 + text-align: right;
  1334 +}
  1335 +.remove-test {
  1336 + margin-left: 10px;
  1337 +}
  1338 +.input-with-select {
  1339 + width: 200px;
  1340 + height: 36px;
  1341 + margin-right: 50px;
  1342 + border-radius: 20px;
  1343 + border: 1px solid #e2e2e2;
  1344 + box-sizing: border-box;
  1345 + background: #fff;
  1346 + :deep(.el-input__inner) {
  1347 + border-radius: 20px;
  1348 + border: none;
  1349 + height: 34px;
  1350 + line-height: 34px;
  1351 + padding-right: 0;
  1352 + }
  1353 + :deep(.el-button) {
  1354 + padding: 12px;
  1355 + }
  1356 +
  1357 + :deep(.el-input-group__append),
  1358 + :deep(.el-input-group__prepend) {
  1359 + border: none;
  1360 + background: transparent;
  1361 + }
  1362 +}
1067 1363 </style>
1068 1364 \ No newline at end of file
... ...