|
|
@@ -4,23 +4,24 @@
|
|
|
<div class="card-header">
|
|
|
<span class="card-title">考试情况统计</span>
|
|
|
<div class="header-right">
|
|
|
- <el-select v-model="filterData.year" size="small" style="width:140px">
|
|
|
- <el-option label="2025-2026 学年" value="2025-2026" />
|
|
|
- <el-option label="2024-2025 学年" value="2024-2025" />
|
|
|
+ <el-select v-model="valueYear" @change="topChange()" size="small" style="width:220px">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in optionList"
|
|
|
+ :key="dict.value"
|
|
|
+ :label="dict.label"
|
|
|
+ :value="dict.value"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
<!-- 分组按钮 -->
|
|
|
<div class="table-top-button-box">
|
|
|
<div>
|
|
|
- <p
|
|
|
- v-for="(btn, i) in filterData.typeBtns"
|
|
|
- :key="btn.value"
|
|
|
- :class="filterData.activeType === btn.value ? 'check-table-button' : ''"
|
|
|
- @click="filterData.activeType = btn.value"
|
|
|
- >{{ btn.label }}</p>
|
|
|
+ <p @click="checkButton(2)" :class="checkIndex == 2?'check-table-button':''">研究生</p>
|
|
|
+ <p @click="checkButton(3)" :class="checkIndex == 3?'check-table-button':''">本科生</p>
|
|
|
+ <p @click="checkButton(1)" :class="checkIndex == 1?'check-table-button':''">教职工</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 导出按钮 -->
|
|
|
- <p class="export-btn" @click="() => {}">
|
|
|
+ <p class="export-btn" @click="exportButton()">
|
|
|
<i class="el-icon-download"></i> 导出数据
|
|
|
</p>
|
|
|
</div>
|
|
|
@@ -29,139 +30,70 @@
|
|
|
<!-- 图表区 -->
|
|
|
<div class="chart-area">
|
|
|
<!-- 堆叠柱状图 -->
|
|
|
- <div class="bar-chart-wrap">
|
|
|
- <div class="chart-legend">
|
|
|
- <span class="leg-item"><i class="dot green"></i>通过</span>
|
|
|
- <span class="leg-item"><i class="dot red"></i>未通过</span>
|
|
|
- <span class="leg-item"><i class="dot gray"></i>未考</span>
|
|
|
- </div>
|
|
|
- <div class="bar-chart">
|
|
|
- <div class="y-axis">
|
|
|
- <span v-for="y in yLabels" :key="y">{{ y }}</span>
|
|
|
- </div>
|
|
|
- <div class="bars-container">
|
|
|
- <div v-for="(g, i) in chartData.barGroups" :key="i" class="bar-group">
|
|
|
- <div class="bar-stack">
|
|
|
- <div class="seg gray" :style="{height: scaleH(g.notExam) + 'px'}">
|
|
|
- <span v-if="g.notExam > 0" class="seg-label">{{ g.notExam }}</span>
|
|
|
- </div>
|
|
|
- <div class="seg red" :style="{height: scaleH(g.fail) + 'px'}">
|
|
|
- <span v-if="g.fail > 0" class="seg-label">{{ g.fail }}</span>
|
|
|
- </div>
|
|
|
- <div class="seg green" :style="{height: scaleH(g.pass) + 'px'}">
|
|
|
- <span v-if="g.pass > 0" class="seg-label">{{ g.pass }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="bar-label">{{ g.label }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
+ <p class="bar-chart-wrap" v-if="!chartData.deptStats[0]" style="color:#999;font-size:14px;line-height:260px;text-align: center;">暂无数据</p>
|
|
|
+ <div class="bar-chart-wrap" v-if="chartData.deptStats[0]" id="bar-chart-wrap" ref="barChart"></div>
|
|
|
<!-- 环形图 -->
|
|
|
- <div class="pie-chart-wrap">
|
|
|
- <div class="donut-wrap">
|
|
|
- <svg viewBox="0 0 120 120" width="160" height="160">
|
|
|
- <!-- 通过 大部分 ~85% -->
|
|
|
- <circle cx="60" cy="60" r="45" fill="none" stroke="#67c23a"
|
|
|
- stroke-width="22"
|
|
|
- stroke-dasharray="238 282"
|
|
|
- stroke-dashoffset="0"
|
|
|
- transform="rotate(-90 60 60)" />
|
|
|
- <!-- 未通过 ~7% -->
|
|
|
- <circle cx="60" cy="60" r="45" fill="none" stroke="#f56c6c"
|
|
|
- stroke-width="22"
|
|
|
- stroke-dasharray="20 282"
|
|
|
- stroke-dashoffset="-238"
|
|
|
- transform="rotate(-90 60 60)" />
|
|
|
- <!-- 未考 ~8% -->
|
|
|
- <circle cx="60" cy="60" r="45" fill="none" stroke="#c0c4cc"
|
|
|
- stroke-width="22"
|
|
|
- stroke-dasharray="24 282"
|
|
|
- stroke-dashoffset="-258"
|
|
|
- transform="rotate(-90 60 60)" />
|
|
|
- <circle cx="60" cy="60" r="28" fill="#fff" />
|
|
|
- </svg>
|
|
|
- <!-- 标注线 -->
|
|
|
- <div class="pie-annotation pie-ann-top">未考</div>
|
|
|
- <div class="pie-annotation pie-ann-right">未通过</div>
|
|
|
- <div class="pie-annotation pie-ann-bottom">通过</div>
|
|
|
- </div>
|
|
|
- <div class="pie-legend">
|
|
|
- <div class="p-item"><i class="dot green"></i><span>通过</span></div>
|
|
|
- <div class="p-item"><i class="dot red"></i><span>未通过</span></div>
|
|
|
- <div class="p-item"><i class="dot gray"></i><span>未考</span></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <p class="pie-chart-wrap" v-if="!chartData.deptStats[0]" style="color:#999;font-size:14px;line-height:260px;text-align: center;">暂无数据</p>
|
|
|
+ <div class="pie-chart-wrap" v-if="chartData.deptStats[0]" id="pie-chart-wrap" ref="pieChart"></div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 筛选 -->
|
|
|
<div class="filter-row">
|
|
|
- <el-select v-model="filterData.college" placeholder="筛选学院" size="small" clearable style="width:130px">
|
|
|
- <el-option v-for="c in filterData.colleges" :key="c" :label="c" :value="c" />
|
|
|
- </el-select>
|
|
|
- <el-select v-model="filterData.examType" placeholder="考试类型" size="small" clearable style="width:120px">
|
|
|
- <el-option label="新生分级考试" value="新生分级考试" />
|
|
|
- <el-option label="应知应会考试" value="应知应会考试" />
|
|
|
+ <el-cascader
|
|
|
+ style="width: 180px"
|
|
|
+ clearable
|
|
|
+ v-model="queryParams.deptId"
|
|
|
+ :options="optionListA"
|
|
|
+ :props="{
|
|
|
+ emitPath:false,
|
|
|
+ checkStrictly: true,
|
|
|
+ value: 'deptId',
|
|
|
+ label: 'deptName',
|
|
|
+ children: 'child',
|
|
|
+ }"
|
|
|
+ :show-all-levels="false"
|
|
|
+ filterable
|
|
|
+ placeholder="筛选学院"
|
|
|
+ @change="queryParamsChange"
|
|
|
+ ></el-cascader>
|
|
|
+ <el-select
|
|
|
+ @change="queryParamsChange"
|
|
|
+ v-model="queryParams.examTypeId" clearable placeholder="考试类型" style="width: 160px">
|
|
|
+ <el-option
|
|
|
+ v-for="dict in optionListB"
|
|
|
+ :key="dict.id"
|
|
|
+ :label="dict.examTypeName"
|
|
|
+ :value="dict.id"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</div>
|
|
|
|
|
|
<!-- 统计表格 -->
|
|
|
- <el-table :data="tableData" border size="small" :span-method="spanMethod">
|
|
|
- <el-table-column prop="college" label="学院" min-width="130" />
|
|
|
- <el-table-column prop="examType" label="考试类型" min-width="120" />
|
|
|
- <el-table-column prop="total" label="应考人数" width="90" align="center" />
|
|
|
- <el-table-column prop="pass" label="通过人数" width="90" align="center" />
|
|
|
- <el-table-column prop="fail" label="未通过人数" width="100" align="center">
|
|
|
- <template slot-scope="scope">
|
|
|
- <span :class="scope.row.examType !== '汇总' ? 'link-blue' : ''">{{ scope.row.fail }}</span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="notExam" label="未考人数" width="90" align="center" />
|
|
|
- <el-table-column prop="rate" label="通过率" width="80" align="center" />
|
|
|
- </el-table>
|
|
|
+
|
|
|
+ <div class="page-content-box">
|
|
|
+ <el-table class="table-box" :data="dataList" border :span-method="objectSpanMethod">
|
|
|
+ <el-table-column prop="deptName" label="学院" />
|
|
|
+ <el-table-column prop="examTypeName" label="考试类型" width="200" />
|
|
|
+ <el-table-column prop="examCount" label="应考人数" width="160" align="center" />
|
|
|
+ <el-table-column prop="passedCount" label="通过人数" width="160" align="center" />
|
|
|
+ <el-table-column prop="notPassedCount" label="未通过人数" width="160" align="center"/>
|
|
|
+ <el-table-column prop="absentCount" label="未考人数" width="160" align="center" />
|
|
|
+ <el-table-column prop="passRate" label="通过率" width="160" align="center" />
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-const colleges = [
|
|
|
- { name: '化学与化工学院', d1: [45, 38, 4, 3, '84%'], d2: [75, 68, 4, 3, '91%'], sum: [120, 106, 8, 6, '88%'] },
|
|
|
- { name: '生命科学学院', d1: [35, 30, 3, 2, '86%'], d2: [60, 54, 4, 2, '90%'], sum: [95, 84, 7, 4, '88%'] },
|
|
|
- { name: '物理学院', d1: [28, 23, 3, 2, '82%'], d2: [50, 44, 3, 3, '88%'], sum: [78, 67, 6, 5, '86%'] },
|
|
|
- { name: '电气工程学院', d1: [40, 35, 3, 2, '88%'], d2: [70, 63, 4, 3, '90%'], sum: [110, 98, 7, 5, '89%'] },
|
|
|
- { name: '材料科学学院', d1: [32, 28, 2, 2, '88%'], d2: [56, 50, 3, 3, '89%'], sum: [88, 78, 5, 5, '89%'] },
|
|
|
- { name: '机械工程学院', d1: [25, 21, 2, 2, '84%'], d2: [47, 42, 3, 2, '89%'], sum: [72, 63, 5, 4, '88%'] },
|
|
|
- { name: '自动化学院', d1: [22, 20, 1, 1, '91%'], d2: [43, 39, 2, 2, '91%'], sum: [65, 59, 3, 3, '91%'] },
|
|
|
- { name: '资源环境学院', d1: [20, 17, 2, 1, '85%'], d2: [36, 32, 2, 2, '89%'], sum: [56, 49, 4, 3, '88%'] },
|
|
|
-]
|
|
|
-
|
|
|
-function buildTableData() {
|
|
|
- const rows = []
|
|
|
- colleges.forEach(c => {
|
|
|
- rows.push({ college: c.name, examType: '新生分级考试', total: c.d1[0], pass: c.d1[1], fail: c.d1[2], notExam: c.d1[3], rate: c.d1[4] })
|
|
|
- rows.push({ college: c.name, examType: '应知应会考试', total: c.d2[0], pass: c.d2[1], fail: c.d2[2], notExam: c.d2[3], rate: c.d2[4] })
|
|
|
- rows.push({ college: c.name, examType: '汇总', total: c.sum[0], pass: c.sum[1], fail: c.sum[2], notExam: c.sum[3], rate: c.sum[4] })
|
|
|
- })
|
|
|
- return rows
|
|
|
-}
|
|
|
-
|
|
|
+import echarts from 'echarts'
|
|
|
+import {
|
|
|
+ examElStatisticsGetAcademicYear,examElStatisticsExamList,examElStatisticsExamChart,
|
|
|
+ examElExamTypeList,systemDeptCurrentDept,
|
|
|
+} from "@/api/safetyEducationExaminationNew/index";
|
|
|
export default {
|
|
|
name: 'ExamSituation',
|
|
|
data() {
|
|
|
return {
|
|
|
- filterData: {
|
|
|
- year: '2025-2026',
|
|
|
- activeType: 'graduate',
|
|
|
- typeBtns: [
|
|
|
- { label: '研究生', value: 'graduate' },
|
|
|
- { label: '本科生', value: 'undergrad' },
|
|
|
- { label: '教职工', value: 'staff' },
|
|
|
- ],
|
|
|
- college: '',
|
|
|
- examType: '',
|
|
|
- colleges: colleges.map(c => c.name),
|
|
|
- },
|
|
|
- yLabels: [120, 100, 80, 60, 40, 20, 0],
|
|
|
chartData: {
|
|
|
barGroups: [
|
|
|
{ label: '化学与化工', pass: 106, fail: 8, notExam: 6 },
|
|
|
@@ -174,40 +106,277 @@ export default {
|
|
|
{ label: '资源环境', pass: 49, fail: 4, notExam: 3 },
|
|
|
]
|
|
|
},
|
|
|
- tableData: buildTableData(),
|
|
|
- spanMap: {}
|
|
|
+ chartList:[],
|
|
|
+ spanMap: {},
|
|
|
+ optionList:[],
|
|
|
+ optionListA:[],
|
|
|
+ optionListB:[],
|
|
|
+ valueYear:'',
|
|
|
+ checkIndex:2,
|
|
|
+ queryParams:{
|
|
|
+ deptId:'',
|
|
|
+ examTypeId:'',
|
|
|
+ },
|
|
|
+ dataList:[
|
|
|
+ {
|
|
|
+ deptName:'学院1',
|
|
|
+ examType:'类型1',
|
|
|
+ total:'1',
|
|
|
+ pass:'2',
|
|
|
+ fail:'3',
|
|
|
+ notExam:'4',
|
|
|
+ rate:'5',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ deptName:'学院12',
|
|
|
+ examType:'类型1',
|
|
|
+ total:'1',
|
|
|
+ pass:'2',
|
|
|
+ fail:'3',
|
|
|
+ notExam:'4',
|
|
|
+ rate:'5',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ deptName:'学院1',
|
|
|
+ examType:'类型2',
|
|
|
+ total:'1',
|
|
|
+ pass:'2',
|
|
|
+ fail:'3',
|
|
|
+ notExam:'4',
|
|
|
+ rate:'5',
|
|
|
+ },
|
|
|
+ ],
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
- this.buildSpanMap()
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.examElExamTypeList();
|
|
|
+ this.systemDeptCurrentDept();
|
|
|
+ this.examElStatisticsGetAcademicYear();
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ if (this._barChart) this._barChart.dispose()
|
|
|
+ if (this._pieChart) this._pieChart.dispose()
|
|
|
},
|
|
|
methods: {
|
|
|
- scaleH(val) {
|
|
|
- return Math.round(val / 120 * 180)
|
|
|
+ //导出
|
|
|
+ exportButton(){
|
|
|
+ let self = this;
|
|
|
+ self.$confirm(`确认导出数据?`, "提示", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(async () => {
|
|
|
+ let obj = {
|
|
|
+ academicYear:this.valueYear,
|
|
|
+ personType:this.checkIndex,
|
|
|
+ deptId:this.queryParams.deptId,
|
|
|
+ examTypeId:this.queryParams.examTypeId,
|
|
|
+ };
|
|
|
+ self.download('/exam/elStatistics/exam/export', {...obj}, '考试情况统计.xlsx')
|
|
|
+ }).catch(() => {})
|
|
|
+ },
|
|
|
+ //图表
|
|
|
+ initBarChart() {
|
|
|
+ const groups = this.chartData.deptStats
|
|
|
+ const chart = echarts.init(this.$refs.barChart)
|
|
|
+ this._barChart = chart
|
|
|
+ chart.setOption({
|
|
|
+ legend: {
|
|
|
+ data: ['通过', '未通过', '未考'],
|
|
|
+ top: 10,
|
|
|
+ itemWidth: 14,
|
|
|
+ itemHeight: 14,
|
|
|
+ textStyle: { fontSize: 12, color: '#555' },
|
|
|
+ },
|
|
|
+ grid: { top: 60, bottom: 60, left: 40, right: 10, containLabel: false },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: groups.map(g => g.deptName),
|
|
|
+ axisLine: { lineStyle: { color: '#ddd' } },
|
|
|
+ axisLabel: { fontSize: 11, color: '#666', rotate: 25 },
|
|
|
+ axisTick: { show: false },
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ splitLine: { lineStyle: { color: '#f0f0f0' } },
|
|
|
+ axisLabel: { fontSize: 11, color: '#aaa' },
|
|
|
+ axisLine: { show: false },
|
|
|
+ axisTick: { show: false },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '通过',
|
|
|
+ type: 'bar',
|
|
|
+ stack: 'total',
|
|
|
+ data: groups.map(g => g.passedCount),
|
|
|
+ itemStyle: { color: '#4fbe7e' },
|
|
|
+ label: { show: true, position: 'inside', fontSize: 11, color: '#fff',
|
|
|
+ formatter: (p) => p.value > 0 ? p.value : '' },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '未通过',
|
|
|
+ type: 'bar',
|
|
|
+ stack: 'total',
|
|
|
+ data: groups.map(g => g.notPassedCount),
|
|
|
+ itemStyle: { color: '#f56c6c' },
|
|
|
+ label: { show: true, position: 'inside', fontSize: 10, color: '#fff',
|
|
|
+ formatter: (p) => p.value > 0 ? p.value : '' },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '未考',
|
|
|
+ type: 'bar',
|
|
|
+ stack: 'total',
|
|
|
+ data: groups.map(g => g.absentCount),
|
|
|
+ itemStyle: { color: '#c0c4cc' },
|
|
|
+ label: { show: true, position: 'inside', fontSize: 10, color: '#fff',
|
|
|
+ formatter: (p) => p.value > 0 ? p.value : '' },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: { type: 'shadow' },
|
|
|
+ },
|
|
|
+ })
|
|
|
+ },
|
|
|
+ //图表
|
|
|
+ initPieChart() {
|
|
|
+ const pass = this.chartData.totalPassed
|
|
|
+ const fail = this.chartData.totalNotPassed
|
|
|
+ const notExam = this.chartData.totalAbsent
|
|
|
+ const chart = echarts.init(this.$refs.pieChart)
|
|
|
+ this._pieChart = chart
|
|
|
+ chart.setOption({
|
|
|
+ legend: {
|
|
|
+ orient: 'horizontal',
|
|
|
+ bottom: 0,
|
|
|
+ data: ['通过', '未通过', '未考'],
|
|
|
+ itemWidth: 12,
|
|
|
+ itemHeight: 12,
|
|
|
+ textStyle: { fontSize: 12, color: '#555' },
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ type: 'pie',
|
|
|
+ radius: ['45%', '68%'],
|
|
|
+ center: ['50%', '45%'],
|
|
|
+ label: {
|
|
|
+ formatter: '{b}',
|
|
|
+ fontSize: 12,
|
|
|
+ color: '#555',
|
|
|
+ },
|
|
|
+ labelLine: { length: 12, length2: 8 },
|
|
|
+ data: [
|
|
|
+ { value: pass, name: '通过', itemStyle: { color: '#4fbe7e' } },
|
|
|
+ { value: fail, name: '未通过', itemStyle: { color: '#f56c6c' } },
|
|
|
+ { value: notExam, name: '未考', itemStyle: { color: '#c0c4cc' } },
|
|
|
+ ],
|
|
|
+ emphasis: {
|
|
|
+ itemStyle: { shadowBlur: 6, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.2)' }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
|
|
|
+ })
|
|
|
+ },
|
|
|
+ //顶部学年切换
|
|
|
+ topChange(){
|
|
|
+ this.examElStatisticsExamChart();
|
|
|
+ this.examElStatisticsExamList();
|
|
|
+ },
|
|
|
+ //身份切换
|
|
|
+ checkButton(val){
|
|
|
+ if(this.checkIndex!=val){
|
|
|
+ this.$set(this,'checkIndex',val);
|
|
|
+ this.examElStatisticsExamChart();
|
|
|
+ this.examElStatisticsExamList();
|
|
|
+ }
|
|
|
},
|
|
|
- buildSpanMap() {
|
|
|
- const map = {}
|
|
|
- this.tableData.forEach((row, i) => {
|
|
|
- if (!map[row.college]) {
|
|
|
- // find count
|
|
|
- let count = 0
|
|
|
- for (let j = i; j < this.tableData.length; j++) {
|
|
|
- if (this.tableData[j].college === row.college) count++
|
|
|
- else break
|
|
|
+ //条件变更
|
|
|
+ queryParamsChange(){
|
|
|
+ this.examElStatisticsExamList();
|
|
|
+ },
|
|
|
+ //数据合并
|
|
|
+ objectSpanMethod({ row, column, rowIndex, columnIndex }) {
|
|
|
+ // 只对第一列(学院列,columnIndex === 0)进行合并
|
|
|
+ if (columnIndex === 0) {
|
|
|
+ const list = this.dataList;
|
|
|
+
|
|
|
+ // 如果是第一行,或者当前行的学院与上一行的学院不同,则开始合并计算
|
|
|
+ if (rowIndex === 0 || row.deptName !== list[rowIndex - 1].deptName) {
|
|
|
+ let rowspan = 1;
|
|
|
+ // 向下遍历,统计有多少行是相同的学院
|
|
|
+ for (let i = rowIndex + 1; i < list.length; i++) {
|
|
|
+ if (list[i].deptName === row.deptName) {
|
|
|
+ rowspan++;
|
|
|
+ } else {
|
|
|
+ break; // 遇到不同的学院,停止计算
|
|
|
+ }
|
|
|
}
|
|
|
- map[i] = count
|
|
|
+ return { rowspan, colspan: 1 };
|
|
|
} else {
|
|
|
- map[i] = 0
|
|
|
+ // 如果当前行的学院与上一行相同,则隐藏当前单元格(被合并了)
|
|
|
+ return { rowspan: 0, colspan: 0 };
|
|
|
}
|
|
|
- })
|
|
|
- this.spanMap = map
|
|
|
+ }
|
|
|
+ // 其他列正常显示
|
|
|
+ return { rowspan: 1, colspan: 1 };
|
|
|
},
|
|
|
- spanMethod({ row, column, rowIndex, columnIndex }) {
|
|
|
- if (columnIndex === 0) {
|
|
|
- const span = this.spanMap[rowIndex]
|
|
|
- if (span !== undefined) return { rowspan: span || 0, colspan: span ? 1 : 0 }
|
|
|
+ //考试统计图表
|
|
|
+ examElStatisticsExamChart(){
|
|
|
+ let obj = {
|
|
|
+ academicYear:this.valueYear,
|
|
|
+ personType:this.checkIndex,
|
|
|
}
|
|
|
- }
|
|
|
+ examElStatisticsExamChart(obj).then(response => {
|
|
|
+ this.$set(this,'chartData',response.data);
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if(response.data.deptStats[0]){
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.initBarChart()
|
|
|
+ this.initPieChart()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //考试统计列表
|
|
|
+ examElStatisticsExamList(){
|
|
|
+ let obj = {
|
|
|
+ academicYear:this.valueYear,
|
|
|
+ personType:this.checkIndex,
|
|
|
+ deptId:this.queryParams.deptId,
|
|
|
+ examTypeId:this.queryParams.examTypeId,
|
|
|
+ }
|
|
|
+ examElStatisticsExamList(obj).then(response => {
|
|
|
+ this.$set(this,'dataList',response.data);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //查询全部考试类型
|
|
|
+ examElExamTypeList(){
|
|
|
+ examElExamTypeList({}).then(response => {
|
|
|
+ this.$set(this,'optionListB',response.data);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //学院列表
|
|
|
+ systemDeptCurrentDept(){
|
|
|
+ systemDeptCurrentDept({}).then(response => {
|
|
|
+ const list = response.data || [];
|
|
|
+ this.formatTreeData(list);
|
|
|
+ this.$set(this,'optionListA',list);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //学年列表
|
|
|
+ examElStatisticsGetAcademicYear(){
|
|
|
+ examElStatisticsGetAcademicYear({}).then(response => {
|
|
|
+ this.$set(this,'optionList',response.data);
|
|
|
+ this.$set(this,'valueYear',response.data[0].value);
|
|
|
+ this.examElStatisticsExamList();
|
|
|
+ this.examElStatisticsExamChart();
|
|
|
+ });
|
|
|
+ },
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
@@ -226,7 +395,7 @@ export default {
|
|
|
align-items: center;
|
|
|
margin-bottom: 16px;
|
|
|
.card-title { font-size: 16px; font-weight: 700; color: #222; }
|
|
|
- .header-right { display: flex; align-items: center; gap: 20px; }
|
|
|
+ .header-right { width:610px;display: flex; align-items: center; gap: 20px; }
|
|
|
}
|
|
|
|
|
|
/* 分组筛选按钮 */
|
|
|
@@ -246,11 +415,11 @@ export default {
|
|
|
&:nth-child(1) { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }
|
|
|
&:nth-child(2) { border-left: none; border-right: none; }
|
|
|
&:nth-child(3) { border-top-right-radius: 4px; border-bottom-right-radius: 4px; }
|
|
|
- &.check-table-button {
|
|
|
- border: 1px solid #0183fa;
|
|
|
- background-color: #0183fa;
|
|
|
- color: #fff;
|
|
|
- }
|
|
|
+ }
|
|
|
+ .check-table-button{
|
|
|
+ border: 1px solid #0183fa!important;
|
|
|
+ background-color: #0183fa!important;;
|
|
|
+ color:#fff!important;;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -279,134 +448,13 @@ export default {
|
|
|
|
|
|
.bar-chart-wrap {
|
|
|
flex: 1;
|
|
|
- padding: 16px;
|
|
|
+ height: 280px;
|
|
|
border-right: 1px solid #eee;
|
|
|
-
|
|
|
- .chart-legend {
|
|
|
- display: flex;
|
|
|
- gap: 20px;
|
|
|
- margin-bottom: 10px;
|
|
|
- font-size: 12px;
|
|
|
- color: #555;
|
|
|
- justify-content: center;
|
|
|
- .leg-item { display: flex; align-items: center; gap: 4px; }
|
|
|
- }
|
|
|
-
|
|
|
- .bar-chart {
|
|
|
- display: flex;
|
|
|
- gap: 4px;
|
|
|
- align-items: flex-end;
|
|
|
- height: 220px;
|
|
|
-
|
|
|
- .y-axis {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: space-between;
|
|
|
- font-size: 11px;
|
|
|
- color: #aaa;
|
|
|
- height: 200px;
|
|
|
- min-width: 28px;
|
|
|
- text-align: right;
|
|
|
- }
|
|
|
-
|
|
|
- .bars-container {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- align-items: flex-end;
|
|
|
- justify-content: space-around;
|
|
|
- height: 200px;
|
|
|
- border-left: 1px solid #e8e8e8;
|
|
|
- border-bottom: 1px solid #e8e8e8;
|
|
|
- padding: 0 8px 20px;
|
|
|
- position: relative;
|
|
|
-
|
|
|
- // 横向网格线
|
|
|
- &::before {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- left: 0; right: 0; top: 0; bottom: 20px;
|
|
|
- background: repeating-linear-gradient(to bottom, #f5f5f5 0, #f5f5f5 1px, transparent 1px, transparent calc(100% / 6));
|
|
|
- pointer-events: none;
|
|
|
- }
|
|
|
-
|
|
|
- .bar-group {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- position: relative;
|
|
|
- z-index: 1;
|
|
|
-
|
|
|
- .bar-stack {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- width: 28px;
|
|
|
- gap: 0;
|
|
|
- position: relative;
|
|
|
-
|
|
|
- .seg {
|
|
|
- width: 100%;
|
|
|
- position: relative;
|
|
|
- &.green { background: #4fbe7e; }
|
|
|
- &.red { background: #f56c6c; }
|
|
|
- &.gray { background: #c0c4cc; }
|
|
|
-
|
|
|
- .seg-label {
|
|
|
- position: absolute;
|
|
|
- top: -16px;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
- font-size: 10px;
|
|
|
- color: #333;
|
|
|
- white-space: nowrap;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .bar-label {
|
|
|
- position: absolute;
|
|
|
- bottom: -18px;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
- font-size: 10px;
|
|
|
- color: #555;
|
|
|
- white-space: nowrap;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
.pie-chart-wrap {
|
|
|
- width: 300px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 20px;
|
|
|
- gap: 16px;
|
|
|
-
|
|
|
- .donut-wrap {
|
|
|
- position: relative;
|
|
|
-
|
|
|
- .pie-annotation {
|
|
|
- position: absolute;
|
|
|
- font-size: 11px;
|
|
|
- color: #555;
|
|
|
- white-space: nowrap;
|
|
|
-
|
|
|
- &.pie-ann-top { top: 10px; left: 50%; transform: translateX(-50%); }
|
|
|
- &.pie-ann-right { top: 50%; right: -8px; transform: translateY(-50%); }
|
|
|
- &.pie-ann-bottom { bottom: 10px; left: 50%; transform: translateX(-50%); color: #4fbe7e; }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .pie-legend {
|
|
|
- display: flex;
|
|
|
- gap: 16px;
|
|
|
- font-size: 12px;
|
|
|
- color: #555;
|
|
|
- .p-item { display: flex; align-items: center; gap: 5px; }
|
|
|
- }
|
|
|
+ width: 320px;
|
|
|
+ height: 280px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -415,18 +463,14 @@ export default {
|
|
|
gap: 20px;
|
|
|
margin-bottom: 12px;
|
|
|
}
|
|
|
+ .page-content-box{
|
|
|
+ height:500px;
|
|
|
+ padding:0;
|
|
|
+ ::v-deep .el-table--medium td:nth-child(1){
|
|
|
+ border-left:1px solid #dfe6ec!important;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
.link-blue { color: #409eff; }
|
|
|
-
|
|
|
- .dot {
|
|
|
- display: inline-block;
|
|
|
- width: 10px;
|
|
|
- height: 10px;
|
|
|
- border-radius: 50%;
|
|
|
- flex-shrink: 0;
|
|
|
- &.green { background: #4fbe7e; }
|
|
|
- &.red { background: #f56c6c; }
|
|
|
- &.gray { background: #c0c4cc; }
|
|
|
- }
|
|
|
}
|
|
|
</style>
|