目录
- 后续需求增加
- 登录首页在设计
- 登录增加验证码
- 功能模块导入、导出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>