基层教学组织评估系统7_后续需求追加(表单数据的字段增加、字体大小、登陆首页再设计、增加验证码、导出excel模块)、改进优化(全局异常处理处理token失效无法登陆bug)、测试维护

目录

  • 后续需求增加
    • 登录首页在设计
    • 登录增加验证码
    • 功能模块导入、导出excel
    • 表单根据下拉选中的个数显示需填写表格个数
    • 功能模块echars数据可视化
  • 改进优化
    • vue登录状态失效就移除token
    • 审核流程修改逻辑优化,优化不选中状态的非法情况

一、后续需求增加
1.登录首页在设计

起初的首页说是不太官方,页面太花,要求重新找个背景图片。另外为了分明的效果,在输入的表单区加了一个白色背景。

在这里插入图片描述
登录上面加一个带底边框的账号登录的标题
在这里插入图片描述
设置css样式
在这里插入图片描述

效果图
在这里插入图片描述

2.登录增加验证码

1.在components组件文件夹新建identify.vue

<template>
  <div class="s-canvas">
    <canvas
      id="s-canvas"
      :width="contentWidth"
      :height="contentHeight"
    ></canvas>
  </div>
</template>
 
<script>
export default {
  name: "SIdentify",
  props: {
    identifyCode: {
      type: String,
      default: "1234",
    },
    fontSizeMin: {
      type: Number,
      default: 25,
    },
    fontSizeMax: {
      type: Number,
      default: 30,
    },
    backgroundColorMin: {
      type: Number,
      default: 255,
    },
    backgroundColorMax: {
      type: Number,
      default: 255,
    },
    colorMin: {
      type: Number,
      default: 0,
    },
    colorMax: {
      type: Number,
      default: 160,
    },
    lineColorMin: {
      type: Number,
      default: 100,
    },
    lineColorMax: {
      type: Number,
      default: 255,
    },
    dotColorMin: {
      type: Number,
      default: 0,
    },
    dotColorMax: {
      type: Number,
      default: 255,
    },
    contentWidth: {
      type: Number,
      default: 128,
    },
    contentHeight: {
      type: Number,
      default: 46,
    },
  },
  methods: {
    // 生成一个随机数
    randomNum(min, max) {
      return Math.floor(Math.random() * (max - min) + min);
    },
    // 生成一个随机的颜色
    randomColor(min, max) {
      let r = this.randomNum(min, max);
      let g = this.randomNum(min, max);
      let b = this.randomNum(min, max);
      return "rgb(" + r + "," + g + "," + b + ")";
    },
    drawPic() {
      let canvas = document.getElementById("s-canvas");
      let ctx = canvas.getContext("2d");
      ctx.textBaseline = "bottom";
      // 绘制背景
      ctx.fillStyle = this.randomColor(
        this.backgroundColorMin,
        this.backgroundColorMax
      );
      ctx.fillRect(0, 0, this.contentWidth, this.contentHeight);
      // 绘制文字
      for (let i = 0; i < this.identifyCode.length; i++) {
        this.drawText(ctx, this.identifyCode[i], i);
      }
      this.drawLine(ctx);
      this.drawDot(ctx);
    },
    drawText(ctx, txt, i) {
      ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax);
      ctx.font =
        this.randomNum(this.fontSizeMin, this.fontSizeMax) + "px SimHei";
      let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1));
      let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5);
      var deg = this.randomNum(-45, 45);
      // 修改坐标原点和旋转角度
      ctx.translate(x, y);
      ctx.rotate((deg * Math.PI) / 180);
      ctx.fillText(txt, 0, 0);
      // 恢复坐标原点和旋转角度
      ctx.rotate((-deg * Math.PI) / 180);
      ctx.translate(-x, -y);
    },
    drawLine(ctx) {
      // 绘制干扰线
      for (let i = 0; i < 5; i++) {
        ctx.strokeStyle = this.randomColor(
          this.lineColorMin,
          this.lineColorMax
        );
        ctx.beginPath();
        ctx.moveTo(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight)
        );
        ctx.lineTo(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight)
        );
        ctx.stroke();
      }
    },
    drawDot(ctx) {
      // 绘制干扰点
      for (let i = 0; i < 80; i++) {
        ctx.fillStyle = this.randomColor(0, 255);
        ctx.beginPath();
        ctx.arc(
          this.randomNum(0, this.contentWidth),
          this.randomNum(0, this.contentHeight),
          1,
          0,
          2 * Math.PI
        );
        ctx.fill();
      }
    },
  },
  watch: {
    identifyCode() {
      this.drawPic();
    },
  },
  mounted() {
    this.drawPic();
  },
};
</script>
 
<style scoped>
.s-canvas {
  height: 38px;
}
.s-canvas canvas {
  margin-top: 2px;
  margin-left: 8px;
}
</style>

2.在Login.vue导入并注册声明Identify组件

在这里插入图片描述
在这里插入图片描述

设置对应的三个变量

在这里插入图片描述

在这里插入图片描述

4.定义点击刷新验证码的方法
在这里插入图片描述
5.加上验证码的判断
在这里插入图片描述
6.加上开始初始化验码
在这里插入图片描述

3.功能模块导入、导出excel

实现下拉框选择导出的方式,有全校导出、年份导出(后面提供年份供选择)、专业导出(后面为包含输入提示的输入框)

然后按表单中的数据筛选之后导出。导出功能开始需求是 校级管理员能导出,后来加上院级管理员需要能导出

1.页面代码

<template>
  <el-card>
    <div slot="header" class="card-header">
      <span>信息表导出</span>
    </div>
    <div>
      <el-row style="margin-left: 22%; margin-bottom: 2%"
        ><el-tag v-show="flag"
          >请选择导出范围(可按全校、年份、专业导出),省级优秀教学组织团队只能按年份导出或全校导出</el-tag
        ></el-row
      >

      <el-row style="margin-left: 40%">
        <el-select v-model="exportType.value" placeholder="请选择">
          <el-option
            v-for="item in exportType.options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>

        <el-date-picker
          v-model="yearSelect"
          type="year"
          value-format="yyyy"
          placeholder="选择年"
          v-show="isYearSelect"
        >
        </el-date-picker>

        <el-autocomplete
          class="inline-input"
          v-model="majorSelect"
          :fetch-suggestions="querySearchInfo"
          placeholder="请输入专业名称"
          :trigger-on-focus="false"
          @select="handleSelectInfo"
          v-show="isMajorSelect"
        ></el-autocomplete>
      </el-row>
      <el-row style="margin-left: 32%; margin-top: 2%">
        <el-button
          @click="exportBaseEducation"
          style="
            font: 14px Helvetica Neue, Helvetica, PingFang SC, Tahoma, Arial,
              sans-serif;
          "
          >导出基层教学组织</el-button
        >
        <el-button
          @click="exportTeam"
          style="
            font: 14x Helvetica Neue, Helvetica, PingFang SC, Tahoma, Arial,
              sans-serif;
          "
          >导出省级优秀基层教学组织团队</el-button
        >
      </el-row>
    </div>
  </el-card>
</template>

在这里插入图片描述

设置变量、watch选中的内容

  • 是否选中按年份导出、年份
  • 是否选中按专业导出、专业

2.按院级导出

export default {
  data() {
    return {
      //判断是否是院级管理员
      flag: true,
      //全部团队数据
      team: [],
      // 全部专业信息,便于提示补全
      majors: [],

      // 所有的信息表
      form: [],
      
      // 选择导出的方式
      exportType: {
        options: [
          {
            value: "college",
            label: "全校导出",
          },
          {
            value: "major",
            label: "按专业导出",
          },
          {
            value: "year",
            label: "按年份导出",
          },
        ],
        
        value: "",
      },
      yearSelect: "",
      isYearSelect: false,
      majorSelect: "",
      isMajorSelect: false,

      //导出基层教学组织excel数据
      baseEducation: [],

      //导出团队excel数据
      teamExcel: [],
    };
  },
  created() {
  // 获取全部的专业的方法
    this.getMajors();
    // 获取全部信息表的方法
    this.getAll();
    // 院级管理员不能全部导出,替换 全校导出 的 下拉框
    if (store.getters.role == "院级管理员") {
      this.exportType.options.splice(0, 2);
      this.exportType.options.push({
        value: "college",
        label: "导出全院基层教学组织表",
      });

      this.flag = false;
    }
  },

在这里插入图片描述

在这里插入图片描述

3.专业输入自动补全

在这里插入图片描述

// 向后端获取专业及其代码
    getMajors() {
      getMajorsInfo()
        .then((result) => {
          //this.arrayOfGrassRootsTeachingSystemName = result.data;
          //console.log(result);

          for (let i = 0; i < result.data.length; i++) {
            if (this.flag) {
              let item = {};
              item.value = result.data[i].nameOfTheMajorInTheSchool;
              console.log(result.data[i]);
              this.majors.push(item);
            } else if (
              result.data[i].nameOfTheMajorInTheSchool == store.getters.college
            ) {
              let item = {};
              item.value = result.data[i].nameOfTheMajorInTheSchool;
              console.log(result.data[i]);
              this.majors.push(item);
            }
          }
        })
        .catch((err) => {
          console.log(err);
        });
    },

    //显示搜索内容
    handleSelectInfo(item) {
      console.log(item);
    },
    //基层教学组织输入框查找相关输入内容
    querySearchInfo(queryString, cb) {
      var majors = this.majors;
      var results = queryString
        ? majors.filter(this.createFilterInfo(queryString))
        : majors;
      // 调用 callback 返回建议列表的数据
      cb(results);
    },
    //过滤出相关输入内容
    createFilterInfo(queryString) {
      return (majors) => {
        return (
          majors.value.toLowerCase().indexOf(queryString.toLowerCase()) !== -1
        );
      };
    },

4.获取全部教学组织、按照条件筛选导出基层教学组织

//获取全部基层教学组织表
    getAll() {
      exportAll()
        .then((result) => {
          // 获取信息表
          console.log(result);
          for (let item in result.data) {
            //console.log("1")
            if (this.flag == false) {
              //console.log("2")
              if (result.data[item].college == store.getters.college) {
                this.form.push(result.data[item]);
                console.log(result.data[item]);
              }
            } else {
              this.form.push(item);
            }
          }
          // this.form = result.data;
          // console.log(this.form);

          // console.log(this.team);
        })
        .catch((err) => {
          console.log(err);
        });
    },
    //导出基层教学组织表
    exportBaseEducation() {
      let flag = 0;
      if (this.isMajorSelect == false && this.isYearSelect == false) flag = 0;
      else if (this.isMajorSelect == true) flag = 1;
      else flag = 2;
      console.log(flag);
      for (let item of this.form) {
        //若是按年份导出
        if (flag === 2) {
          console.log(item.createYear);
          console.log(this.yearSelect);

          if (item.createYear != this.yearSelect) continue;
        }
        for (let items of item.faceSchoolMajors) {
          //若是按专业导出
          if (flag === 1) {
            if (items.schoolOrientedProfessionalTitles != this.majorSelect) {
              continue;
            }
          }
          console.log(item.faceSchoolMajors);
          let tempData = {};
          tempData.organization = item.organization;
          tempData.type = item.type;
          tempData.level = item.level;
          tempData.createYear = item.createYear;
          tempData.principal = item.principal;
          tempData.principalNumber = item.principalNumber;
          tempData.faceMultiple = item.faceMultiple;
          tempData.schoolOrientedProfessionalTitles =
            items.schoolOrientedProfessionalTitles;
          tempData.schoolOrientedProfessionalTitlesCode =
            items.schoolOrientedProfessionalTitlesCode;
          tempData.schoolOrientedProfessionalTitlesProporation =
            items.schoolOrientedProfessionalTitlesProporation;
          this.baseEducation.push(tempData);

          console.log(tempData);
        }
      }
      // 调用导出组件函数
      this.exportToExcel();
    },
//导出优秀基层教学组织团队表
    exportTeam() {
      let flag = 0;
      if (this.isMajorSelect == false && this.isYearSelect == false) flag = 0;
      else if (this.isMajorSelect == true) flag = 1;
      else flag = 2;
      console.log(flag);

      for (let item of this.form) {
        //若是按年份导出
        if (flag == 2) {
          if (item.getTime != this.yearSelect) continue;
        }
        for (let items of item.teacher) {
          let tempData = {};

          tempData.teacherNumber = items.teacherNumber;
          tempData.teacherName = items.teacherName;
          tempData.isPrincipal = items.isPrincipal;
          tempData.teamName = item.teamName;
          tempData.baseEducationType = item.baseEducationType;
          tempData.teamType = item.teamType;
          tempData.getTime = item.getTime;
          tempData.teamLevel = item.teamLevel;
          tempData.awardDepartment = item.awardDepartment;

          this.teamExcel.push(tempData);
          console.log(tempData);
        }
      }
      // 调用导出组件函数
      this.exportTeamToExcel();
    },

5.从对象数组中导出excel的组件函数

导出excel的组件Export2Excel.js

/* eslint-disable */
require('script-loader!file-saver');
// require('script-loader!src/vendor/Blob');
require('./Blob');
require('script-loader!xlsx/dist/xlsx.core.min');

function generateArray(table) {
  var out = [];
  var rows = table.querySelectorAll('tr');
  var ranges = [];
  for (var R = 0; R < rows.length; ++R) {
    var outRow = [];
    var row = rows[R];
    var columns = row.querySelectorAll('td');
    for (var C = 0; C < columns.length; ++C) {
      var cell = columns[C];
      var colspan = cell.getAttribute('colspan');
      var rowspan = cell.getAttribute('rowspan');
      var cellValue = cell.innerText;
      if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;

      //Skip ranges
      ranges.forEach(function (range) {
        if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
          for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
        }
      });

      //Handle Row Span
      if (rowspan || colspan) {
        rowspan = rowspan || 1;
        colspan = colspan || 1;
        ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}});
      }
      ;

      //Handle Value
      outRow.push(cellValue !== "" ? cellValue : null);

      //Handle Colspan
      if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
    }
    out.push(outRow);
  }
  return [out, ranges];
};

function datenum(v, date1904) {
  if (date1904) v += 1462;
  var epoch = Date.parse(v);
  return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}

function sheet_from_array_of_arrays(data, opts) {
  var ws = {};
  var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}};
  for (var R = 0; R != data.length; ++R) {
    for (var C = 0; C != data[R].length; ++C) {
      if (range.s.r > R) range.s.r = R;
      if (range.s.c > C) range.s.c = C;
      if (range.e.r < R) range.e.r = R;
      if (range.e.c < C) range.e.c = C;
      var cell = {v: data[R][C]};
      if (cell.v == null) continue;
      var cell_ref = XLSX.utils.encode_cell({c: C, r: R});

      if (typeof cell.v === 'number') cell.t = 'n';
      else if (typeof cell.v === 'boolean') cell.t = 'b';
      else if (cell.v instanceof Date) {
        cell.t = 'n';
        cell.z = XLSX.SSF._table[14];
        cell.v = datenum(cell.v);
      }
      else cell.t = 's';

      ws[cell_ref] = cell;
    }
  }
  if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
  return ws;
}

function Workbook() {
  if (!(this instanceof Workbook)) return new Workbook();
  this.SheetNames = [];
  this.Sheets = {};
}

function s2ab(s) {
  var buf = new ArrayBuffer(s.length);
  var view = new Uint8Array(buf);
  for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
  return buf;
}

export function export_table_to_excel(id) {
  var theTable = document.getElementById(id);
  console.log('a')
  var oo = generateArray(theTable);
  var ranges = oo[1];

  /* original data */
  var data = oo[0];
  var ws_name = "SheetJS";
  console.log(data);

  var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);

  /* add ranges to worksheet */
  // ws['!cols'] = ['apple', 'banan'];
  ws['!merges'] = ranges;

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});

  saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
}

function formatJson(jsonData) {
  console.log(jsonData)
}

export function export_json_to_excel(th, jsonData, defaultTitle) {

  /* original data */

  var data = jsonData;
  data.unshift(th);
  var ws_name = "SheetJS";

  var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);


  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
  var title = defaultTitle || '列表'
  saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx")
}
//导出基层教学组织excel
    exportToExcel() {
      //excel数据导出
      require.ensure([], () => {
        const { export_json_to_excel } = require("../../utils/Export2Excel");
        const tHeader = [
          "基层教学组织名称",
          "基层教学组织类型",
          "基层教学组织级别",
          "设立时间",
          "负责人姓名",
          "负责人工号",
          "面向校内专业个数",
          "面向校内专业(大类)名称",
          "面向校内专业(大类)代码",
          "面向专业的比例",
        ];
        const filterVal = [
          "organization",
          "type",
          "level",
          "createYear",
          "principal",
          "principalNumber",
          "faceMultiple",
          "schoolOrientedProfessionalTitles",
          "schoolOrientedProfessionalTitlesCode",
          "schoolOrientedProfessionalTitlesProporation",
        ];
        const list = this.baseEducation;
        const data = this.formatJson(filterVal, list);
        export_json_to_excel(tHeader, data, "基层教学组织表");
        this.baseEducation = [];
      });
    },

导出

//导出优秀教学组织团队excel
    exportTeamToExcel() {
      //excel数据导出
      require.ensure([], () => {
        const { export_json_to_excel } = require("../../utils/Export2Excel");
        const tHeader = [
          "教师工号",
          "教师姓名",
          "是否团队负责人",
          "团队名称",
          "类型",
          "类别",
          "获得时间",
          "等级",
          "授予部门",
        ];
        const filterVal = [
          "teacherNumber",
          "teacherName",
          "isPrincipal",
          "teamName",
          "baseEducationType",
          "teamType",
          "getTime",
          "teamLevel",
          "awardDepartment",
        ];
        const list = this.teamExcel;
        const data = this.formatJson(filterVal, list);
        export_json_to_excel(tHeader, data, "优秀基层教学组织团队表");
        this, (this.teamExcel = []);
      });
    },
    formatJson(filterVal, jsonData) {
      return jsonData.map((v) => filterVal.map((j) => v[j]));
    },
  },
4.表单根据下拉选中的个数显示需填写表的行个数

1.下拉框选中个数

在这里插入图片描述

表table

	<el-row style="width: 80%">
            <el-form>
              <!-- 表的title -->
              <el-form-item
                class="el-form-item_label"
                label="面向校内专业(大类)名称、比例填写"
              ></el-form-item>
              <!-- <el-button @click="faceSchoolMajorDialog">添加</el-button> -->

              <!-- 表 -->
              <el-table :data="form.info.faceSchoolMajors">
                <el-table-column
                  prop="schoolOrientedProfessionalTitles"
                  label="面向校内专业(大类)名称"
                ></el-table-column>
                <el-table-column
                  prop="schoolOrientedProfessionalTitlesCode"
                  label="面向校内专业代码(大类)"
                ></el-table-column>
                <el-table-column
                  prop="schoolOrientedProfessionalTitlesProporation"
                  label="面向校内专业比例"
                ></el-table-column>
                <el-table-column fixed="right" label="操作" width="100">
                  <template slot-scope="scope">
                    <el-button
                      type="text"
                      size="small"
                      @click="editFaceSchoolMajor(scope.row, scope.$index)"
                      v-show="
                        scope.schoolOrientedProfessionalTitlesProporation ===
                        ''
                      "
                      >编辑</el-button
                    >
                    <el-button
                      type="text"
                      size="small"
                      @click="deleteFaceSchoolMajor(scope.row, scope.$index)"
                      >删除</el-button
                    >
                  </template>
                </el-table-column>
              </el-table>
            </el-form>
          </el-row>

data数据

data() {
    return {
      options: [
        0,
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        11,
        12,
        13,
        14,
        15,
        16,
        17,
        18,
        19,
        20,
      ],
      myFlag: false,
      total: 0,
      //面向专业,名称,比例数据暂时存储
      tempData: {},
      //面向专业,名称,比例对话框显示
      dialogVisible: false,
      //面向专业,名称,比例对话框中按钮选择
      flag: false,
      //面向专业,名称,比例所编辑行index
      editorIndex: 0,

      //基层组织列表 提示
      arrayOfGrassRootsTeachingSystemName: [],

      // 专业及其代码 提示
      majors: [],
      //标识是否是在面向专业个数出删除元素
      deleteFlag: false,

      //标识是否能填写团队信息
      teamFlag: false,

      //标识填写团队信息的对话框的显示
      teamInfoVisible: false,
      //表示团队教师信息填写对话框的显示
      teacherInfoVisible: false,
      //团队教师信息的暂时存储
      tempDataOfteacher: {},
      //标识当前操作为添加教师信息还是修改
      teacherInfoFlag: false,

      updateHidden: "none",
      buttenHidden: "",
      active: 0,
      form: {
        info: {
          formID: "",
          userNumber: "",
          organization: "",
          college: "",
          principal: "",
          professionalTitle: "",
          status: "等待审核",
          reviewer: "",
          totalScore: "",
          userNumberOfMarker: "",
          userNumberOfReviewer: "",

          // 新增
          type: "",
          level: "",
          createYear: "",
          principalNumber: "",
          faceMultiple: "",
          faceSchoolMajors: [],
          // schoolOrientedProfessionalTitles: "",
          // schoolOrientedProfessionalTitlesCode: "",
          // schoolOrientedProfessionalTitlesProportion: "",

          //获奖等级
          awardLevel: "",
          //教师姓名,工号,是否团对负责人
          teacher: [],
          //教师工号
          //teacherNumber: [],
          //是否为团队负责人
          //isPrincipal: "",

          //团队名称
          teamName: "",
          //类型
          baseEducationType: "",
          //类别
          teamType: "",
          //获得时间
          getTime: "",
          //等级
          teamLevel: "",
          //授予部门
          awardDepartment: "",
        },
        principalID: "",
        membersID: "",
        ruleAndRegulationID: "",
        teamBuildingID: "",
        teachingOrganizationID: "",
        courseMaterialID: "",
        teachingResearchID: "",
        specialtyConstructionID: "",
        practicalTeachingID: "",
        conditionGuaranteeID: "",
        talentCultivationAbilityID: "",
        futureConstructionPlanID: "",
        opinionFeedbackID: "",
      },
      formID: "",
      // 提交表单的时候,需要保存默认数据数据到opinionFeedback 表,然后返回opinionFeedbackID
      opinionFeedback: {
        content: {
          html: "<div style='font-family: 仿宋; font-size: 12pt''></div>",
        },
      },
    };
  },

2.watch监控选中的个数动态生成table的行数,动态显示优秀团队填报按钮

  watch: {
    //监听面向专业的个数变化
    "form.info.faceMultiple": function (newval, old) {
      // 选中面向所有专业
      if (newval === "所有专业") {
        // 删除所有行
        this.form.info.faceSchoolMajors.splice(
          0,
          this.form.info.faceSchoolMajors.length
        );
        // 设置数组长度及其内容
        Vue.set(this.form.info.faceSchoolMajors, 0, {
          schoolOrientedProfessionalTitles: "面向全校所有专业",
          schoolOrientedProfessionalTitlesCode: "000000",
          schoolOrientedProfessionalTitlesProporation: "无",
        });
      } else if (this.myFlag) {
        this.myFlag = !this.myFlag;
      } else {
        if (old === "") old = 0;
        if (old === "所有专业") {
          this.form.info.faceSchoolMajors.splice(
            0,
            this.form.info.faceSchoolMajors.length
          );
          old = 0;
        }
        if (this.deleteFlag === true) {
          this.deleteFlag = false;
        } else {
          if (newval > old) {
            for (let i = old; i < newval; i++) {
              Vue.set(this.form.info.faceSchoolMajors, i, {
                schoolOrientedProfessionalTitlesProporation: 0,
              });
            }
          } else {
            if (newval == 0) {
              this.form.info.faceSchoolMajors.splice(
                0,
                this.form.info.faceSchoolMajors.length
              );
            } else {
              for (let i = newval; i < old; i++) {
                let a = this.form.info.faceSchoolMajors[i];
                this.total -= a.schoolOrientedProfessionalTitlesProporation;
                this.form.info.faceSchoolMajors.splice(i, 1);
              }
              if (newval === "" || newval === 0) this.total = 0;
            }
          }
        }
      }
    },
    //监听是否为省级优秀教学组织
    "form.info.awardLevel": function (newval, old) {
      if (newval === "省级优秀") {
        this.teamFlag = true;
      } else {
        this.teamFlag = false;
      }
    },
  },

3.优秀教师团队成员表的增删改

//一、填写团队信息对话框显示
    inputTeamInfo() {
      this.teamInfoVisible = true;
    },
    //确认团队信息
    confirmTeamInfo() {
      this.teamInfoVisible = false;
    },
    //添加教师信息
    addTeacher() {
      this.teacherInfoVisible = true;
      this.teacherInfoFlag = true;
    },
    //教师信息确认添加
    confirmTeacherInfoAdd() {
      Vue.set(
        this.form.info.teacher,
        this.form.info.teacher.length,
        this.tempDataOfteacher
      );
      this.tempDataOfteacher = {};
      this.teacherInfoVisible = false;
    },
    //教师信息取消添加
    cancelTeacherInfoAdd() {
      this.tempDataOfteacher = {};
      this.teacherInfoVisible = false;
    },
    //编辑教师信息
    editTeacherInfo(row, index = 0) {
      this.teacherInfoFlag = false;
      const temp = _.cloneDeep(row);
      this.tempDataOfteacher = temp;
      this.editorIndex = index;
      //this.flag = true;
      this.teacherInfoVisible = true;
    },
    //教师信息确认修改
    confirmTeacherInfoUpdate() {
      Vue.set(this.form.info.teacher, this.editorIndex, this.tempDataOfteacher);
      this.tempDataOfteacher = {};
      this.teacherInfoVisible = false;
      //this.flag = false;
    },

4.专业及其代码更新、编辑、删除

//二、面向专业,比例,代码对话框显示
    faceSchoolMajorDialog() {
      this.flag = false;
      this.tempData = {};
      this.dialogVisible = true;
    },
    //面向专业,比例,代码删除
    deleteTeacherInfo(row, index = 0) {
      this.form.info.teacher.splice(index, 1);
    },


    //编辑面向专业,比例,代码
    editFaceSchoolMajor(row, index = 0) {
      const temp = _.cloneDeep(row);
      console.log(temp);
      this.tempData = temp;
      this.editorIndex = index;
      this.flag = true;
      this.dialogVisible = true;
      this.total -= this.tempData.schoolOrientedProfessionalTitlesProporation;
    },
    //面向专业,比例,代码确认修改
    confirmUpdate() {
      console.log(this.total);
      this.total =
        this.total + this.tempData.schoolOrientedProfessionalTitlesProporation;
      console.log(this.total);
      if (this.total > 100) {
        this.$message.error("总比例超出100,请修改");
        this.total -= this.tempData.schoolOrientedProfessionalTitlesProporation;
      } else {
        //console.log(this.totalProportion)

        // 点击确定之后,将当前的编辑索引数组值设置为tempData的值
        Vue.set(
          this.form.info.faceSchoolMajors,
          this.editorIndex,
          this.tempData
        );
        this.tempData = {};
        this.dialogVisible = false;
        this.flag = false;
      }
    },
    //面向专业,比例,代码删除
    deleteFaceSchoolMajor(row, index = 0) {
      this.form.info.faceSchoolMajors.splice(index, 1);
      this.total -= row.schoolOrientedProfessionalTitlesProporation;
      //删除flag变为true
      this.deleteFlag = true;
      //面向专业个数减一
      this.form.info.faceMultiple--;
      if (
        this.form.info.faceMultiple === 0 ||
        this.form.info.faceMultiple.toString().indexOf("NaN") === 0
      )
        this.form.info.faceMultiple = 0;
    },
5.功能模块echars数据可视化

1.main.js导入echars插件

在这里插入图片描述

2.页面

<template>
  <div>
    <el-card>
    <div id="myChart3" :style="{ width: '1400px', height: '400px' }"></div>
    </el-card>
    <el-card class="chart1">
    <div id="myChart" :style="{ width: '400px', height: '400px' }"></div>
    </el-card>
    <el-card class="chart2">
    <div   id="myChart1" :style="{ width: '400px', height: '400px' }"></div>
    </el-card>
    <el-card class="chart3">
    <div id="myChart2" :style="{ width: '400px', height: '400px' }"></div>
    </el-card>
  </div>
</template>

<script>
export default {
  name: "hello",
  components: {},
  data() {
    return {
      msg: "Welcome to Your Vue.js App",
      option: {},
    };
  },
  mounted() {
    this.drawLine();
  },
  methods: {
    drawLine() {
      // 基于准备好的dom,初始化echarts实例
      let myChart = this.$echarts.init(document.getElementById("myChart"));
      // 绘制图表1-柱状图
      myChart.setOption({
        title: { text: "基层教学组织表得分情况", left: "center" },
        tooltip: {},
        xAxis: {
          data: [
            "[40,60)",
            "[60,70)",
            "[80,90)",
            "[90,100)",
            "[100,110)",
            "[110,120)",
          ],
        },
        yAxis: {},
        series: [
          {
            name: "得分情况",
            type: "bar",
            data: [5, 20, 36, 10, 10, 20],
          },
        ],
      });

      // 基于准备好的dom,初始化echarts实例
      let myChart1 = this.$echarts.init(document.getElementById("myChart1"));
      // 绘制图表2-饼图
      myChart1.setOption({
        title: { text: "基层教学组织获批等级", left: "center" },
        series: {
          type: "sunburst",
          data: [
            {
              name: "国家级",
              value: 10,
              children: [
                {
                  value: 3,
                  name: "国家级优秀",
                },
                {
                  value: 5,
                  name: "国家级一般",
                },
              ],
            },
            {
              name: "省级",
              children: [
                {
                  name: "省级优秀",
                  value: 4,
                },
                {
                  name: "省级一般",
                  value: 2,
                },
              ],
            },
            {
              name: "校级",
              value: 3,
            },
          ],
        },
      });

      // 基于准备好的dom,初始化echarts实例
      let myChart2 = this.$echarts.init(document.getElementById("myChart2"));
      // 绘制图表3-饼图
      myChart2.setOption({
        title: {
          text: "优秀基层教学组织表统计",
          left: "center",
        },
        tooltip: {
          trigger: "item",
          formatter: "{a} <br/>{b} : {c} ({d}%)",
        },
        legend: {
          bottom: 10,
          left: "center",
          data: [
            "软件学院",
            "商学院",
            "数学与统计学院",
            "经济学院",
            "环境与规划学院",
          ],
        },
        series: [
          {
            type: "pie",
            radius: "65%",
            center: ["50%", "50%"],
            selectedMode: "single",
            data: [
              {
                value: 1548,
                name: "软件学院",
              },
              { value: 735, name: "商学院" },
              { value: 510, name: "数学与统计学院" },
              { value: 434, name: "经济学院" },
              { value: 335, name: "环境与规划学院" },
            ],
          },
        ],
      });
      // 基于准备好的dom,初始化echarts实例
      let myChart3 = this.$echarts.init(document.getElementById("myChart3"));
      // 绘制图表4-折线图
      myChart3.setOption({
         title: { text: "历年基层教学组织获批等级数量", left: "center" },
        tooltip: {
          //设置tip提示
          trigger: "axis",
        },

        
        color: ["#8AE09F", "#FA6F53"], //设置区分(每条线是什么颜色,和 legend 一一对应)
        xAxis: {
          //设置x轴
          type: "category",
          boundaryGap: false, //坐标轴两边不留白
          data: [
            "2015",
            "2016",
            "2017",
            "2018",
            "2019",
            "2020",
            "2021",
          ],
          name: "年份", //X轴 name
          nameTextStyle: {
            //坐标轴名称的文字样式
            color: "#FA6F53",
            fontSize: 16,
            padding: [0, 0, 0, 20],
          },
          axisLine: {
            //坐标轴轴线相关设置。
            lineStyle: {
              color: "#FA6F53",
            },
          },
        },
        yAxis: {
          name: "获批等级数量",
          nameTextStyle: {
            color: "#FA6F53",
            fontSize: 16,
            padding: [0, 0, 10, 0],
          },
          axisLine: {
            lineStyle: {
              color: "#FA6F53",
            },
          },
          type: "value",
        },
        series: [
          {
            name: "国家级获批数量",
            data: [220, 232, 201, 234, 290, 230, 220],
            type: "line", // 类型为折线图
            lineStyle: {
              // 线条样式 => 必须使用normal属性
              normal: {
                color: "#8AE09F",
              },
            },
          },
          {
            name: "省级获批数量",
            data: [120, 200, 150, 80, 70, 110, 130],
            type: "line",
            lineStyle: {
              normal: {
                color: "#FA6F53",
              },
            },
          },
        ],
      });
    },
  },
};
</script>

<style scoped>

.chart1 {
  margin-left: 20px;
  margin-top: 20px;
  float: left;
}
.chart2 {
   margin-top: 20px;
  margin-left: 50px;
  float: left;
}
.chart3 {
   margin-top: 20px;
  margin-left: 50px;
  float: left;
}

</style>
二、改进优化
1.vue登录状态失效就移除token

promission.js路由器卫士

在这里插入图片描述

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.beforeEach(async (to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {

      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        // 还没有角色信息
        if (store.getters.role.length === 0) {
          // get user info
          await store.dispatch('user/getInfo').then(res => {
            const roles = res.role;
            store.dispatch('GenerateRoutes', { roles }).then(() => {
              //console.log(store.getters.addRoutes)
              // 根据角色动态挂载路由
              router.addRoutes(store.getters.addRoutes.permission.addRouters)
              next({ ...to, replace: true })
            }
            )
          }
          ).catch(error => {
            console.log(error)
          });
        }
        // 登录信息失效
        else {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
          next()
        }
      }
    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})

2.审核流程修改逻辑优化,优化不选中状态的非法情况

1.不选状态无法提交

// 4.更新审核状态、反馈内容
    async submit() {
      // 判断返回状态是否为空
      if (this.status === "") return this.$message.info("请选择是是否审核通过");
      this.getHtml();

      if (this.form.content.html === "")
        return this.$message.info("反馈意见不能为空");
      await this.$parent.$parent.updateForm();

      // 子组件:更新反馈内容
      this.updateTable();
      this.back();
    },

2.等待审核状态下都可以直接修改

<template slot-scope="scope">
            <!-- 申请更新信息表按钮 -->
            <el-row
              ><el-button
                @click="applicationForUpdate(scope.row)"
                v-if="scope.row.status !== '返回修改' && scope.row.status !== '等待审核'"
                v-has="roles"
                >申请修改</el-button
              ></el-row
            >
            <el-row
              ><el-button
                @click="handleEdit(scope.row)"
                v-if="scope.row.status == '返回修改' || scope.row.status == '等待审核'"
                v-has="roles"
                >修改内容</el-button
              ></el-row
            >
            <el-row>
              <el-button @click="handleRowClick(scope.row)">
                显示详情
              </el-button>
            </el-row>
            <el-row>
              <el-button
                v-if="scope.row.status == '评定结束'"
                @click="viewScores(scope.row)"
              >
                查看分数
              </el-button>
            </el-row>
          </template>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

scl、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值