Commit 881a7e55a938ea64823d6d7d11e79e250aac9b2c

Authored by 梁保满
1 parent 3ac930bd

多班对比

src/views/basic/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 class="setMinScore" @click="openDia" round size="small"
  21 + >对比成绩等级设置</el-button
  22 + >
  23 + </div>
  24 + <div id="print-content" class="table-box" v-loading="loading">
  25 + <el-table
  26 + :max-height="tableMaxHeight"
  27 + v-show="type == 0"
  28 + :data="tableData"
  29 + border
  30 + style="width: 100%"
  31 + >
  32 + <el-table-column
  33 + type="index"
  34 + label="序号"
  35 + fixed
  36 + align="center"
  37 + width="60"
  38 + ></el-table-column>
  39 + <el-table-column
  40 + prop="className"
  41 + label="班级"
  42 + align="center"
  43 + fixed
  44 + ></el-table-column>
  45 + <el-table-column label="测验人数/班级人数" align="center" width="84">
  46 + <template slot-scope="scope">
  47 + <p v-for="(item, index) in scope.row.count.split('/')">
  48 + {{ item }}{{ index == 0 ? "/" : "" }}
  49 + </p>
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column
  53 + prop="percent"
  54 + label="参与度"
  55 + align="center"
  56 + ></el-table-column>
  57 + <el-table-column
  58 + prop="avg"
  59 + label="班平均分"
  60 + align="center"
  61 + ></el-table-column>
  62 + <el-table-column
  63 + prop="max"
  64 + label="班最高分"
  65 + sortable
  66 + align="center"
  67 + ></el-table-column>
  68 + <el-table-column
  69 + prop="min"
  70 + label="班最低分"
  71 + sortable
  72 + align="center"
  73 + ></el-table-column>
  74 +
  75 + <el-table-column
  76 + v-for="(item, index) in defaultLevels.levels"
  77 + :label="item[0] + '数(率)'"
  78 + align="center"
  79 + ><template slot-scope="scoped">
  80 + <p class="p1">{{ scoped.row.levels[index].people }}</p>
  81 + <p class="p1">({{ scoped.row.levels[index].percent }})</p>
  82 + </template></el-table-column
  83 + >
  84 + </el-table>
  85 + <el-table
  86 + v-show="type == 1"
  87 + :max-height="tableMaxHeight"
  88 + :data="tableData2"
  89 + border
  90 + style="width: 100%"
  91 + >
  92 + <el-table-column
  93 + prop="rank"
  94 + label="排名"
  95 + sortable
  96 + align="center"
  97 + ></el-table-column>
  98 + <el-table-column
  99 + prop="name"
  100 + label="姓名"
  101 + align="center"
  102 + ></el-table-column>
  103 + <el-table-column
  104 + prop="className"
  105 + label="班级"
  106 + align="center"
  107 + ></el-table-column>
  108 + <el-table-column
  109 + prop="score"
  110 + label="总分"
  111 + sortable
  112 + align="center"
  113 + ></el-table-column>
  114 + <el-table-column
  115 + prop="levelName"
  116 + label="成绩等级"
  117 + align="center"
  118 + ></el-table-column>
  119 + </el-table>
  120 + </div>
  121 + <div class="down">
  122 + <div>
  123 + <el-button
  124 + v-loading="exportLoading"
  125 + @click="exportData"
  126 + type="primary"
  127 + plain
  128 + round
  129 + icon="fa fa-cloud-download"
  130 + >导出报表</el-button
  131 + >
  132 + <el-button
  133 + v-if="!this.$store.getters.code"
  134 + @click="print"
  135 + type="primary"
  136 + plain
  137 + round
  138 + icon="el-icon-printer"
  139 + >打印</el-button
  140 + >
  141 + </div>
  142 + </div>
  143 +
  144 + <el-dialog
  145 + :close-on-click-modal="false"
  146 + title="等级设置"
  147 + :visible.sync="diaLogBox"
  148 + width="800px"
  149 + @closed="closeDia"
  150 + >
  151 + <el-form class="use-form">
  152 + <el-form-item class="use-form-item-box">
  153 + <el-form-item label="等级名称:" class="use-form-item">
  154 + <el-select
  155 + size="small"
  156 + v-model="fromData.type"
  157 + @change="changeType"
  158 + >
  159 + <el-option label="优良合格不合格" :value="0"></el-option>
  160 + <el-option label="ABCD" :value="1"></el-option>
  161 + <el-option label="自定义" :value="2"></el-option>
  162 + </el-select>
  163 + </el-form-item>
  164 + <el-form-item label="等级设置模式:" class="use-form-item">
  165 + <el-select size="small" v-model="fromData.levelType">
  166 + <el-option label="按分数比例" :value="0"></el-option>
  167 + <el-option label="按已考人数比例" :value="1"></el-option>
  168 + </el-select>
  169 + </el-form-item>
  170 + </el-form-item>
  171 + <el-form-item>
  172 + <div class="dia-tab-box">
  173 + <p class="dia-tab-tit">
  174 + <span class="item1">编号</span>
  175 + <span class="item2"><i>*</i>等级名称</span>
  176 + <span class="item3"><i>*</i>等级最高</span>
  177 + <span class="item3"><i>*</i>等级最低</span>
  178 + <span class="item"></span>
  179 + </p>
  180 + <div
  181 + class="dia-tab-item"
  182 + v-for="(item, index) in fromData.levels"
  183 + >
  184 + <span class="item1">{{ index + 1 }}</span>
  185 + <p class="item2">
  186 + <el-input
  187 + class="score-ipt"
  188 + v-model="item[0]"
  189 + :maxlength="12"
  190 + @keydown.native="keydownRange($event)"
  191 + ></el-input>
  192 + </p>
  193 + <p class="item3">
  194 + <el-input
  195 + class="score-ipt"
  196 + type="number"
  197 + v-model="item[1]"
  198 + :min="item[2]"
  199 + :max="index == 0 ? 100 : fromData.levels[index - 1][2]"
  200 + @keydown.native="keydownRange($event)"
  201 + ></el-input>
  202 + %
  203 + <template v-if="fromData.levelType == 0">
  204 + ({{ index != 0 ? "不含" : ""
  205 + }}{{
  206 + Number(((item[1] / 100) * examPaperScore).toFixed(1))
  207 + }}分)
  208 + </template>
  209 + <template v-else>{{ index != 0 ? "不含" : "" }}</template>
  210 + </p>
  211 + <p>~</p>
  212 + <p class="item3">
  213 + <el-input
  214 + class="score-ipt"
  215 + type="number"
  216 + v-model="item[2]"
  217 + :min="0"
  218 + :max="item[1]"
  219 + @keydown.native="keydownRange($event)"
  220 + ></el-input>
  221 + %
  222 + <template v-if="fromData.levelType == 0">
  223 + ({{
  224 + Number(((item[2] / 100) * examPaperScore).toFixed(1))
  225 + }}分)
  226 + </template>
  227 + </p>
  228 + <p class="item">
  229 + <el-link
  230 + type="danger"
  231 + :underline="false"
  232 + @click="fromData.levels.splice(index, 1)"
  233 + >删除</el-link
  234 + >
  235 + </p>
  236 + </div>
  237 + <div class="add">
  238 + <p @click="fromData.levels.push(['', '', ''])">
  239 + <el-button
  240 + size="mini"
  241 + icon="el-icon-plus"
  242 + circle
  243 + type="primary"
  244 + ></el-button
  245 + >添加一行
  246 + </p>
  247 + </div>
  248 + </div>
  249 + </el-form-item>
  250 + </el-form>
  251 +
  252 + <div class="dialog-footer" slot="footer" align="center">
  253 + <el-button type="danger" @click="savefrom">保存</el-button>
  254 + <el-button @click="diaLogBox = false">取 消</el-button>
  255 + </div>
  256 + </el-dialog>
  257 + </div>
  258 + </div>
  259 +</template>
  260 +
  261 +<script>
  262 +import { downloadFile, tablePrint } from "@/utils";
  263 +export default {
  264 + data() {
  265 + return {
  266 + ids: "",
  267 + title: "",
  268 + subjectNames: "",
  269 + tabList: ["班级对比情况", "学生成绩排名"],
  270 + type: 0,
  271 + loading: false,
  272 + exportLoading: false,
  273 + diaLogBox: false,
  274 + fromData: {
  275 + type: 0,
  276 + levelType: 0,
  277 + levels: [
  278 + ["优秀", 100, 90],
  279 + ["良好", 89.9, 70],
  280 + ["合格", 69.9, 60],
  281 + ["不合格", 59.9, 0],
  282 + ],
  283 + },
  284 + defaultLevels: {
  285 + levelType: 0,
  286 + levels: [],
  287 + },
  288 + tableMaxHeight: 600,
  289 + tableData: [],
  290 + tableData2: [],
  291 + examPaperScore: 100, //卷面最高分
  292 + };
  293 + },
  294 + async created() {
  295 + this.ids = this.$route.query.ids;
  296 + await this._QueryData();
  297 + await this._QueryDefaultLevels();
  298 + },
  299 + destroyed() {
  300 + sessionStorage.setItem("levelFromData", "");
  301 + },
  302 + methods: {
  303 + // 禁止输入负数
  304 + keydownRange(event) {
  305 + if (event.key == "-" || event.key == "e") {
  306 + event.returnValue = "";
  307 + }
  308 + },
  309 + print() {
  310 + tablePrint(
  311 + "print-content",
  312 + `多班_${this.subjectNames}_${this.title}_测练成绩对比分析`
  313 + );
  314 + },
  315 + setType(type) {
  316 + console.log(this.$refs.main.offsetHeight - 50);
  317 + this.tableMaxHeight = this.$refs.main.offsetHeight;
  318 + this.type = type;
  319 + },
  320 + openDia() {
  321 + this.diaLogBox = true;
  322 + },
  323 + closeDia() {
  324 + let levelFromData = sessionStorage.getItem("levelFromData");
  325 + if (levelFromData) {
  326 + levelFromData = JSON.parse(levelFromData);
  327 + this.fromData.type = levelFromData.type;
  328 + this.fromData.levelType = levelFromData.levelType;
  329 + this.fromData.levels = [...levelFromData.levels];
  330 + } else {
  331 + this.fromData.type = 0;
  332 + this.fromData.levelType = this.defaultLevels.levelType;
  333 + this.fromData.levels = [...this.defaultLevels.levels];
  334 + }
  335 + },
  336 + changeType(val) {
  337 + if (val == this.defaultLevels.type) {
  338 + this.fromData.levels = [...this.defaultLevels.levels];
  339 + } else {
  340 + this.fromData.levels = this.fromData.levels.splice(0, 4);
  341 + if (val == 0) {
  342 + this.fromData.levels = this.fromData.levels.map((item, index) => {
  343 + let arrTxt = ["优秀", "良好", "合格", "不合格"];
  344 + return [arrTxt[index], item[1], item[2]];
  345 + });
  346 + } else if (val == 1) {
  347 + this.fromData.levels = this.fromData.levels.map((item, index) => {
  348 + let arrTxt = ["A", "B", "C", "D"];
  349 + return [arrTxt[index], item[1], item[2]];
  350 + });
  351 + } else {
  352 + this.fromData.levels = this.fromData.levels.map((item, index) => {
  353 + return ["", item[1], item[2]];
  354 + });
  355 + }
  356 + }
  357 + },
  358 + savefrom() {
  359 + for (let i = 0; i < this.fromData.levels.length; i++) {
  360 + if (this.fromData.levels[i].includes("")) {
  361 + this.$message.warning("请补全编号" + (i + 1) + "设置信息!");
  362 + return;
  363 + }
  364 + }
  365 + if (this.fromData.levels.length == 0) {
  366 + this.$message.warning("请添加等级设置!");
  367 + return;
  368 + }
  369 + let nums = [];
  370 + let ERR_OK = false;
  371 + this.fromData.levels.map((item) => {
  372 + nums.push(Number(item[1]));
  373 + nums.push(Number(item[2]));
  374 + });
  375 + for (let i = 0; i < nums.length; i++) {
  376 + if (nums[i + 1] && nums[i + 1] > nums[i]) {
  377 + ERR_OK = true;
  378 + this.$message.warning("高等级比例不能低于低等级比例!请检查");
  379 + break;
  380 + }
  381 + }
  382 + if (ERR_OK) return;
  383 + this.tableData = [];
  384 + this.tableData2 = [];
  385 + this.defaultLevels.type = this.fromData.type;
  386 + this.defaultLevels.levelType = this.fromData.levelType;
  387 + this.defaultLevels.levels = [...this.fromData.levels];
  388 + sessionStorage.setItem("levelFromData", JSON.stringify(this.fromData));
  389 + this.diaLogBox = false;
  390 + this._QueryData({
  391 + levelType: this.fromData.levelType,
  392 + levels: this.fromData.levels,
  393 + });
  394 + },
  395 +
  396 + async _QueryDefaultLevels() {
  397 + const { data, info, status } = await this.$request.defaultLevels();
  398 + if (status === 0) {
  399 + this.defaultLevels = { ...data } || {
  400 + levelType: 0,
  401 + levels: [
  402 + ["优秀", 100, 90],
  403 + ["良好", 89.9, 70],
  404 + ["合格", 69.9, 60],
  405 + ["不合格", 59.9, 0],
  406 + ],
  407 + };
  408 + this.defaultLevels.type = 0
  409 + this.fromData.levelType = this.defaultLevels.levelType;
  410 + this.fromData.levels = [...this.defaultLevels.levels];
  411 + sessionStorage.setItem(
  412 + "levelFromData",
  413 + JSON.stringify(this.defaultLevels)
  414 + );
  415 + } else {
  416 + this.$message.error(info);
  417 + }
  418 + },
  419 + async _QueryData(params) {
  420 + let query = {};
  421 + if (params) {
  422 + let paramObj = JSON.parse(JSON.stringify(params))
  423 + if (paramObj.levelType == 0) {
  424 + paramObj.levels = paramObj.levels.map((item) => {
  425 + item[1] = ((item[1] / 100) * this.examPaperScore).toFixed(1);
  426 + item[2] = ((item[2] / 100) * this.examPaperScore).toFixed(1);
  427 + return item;
  428 + });
  429 + }
  430 + query = { ...paramObj };
  431 + }
  432 + const { data, info, status } = await this.$request.examMultiClassReport({
  433 + examIds: this.ids,
  434 + ...query,
  435 + });
  436 + if (status === 0) {
  437 + this.title = data.title;
  438 + this.examPaperScore = data.examPaperScore || 100;
  439 + this.subjectNames = data.subjectName;
  440 + this.tableData = data.classes || [];
  441 + this.tableData2 =
  442 + data.students.map((item) => {
  443 + item.score = Number(item.score);
  444 + return item;
  445 + }) || [];
  446 + } else {
  447 + this.$message.error(info);
  448 + }
  449 + },
  450 +
  451 + //导出
  452 + async exportData() {
  453 + if (this.exportLoading == true) return;
  454 + this.exportLoading = true;
  455 + let params = { ...this.fromData };
  456 + if (params.levelType == 0) {
  457 + params.levels = params.levels.map((item) => {
  458 + console.log(item);
  459 + item[1] = ((item[1] / 100) * this.examPaperScore).toFixed(1);
  460 + item[2] = ((item[2] / 100) * this.examPaperScore).toFixed(1);
  461 + return item;
  462 + });
  463 + }
  464 + const data = await this.$request.exportExamMultiReport({
  465 + examIds: this.ids,
  466 + levels: params.levels,
  467 + levelType: params.levelType,
  468 + });
  469 + this.exportLoading = false;
  470 + if (data) {
  471 + let blob = new Blob([data], {
  472 + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  473 + });
  474 + downloadFile(
  475 + `多班_${this.subjectNames}_${this.title}_测练成绩对比分析`,
  476 + blob
  477 + );
  478 + } else {
  479 + this.$message.error("下载失败");
  480 + }
  481 + },
  482 + },
  483 +};
  484 +</script>
  485 +
  486 +<style lang="scss" scoped>
  487 +.page-container {
  488 + position: relative;
  489 + height: 100%;
  490 + .table-box {
  491 + min-height: 100%;
  492 + }
  493 + &.active {
  494 + overflow: hidden;
  495 + }
  496 + .content-header {
  497 + width: 100%;
  498 + position: relative;
  499 + .setMinScore {
  500 + position: absolute;
  501 + bottom: 0;
  502 + right: 0;
  503 + }
  504 + }
  505 + .page-content {
  506 + padding: 20px 20px 0;
  507 + }
  508 +}
  509 +.tab-box {
  510 + width: 400px;
  511 + margin: 0 auto 12px;
  512 + background: #f8f8f8;
  513 + border-radius: 20px;
  514 + display: flex;
  515 + user-select: none;
  516 + .tab-item {
  517 + flex: 1;
  518 + height: 40px;
  519 + line-height: 40px;
  520 + text-align: center;
  521 + font-size: 16px;
  522 + color: #666;
  523 + font-weight: 500;
  524 + background: transparent;
  525 + border-radius: 20px;
  526 + cursor: pointer;
  527 + &.active {
  528 + background: #667ffd;
  529 + color: #fff;
  530 + }
  531 + }
  532 +}
  533 +.down {
  534 + padding-top: 20px;
  535 + width: 100%;
  536 + display: flex;
  537 + justify-content: space-between;
  538 +}
  539 +.use-form {
  540 + padding: 0 12px;
  541 + .use-form-item-box {
  542 + :deep(.el-form-item__content) {
  543 + display: flex;
  544 + }
  545 + .use-form-item {
  546 + width: 40%;
  547 + margin-right: 20px;
  548 + }
  549 + }
  550 +}
  551 +.dia-tab-box {
  552 + .dia-tab-tit,
  553 + .dia-tab-item {
  554 + margin-bottom: 10px;
  555 + i {
  556 + color: #f30;
  557 + padding-right: 5px;
  558 + }
  559 + display: flex;
  560 + .item {
  561 + width: 40px;
  562 + }
  563 + .item1 {
  564 + padding-left: 10px;
  565 + width: 10%;
  566 + }
  567 + .item2 {
  568 + width: 18%;
  569 + }
  570 + .item3 {
  571 + padding-left: 12px;
  572 + flex: 1;
  573 + }
  574 + .score-ipt {
  575 + width: 100px;
  576 + }
  577 + }
  578 + .dia-tab-tit {
  579 + background: rgba(243, 243, 243, 1);
  580 + }
  581 + .add {
  582 + display: flex;
  583 + justify-content: center;
  584 + margin: 0 auto;
  585 + p {
  586 + cursor: pointer;
  587 + }
  588 + .el-button {
  589 + margin-right: 6px;
  590 + }
  591 + }
  592 +}
  593 +.p1 {
  594 + line-height: 18px;
  595 +}
  596 +</style>
0 \ No newline at end of file 597 \ No newline at end of file