初始化
This commit is contained in:
408
src/views/diagnostic/DataView/cpnt/FdyList.vue
Normal file
408
src/views/diagnostic/DataView/cpnt/FdyList.vue
Normal file
@@ -0,0 +1,408 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
|
||||
label-width="68px">
|
||||
<el-form-item label="学号" prop="stuNo">
|
||||
<el-input v-model="queryParams.stuNo" placeholder="请输入学号" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学生状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择学生状态" clearable style="width: 240px">
|
||||
<el-option v-for="dict in dict.type.srs_stu_status" :key="dict.value" :label="dict.label"
|
||||
:value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="loading" :data="studentList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="学号" align="center" prop="stuNo" width="150" />
|
||||
<el-table-column label="姓名" align="center" prop="name" width="100" />
|
||||
<el-table-column label="性别" align="center" prop="gender" />
|
||||
<el-table-column label="学院名称" align="center" prop="deptId">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.dept.deptName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="专业名称" align="center" prop="majorId" width="250">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.srsMajors.majorName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="班级名称" align="center" prop="classId" width="270">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.srsClass.className }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="学生状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.srs_stu_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view"
|
||||
@click="picVClick(scope.row)">查看报告</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<el-dialog :visible.sync="picV" fullscreen append-to-body>
|
||||
<look v-if="picV" :reportData="reportData" />
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listOwnStu as listStudent, getStudent, delStudent, addStudent, updateStudent, getClassName, initPwd, initOnePwd } from "@/api/stuCQS/basedata/student";
|
||||
import { getTokenKeySessionStorage } from "@/utils/auth";
|
||||
|
||||
|
||||
import look from "@/views/diagnostic/DiaFillOutReport/look";
|
||||
|
||||
export default {
|
||||
name: "own-Student",
|
||||
dicts: ['srs_stu_status'],
|
||||
|
||||
components: {
|
||||
look
|
||||
},
|
||||
props: {
|
||||
reportData: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pic_stu_no: null,
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 学生信息表格数据
|
||||
studentList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
stuNo: null,
|
||||
gender: null,
|
||||
birthday: null,
|
||||
idCard: null,
|
||||
gradeId: null,
|
||||
deptId: null,
|
||||
majorId: null,
|
||||
classId: null,
|
||||
phone: null,
|
||||
address: null,
|
||||
status: null,
|
||||
},
|
||||
// 学生导入参数
|
||||
upload: {
|
||||
// 是否显示弹出层(用户导入)
|
||||
open: false,
|
||||
// 弹出层标题(用户导入)
|
||||
title: "",
|
||||
// 是否禁用上传
|
||||
isUploading: false,
|
||||
// 是否更新已经存在的学生数据
|
||||
updateSupport: 0,
|
||||
// 设置上传的请求头部
|
||||
headers: { Authorization: "Bearer " + getTokenKeySessionStorage() },
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + "/system/student/importData"
|
||||
},
|
||||
// 学生状态导入参数
|
||||
upload2: {
|
||||
// 是否显示弹出层(用户导入)
|
||||
open: false,
|
||||
// 弹出层标题(用户导入)
|
||||
title: "",
|
||||
// 是否禁用上传
|
||||
isUploading: false,
|
||||
// 是否更新已经存在的学生数据
|
||||
updateSupport: 0,
|
||||
// 设置上传的请求头部
|
||||
headers: { Authorization: "Bearer " + getTokenKeySessionStorage() },
|
||||
// 上传的地址
|
||||
url: process.env.VUE_APP_BASE_API + "/system/student/imporStatustData"
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: "名字不能为空", trigger: "change" }
|
||||
],
|
||||
stuNo: [
|
||||
{ required: true, message: "学号不能为空", trigger: "change" }
|
||||
],
|
||||
gender: [
|
||||
{ required: true, message: "性别不能为空", trigger: "change" }
|
||||
],
|
||||
idCard: [
|
||||
{ required: true, message: "身份证不能为空", trigger: "change" }
|
||||
],
|
||||
majorId: [
|
||||
{ required: true, message: "所属班级不能为空", trigger: "change" }
|
||||
],
|
||||
phone: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "change" }
|
||||
],
|
||||
address: [
|
||||
{ required: true, message: "手机号不能为空", trigger: "change" }
|
||||
],
|
||||
delFlag: [
|
||||
{ required: true, message: "删除标志不能为空", trigger: "blur" }
|
||||
]
|
||||
},
|
||||
|
||||
ClassNameList: [],//班级名称
|
||||
classVlue1: [],//班级搜索选择
|
||||
classVlue2: [],//班级添加修改选择
|
||||
|
||||
picV: false,
|
||||
token: getTokenKeySessionStorage()
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.getClassNameList();
|
||||
},
|
||||
methods: {
|
||||
picVClick(row) {
|
||||
this.reportData.stuNo = row.stuNo;
|
||||
this.reportData.className = row.srsClass.className;
|
||||
this.reportData.studentName = row.name;
|
||||
this.picV = true;
|
||||
},
|
||||
async doInitPwdOne(val) {
|
||||
let sdata = {
|
||||
username: val.stuNo
|
||||
}
|
||||
let res = await initOnePwd(sdata);
|
||||
if (res.code == 200) {
|
||||
this.$message.success(res.msg);
|
||||
}
|
||||
},
|
||||
doInitPwd() {
|
||||
this.$message.info("正在初始化中,请稍候");
|
||||
initPwd().then(res => {
|
||||
this.$message.info(res.msg);
|
||||
});
|
||||
|
||||
},
|
||||
/** 查询学生信息列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listStudent(this.queryParams).then(response => {
|
||||
this.studentList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
getClassNameList() {
|
||||
getClassName().then(res => {
|
||||
this.ClassNameList = res.data
|
||||
})
|
||||
},
|
||||
//搜索班级选择
|
||||
handleChange1(value) {
|
||||
this.queryParams.classId = value[2]
|
||||
console.log(value);
|
||||
},
|
||||
//班级选择添加修改
|
||||
handleChange2(value) {
|
||||
this.form.classId = value[2]
|
||||
console.log(value);
|
||||
},
|
||||
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
stuId: null,
|
||||
name: null,
|
||||
stuNo: null,
|
||||
gender: null,
|
||||
birthday: null,
|
||||
idCard: null,
|
||||
deptId: null,
|
||||
majorId: null,
|
||||
classId: null,
|
||||
phone: null,
|
||||
address: null,
|
||||
status: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateBy: null,
|
||||
updateTime: null,
|
||||
delFlag: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.classVlue1 = [],
|
||||
this.handleQuery();
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.stuId)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.classVlue2 = [],
|
||||
this.open = true;
|
||||
this.title = "添加学生信息";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const stuId = row.stuId || this.ids
|
||||
getStudent(stuId).then(response => {
|
||||
this.form = response.data;
|
||||
var data = response.data;
|
||||
this.classVlue2 = [data.dept.deptId, data.srsMajors.majorId, data.srsClass.classId]
|
||||
console.log(this.classVlue2);
|
||||
this.open = true;
|
||||
this.title = "修改学生信息";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.stuId != null) {
|
||||
updateStudent(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addStudent(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const stuIds = row.stuId || this.ids;
|
||||
this.$modal.confirm('是否确认删除学生信息编号为"' + stuIds + '"的数据项?').then(function () {
|
||||
return delStudent(stuIds);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => { });
|
||||
},
|
||||
/** 导入按钮操作 */
|
||||
handleImport() {
|
||||
this.upload.title = "学生导入";
|
||||
this.upload.open = true;
|
||||
},
|
||||
handleImportStatus() {
|
||||
this.upload2.title = "学生状态导入";
|
||||
this.upload2.open = true;
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('system/student/export', {
|
||||
...this.queryParams
|
||||
}, `student_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
/** 下载模板操作 */
|
||||
importTemplate() {
|
||||
this.download('system/student/importTemplate', {
|
||||
}, `student_info_template_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
/** 下载模板操作 */
|
||||
importStatusTemplate() {
|
||||
debugger;
|
||||
this.download('system/student/importTemplate2', {
|
||||
}, `studentstatus_info_template_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
// 文件上传中处理
|
||||
handleFileUploadProgress(event, file, fileList) {
|
||||
this.upload.isUploading = true;
|
||||
this.upload2.isUploading = true;
|
||||
},
|
||||
// 文件上传成功处理
|
||||
handleFileSuccess(response, file, fileList) {
|
||||
this.upload.open = false;
|
||||
this.upload.isUploading = false;
|
||||
this.$refs.upload.clearFiles();
|
||||
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
|
||||
this.getList();
|
||||
},
|
||||
// 提交上传文件
|
||||
submitFileForm() {
|
||||
// console.log(this.token);
|
||||
this.$refs.upload.submit();
|
||||
},
|
||||
// 提交上传文件
|
||||
submitFileForm2() {
|
||||
this.$refs.upload2.submit();
|
||||
},
|
||||
// 文件上传成功处理
|
||||
handleFileSuccess2(response, file, fileList) {
|
||||
debugger;
|
||||
this.upload2.open = false;
|
||||
this.upload2.isUploading = false;
|
||||
this.$refs.upload2.clearFiles();
|
||||
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
|
||||
this.getList();
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.stu_pic {
|
||||
margin: 0px;
|
||||
background: url("~@/assets/stu_pic/stu.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
||||
201
src/views/diagnostic/DataView/cpnt/TotalForm.vue
Normal file
201
src/views/diagnostic/DataView/cpnt/TotalForm.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-table :data="tableData" :span-method="objectSpanMethod" border style="width: 100%">
|
||||
<!-- 维度名称列(将合并相同内容) -->
|
||||
<el-table-column label="维度名称" align="center" prop="dimension" width="180" />
|
||||
|
||||
<el-table-column label="质控点名称" align="center" prop="controlPoint" />
|
||||
<el-table-column label="指标名称" align="center" prop="indicatorName" />
|
||||
|
||||
<el-table-column label="学校合格标准" align="center" prop="xgStandard" />
|
||||
<el-table-column label="学院合格标准" align="center" prop="xwStandard" v-if="deptColV" />
|
||||
<el-table-column label="在校人数" align="center" prop="stuCount" />
|
||||
<el-table-column label="达成人数" align="center" prop="finishCount" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stuCount
|
||||
? ((scope.row.finishCount / scope.row.stuCount) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isEmpty } from "@/api/helpFunc";
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
name: "TotalForm",
|
||||
props: {
|
||||
tableData: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
saveLoading: false,
|
||||
submitLoading: false,
|
||||
detailsList: [],
|
||||
modifiedData: [],
|
||||
spanArr: [], // 用于存储维度名称列的合并规则
|
||||
qcSpanArr: [], // 用于存储质控点名称列的合并规则
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
reportId: this.reportId
|
||||
},
|
||||
initialData: [
|
||||
{
|
||||
dimension: "思想成长",
|
||||
controlPoint: "质控点1",
|
||||
indicatorName: "指标1",
|
||||
schoolQualifiedStandard: "",
|
||||
secondaryCollegeStandard: "",
|
||||
personalTargetStandard: ""
|
||||
},
|
||||
{
|
||||
dimension: "思想成长",
|
||||
controlPoint: "质控点2",
|
||||
indicatorName: "指标2",
|
||||
schoolQualifiedStandard: "",
|
||||
secondaryCollegeStandard: "",
|
||||
personalTargetStandard: ""
|
||||
},
|
||||
{
|
||||
dimension: "学业发展",
|
||||
controlPoint: "质控点3",
|
||||
indicatorName: "指标3",
|
||||
schoolQualifiedStandard: "",
|
||||
secondaryCollegeStandard: "",
|
||||
personalTargetStandard: ""
|
||||
},
|
||||
{
|
||||
dimension: "学业发展",
|
||||
controlPoint: "质控点4",
|
||||
indicatorName: "指标4",
|
||||
schoolQualifiedStandard: "",
|
||||
secondaryCollegeStandard: "",
|
||||
personalTargetStandard: ""
|
||||
},
|
||||
{
|
||||
dimension: "学业发展",
|
||||
controlPoint: "质控点5",
|
||||
indicatorName: "指标5",
|
||||
schoolQualifiedStandard: "",
|
||||
secondaryCollegeStandard: "",
|
||||
personalTargetStandard: ""
|
||||
}
|
||||
],
|
||||
deptColV: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
// 计算合并规则的方法 - 保持原始顺序
|
||||
getSpanArr(data) {
|
||||
this.spanArr = [];
|
||||
this.qcSpanArr = [];
|
||||
|
||||
// 记录上一行的维度和质控点
|
||||
let prevDimension = null;
|
||||
let prevQcPoint = null;
|
||||
|
||||
// 记录当前维度和质控点的合并行数
|
||||
let currentDimensionRowspan = 0;
|
||||
let currentQcRowspan = 0;
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const current = data[i];
|
||||
|
||||
// 处理维度名称列的合并
|
||||
if (prevDimension === null || prevDimension !== current.dimension) {
|
||||
// 新维度,开始新的合并组
|
||||
this.spanArr.push(1);
|
||||
currentDimensionRowspan = 1;
|
||||
prevDimension = current.dimension;
|
||||
} else {
|
||||
// 延续当前维度的合并组
|
||||
this.spanArr[i - currentDimensionRowspan] += 1;
|
||||
this.spanArr.push(0);
|
||||
currentDimensionRowspan += 1;
|
||||
}
|
||||
|
||||
// 处理质控点名称列的合并
|
||||
if (prevDimension !== current.dimension || prevQcPoint !== current.controlPoint) {
|
||||
// 新维度或新质控点,开始新的合并组
|
||||
this.qcSpanArr.push(1);
|
||||
currentQcRowspan = 1;
|
||||
prevQcPoint = current.controlPoint;
|
||||
} else {
|
||||
// 延续当前质控点的合并组
|
||||
this.qcSpanArr[i - currentQcRowspan] += 1;
|
||||
this.qcSpanArr.push(0);
|
||||
currentQcRowspan += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 合并单元格的方法
|
||||
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
|
||||
if (columnIndex === 0) {
|
||||
const _row = this.spanArr[rowIndex];
|
||||
const _col = _row > 0 ? 1 : 0;
|
||||
return {
|
||||
rowspan: _row,
|
||||
colspan: _col
|
||||
};
|
||||
} else if (columnIndex === 1) {
|
||||
const _row = this.qcSpanArr[rowIndex];
|
||||
const _col = _row > 0 ? 1 : 0;
|
||||
return {
|
||||
rowspan: _row,
|
||||
colspan: _col
|
||||
};
|
||||
}
|
||||
// 其他列不合并
|
||||
return { rowspan: 1, colspan: 1 };
|
||||
},
|
||||
|
||||
|
||||
formatDate(date) {
|
||||
const d = new Date(date);
|
||||
return [
|
||||
d.getFullYear(),
|
||||
String(d.getMonth() + 1).padStart(2, '0'),
|
||||
String(d.getDate()).padStart(2, '0')
|
||||
].join('-') + ' ' + [
|
||||
String(d.getHours()).padStart(2, '0'),
|
||||
String(d.getMinutes()).padStart(2, '0'),
|
||||
String(d.getSeconds()).padStart(2, '0')
|
||||
].join(':');
|
||||
},
|
||||
|
||||
},
|
||||
created() {
|
||||
if (!isEmpty(this.tableData)) {
|
||||
if (!isEmpty(this.tableData[0].xwStandard)) {
|
||||
this.deptColV = true;
|
||||
}
|
||||
}
|
||||
this.getSpanArr(this.tableData);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
534
src/views/diagnostic/DataView/fdy.vue
Normal file
534
src/views/diagnostic/DataView/fdy.vue
Normal file
@@ -0,0 +1,534 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card class="box-card">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="120px">
|
||||
<el-form-item label="报告" prop="relId">
|
||||
<el-select v-model="queryParams.relId" placeholder="请选择报告">
|
||||
<el-option v-for="item in relList" :key="item.relId" :label="item.reportName"
|
||||
:value="item.relId"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
<el-button type="primary" icon="el-icon-search" plain @click="queryData">查询</el-button>
|
||||
<el-button type="success" icon="el-icon-view" plain @click="lookVClick">查看学生数据</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="班级" prop="classId">
|
||||
<el-select v-model="queryParams.classId" placeholder="请选择班级" filterable clearable>
|
||||
<el-option v-for="(v, i) in search_class_list" :key="i" :label="v.className" :value="v.classId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>报告达成率(报告的全部指标都达成的情况)</span>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div ref="reportFinishChart" style="height: 400px"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>指标达成率(学生达成了多少个指标)</span>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div ref="itemFinishChart" style="height: 400px"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各班级报告达成率</span>
|
||||
<el-button @click='exportClassFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedClassFinishList">
|
||||
<el-table-column label="班级" width="140" align="center" prop="class_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageClassFinish" :page-size="pageSizeClassFinish"
|
||||
:total="classFinishList.length" @current-change="handleClassFinishPageChange"
|
||||
@size-change="handleClassFinishSizeChange" :page-sizes="[10, 20, 50, 100]" :pager-count="5"
|
||||
style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各班级指标达成率</span>
|
||||
<el-button @click='exportClassItemFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedClassItemFinishList">
|
||||
<el-table-column label="班级" width="140" align="center" prop="class_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageClassItemFinish" :page-size="pageSizeClassItemFinish"
|
||||
:total="classItemFinishList.length" @current-change="handleClassItemFinishPageChange"
|
||||
@size-change="handleClassItemFinishSizeChange" :page-sizes="[10, 20, 50, 100]"
|
||||
:pager-count="5" style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>指标达成情况</span>
|
||||
<el-button @click='exportTable("TotalForm", searchRelName
|
||||
+ "--" + searchClassName + "指标达成情况")' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<TotalForm id="TotalForm" v-if="tableV" :tableData="tableData" />
|
||||
</el-card>
|
||||
|
||||
<table id="tempTable">
|
||||
|
||||
</table>
|
||||
|
||||
<el-dialog :visible.sync="lookV" fullscreen append-to-body>
|
||||
<FdyList v-if="lookV" :reportData="lookData" />
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
countFdyItemFinishByRelId as countItemFinishByRelId,
|
||||
countFdyFinishNumByRelId as countFinishNumByRelId,
|
||||
countFdyItemFinishNumByRelId as countItemFinishNumByRelId,
|
||||
countFdyClassFinishNumByRelId as countClassFinishNumByRelId,
|
||||
countFdyClassItemFinishNumByRelId as countClassItemFinishNumByRelId
|
||||
} from "@/api/diagnostic/reportStandards";
|
||||
|
||||
import { listAllRelease } from '@/api/diagnostic/DiaReportRelease';
|
||||
|
||||
import { listOwnClass as listClass } from "@/api/stuCQS/info-fill/stu_eva_task";
|
||||
|
||||
import { isEmpty, fullLoading } from '@/api/helpFunc';
|
||||
|
||||
import TotalForm from './cpnt/TotalForm';
|
||||
import FdyList from "./cpnt/FdyList.vue";
|
||||
|
||||
import * as echarts from 'echarts';
|
||||
import XLSX from 'xlsx';
|
||||
|
||||
export default {
|
||||
name: "DataView",
|
||||
components: {
|
||||
TotalForm,
|
||||
FdyList
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isEmpty,
|
||||
|
||||
queryParams: {
|
||||
relId: null
|
||||
},
|
||||
relList: [],
|
||||
gradeList: [],
|
||||
search_major_list: [],
|
||||
search_class_list: [],
|
||||
|
||||
|
||||
tableData: [],
|
||||
tableV: false,
|
||||
|
||||
reportFinishChart: null,
|
||||
itemFinishChart: null,
|
||||
|
||||
majorItemFinishList: [],
|
||||
majorFinishList: [],
|
||||
|
||||
gradeItemFinishList: [],
|
||||
gradeFinishList: [],
|
||||
|
||||
classItemFinishList: [],
|
||||
classFinishList: [],
|
||||
|
||||
searchRelName: "",
|
||||
searchMajorName: "",
|
||||
searchClassName: "",
|
||||
searchGradeName: "",
|
||||
|
||||
currentPageMajorFinish: 1,
|
||||
pageSizeMajorFinish: 10,
|
||||
|
||||
currentPageMajorItemFinish: 1,
|
||||
pageSizeMajorItemFinish: 10,
|
||||
|
||||
currentPageClassFinish: 1,
|
||||
pageSizeClassFinish: 10,
|
||||
|
||||
currentPageClassItemFinish: 1,
|
||||
pageSizeClassItemFinish: 10,
|
||||
|
||||
lookV: false,
|
||||
lookData: {},
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.listAllRelease();
|
||||
this.listClass();
|
||||
},
|
||||
mounted() {
|
||||
this.initCharts();
|
||||
},
|
||||
computed: {
|
||||
pagedClassFinishList() {
|
||||
const start = (this.currentPageClassFinish - 1) * this.pageSizeClassFinish;
|
||||
const end = start + this.pageSizeClassFinish;
|
||||
return this.classFinishList.slice(start, end);
|
||||
},
|
||||
pagedClassItemFinishList() {
|
||||
const start = (this.currentPageClassItemFinish - 1) * this.pageSizeClassItemFinish;
|
||||
const end = start + this.pageSizeClassItemFinish;
|
||||
return this.classItemFinishList.slice(start, end);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
lookVClick() {
|
||||
if (isEmpty(this.queryParams.relId)) {
|
||||
this.$message.warning("请先选择报告");
|
||||
return;
|
||||
}
|
||||
this.lookData = {};
|
||||
let reportName = this.relList.find(item => item.relId == this.queryParams.relId).reportName;
|
||||
let reportId = this.relList.find(item => item.relId == this.queryParams.relId).reportId;
|
||||
let sdata = {
|
||||
relId: this.queryParams.relId,
|
||||
reportName,
|
||||
reportId
|
||||
}
|
||||
this.lookData = sdata;
|
||||
this.lookV = true;
|
||||
},
|
||||
exportClassFinishList() {
|
||||
let classFinishList = [...this.classFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '班级', '在校生数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
classFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.class_name,
|
||||
row.stu_num,
|
||||
row.finish_num,
|
||||
row.stu_num
|
||||
? ((row.finish_num / row.stu_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各班级报告达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchMajorName;
|
||||
XLSX.writeFile(workbook, title + '各班级报告达成统计.xlsx');
|
||||
},
|
||||
exportClassItemFinishList() {
|
||||
let classItemFinishList = [...this.classItemFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '班级', '在校生数', '总指标数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
classItemFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.class_name,
|
||||
row.stu_num,
|
||||
row.total_num,
|
||||
row.finish_num,
|
||||
row.total_num
|
||||
? ((row.finish_num / row.total_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各班级指标达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchMajorName;
|
||||
XLSX.writeFile(workbook, title + '各班级指标达成统计.xlsx');
|
||||
},
|
||||
|
||||
exportTable(id, title) {
|
||||
let thead = document.getElementById(id).getElementsByTagName('thead')[0];
|
||||
let tbody = document.getElementById(id).getElementsByTagName('tbody')[0];
|
||||
let tempTable = document.getElementById('tempTable');
|
||||
if (thead) {
|
||||
tempTable.appendChild(thead.cloneNode(true))
|
||||
}
|
||||
if (tbody) {
|
||||
Array.from(tbody.getElementsByTagName('td')).forEach(td => {
|
||||
if (td.innerText.trim().endsWith('%')) {
|
||||
td.innerHTML = `<span style="mso-number-format:'\\@';">${td.innerText}</span>`;
|
||||
}
|
||||
});
|
||||
tempTable.appendChild(tbody.cloneNode(true))
|
||||
}
|
||||
const wb = XLSX.utils.table_to_book(tempTable, { sheet: 'Sheet1', cellText: true })
|
||||
XLSX.writeFile(wb, title + ".xlsx");
|
||||
tempTable.innerHTML = '';
|
||||
},
|
||||
|
||||
handleClassItemFinishPageChange(page) {
|
||||
this.currentPageClassItemFinish = page;
|
||||
},
|
||||
handleClassItemFinishSizeChange(size) {
|
||||
this.pageSizeClassItemFinish = size;
|
||||
this.currentPageClassItemFinish = 1;
|
||||
},
|
||||
handleClassFinishPageChange(page) {
|
||||
this.currentPageClassFinish = page;
|
||||
},
|
||||
handleClassFinishSizeChange(size) {
|
||||
this.pageSizeClassFinish = size;
|
||||
this.currentPageClassFinish = 1;
|
||||
},
|
||||
|
||||
async queryData() {
|
||||
let sdata = { ...this.queryParams };
|
||||
if (isEmpty(sdata.relId)) {
|
||||
this.$message.info("请选择报告");
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchRelName = this.relList.find(item => item.relId == sdata.relId).reportName;
|
||||
|
||||
if (!isEmpty(sdata.classId)) {
|
||||
this.searchClassName = this.search_class_list.find(item => item.classId == sdata.classId).className;
|
||||
}
|
||||
|
||||
// 只开一次 loading
|
||||
let loading = fullLoading(this);
|
||||
// 并行等待接口
|
||||
try {
|
||||
await Promise.all([
|
||||
this.countFinishNumByRelId(true), // 传入参数表示不在内部开loading
|
||||
this.countItemFinishByRelId(true),
|
||||
this.countItemFinishNumByRelId(true),
|
||||
this.countClassFinishNumByRelId(true),
|
||||
this.countClassItemFinishNumByRelId(true),
|
||||
]);
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
},
|
||||
async countClassFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countClassFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.classFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countClassItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countClassItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.classItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
async countItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
let temp = { ...res.data };
|
||||
let data = [];
|
||||
data.push({ value: temp.finish_num, name: '已达成' });
|
||||
data.push({ value: temp.total_num - temp.finish_num, name: '未达成' });
|
||||
this.renderPieChart(this.itemFinishChart, '指标达成率', data);
|
||||
}
|
||||
},
|
||||
async countFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
let temp = { ...res.data };
|
||||
let data = [];
|
||||
data.push({ value: temp.finish_num, name: '已达成' });
|
||||
data.push({ value: temp.stu_num - temp.finish_num, name: '未达成' });
|
||||
this.renderPieChart(this.reportFinishChart, '报告达成率', data);
|
||||
}
|
||||
},
|
||||
|
||||
async countItemFinishByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let sdata = { ...this.queryParams };
|
||||
this.tableV = false;
|
||||
let res = await countItemFinishByRelId(sdata);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.tableV = true;
|
||||
this.tableData = [...res.data];
|
||||
}
|
||||
},
|
||||
renderPieChart(chart, title, data) {
|
||||
// 添加数据检查
|
||||
if (!data || !Array.isArray(data)) {
|
||||
console.warn('数据格式不正确或为空:', data);
|
||||
data = []; // 设置为空数组,避免报错
|
||||
}
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: title,
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '达成情况',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
center: ['70%', '50%'],
|
||||
data: [...data],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 如果数据为空,显示暂无数据
|
||||
if (data.length === 0) {
|
||||
option.title.subtext = '暂无数据';
|
||||
}
|
||||
|
||||
chart.setOption(option);
|
||||
},
|
||||
initCharts() {
|
||||
if (this.$refs.reportFinishChart && this.$refs.itemFinishChart) {
|
||||
this.reportFinishChart = echarts.init(this.$refs.reportFinishChart);
|
||||
this.itemFinishChart = echarts.init(this.$refs.itemFinishChart);
|
||||
}
|
||||
},
|
||||
async listClass() {
|
||||
let res = await listClass();
|
||||
if (res.code == 200) {
|
||||
this.search_class_list = [...res.data];
|
||||
}
|
||||
},
|
||||
|
||||
async listAllRelease() {
|
||||
let res = await listAllRelease();
|
||||
if (res.code == 200) {
|
||||
this.relList = [...res.data];
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.box-card {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.mt20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
</style>
|
||||
739
src/views/diagnostic/DataView/index.vue
Normal file
739
src/views/diagnostic/DataView/index.vue
Normal file
@@ -0,0 +1,739 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card class="box-card">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="120px">
|
||||
<el-form-item label="报告" prop="relId">
|
||||
<el-select v-model="queryParams.relId" placeholder="请选择报告">
|
||||
<el-option v-for="item in relList" :key="item.relId" :label="item.reportName"
|
||||
:value="item.relId"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
<el-button type="primary" icon="el-icon-search" plain @click="queryData">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级" prop="gradeId">
|
||||
<el-select v-model="queryParams.gradeId" placeholder="请选择年级" clearable>
|
||||
<el-option v-for="item in gradeList" :key="item.gradeId" :label="item.gradeName"
|
||||
:value="item.gradeId"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学院" prop="deptId">
|
||||
<el-select size="mini" @change="changeSearchDept" v-model="queryParams.deptId" placeholder="请选择学院"
|
||||
clearable>
|
||||
<el-option v-for="(v, i) in deptList" :key="i" :label="v.label" :value="v.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业" prop="majorId">
|
||||
<el-select @change="changeSearchMajor" v-model="queryParams.majorId" placeholder="请先选择学院再选择专业"
|
||||
filterable clearable>
|
||||
<el-option v-for="(v, i) in search_major_list" :key="i" :label="v.majorName" :value="v.majorId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班级" prop="classId">
|
||||
<el-select v-model="queryParams.classId" placeholder="请先选择专业再选择班级" filterable clearable>
|
||||
<el-option v-for="(v, i) in search_class_list" :key="i" :label="v.className" :value="v.classId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>报告达成率(报告的全部指标都达成的情况)</span>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div ref="reportFinishChart" style="height: 400px"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>指标达成率(学生达成了多少个指标)</span>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div ref="itemFinishChart" style="height: 400px"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各年级报告达成率(可根据学院、专业查询)</span>
|
||||
<el-button
|
||||
@click='exportTable("gradeFinishList", searchRelName + "--" + searchDeptName + "--" + searchMajorName + "各年级报告达成率")'
|
||||
style="float: right;" icon="el-icon-download" type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table id="gradeFinishList" :data="gradeFinishList">
|
||||
<el-table-column label="年级" width="140" align="center" prop="grade_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各年级指标达成率(可根据学院、专业查询)</span>
|
||||
<el-button
|
||||
@click='exportTable("gradeItemFinishList", searchRelName + "--" + searchDeptName + "--" + searchMajorName + "各年级指标达成率")'
|
||||
style="float: right;" icon="el-icon-download" type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table id="gradeItemFinishList" :data="gradeItemFinishList">
|
||||
<el-table-column label="年级" width="140" align="center" prop="grade_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各学院报告达成率(可根据年级查询)</span>
|
||||
<el-button
|
||||
@click='exportTable("deptFinishList", searchRelName + "--" + searchGradeName + "各学院报告达成率")'
|
||||
style="float: right;" icon="el-icon-download" type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table id="deptFinishList" :data="deptFinishList">
|
||||
<el-table-column label="学院" width="140" align="center" prop="dept_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各学院指标达成率(可根据年级查询)</span>
|
||||
<el-button
|
||||
@click='exportTable("deptItemFinishList", searchRelName + "--" + searchGradeName + "各学院指标达成率")'
|
||||
style="float: right;" icon="el-icon-download" type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table id="deptItemFinishList" :data="deptItemFinishList">
|
||||
<el-table-column label="学院" width="140" align="center" prop="dept_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各专业报告达成率(可根据年级、学院查询)</span>
|
||||
<el-button @click='exportMajorFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedMajorFinishList">
|
||||
<el-table-column label="学院" width="140" align="center" prop="dept_name" />
|
||||
<el-table-column label="专业" width="140" align="center" prop="major_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageMajorFinish" :page-size="pageSizeMajorFinish"
|
||||
:total="majorFinishList.length" @current-change="handleMajorFinishPageChange"
|
||||
@size-change="handleMajorFinishSizeChange" :page-sizes="[10, 20, 50, 100]" :pager-count="5"
|
||||
style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各专业指标达成率(可根据年级、学院查询)</span>
|
||||
<el-button @click='exportMajorItemFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedMajorItemFinishList">
|
||||
<el-table-column label="学院" width="140" align="center" prop="dept_name" />
|
||||
<el-table-column label="专业" width="140" align="center" prop="major_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageMajorItemFinish" :page-size="pageSizeMajorItemFinish"
|
||||
:total="majorItemFinishList.length" @current-change="handleMajorItemFinishPageChange"
|
||||
@size-change="handleMajorItemFinishSizeChange" :page-sizes="[10, 20, 50, 100]"
|
||||
:pager-count="5" style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>指标达成情况</span>
|
||||
<el-button @click='exportTable("TotalForm", searchRelName + "--" + searchGradeName
|
||||
+ "--" + searchDeptName
|
||||
+ "--" + searchMajorName
|
||||
+ "--" + searchClassName + "指标达成情况")' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchDeptName) ? "" : searchDeptName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<TotalForm id="TotalForm" v-if="tableV" :tableData="tableData" />
|
||||
</el-card>
|
||||
|
||||
<table id="tempTable">
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
countItemFinishByRelId, countFinishNumByRelId, countItemFinishNumByRelId, countDeptItemFinishNumByRelId, countDeptFinishNumByRelId,
|
||||
countMajorFinishNumByRelId, countMajorItemFinishNumByRelId, countGradeFinishNumByRelId, countGradeItemFinishNumByRelId
|
||||
} from "@/api/diagnostic/reportStandards";
|
||||
|
||||
import { listAllRelease } from '@/api/diagnostic/DiaReportRelease';
|
||||
import { listEnableGrade } from '@/api/stuCQS/basedata/grade';
|
||||
import { getDeptName } from "@/api/system/dept";
|
||||
import { listMajors } from "@/api/stuCQS/basedata/majors";
|
||||
import { listClass } from "@/api/stuCQS/basedata/class";
|
||||
|
||||
|
||||
import { isEmpty, fullLoading } from '@/api/helpFunc';
|
||||
|
||||
import TotalForm from './cpnt/TotalForm';
|
||||
|
||||
import * as echarts from 'echarts';
|
||||
import XLSX from 'xlsx';
|
||||
|
||||
export default {
|
||||
name: "DataView",
|
||||
components: {
|
||||
TotalForm
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isEmpty,
|
||||
|
||||
queryParams: {
|
||||
relId: null
|
||||
},
|
||||
relList: [],
|
||||
gradeList: [],
|
||||
deptList: [],
|
||||
search_major_list: [],
|
||||
search_class_list: [],
|
||||
|
||||
|
||||
tableData: [],
|
||||
tableV: false,
|
||||
|
||||
reportFinishChart: null,
|
||||
itemFinishChart: null,
|
||||
|
||||
deptItemFinishList: [],
|
||||
deptFinishList: [],
|
||||
|
||||
majorItemFinishList: [],
|
||||
majorFinishList: [],
|
||||
|
||||
gradeItemFinishList: [],
|
||||
gradeFinishList: [],
|
||||
|
||||
searchRelName: "",
|
||||
searchDeptName: "",
|
||||
searchMajorName: "",
|
||||
searchClassName: "",
|
||||
searchGradeName: "",
|
||||
|
||||
currentPageMajorFinish: 1,
|
||||
pageSizeMajorFinish: 10,
|
||||
|
||||
currentPageMajorItemFinish: 1,
|
||||
pageSizeMajorItemFinish: 10,
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.listAllRelease();
|
||||
this.listEnableGrade();
|
||||
this.listDept();
|
||||
},
|
||||
mounted() {
|
||||
this.initCharts();
|
||||
},
|
||||
computed: {
|
||||
pagedMajorFinishList() {
|
||||
const start = (this.currentPageMajorFinish - 1) * this.pageSizeMajorFinish;
|
||||
const end = start + this.pageSizeMajorFinish;
|
||||
return this.majorFinishList.slice(start, end);
|
||||
},
|
||||
pagedMajorItemFinishList() {
|
||||
const start = (this.currentPageMajorItemFinish - 1) * this.pageSizeMajorItemFinish;
|
||||
const end = start + this.pageSizeMajorItemFinish;
|
||||
return this.majorItemFinishList.slice(start, end);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
exportMajorFinishList() {
|
||||
let majorFinishList = [...this.majorFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '在校生数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
majorFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.stu_num,
|
||||
row.finish_num,
|
||||
row.stu_num
|
||||
? ((row.finish_num / row.stu_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各专业报告达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchGradeName + "--" + this.searchDeptName;
|
||||
XLSX.writeFile(workbook, title + '各专业报告达成统计.xlsx');
|
||||
},
|
||||
exportMajorItemFinishList() {
|
||||
let majorItemFinishList = [...this.majorItemFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '在校生数', '总指标数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
majorItemFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.stu_num,
|
||||
row.total_num,
|
||||
row.finish_num,
|
||||
row.total_num
|
||||
? ((row.finish_num / row.total_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各专业指标达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchGradeName + "--" + this.searchDeptName;
|
||||
XLSX.writeFile(workbook, title + '各专业指标达成统计.xlsx');
|
||||
},
|
||||
exportTable(id, title) {
|
||||
let thead = document.getElementById(id).getElementsByTagName('thead')[0];
|
||||
let tbody = document.getElementById(id).getElementsByTagName('tbody')[0];
|
||||
let tempTable = document.getElementById('tempTable');
|
||||
if (thead) {
|
||||
tempTable.appendChild(thead.cloneNode(true))
|
||||
}
|
||||
if (tbody) {
|
||||
Array.from(tbody.getElementsByTagName('td')).forEach(td => {
|
||||
if (td.innerText.trim().endsWith('%')) {
|
||||
td.innerHTML = `<span style="mso-number-format:'\\@';">${td.innerText}</span>`;
|
||||
}
|
||||
});
|
||||
tempTable.appendChild(tbody.cloneNode(true))
|
||||
}
|
||||
const wb = XLSX.utils.table_to_book(tempTable, { sheet: 'Sheet1', cellText: true })
|
||||
XLSX.writeFile(wb, title + ".xlsx");
|
||||
tempTable.innerHTML = '';
|
||||
},
|
||||
|
||||
handleMajorItemFinishPageChange(page) {
|
||||
this.currentPageMajorItemFinish = page;
|
||||
},
|
||||
handleMajorItemFinishSizeChange(size) {
|
||||
this.pageSizeMajorItemFinish = size;
|
||||
this.currentPageMajorItemFinish = 1;
|
||||
},
|
||||
handleMajorFinishPageChange(page) {
|
||||
this.currentPageMajorFinish = page;
|
||||
},
|
||||
handleMajorFinishSizeChange(size) {
|
||||
this.pageSizeMajorFinish = size;
|
||||
this.currentPageMajorFinish = 1;
|
||||
},
|
||||
async queryData() {
|
||||
let sdata = { ...this.queryParams };
|
||||
if (isEmpty(sdata.relId)) {
|
||||
this.$message.info("请选择报告");
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchRelName = this.relList.find(item => item.relId == sdata.relId).reportName;
|
||||
|
||||
if (!isEmpty(sdata.deptId)) {
|
||||
this.searchDeptName = this.deptList.find(item => item.value == sdata.deptId).label;
|
||||
}
|
||||
if (!isEmpty(sdata.majorId)) {
|
||||
this.searchMajorName = this.search_major_list.find(item => item.majorId == sdata.majorId).majorName;
|
||||
}
|
||||
if (!isEmpty(sdata.classId)) {
|
||||
this.searchClassName = this.search_class_list.find(item => item.classId == sdata.classId).className;
|
||||
}
|
||||
if (!isEmpty(sdata.gradeId)) {
|
||||
this.searchGradeName = this.gradeList.find(item => item.gradeId == sdata.gradeId).gradeName;
|
||||
}
|
||||
|
||||
// 只开一次 loading
|
||||
let loading = fullLoading(this);
|
||||
// 并行等待接口
|
||||
try {
|
||||
await Promise.all([
|
||||
this.countFinishNumByRelId(true), // 传入参数表示不在内部开loading
|
||||
this.countItemFinishByRelId(true),
|
||||
this.countItemFinishNumByRelId(true),
|
||||
this.countDeptItemFinishNumByRelId(true),
|
||||
this.countDeptFinishNumByRelId(true),
|
||||
this.countMajorFinishNumByRelId(true),
|
||||
this.countMajorItemFinishNumByRelId(true),
|
||||
this.countGradeFinishNumByRelId(true),
|
||||
this.countGradeItemFinishNumByRelId(true),
|
||||
]);
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
},
|
||||
async countGradeItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countGradeItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.gradeItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countGradeFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countGradeFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.gradeFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countMajorItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countMajorItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.majorItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countMajorFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countMajorFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.majorFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countDeptFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countDeptFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.deptFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countDeptItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countDeptItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.deptItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
let temp = { ...res.data };
|
||||
let data = [];
|
||||
data.push({ value: temp.finish_num, name: '已达成' });
|
||||
data.push({ value: temp.total_num - temp.finish_num, name: '未达成' });
|
||||
this.renderPieChart(this.itemFinishChart, '指标达成率', data);
|
||||
}
|
||||
},
|
||||
async countFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
let temp = { ...res.data };
|
||||
let data = [];
|
||||
data.push({ value: temp.finish_num, name: '已达成' });
|
||||
data.push({ value: temp.stu_num - temp.finish_num, name: '未达成' });
|
||||
this.renderPieChart(this.reportFinishChart, '报告达成率', data);
|
||||
}
|
||||
},
|
||||
|
||||
async countItemFinishByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let sdata = { ...this.queryParams };
|
||||
this.tableV = false;
|
||||
let res = await countItemFinishByRelId(sdata);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.tableV = true;
|
||||
this.tableData = [...res.data];
|
||||
}
|
||||
},
|
||||
renderPieChart(chart, title, data) {
|
||||
// 添加数据检查
|
||||
if (!data || !Array.isArray(data)) {
|
||||
console.warn('数据格式不正确或为空:', data);
|
||||
data = []; // 设置为空数组,避免报错
|
||||
}
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: title,
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '达成情况',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
center: ['70%', '50%'],
|
||||
data: [...data],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 如果数据为空,显示暂无数据
|
||||
if (data.length === 0) {
|
||||
option.title.subtext = '暂无数据';
|
||||
}
|
||||
|
||||
chart.setOption(option);
|
||||
},
|
||||
initCharts() {
|
||||
if (this.$refs.reportFinishChart && this.$refs.itemFinishChart) {
|
||||
this.reportFinishChart = echarts.init(this.$refs.reportFinishChart);
|
||||
this.itemFinishChart = echarts.init(this.$refs.itemFinishChart);
|
||||
}
|
||||
},
|
||||
async changeSearchMajor() {
|
||||
let sdata = {
|
||||
pageNum: 1,
|
||||
pageSize: 100,
|
||||
majorId: this.queryParams.majorId
|
||||
}
|
||||
let res = await listClass(sdata);
|
||||
if (res.code == 200) {
|
||||
this.search_class_list = [...res.rows];
|
||||
}
|
||||
},
|
||||
async changeSearchDept() {
|
||||
let sdata = {
|
||||
collegeId: this.queryParams.deptId,
|
||||
pageNum: 1,
|
||||
pageSize: 100
|
||||
}
|
||||
let res = await listMajors(sdata);
|
||||
this.search_major_list = [...res.rows];
|
||||
},
|
||||
async listDept() {
|
||||
let res = await getDeptName();
|
||||
this.deptList = [...res.data];
|
||||
},
|
||||
|
||||
async listAllRelease() {
|
||||
let res = await listAllRelease();
|
||||
if (res.code == 200) {
|
||||
this.relList = [...res.data];
|
||||
}
|
||||
},
|
||||
async listEnableGrade() {
|
||||
let res = await listEnableGrade();
|
||||
if (res.code == 200) {
|
||||
this.gradeList = [...res.data];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.box-card {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.mt20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
</style>
|
||||
812
src/views/diagnostic/DataView/xw.vue
Normal file
812
src/views/diagnostic/DataView/xw.vue
Normal file
@@ -0,0 +1,812 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card class="box-card">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="120px">
|
||||
<el-form-item label="报告" prop="relId">
|
||||
<el-select v-model="queryParams.relId" placeholder="请选择报告">
|
||||
<el-option v-for="item in relList" :key="item.relId" :label="item.reportName"
|
||||
:value="item.relId"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
<el-button type="primary" icon="el-icon-search" plain @click="queryData">查询</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级" prop="gradeId">
|
||||
<el-select v-model="queryParams.gradeId" placeholder="请选择年级" clearable>
|
||||
<el-option v-for="item in gradeList" :key="item.gradeId" :label="item.gradeName"
|
||||
:value="item.gradeId"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业" prop="majorId">
|
||||
<el-select @change="changeSearchMajor" v-model="queryParams.majorId" placeholder="请选择专业" filterable
|
||||
clearable>
|
||||
<el-option v-for="(v, i) in search_major_list" :key="i" :label="v.majorName" :value="v.majorId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班级" prop="classId">
|
||||
<el-select v-model="queryParams.classId" placeholder="请先选择专业再选择班级" filterable clearable>
|
||||
<el-option v-for="(v, i) in search_class_list" :key="i" :label="v.className" :value="v.classId">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>报告达成率(报告的全部指标都达成的情况)</span>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div ref="reportFinishChart" style="height: 400px"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>指标达成率(学生达成了多少个指标)</span>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<div ref="itemFinishChart" style="height: 400px"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各年级报告达成率(可根据专业查询)</span>
|
||||
<el-button
|
||||
@click='exportTable("gradeFinishList", searchRelName + "--" + searchMajorName + "各年级报告达成率")'
|
||||
style="float: right;" icon="el-icon-download" type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table id="gradeFinishList" :data="gradeFinishList">
|
||||
<el-table-column label="年级" width="140" align="center" prop="grade_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各年级指标达成率(可根据专业查询)</span>
|
||||
<el-button
|
||||
@click='exportTable("gradeItemFinishList", searchRelName + "--" + searchMajorName + "各年级指标达成率")'
|
||||
style="float: right;" icon="el-icon-download" type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table id="gradeItemFinishList" :data="gradeItemFinishList">
|
||||
<el-table-column label="年级" width="140" align="center" prop="grade_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各专业报告达成率(可根据年级查询)</span>
|
||||
<el-button @click='exportMajorFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedMajorFinishList">
|
||||
<el-table-column label="专业" width="140" align="center" prop="major_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageMajorFinish" :page-size="pageSizeMajorFinish"
|
||||
:total="majorFinishList.length" @current-change="handleMajorFinishPageChange"
|
||||
@size-change="handleMajorFinishSizeChange" :page-sizes="[10, 20, 50, 100]" :pager-count="5"
|
||||
style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各专业指标达成率(可根据年级查询)</span>
|
||||
<el-button @click='exportMajorItemFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedMajorItemFinishList">
|
||||
<el-table-column label="专业" width="140" align="center" prop="major_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageMajorItemFinish" :page-size="pageSizeMajorItemFinish"
|
||||
:total="majorItemFinishList.length" @current-change="handleMajorItemFinishPageChange"
|
||||
@size-change="handleMajorItemFinishSizeChange" :page-sizes="[10, 20, 50, 100]"
|
||||
:pager-count="5" style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="mt20">
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各班级报告达成率(可根据年级、专业查询)</span>
|
||||
<el-button @click='exportClassFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedClassFinishList">
|
||||
<el-table-column label="班级" width="140" align="center" prop="class_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.stu_num
|
||||
? ((scope.row.finish_num / scope.row.stu_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageClassFinish" :page-size="pageSizeClassFinish"
|
||||
:total="classFinishList.length" @current-change="handleClassFinishPageChange"
|
||||
@size-change="handleClassFinishSizeChange" :page-sizes="[10, 20, 50, 100]" :pager-count="5"
|
||||
style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>各班级指标达成率(可根据年级、专业查询)</span>
|
||||
<el-button @click='exportClassItemFinishList()' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-table :data="pagedClassItemFinishList">
|
||||
<el-table-column label="班级" width="140" align="center" prop="class_name" />
|
||||
<el-table-column label="在校生数" align="center" prop="stu_num" />
|
||||
<el-table-column label="总指标数" align="center" prop="total_num" />
|
||||
<el-table-column label="达成数" align="center" prop="finish_num" />
|
||||
<el-table-column label="达成率" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{
|
||||
scope.row.total_num
|
||||
? ((scope.row.finish_num / scope.row.total_num) * 100).toFixed(4)
|
||||
: '0.0000'
|
||||
}}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination background layout="sizes, prev, pager, next"
|
||||
:current-page="currentPageClassItemFinish" :page-size="pageSizeClassItemFinish"
|
||||
:total="classItemFinishList.length" @current-change="handleClassItemFinishPageChange"
|
||||
@size-change="handleClassItemFinishSizeChange" :page-sizes="[10, 20, 50, 100]"
|
||||
:pager-count="5" style="text-align: right; margin-top: 20px;" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>指标达成情况</span>
|
||||
<el-button @click='exportTable("TotalForm", searchRelName + "--" + searchGradeName
|
||||
+ "--" + searchMajorName
|
||||
+ "--" + searchClassName + "指标达成情况")' style="float: right;" icon="el-icon-download"
|
||||
type="text">导出</el-button>
|
||||
<br />
|
||||
<span style="font-size: 10px;color: red;">
|
||||
当前数据:{{ isEmpty(searchRelName) ? "" : searchRelName }}--
|
||||
{{ isEmpty(searchGradeName) ? "" : searchGradeName }}--
|
||||
{{ isEmpty(searchMajorName) ? "" : searchMajorName }}--
|
||||
{{ isEmpty(searchClassName) ? "" : searchClassName }}
|
||||
</span>
|
||||
</div>
|
||||
<TotalForm id="TotalForm" v-if="tableV" :tableData="tableData" />
|
||||
</el-card>
|
||||
|
||||
<table id="tempTable">
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
countXwItemFinishByRelId as countItemFinishByRelId,
|
||||
countXwFinishNumByRelId as countFinishNumByRelId,
|
||||
countXwItemFinishNumByRelId as countItemFinishNumByRelId,
|
||||
countXwMajorFinishNumByRelId as countMajorFinishNumByRelId,
|
||||
countXwMajorItemFinishNumByRelId as countMajorItemFinishNumByRelId,
|
||||
countXwGradeFinishNumByRelId as countGradeFinishNumByRelId,
|
||||
countXwGradeItemFinishNumByRelId as countGradeItemFinishNumByRelId,
|
||||
countXwClassFinishNumByRelId as countClassFinishNumByRelId,
|
||||
countXwClassItemFinishNumByRelId as countClassItemFinishNumByRelId
|
||||
} from "@/api/diagnostic/reportStandards";
|
||||
|
||||
import { listAllRelease } from '@/api/diagnostic/DiaReportRelease';
|
||||
import { listEnableGrade } from '@/api/stuCQS/basedata/grade';
|
||||
|
||||
import { listOwnMajor as listMajors } from "@/api/stuCQS/info-fill/cqScore";
|
||||
import { listClass } from "@/api/stuCQS/basedata/class";
|
||||
|
||||
|
||||
import { isEmpty, fullLoading } from '@/api/helpFunc';
|
||||
|
||||
import TotalForm from './cpnt/TotalForm';
|
||||
|
||||
import * as echarts from 'echarts';
|
||||
import XLSX from 'xlsx';
|
||||
|
||||
export default {
|
||||
name: "DataView",
|
||||
components: {
|
||||
TotalForm
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isEmpty,
|
||||
|
||||
queryParams: {
|
||||
relId: null
|
||||
},
|
||||
relList: [],
|
||||
gradeList: [],
|
||||
search_major_list: [],
|
||||
search_class_list: [],
|
||||
|
||||
|
||||
tableData: [],
|
||||
tableV: false,
|
||||
|
||||
reportFinishChart: null,
|
||||
itemFinishChart: null,
|
||||
|
||||
majorItemFinishList: [],
|
||||
majorFinishList: [],
|
||||
|
||||
gradeItemFinishList: [],
|
||||
gradeFinishList: [],
|
||||
|
||||
classItemFinishList: [],
|
||||
classFinishList: [],
|
||||
|
||||
searchRelName: "",
|
||||
searchMajorName: "",
|
||||
searchClassName: "",
|
||||
searchGradeName: "",
|
||||
|
||||
currentPageMajorFinish: 1,
|
||||
pageSizeMajorFinish: 10,
|
||||
|
||||
currentPageMajorItemFinish: 1,
|
||||
pageSizeMajorItemFinish: 10,
|
||||
|
||||
currentPageClassFinish: 1,
|
||||
pageSizeClassFinish: 10,
|
||||
|
||||
currentPageClassItemFinish: 1,
|
||||
pageSizeClassItemFinish: 10,
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.listAllRelease();
|
||||
this.listEnableGrade();
|
||||
this.listMajors();
|
||||
},
|
||||
mounted() {
|
||||
this.initCharts();
|
||||
},
|
||||
computed: {
|
||||
pagedMajorFinishList() {
|
||||
const start = (this.currentPageMajorFinish - 1) * this.pageSizeMajorFinish;
|
||||
const end = start + this.pageSizeMajorFinish;
|
||||
return this.majorFinishList.slice(start, end);
|
||||
},
|
||||
pagedMajorItemFinishList() {
|
||||
const start = (this.currentPageMajorItemFinish - 1) * this.pageSizeMajorItemFinish;
|
||||
const end = start + this.pageSizeMajorItemFinish;
|
||||
return this.majorItemFinishList.slice(start, end);
|
||||
},
|
||||
|
||||
pagedClassFinishList() {
|
||||
const start = (this.currentPageClassFinish - 1) * this.pageSizeClassFinish;
|
||||
const end = start + this.pageSizeClassFinish;
|
||||
return this.classFinishList.slice(start, end);
|
||||
},
|
||||
pagedClassItemFinishList() {
|
||||
const start = (this.currentPageClassItemFinish - 1) * this.pageSizeClassItemFinish;
|
||||
const end = start + this.pageSizeClassItemFinish;
|
||||
return this.classItemFinishList.slice(start, end);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
exportClassFinishList() {
|
||||
let classFinishList = [...this.classFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '班级', '在校生数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
classFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.class_name,
|
||||
row.stu_num,
|
||||
row.finish_num,
|
||||
row.stu_num
|
||||
? ((row.finish_num / row.stu_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各班级报告达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchGradeName + "--" + this.searchMajorName;
|
||||
XLSX.writeFile(workbook, title + '各班级报告达成统计.xlsx');
|
||||
},
|
||||
exportClassItemFinishList() {
|
||||
let classItemFinishList = [...this.classItemFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '班级', '在校生数', '总指标数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
classItemFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.class_name,
|
||||
row.stu_num,
|
||||
row.total_num,
|
||||
row.finish_num,
|
||||
row.total_num
|
||||
? ((row.finish_num / row.total_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各班级指标达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchGradeName + "--" + this.searchMajorName;
|
||||
XLSX.writeFile(workbook, title + '各班级指标达成统计.xlsx');
|
||||
},
|
||||
exportMajorFinishList() {
|
||||
let majorFinishList = [...this.majorFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '在校生数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
majorFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.stu_num,
|
||||
row.finish_num,
|
||||
row.stu_num
|
||||
? ((row.finish_num / row.stu_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各专业报告达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchGradeName;
|
||||
XLSX.writeFile(workbook, title + '各专业报告达成统计.xlsx');
|
||||
},
|
||||
exportMajorItemFinishList() {
|
||||
let majorItemFinishList = [...this.majorItemFinishList];
|
||||
const data = [
|
||||
['学院', '专业', '在校生数', '总指标数', '达成数', '达成率']
|
||||
];
|
||||
|
||||
majorItemFinishList.forEach(row => {
|
||||
data.push([
|
||||
row.dept_name,
|
||||
row.major_name,
|
||||
row.stu_num,
|
||||
row.total_num,
|
||||
row.finish_num,
|
||||
row.total_num
|
||||
? ((row.finish_num / row.total_num) * 100).toFixed(4) + '%'
|
||||
: '0.0000%'
|
||||
]);
|
||||
});
|
||||
const worksheet = XLSX.utils.aoa_to_sheet(data);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, '各专业指标达成统计');
|
||||
|
||||
let title = this.searchRelName + "--" + this.searchGradeName;
|
||||
XLSX.writeFile(workbook, title + '各专业指标达成统计.xlsx');
|
||||
},
|
||||
exportTable(id, title) {
|
||||
let thead = document.getElementById(id).getElementsByTagName('thead')[0];
|
||||
let tbody = document.getElementById(id).getElementsByTagName('tbody')[0];
|
||||
let tempTable = document.getElementById('tempTable');
|
||||
if (thead) {
|
||||
tempTable.appendChild(thead.cloneNode(true))
|
||||
}
|
||||
if (tbody) {
|
||||
Array.from(tbody.getElementsByTagName('td')).forEach(td => {
|
||||
if (td.innerText.trim().endsWith('%')) {
|
||||
td.innerHTML = `<span style="mso-number-format:'\\@';">${td.innerText}</span>`;
|
||||
}
|
||||
});
|
||||
tempTable.appendChild(tbody.cloneNode(true))
|
||||
}
|
||||
const wb = XLSX.utils.table_to_book(tempTable, { sheet: 'Sheet1', cellText: true })
|
||||
XLSX.writeFile(wb, title + ".xlsx");
|
||||
tempTable.innerHTML = '';
|
||||
},
|
||||
|
||||
handleClassItemFinishPageChange(page) {
|
||||
this.currentPageClassItemFinish = page;
|
||||
},
|
||||
handleClassItemFinishSizeChange(size) {
|
||||
this.pageSizeClassItemFinish = size;
|
||||
this.currentPageClassItemFinish = 1;
|
||||
},
|
||||
handleClassFinishPageChange(page) {
|
||||
this.currentPageClassFinish = page;
|
||||
},
|
||||
handleClassFinishSizeChange(size) {
|
||||
this.pageSizeClassFinish = size;
|
||||
this.currentPageClassFinish = 1;
|
||||
},
|
||||
|
||||
handleMajorItemFinishPageChange(page) {
|
||||
this.currentPageMajorItemFinish = page;
|
||||
},
|
||||
handleMajorItemFinishSizeChange(size) {
|
||||
this.pageSizeMajorItemFinish = size;
|
||||
this.currentPageMajorItemFinish = 1;
|
||||
},
|
||||
handleMajorFinishPageChange(page) {
|
||||
this.currentPageMajorFinish = page;
|
||||
},
|
||||
handleMajorFinishSizeChange(size) {
|
||||
this.pageSizeMajorFinish = size;
|
||||
this.currentPageMajorFinish = 1;
|
||||
},
|
||||
async queryData() {
|
||||
let sdata = { ...this.queryParams };
|
||||
if (isEmpty(sdata.relId)) {
|
||||
this.$message.info("请选择报告");
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchRelName = this.relList.find(item => item.relId == sdata.relId).reportName;
|
||||
|
||||
if (!isEmpty(sdata.majorId)) {
|
||||
this.searchMajorName = this.search_major_list.find(item => item.majorId == sdata.majorId).majorName;
|
||||
}
|
||||
if (!isEmpty(sdata.classId)) {
|
||||
this.searchClassName = this.search_class_list.find(item => item.classId == sdata.classId).className;
|
||||
}
|
||||
if (!isEmpty(sdata.gradeId)) {
|
||||
this.searchGradeName = this.gradeList.find(item => item.gradeId == sdata.gradeId).gradeName;
|
||||
}
|
||||
|
||||
// 只开一次 loading
|
||||
let loading = fullLoading(this);
|
||||
// 并行等待接口
|
||||
try {
|
||||
await Promise.all([
|
||||
this.countFinishNumByRelId(true), // 传入参数表示不在内部开loading
|
||||
this.countItemFinishByRelId(true),
|
||||
this.countItemFinishNumByRelId(true),
|
||||
this.countMajorFinishNumByRelId(true),
|
||||
this.countMajorItemFinishNumByRelId(true),
|
||||
this.countGradeFinishNumByRelId(true),
|
||||
this.countGradeItemFinishNumByRelId(true),
|
||||
this.countClassFinishNumByRelId(true),
|
||||
this.countClassItemFinishNumByRelId(true),
|
||||
]);
|
||||
} finally {
|
||||
loading.close();
|
||||
}
|
||||
},
|
||||
async countClassFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countClassFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.classFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countClassItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countClassItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.classItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countGradeItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countGradeItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.gradeItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countGradeFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countGradeFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.gradeFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countMajorItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countMajorItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.majorItemFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
async countMajorFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countMajorFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.majorFinishList = [...res.data];
|
||||
}
|
||||
},
|
||||
|
||||
async countItemFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countItemFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
let temp = { ...res.data };
|
||||
let data = [];
|
||||
data.push({ value: temp.finish_num, name: '已达成' });
|
||||
data.push({ value: temp.total_num - temp.finish_num, name: '未达成' });
|
||||
this.renderPieChart(this.itemFinishChart, '指标达成率', data);
|
||||
}
|
||||
},
|
||||
async countFinishNumByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let res = await countFinishNumByRelId(this.queryParams);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
let temp = { ...res.data };
|
||||
let data = [];
|
||||
data.push({ value: temp.finish_num, name: '已达成' });
|
||||
data.push({ value: temp.stu_num - temp.finish_num, name: '未达成' });
|
||||
this.renderPieChart(this.reportFinishChart, '报告达成率', data);
|
||||
}
|
||||
},
|
||||
|
||||
async countItemFinishByRelId(noLoading) {
|
||||
let loading;
|
||||
if (!noLoading) loading = fullLoading(this);
|
||||
let sdata = { ...this.queryParams };
|
||||
this.tableV = false;
|
||||
let res = await countItemFinishByRelId(sdata);
|
||||
if (loading) loading.close();
|
||||
if (res.code == 200) {
|
||||
this.tableV = true;
|
||||
this.tableData = [...res.data];
|
||||
}
|
||||
},
|
||||
renderPieChart(chart, title, data) {
|
||||
// 添加数据检查
|
||||
if (!data || !Array.isArray(data)) {
|
||||
console.warn('数据格式不正确或为空:', data);
|
||||
data = []; // 设置为空数组,避免报错
|
||||
}
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: title,
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '达成情况',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
center: ['70%', '50%'],
|
||||
data: [...data],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 如果数据为空,显示暂无数据
|
||||
if (data.length === 0) {
|
||||
option.title.subtext = '暂无数据';
|
||||
}
|
||||
|
||||
chart.setOption(option);
|
||||
},
|
||||
initCharts() {
|
||||
if (this.$refs.reportFinishChart && this.$refs.itemFinishChart) {
|
||||
this.reportFinishChart = echarts.init(this.$refs.reportFinishChart);
|
||||
this.itemFinishChart = echarts.init(this.$refs.itemFinishChart);
|
||||
}
|
||||
},
|
||||
async changeSearchMajor() {
|
||||
let sdata = {
|
||||
pageNum: 1,
|
||||
pageSize: 100,
|
||||
majorId: this.queryParams.majorId
|
||||
}
|
||||
let res = await listClass(sdata);
|
||||
if (res.code == 200) {
|
||||
this.search_class_list = [...res.rows];
|
||||
}
|
||||
},
|
||||
async listMajors() {
|
||||
let res = await listMajors();
|
||||
this.search_major_list = [...res.data];
|
||||
},
|
||||
|
||||
|
||||
async listAllRelease() {
|
||||
let res = await listAllRelease();
|
||||
if (res.code == 200) {
|
||||
this.relList = [...res.data];
|
||||
}
|
||||
},
|
||||
async listEnableGrade() {
|
||||
let res = await listEnableGrade();
|
||||
if (res.code == 200) {
|
||||
this.gradeList = [...res.data];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.box-card {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.mt20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user