rt-sim-training-client/src/views/studentManage/index.vue

689 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="joylink-card">
<div style="margin-top: 20px;width: 90%; position: absolute; left: 5%; height: 100%;">
<el-row>
<el-col :span="20">
<el-form ref="form" :model="form" :rules="rules" label-width="120px" size="mini" style="width: 100%;margin-top: 10px;">
<el-row>
<el-col :span="6">
<el-form-item label="班级:" prop="classId">
<el-select v-model="form.classId" placeholder="请选择" @change="getLessonByClassId">
<el-option
v-for="item in classList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="考勤天数:" prop="attendanceDays">
<el-input-number v-model="form.attendanceDays" :min="1" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="学期起始日期:" prop="termBeginDate">
<el-date-picker
v-model="form.termBeginDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="学期结束日期:" prop="termEndDate">
<el-date-picker
v-model="form.termEndDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="教学类型:"><span>行调</span></el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="课程:" prop="centerLessonId">
<el-select v-model="form.centerLessonId" clearable placeholder="请选择" @change="centerLessonChange">
<el-option
v-for="item in centerLessonList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="试卷:" prop="centerExamPaperId">
<el-select v-model="form.centerExamPaperId" clearable placeholder="请选择">
<el-option
v-for="item in centerExamPaperList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="教学类型:"><span>现地</span></el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="课程:" prop="localLessonId">
<el-select v-model="form.localLessonId" clearable placeholder="请选择" @change="localLessonChange">
<el-option
v-for="item in localLessonList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="试卷:" prop="localExamPaperId">
<el-select v-model="form.localExamPaperId" clearable placeholder="请选择">
<el-option
v-for="item in localExamPaperList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-col>
<el-col :span="4">
<el-button type="primary" size="mini" @click="query">查询</el-button>
<el-button type="primary" class="uploadDemo" size="mini" style="margin-top: 10px;">
<input
id="importResults"
ref="files"
type="file"
class="file_box"
accept=".json, application/json, .csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
@change="importResults"
>
导入学生信息
</el-button>
<el-button type="primary" size="mini" style="margin-top: 10px;" @click="exportResults">成绩导出</el-button></el-col>
</el-row>
<div style="height: calc(100% - 270px);">
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-table
:data="tableData"
border
>
<el-table-column prop="index" label="序号" />
<el-table-column
prop="studentID"
label="学号"
/>
<el-table-column
prop="name"
label="姓名"
/>
<el-table-column label="考勤(10分)" prop="attendance" width="180" />
<el-table-column label="技能操作(30分)">
<el-table-column v-if="showLocal" :label="'ATS现地('+ lessonSocre +'分)'" prop="localLessonPassRate" />
<el-table-column v-if="showCenter" :label="'ATS行调('+ lessonSocre+'分)'" prop="centerLessonPassRate" />
</el-table-column>
<el-table-column label="考试成绩(60分)">
<el-table-column v-if="showLocal" :label="'ATS现地('+ examSocre+'分)'" prop="localExamSocreRadio" />
<el-table-column v-if="showCenter" :label="'ATS行调('+ examSocre+'分)'" prop="centerExamSocreRadio" />
</el-table-column>
<el-table-column label="期末成绩(100分)" prop="totolScore" />
</el-table>
</el-scrollbar>
</div>
</div>
</div>
</template>
<script>
import { getLessonDrftList } from '@/api/jmap/lessondraft';
import XLSX from 'xlsx';
import { convertSheetToList } from '@/utils/runPlan';
import { importStudentResults, exportStudentResults } from '@/api/management/user';
import { getSessionStorage } from '@/utils/auth';
import { ProjectCode } from '@/scripts/ProjectConfig';
import { getProjectClassList } from '@/api/management/user';
import { getLessonByClassId } from '@/api/jmap/lesson';
import { getExamList } from '@/api/management/exam';
export default {
name: 'StudentManage',
components: {
},
data() {
var validatePass = (rule, value, callback) => {
if (this.form.attendanceDays && this.form.termBeginDate && this.form.termEndDate) {
const timeDifference = new Date(this.form.termEndDate).valueOf() - new Date(this.form.termBeginDate).valueOf();
if (timeDifference < (this.form.attendanceDays - 1) * 24 * 3600 * 1000) {
callback(new Error('学期日期间隔不得小于考勤天数!'));
} else {
this.$refs.form.clearValidate('attendanceDays');
this.$refs.form.clearValidate('termBeginDate');
this.$refs.form.clearValidate('termEndDate');
callback();
}
} else {
callback();
}
};
var validatePrdParam = (rule, value, callback) => {
if ((this.form.localLessonId && this.form.localExamPaperId) || (this.form.centerLessonId && this.form.centerExamPaperId)) {
callback();
} else {
callback(new Error('至少选择一类课程试卷!'));
}
};
return {
loading: false,
classList: [],
localLessonList: [],
centerLessonList: [],
localExamPaperList: [],
centerExamPaperList: [],
showLocal: false,
showCenter: false,
tableData: [],
props: { multiple: true, value: 'id', label: 'name' },
form: {
attendanceDays: 1,
classId: '',
termBeginDate: '',
termEndDate: '',
localLessonId: '',
centerLessonId: '',
localExamPaperId: '',
centerExamPaperId: ''
},
examDataList: [
{
id: '01',
name: '现地',
children: []
}, {
id: '02',
name: '行调',
children: []
}
],
rules: {
classId: [{ required: true, message: '请选择班级', trigger: 'change' }],
attendanceDays: [
{required: true, message: '请输入考勤天数', trigger: 'blur'},
{required: true, message: '请输入考勤天数', trigger: 'change'},
{validator: validatePass, trigger: 'blur' },
{validator: validatePass, trigger: 'change'}
],
termBeginDate: [{required: true, message: '请选择开始日期', trigger: 'change'}, {validator: validatePass, trigger: 'change' }],
termEndDate: [{required: true, message: '请选择结束日期', trigger: 'change'}, {validator: validatePass, trigger: 'change' }],
localExamPaperId: [{validator: validatePrdParam, trigger: 'change'}],
centerExamPaperId: [{validator: validatePrdParam, trigger: 'change'}]
},
pagerConfig: {
pageSize: 'pageSize',
pageIndex: 'pageNum'
},
queryForm: {
show: false
},
queryList: {
query: this.queryFunction,
selectCheckShow: false,
indexShow: true,
columns: [
]
},
exportData: {
classId: '',
localLessonId: ''
}
};
},
computed: {
mapId() {
return this.$route.params.mapId;
},
project() {
return getSessionStorage('project');
},
lessonSocre() {
return this.showLocal && this.showCenter ? 15 : 30;
},
examSocre() {
return this.showLocal && this.showCenter ? 30 : 60;
}
},
watch: {
$route() {
this.refresh();
}
},
mounted() {
this.classList = [];
getProjectClassList(ProjectCode[this.project]).then(resp => {
this.classList = resp.data;
}).catch(() =>{
this.$message.error('获取班级数据失败!');
});
},
methods: {
queryFunction(params) {
return getLessonDrftList(this.$route.params.mapId, params);
},
importResults(e) {
const obj = this.$refs.files;
if (obj.files) {
const file = obj.files[0];
this.handleImportResults(file);
obj.value = '';
}
},
query() {
this.$refs.form.validate((valid) => {
if (valid) {
if ((this.form.localLessonId && this.form.localExamPaperId) || (this.form.centerLessonId && this.form.centerExamPaperId)) {
const prdParams = [];
if (this.form.localLessonId && this.form.localExamPaperId) {
prdParams.push({prdType: '01', lessonId: this.form.localLessonId, examPaperId: this.form.localExamPaperId});
}
if (this.form.centerLessonId && this.form.centerExamPaperId) {
prdParams.push({prdType: '02', lessonId: this.form.centerLessonId, examPaperId: this.form.centerExamPaperId});
}
const params = {
attendanceDays: this.form.attendanceDays,
classId:this.form.classId,
termBeginDate: this.form.termBeginDate,
termEndDate: this.form.termEndDate,
prdParams: prdParams
};
this.exportData = {
classId: '',
localLessonId: ''
};
exportStudentResults(ProjectCode[this.project], params).then(resp => {
this.tableData = [];
this.showLocal = false;
this.showCenter = false;
this.exportData = {
classId: params.classId
};
resp.data.forEach((item, index) => {
let localExamSocreRadio = -1;
let localLessonPassRate = -1;
let centerExamSocreRadio = -1;
let centerLessonPassRate = -1;
let totolScore = 0;
item.scores.forEach(elem => {
if (elem.prdType === '01') {
this.showLocal = true;
localExamSocreRadio = elem.examSocreRadio * 60 / item.scores.length;
localLessonPassRate = elem.lessonPassRate * 30 / item.scores.length;
totolScore += localExamSocreRadio * 100;
totolScore += localLessonPassRate * 100;
} else if (elem.prdType === '02') {
this.showCenter = true;
centerExamSocreRadio = elem.examSocreRadio * 60 / item.scores.length;
centerLessonPassRate = elem.lessonPassRate * 30 / item.scores.length;
totolScore += centerExamSocreRadio * 100;
totolScore += centerLessonPassRate * 100;
}
});
totolScore += item.attendance * 100 * 10;
this.tableData.push(
{
index: index + 1,
name: item.name,
studentID: item.studentID,
attendance: Math.round(item.attendance * 10) / 10,
localExamSocreRadio: Math.round(localExamSocreRadio * 10) / 10,
localLessonPassRate: Math.round(localLessonPassRate * 10) / 10,
centerExamSocreRadio: Math.round(centerExamSocreRadio * 10) / 10,
centerLessonPassRate: Math.round(centerLessonPassRate * 10) / 10,
totolScore: Math.round(totolScore) / 100
});
});
}).catch(() =>{
this.$message.error('获取学生考试成绩失败!');
});
} else {
this.$messageBox('您至少需选择一种产品类型下的课程与考试!');
}
}
});
},
localLessonChange(lessonId) {
this.localExamPaperList = [];
this.form.localExamPaperId = '';
if (lessonId) {
getExamList({lessonId:lessonId, pageSize:999, pageNum:1}).then(resp => {
this.localExamPaperList = resp.data.list;
}).catch(()=> {
this.$message.error('获取试卷列表失败!');
});
}
},
centerLessonChange(lessonId) {
this.centerExamPaperList = [];
this.form.centerExamPaperId = '';
if (lessonId) {
getExamList({lessonId:lessonId, pageSize:999, pageNum:1}).then(resp => {
this.centerExamPaperList = resp.data.list;
}).catch(()=> {
this.$message.error('获取试卷列表失败!');
});
}
},
getLessonByClassId(classId) {
this.localLessonList = [];
this.centerLessonList = [];
this.form.localLessonId = '';
this.form.centerLessonId = '';
this.localExamPaperList = [];
this.form.localExamPaperId = '';
this.centerExamPaperList = [];
this.form.centerExamPaperId = '';
if (classId) {
getLessonByClassId(classId).then(resp => {
this.lessonList = resp.data;
this.lessonList.forEach(item => {
if (item.prdType === '01') {
this.localLessonList.push(item);
} else if (item.prdType === '02') {
this.centerLessonList.push(item);
}
});
}).catch(()=> {
this.$message.error('获取课程列表失败!');
});
}
},
handleImportResults(file) {
const studentData = { className: '', students:[] };
if (file) {
setTimeout(() => {
const that = this;
const reader = new FileReader();
if (reader) {
reader.onload = function (e) {
let wb;
const data = e.target.result;
if (that.rABS) {
wb = XLSX.read(btoa(that.fixdata(data)), { // 手动转化
type: 'base64'
});
} else {
wb = XLSX.read(data, {
type: 'binary'
});
}
if (wb) {
try {
const students = [];
for (const index in wb.Sheets) {
const dataList = convertSheetToList(wb.Sheets[index], true);
const className = dataList[0][2].split(' ')[0].replace(/\s*/g, '').split('')[1];
studentData.className = className;
for ( let i = 5; i <= dataList[0].length; i++) {
if (dataList[2][i] && dataList[1][i]) {
students.push({studentID:dataList[2][i], name: dataList[1][i]});
}
}
studentData.students = students;
}
importStudentResults(ProjectCode[that.project], studentData).then(resp => {
that.classList = [];
getProjectClassList(ProjectCode[that.project]).then(respon => {
that.classList = respon.data;
}).catch(() =>{
that.$message.error('获取班级数据失败!');
});
that.$message.success('学生信息导入成功!');
}).catch((err) => {
that.$message.error('学生信息导入失败:' + err.message);
});
} catch (error) {
that.$message.warning(`解析成绩单失败:${error}`);
}
}
};
if (that.rABS) {
reader.readAsArrayBuffer(file);
} else {
reader.readAsBinaryString(file);
}
}
}, 200);
}
},
handelData() {
},
exportResults() {
if (!this.tableData || !this.tableData.length) {
this.$message.error('暂无导出数据!');
return;
}
let className = '';
this.classList.forEach(item => {
if (item.id === this.exportData.classId) {
className = item.name;
}
});
const wb = XLSX.utils.book_new();
let cellNum = 0;
let data = [{A:'贵 州 装 备 制 造 职 业 学 院'}, {A:'实 训 成 绩 登 记 表'}, {A:`班级:${className} 实训课程名称: 20XX 学年 第 学期 `}];
const data1 = [{A: '序号', B: '姓名', C:'学号', D:'考勤(10分)', E: '技能操作(30分)', F: '', G: '考试成绩(60分)', H: '', I: '期末成绩', J: '备注'}, {E: 'ATS现地(15分)', F: 'ATS行调(15分)', G: 'ATS现地(30分)', H: 'ATS行调(30分)'}];
const data2 = [{A: '序号', B: '姓名', C:'学号', D:'考勤(10分)', E: '技能操作(30分)', F: '考试成绩(60分)', G: '期末成绩', H: '备注'}, { E: 'ATS现地(30分)', F: 'ATS现地(60分)'}];
const data3 = [{A: '序号', B: '姓名', C:'学号', D:'考勤(10分)', E: '技能操作(30分)', F: '考试成绩(60分)', G: '期末成绩', H: '备注'}, {E: 'ATS行调(30分)', F: 'ATS行调(60分)'}];
if (this.showCenter && this.showLocal) {
data = [...data, ...data1];
cellNum = 9;
this.tableData.forEach(item => {
data.push({
A: item.index,
B: item.name,
C: item.studentID,
D: item.attendance,
E: item.localLessonPassRate,
F: item.centerLessonPassRate,
G: item.localExamSocreRadio,
H: item.centerExamSocreRadio,
I: item.totolScore,
J: ''
});
});
} else if (this.showCenter) {
data = [...data, ...data3];
cellNum = 7;
this.tableData.forEach(item => {
data.push({
A: item.index,
B: item.name,
C: item.studentID,
D: item.attendance,
E: item.centerLessonPassRate,
F: item.centerExamSocreRadio,
G: item.totolScore,
H: ''
});
});
} else if (this.showLocal) {
data = [...data, ...data2];
cellNum = 7;
this.tableData.forEach(item => {
data.push({
A: item.index,
B: item.name,
C: item.studentID,
D: item.attendance,
E: item.localLessonPassRate,
F: item.localExamSocreRadio,
G: item.totolScore,
H: ''
});
});
}
const ws = XLSX.utils.json_to_sheet(data, {skipHeader:true});
ws['A1'].s = { // 设置副标题样式
font: {
name: '宋体',
sz: 20,
color: {rgb: '#000000'},
bold: true,
italic: false,
underline: false
},
alignment: {
horizontal: 'center',
vertical: 'center'
}
};
ws['A2'].s = { // 设置副标题样式
font: {
name: '宋体',
sz: 16,
color: {rgb: '#000000'},
bold: true,
italic: false,
underline: false
},
alignment: {
horizontal: 'center',
vertical: 'center'
}
};
ws['A3'].s = { // 设置副标题样式
font: {
name: '宋体',
sz: 12,
color: {rgb: '#000000'},
bold: false,
italic: false,
underline: false
},
alignment: {
horizontal: 'center',
vertical: 'center'
}
};
ws['!merges'] = [
{
s: {c: 0, r: 0},
e: {c: cellNum, r: 0}
},
{
s: {c: 0, r: 1},
e: {c: cellNum, r: 1}
},
{
s: {c: 0, r: 2},
e: {c: cellNum, r: 2}
},
{
s: {c: 0, r: 3},
e: {c: 0, r: 4}
},
{
s: {c: 1, r: 3},
e: {c: 1, r: 4}
},
{
s: {c: 2, r: 3},
e: {c: 2, r: 4}
},
{
s: {c: 3, r: 3},
e: {c: 3, r: 4}
}
];
if (this.showCenter && this.showLocal) {
ws['!merges'].push({
s: {c: 4, r: 3},
e: {c: 5, r: 3}
});
ws['!merges'].push({
s: {c: 6, r: 3},
e: {c: 7, r: 3}
});
ws['!merges'].push({
s: {c: 8, r: 3},
e: {c: 8, r: 4}
});
ws['!merges'].push({
s: {c: 9, r: 3},
e: {c: 9, r: 4}
});
} else {
ws['!merges'].push({
s: {c: 6, r: 3},
e: {c: 6, r: 4}
});
ws['!merges'].push({
s: {c: 7, r: 3},
e: {c: 7, r: 4}
});
}
ws['!cols'] = [
{width: 10},
{width: 10},
{width: 10},
{width: 15},
{width: 15},
{width: 15},
{width: 15},
{width: 15},
{width: 15},
{width: 15}
];
XLSX.utils.book_append_sheet(wb, ws, 'file');
XLSX.writeFile(wb, '成绩单' + '.xlsx');
},
refresh() {
this.$refs.queryListPage.refresh(true);
}
}
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@import "src/styles/mixin.scss";
.joylink-card{
height: 100%;
overflow: auto;
}
.file_box {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
opacity: 0;
cursor: pointer;
z-index: 100;
}
.uploadDemo {
position: relative;
overflow: hidden;
margin-right: 3px;
cursor: pointer;
padding: 0 15px;
height: 28px;
}
</style>