rt-sim-training-client/src/views/studentManage/index.vue
2020-05-13 17:59:08 +08:00

639 lines
25 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%;">
<el-row>
<el-col :span="20">
<el-form ref="form" :model="form" :rules="rules" label-width="100px" 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" 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" 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" 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" 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>
<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>
</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() {
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'}],
termBeginDate: [{required: true, message: '请选择开始日期', trigger: 'change'}],
termEndDate: [{required: true, message: '请选择结束日期', 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() {
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 * 100 * 60 / 100 / item.scores.length;
localLessonPassRate = elem.lessonPassRate * 100 * 30 / 100 / item.scores.length;
totolScore += localExamSocreRadio;
totolScore += localLessonPassRate;
} else if (elem.prdType === '02') {
this.showCenter = true;
centerExamSocreRadio = elem.examSocreRadio * 100 * 60 / 100 / item.scores.length;
centerLessonPassRate = elem.lessonPassRate * 100 * 30 / 100 / item.scores.length;
totolScore += centerExamSocreRadio;
totolScore += centerLessonPassRate;
}
});
totolScore += item.attendance * 100 * 10 / 100;
this.tableData.push(
{
index: index + 1,
name: item.name,
studentID: item.studentID,
attendance: item.attendance * 100 * 10 / 100,
localExamSocreRadio:localExamSocreRadio,
localLessonPassRate: localLessonPassRate,
centerExamSocreRadio: centerExamSocreRadio,
centerLessonPassRate: centerLessonPassRate,
totolScore: totolScore
});
});
}).catch(() =>{
this.$message.error('获取学生考试成绩失败!');
});
} else {
this.$messageBox('您至少需选择一种产品类型下的课程与考试!');
}
}
});
},
localLessonChange(lessonId) {
this.localExamPaperList = [];
if (lessonId) {
getExamList({lessonId:lessonId, pageSize:999, pageNum:1}).then(resp => {
this.localExamPaperList = resp.data.list;
}).catch(()=> {
this.$message.error('获取试卷列表失败!');
});
}
},
centerLessonChange(lessonId) {
this.centerExamPaperList = [];
if (lessonId) {
getExamList({lessonId:lessonId, pageSize:999, pageNum:1}).then(resp => {
this.centerExamPaperList = resp.data.list;
}).catch(()=> {
this.$message.error('获取试卷列表失败!');
});
}
},
getLessonByClassId(classId) {
this.lessonList = [];
if (classId) {
getLessonByClassId(classId).then(resp => {
this.lessonList = resp.data;
this.lessonList.forEach(item => {
if (item.prdType === '01') {
this.localExamPaperList.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.$message.success('学生成绩导入成功!');
}).catch(error => {
that.$message.error('学生成绩导入失败!');
});
} 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>