CET-vue-3.0/src/views/cet/universityDashboard.vue

982 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 style="background: #ececec; padding: 5px 5px">
<a-card :loading="loading" :bordered="false">
<template #extra>
<div class="search-row">
<!-- <div v-if="topCollege != null" style="margin-bottom: 5px;margin-right: 10px;">
<span style="font-size: 15px">当前数据为 </span>
<span style="color: red; font-size: 20px">{{ topCollege }}</span>
<span v-if="topMajor != null && topMajor != ''" style="color: red; font-size: 18px"> / {{ topMajor
}}</span>
<span style="font-size: 15px"> 的 </span>
<span style="color: red; font-size: 18px">{{ topEntrydate }}</span>
<span style="font-size: 15px"> 级数据</span>
</div> -->
<div class="stats-container" v-if="total && total > 0">
<span>{{ totalName }}总人数:{{ total }}</span>
<span>累计通过人数: {{ passNumberBottom }}</span>
<span>累计总通过率: {{ passRateBottom }}</span>
</div>
<a-cascader v-model:value="collegeMajor" :options="collegeMajorOptions" change-on-select />
<a-select v-model:value="entrydate" style="margin-left: 10px; width: 100px" :options="entrydateOptions" />
<a-button style="margin-left: 10px" type="primary" @click="query">查询</a-button>
</div>
<!-- <a-button @click=test()>test</a-button> -->
</template>
<a-row :gutter="12">
<a-col :xl="14">
<div style="padding-left: 10px; min-height: 200px">
<a-table size="small" :dataSource="dataSourceCet4" :columns="columns" :pagination="false" bordered
:scroll="{ y: 290 }">
<template #passRateSlot>
累计总通过率
<a-tooltip :title="'累计通过人数 / ' + totalName + '总人数'" placement="top">
<a-icon type="question-circle" />
</a-tooltip>
</template>
</a-table>
</div>
</a-col>
<a-col :xl="10" >
<a-card class="card-with-piechart">
<div style="width: 100%; height: 200px" class="piechart" id="piechart"> </div>
</a-card>
</a-col>
</a-row>
<!-- <div style="height: 300px;">
<a-empty style="margin-top: 100px" />
</div> -->
</a-card>
</div>
<div class="bottom-box">
<div class="left-side">
<a-card :loading="loading" :bordered="false">
<div style="width: 100%; height: 350px" id="map2"> </div>
</a-card>
</div>
<div class="right-side">
<!-- <a-row :gutter="12"> -->
<!-- <a-col :xl="16"> -->
<a-card :loading="map1loading">
<!-- <div class="query">
<span
style="font-size: 15px; margin-right: 10px; display: flex; justify-content: center; align-items: center; font-weight: bold">年级:
</span>
<a-select v-model:value="oneentrydate" style="width: 200px" :options="entrydateOptions" />
<a-button style="margin-left: 10px" type="primary" @click="allQuery">查询</a-button>
</div> -->
<div id="map1" style="width: 100%; height: 350px"></div>
</a-card>
<!-- </a-col> -->
<!-- </a-row> -->
</div>
</div>
</template>
<script>
import { defHttp } from '/@/utils/http/axios';
import * as echarts from 'echarts';
import { message } from 'ant-design-vue';
export default {
data() {
return {
activeKey: '1',
allCollege: [],
showBox: false,
showGroup: false,
oneentrydate: null,
collegeentrydate: [],
majorentrydate: [],
lastMajorEntrydate: [],
checkedOptions: [],
collegetab2: [],
collegeMajorOptions: [],
collegeMajor: [],
loading: false,
dataSourceCet4: [],
columns: [
{
title: '学年',
dataIndex: 'grade',
key: 'grade',
align: 'center',
customCell: (_, index) => ({
rowSpan: index % 2 === 0 ? 2 : 0, //每两行合并一次grade列的单元格rowSpan为跨度
}),
},
{
title: '考试批次',
dataIndex: 'batch',
key: 'batch',
align: 'center',
},
{
title: '参加人数',
dataIndex: 'attendNumber',
key: 'attendNumber',
align: 'center',
},
{
title: '通过人数',
dataIndex: 'passNumber',
key: 'passNumber',
align: 'center',
},
{
title: '本批次通过率',
dataIndex: 'batchpassrate',
key: 'batchpassrate',
align: 'center',
},
{
slots: { title: 'passRateSlot' },
dataIndex: 'gradepassrate',
key: 'gradepassrate',
align: 'center',
customCell: (_, index) => ({
rowSpan: index % 2 === 0 ? 2 : 0,
}),
},
],
Url: {
getEntrydate: '/cet/getEntrydate',
getCollege: '/cet/getCollege',
getData: '/cet/getData',
getCollegeMajor: '/cet/getCollegeMajor',
getBatch: '/cet/getBatch',
getEntrydate: '/cet/getEntrydate',
getCollegeRate: '/cet/getRateByCollege',
getAllRate: '/cet/getAllRate',
getMajor: '/cet/getMajorByCollege',
getMajorRate: '/cet/getRateByMajor',
getRateByMajor: '/cet/getRateByMajor',
},
map1loading: false,
collegeOptions: [],
batchOptions: [],
levelOptions: [
{ value: 'cet4', label: '英语四级' },
{ value: 'cet6', label: '英语六级' },
],
visible: false,
level: null,
college: [],
batch: null,
entrydateOptions: [],
entrydate: [],
majorCheckOn: [],
//对不同的学院选择的专业进行记忆化
lastCollegeMajor: [],
majorLength: 0,
majorOptions: [],
//对学院对比学院进行记忆化上次选择结果
lastCollege: [],
//对学院对比学院进行记忆化上次选择结果
lastCollegeEntrydate: [],
total: 0,
totalName: '',
passNumberBottom: 0,
passRateBottom: 0,
passRatePie: [],
lineXData: [],
lineYData: [],
collegeOptions: [],
collegeMajorOptions: [],
entrydateOptions: [],
college: null,
entrydate: 2017, //年级选择器
//设置默认值为全校
collegeMajor: ['全校'], //学院专业选择器
topCollege: null, //顶部选择器
topMajor: null, //顶部选择器
topEntrydate: null, //顶部选择器
};
},
mounted() {
this.getEntrydateAndCollegeData();
this.getCollegeMajorData();
this.query();
// this.allQuery();
this.getCollegeOptions();
this.getEntrydate();
},
methods: {
allQuery() {
this.map1loading = true;
console.log('查询===========ddddddddddd');
let college = ['全校'];
let query = 'tab1';
if (this.oneentrydate == null) {
this.oneentrydate = '2017';
}
this.queryChart(query, college, [this.entrydate]);
this.majorPassRate();
this.gradePassRate();
},
async majorQuery() {
if (this.majorentrydate.length == 0) {
message.error('请选择年级');
return;
}
if (this.collegeMajor.length == 0 || this.collegeMajor == null) {
message.error('请选择学院');
return;
}
if (this.lastCollegeMajor.length == 0 || this.lastCollegeMajor == null) {
message.error('请选择专业');
return;
}
this.tab3loading = true;
let res = null;
try {
let params = {
college: this.lastCollegeMajor,
entrydate: this.majorentrydate,
};
res = await defHttp.post({ url: this.Url.getRateByMajor, params });
} finally {
console.log(res, 'res');
this.tab3loading = false;
this.$nextTick(() => {
this.drawChart(res.data, 'tab3');
});
}
},
//获取学院专业级联数据
async getCollegeMajorData() {
const res = await defHttp.get({ url: this.Url.getCollegeMajor });
//通过map方法将数据转换为级联选择器需要的数据格式
this.collegeMajorOptions = res.collegeMajor.map((item) => {
return {
value: item.college,
label: item.college,
children: item.major.map((major) => {
return {
value: major,
label: major,
};
}),
};
});
// this.collegeMajor = ['东语学院'];
console.log(this.collegeMajor, 'collegeMajor');
console.log(this.collegeMajorOptions, 'collegeMajorOptions1');
},
getCollegeOptions() {
defHttp.get({ url: this.Url.getCollege }).then((res) => {
this.collegeOptions = res.colleges;
// 手动添加一个全校字段
// this.collegeOptions.unshift({ value: '全校', label: '全校' });
// this.collegeOptions.forEach(option => {
// if (option.value !== '全校') {
// option.disabled = true;
//}
// });
// this.college = ['全校'];
// this.collegetab2 = ['地理科学学院', '文学院'];
console.log(this.collegeOptions, 'collegeOptions');
});
},
// 年级通过率
async gradePassRate() {
this.map2loading = true;
const getEntrydate = await defHttp.get({ url: this.Url.getEntrydate });
this.entrydateOptions = getEntrydate.entrydates;
const name = ['西语学院'];
},
// 各专业通过率
async majorPassRate() {
this.map3loading = true;
const name = '西语学院';
},
dataChart(data, tab) {
let seriesData = [];
let xData = [];
let colors = [
'#5370c5',
'#ffffff',
'#fac858',
'#ee6666',
'#73c0de',
'#FF6A6A',
'#FFA500',
'#EE2C2C',
'#90EE90',
'#008B8B',
'#FFC0CB',
'#FFDAB9',
'#FFDEAD',
'#FFE4B5',
'#FFE4C4',
'#FFE4E1',
'#FFEBCD',
'#FFEFD5',
'#FFFAF0',
'#FFFAFA',
'#FFFFE0',
'#FFFFF0',
'#FFFFFF',
'#F0F8FF',
'#FAEBD7',
'#FAF0E6',
'#FAFAD2',
'#F5FFFA',
'#F8F8FF',
'#F0FFF0',
'#F0FFFF',
'#F0E68C',
'#F0F8FF',
'#F0FFF0',
'#F0FFFF',
'#F4A460',
'#F5DEB3',
'#F5F5DC',
'#F5F5F5',
'#F5FFFA',
'#F8F8FF',
'#F9EBEA',
'#FAD7A0',
'#FAF0E6',
'#FAFAD2',
'#FAF0E6 ',
];
let j = 0;
for (let i in data) {
xData = [];
let yData = [];
for (let key in data[i]) {
xData.push(data[i][key].college);
// 将数据转换为百分比(加上%
yData.push(data[i][key].passRate);
}
xData = xData.map((label) => label.split('').join('\n')); //将x轴竖着展示
seriesData.push({
name: i + '级累计总通过率',
type: 'bar',
//设置柱状图大小
barWidth: 1,
data: yData,
//柱子间距
barGap: '20%',
//颜色
itemStyle: {
normal: {
label: {
show: true, //开启显示
position: 'top', //在上方显示
formatter: '{c}%',
textStyle: {
//数值样式
color: 'black',
fontSize: 13,
},
},
color: colors[j++],
},
},
});
if (j == colors.length) {
j = 0;
}
let rankData = yData
.slice()
.sort((a, b) => b - a)
.map((value) => yData.indexOf(value) + 1);
//如果选择全校,增加排名
seriesData.push({
name: i + '级累计总通过率排名',
type: 'line',
yAxisIndex: 1,
data: rankData,
bar: {},
show: false,
itemStyle: {
normal: {
label: {
show: false, //开启显示
position: 'top', //在上方显示
formatter: '{c}',
textStyle: {
//数值样式
color: 'black',
fontSize: 8,
},
},
color: colors[j++],
},
},
});
if (j == colors.length) {
j = 0;
}
}
console.log('实例化图表');
let myChart = null;
myChart = echarts.init(document.getElementById('map1'));
// 指定图表的配置项和数据
// const college1 = this.college;
let option = {
title: {
text: '本年级各学院四级通过率排名',
textStyle: {
fontSize: 16,
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
formatter: function (params) {
//生成tooltip,加上小圆球
let result = params[0].name + '<br>';
for (let i = 0; i < params.length; i++) {
result += params[i].marker + params[i].seriesName + ' : ' + params[i].value + '%' + '<br>';
}
if (tab == 'tab1') {
result =
params[0].name +
'<br/>' +
'<table>' +
'<tr><td>' +
params[0].marker +
params[0].seriesName +
'</td><td style="font-weight: bold;">' +
'&nbsp;&nbsp;&nbsp;&nbsp;' +
params[0].value +
'%' +
'</td></tr>' +
'<tr><td>' +
params[1].marker +
params[1].seriesName +
'</td><td style="font-weight: bold;">' +
'&nbsp;&nbsp;&nbsp;&nbsp;' +
params[1].value +
'</td></tr>' +
'</table>';
}
return result;
},
},
toolbox: {
// show: true,
// feature: {
// magicType: { show: true, type: ['line', 'bar'] },
// restore: { show: true },
// saveAsImage: { show: true },
// },
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: [
{
type: 'category',
data: xData,
axisLabel: {
interval: 0, //代表显示所有x轴标签显示
rotate: 0, //代表倾斜0度显示
},
},
],
yAxis: [
{
type: 'value',
name: '通过率',
axisLabel: {
formatter: '{value} %',
},
},
{
type: 'value',
name: '排名',
show: false,
},
],
series: seriesData,
};
option.series = [
{
name: '累计总通过率',
type: 'bar',
data: seriesData[0].data,
//设置柱状图大小
barWidth: 16,
// barWidth: '60%',
itemStyle: {
normal: {
label: {
show: true, //开启显示
position: 'top', //在上方显示
formatter: '{c}%',
textStyle: {
//数值样式
color: 'black',
fontSize: 10,
},
},
color: colors[0],
},
},
},
{
name: '排名',
type: 'bar',
data: seriesData[1].data,
label: {
show: false,
position: 'inside',
formatter: '{c}',
},
yAxisIndex: 1,
color: colors[1],
},
];
myChart.setOption(option, true);
// 使用刚指定的配置项和数据显示图表。
myChart.on('click', async (params) => {
console.log(
this.collegeOptions.map((item) => item.value),
'collegeOptions'
);
console.log(this.collegeOptions.map((item) => item.value).includes(name), 'bool');
});
},
// 获取批次数据
async getBatch() {
const getBatch = await defHttp.get({ url: this.Url.getBatch });
this.batchOptions = getBatch.batches;
this.batch = this.batchOptions[0].value;
this.level = this.levelOptions[0].value;
},
//获取年级数据
async getEntrydate() {
const getEntrydate = await defHttp.get({ url: this.Url.getEntrydate });
this.entrydateOptions = getEntrydate.entrydates;
this.oneentrydate = this.entrydateOptions[0].value;
// this.collegeentrydate = [this.entrydateOptions[0].value];
// this.majorentrydate = [this.entrydateOptions[0].value];
// this.entrydate.push (this.entrydateOptions[0].value);
},
// 查询数据
async queryChart(query, college, entrydate) {
console.log('dddddddddddddddddddddddd');
this.visible = false;
let result = null;
// console.log(this.college, this.entrydate);
// //如果this.college和this.batch为null则先赋静态值
// if (this.college === null || this.college.length === 0) {
// this.college = ['全校'];
// }
// if (!this.entrydate || this.entrydate.length === 0) {
// this.entrydate = ['2017'];
// }
try {
// console.log(this.college, this.entrydate)
let params = {
college: college,
entrydate: [String(entrydate[0])],
level: 'cet4',
};
let url = query == 'tab1' ? this.Url.getAllRate : this.Url.getCollegeRate;
console.log(params.college, 'college');
result = await defHttp.post({ url: url, params });
//使数据按照passRate从大到小排序
// result.data.sort((a, b) => {
// return b.passRate - a.passRate;
// });
console.log('data', result.data);
} finally {
this.map1loading=false;
this.$nextTick(() => {
console.log('调用==============');
this.dataChart(result.data, query);
});
}
},
// 获取年级和学院数据
async getEntrydateAndCollegeData() {
const getEntrydate = await defHttp.get({ url: this.Url.getEntrydate });
const getCollege = await defHttp.get({ url: this.Url.getCollege });
this.collegeOptions = getCollege.colleges;
// 手动添加一个全校字段
this.collegeOptions.unshift({ value: '全校', label: '全校' });
this.college = this.collegeOptions[0].value;
this.entrydateOptions = getEntrydate.entrydates;
// this.entrydate = this.entrydateOptions[0].value;
},
//获取学院专业级联数据
async getCollegeMajorData() {
const res = await defHttp.get({ url: this.Url.getCollegeMajor });
//通过map方法将数据转换为级联选择器需要的数据格式
this.collegeMajorOptions = res.collegeMajor.map((item) => {
return {
value: item.college,
label: item.college,
children: item.major.map((major) => {
return {
value: major,
label: major,
};
}),
};
});
//手动添加一个专升本字段
this.collegeMajorOptions.unshift({ value: '专升本', label: '专升本' });
// 手动添加一个全校字段
this.collegeMajorOptions.unshift({ value: '全校', label: '全校' });
// this.collegeMajor = ['全校'];
console.log(this.collegeMajorOptions);
},
// 查询数据
async query() {
try {
this.allQuery();
//如果this.collegeMajor[1]不存在则设为null
let major = this.collegeMajor.length > 1 ? this.collegeMajor[1] : '';
this.topCollege = this.collegeMajor[0];
this.topMajor = major;
this.topEntrydate = this.entrydate;
if (this.college) this.loading = true;
let params = {
college: this.collegeMajor[0],
major: major,
entrydate: this.entrydate,
};
console.log('params', params);
const result = await defHttp.get({ url: this.Url.getData, params });
let tableData = [];
let piedata = [];
let passrate = 0;
let index = 0;
const passRate = {};
if (result.cet4['大一学年'] != undefined) {
passRate['大一学年'] = result.cet4['大一学年'];
}
if (result.cet4['大二学年'] != undefined) {
passRate['大二学年'] = result.cet4['大二学年'];
}
if (result.cet4['大三学年'] != undefined) {
passRate['大三学年'] = result.cet4['大三学年'];
}
if (result.cet4['大四学年'] != undefined) {
passRate['大四学年'] = result.cet4['大四学年'];
}
result.cet4 = passRate;
this.lineXData = [];
this.lineYData = [];
for (let grade in result.cet4) {
result.cet4[grade].forEach((item) => {
this.lineXData.push(item.batch);
this.lineYData.push((item.batchpassrate * 100).toFixed(1));
if (index % 2 == 0) {
piedata.push({ value: parseFloat(item.gradepassrate - passrate).toFixed(3), name: grade + '时通过' });
passrate = parseFloat(item.gradepassrate).toFixed(3);
}
index++;
tableData.push({
grade: grade,
attendNumber: item.attendNumber,
batch: item.batch,
gradepassrate: (item.gradepassrate * 100).toFixed(1) + '%',
passNumber: item.passNumber,
batchpassrate: (item.batchpassrate * 100).toFixed(1) + '%',
});
});
}
console.log('tableData', tableData);
this.dataSourceCet4 = tableData; //表格数据
this.total = result.total; //总人数
this.totalName = result.totalName; //总人数名称
this.passNumberBottom = result.passNumber; //通过人数
this.passRateBottom = (result.passRate * 100).toFixed(1) + '%'; //通过率
//内置饼图
this.passRatePie = []; //清空数据
this.passRatePie.push({ value: result.passRate, name: '已通过' });
this.passRatePie.push({ value: 1 - result.passRate, name: '未通过' });
piedata.push({ value: (1 - passrate).toFixed(3), name: '未通过' }); //外置饼图
setTimeout(() => {
this.drawPieChart(piedata);
this.map2Chart();
}, 100);
// this.drawPieChart();
} finally {
this.loading = false;
}
},
test() {
defHttp.get({ url: '/cet/getTest' });
},
map2Chart() {
var myChart = echarts.init(document.getElementById('map2'));
var option = {
title: {
text: '各批次通过率分析',
left: 'left',
top: '0%',
textStyle: {
fontSize: 16,
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
formatter: function (params) {
return (
params[0].name +
'<br/>' +
'<table>' +
'<tr><td>' +
params[0].marker +
'</td><td style="font-weight: bold;">' +
'&nbsp;&nbsp;&nbsp;&nbsp;' +
params[0].value +
'%' +
'</td></tr>' +
'<tr>' +
'</table>'
);
},
},
grid: {
// top: '50px',
top: '15%',
left: '50px',
right: '50px',
// bottom: '30px',
bottom: '30%',
},
xAxis: {
type: 'category',
data: this.lineXData,
},
yAxis: {
type: 'value',
},
series: [
{
data: this.lineYData,
type: 'line',
itemStyle: {
normal: {
label: {
show: true, //开启显示
position: 'top', //在上方显示
textStyle: {
//数值样式
color: 'black',
fontSize: 12,
},
formatter: '{c}%',
},
},
},
},
],
};
option && myChart.setOption(option);
},
drawPieChart(piedata) {
console.log(this.passRatePie);
console.log('piedata', piedata);
let myChart = echarts.init(document.getElementById('piechart'));
let option = {
tooltip: {
trigger: 'item',
confine: false,
avoidLabelOverlap: true,
//字体大小
itemStyle: {
fontSize: 100,
},
},
title: {
text: '四级通过率分析',
left: 'left',
top: '0%',
textStyle: {
fontSize: 15,
},
},
legend: {
top: 'center',
right: '0%',
orient: 'vertical',
},
color: ['#b3cde0', '#6497b1', '#005b96', '#03396c', '#e5e5e5'],
series: [
//外圈饼图
{
name: '四级通过率',
type: 'pie',
center: ['30%', '60%'],
radius: ['30%', '70%'],
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2,
},
label: {
show: true,
fontSize: 13,
overflow: 'truncate',
minMargin: -1,
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
label: {
show: true,
fontSize: 13,
fontWeight: 'bold',
},
},
data: piedata,
},
],
};
myChart.setOption(option);
},
},
};
</script>
<style lang="less" scoped>
* {
font-size: 12px;
}
::v-deep .ant-card-body {
padding: 4px;
}
::v-deep {
.ant-table-cell {
font-size: 12px;
}
}
.card-with-piechart {
margin-top: 1px;
margin-bottom: 20px;
padding-top: 10px;
height:100%; /* 调整高度 */
}
.container {
display: flex;
background-color: #fff;
// padding: 15px;
padding: 5px 15px;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
}
.title {
font-size: 34px;
color: rgb(8, 8, 8);
font-weight: bold;
}
.stats-container {
margin-right:270px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 90px;
// margin-top: 10px;
// padding: 10px;
// background-color: #f8f8f8f8;
// /* 背景颜色 */
// border-radius: 12px;
// /* 圆角边框 */
}
.stats-container span {
padding: 15px 30px;
/* 调整内边距 */
font-size: 15px;
color: #292929;
/* 文本颜色 */
white-space: nowrap;
/* 防止文本换行 */
flex: 1;
/* 每个项目占据相同的空间 */
text-align: center;
/* 文本居中 */
margin: 0 10px;
/* 调整外边距 */
}
.bottom-box {
display: flex;
column-gap: 10px;
padding: 0 5px;
.left-side {
// margin-top: 41px;
width: 40%;
}
.right-side {
position: relative;
flex: 1;
}
}
.search-row {
display: flex;
align-items: center;
}
.query {
right: 3%;
top: 10px;
position: absolute;
padding-left: 20px;
margin-bottom: 10px;
display: flex;
align-items: center;
z-index:9999;
}
</style>