ExamSituation.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. <!-- 考试情况统计 -->
  2. <template>
  3. <div class="exam-situation-card">
  4. <div class="card-header">
  5. <span class="card-title">考试情况统计</span>
  6. <div class="header-right">
  7. <el-select v-model="valueYear" @change="topChange()" size="small" style="width:220px">
  8. <el-option
  9. v-for="dict in optionList"
  10. :key="dict.value"
  11. :label="dict.label"
  12. :value="dict.value"
  13. />
  14. </el-select>
  15. <!-- 分组按钮 -->
  16. <div class="table-top-button-box">
  17. <div>
  18. <p @click="checkButton(2)" :class="checkIndex == 2?'check-table-button':''">研究生</p>
  19. <p @click="checkButton(3)" :class="checkIndex == 3?'check-table-button':''">本科生</p>
  20. <p @click="checkButton(1)" :class="checkIndex == 1?'check-table-button':''">教职工</p>
  21. </div>
  22. </div>
  23. <!-- 导出按钮 -->
  24. <p class="export-btn" @click="exportButton()">
  25. <i class="el-icon-download"></i> 导出数据
  26. </p>
  27. </div>
  28. </div>
  29. <!-- 图表区 -->
  30. <div class="chart-area">
  31. <!-- 堆叠柱状图 -->
  32. <p class="bar-chart-wrap" v-if="!chartData.deptStats[0]" style="color:#999;font-size:14px;line-height:260px;text-align: center;">暂无数据</p>
  33. <div class="bar-chart-wrap" v-if="chartData.deptStats[0]" id="bar-chart-wrap" ref="barChart"></div>
  34. <!-- 环形图 -->
  35. <p class="pie-chart-wrap" v-if="!chartData.deptStats[0]" style="color:#999;font-size:14px;line-height:260px;text-align: center;">暂无数据</p>
  36. <div class="pie-chart-wrap" v-if="chartData.deptStats[0]" id="pie-chart-wrap" ref="pieChart"></div>
  37. </div>
  38. <!-- 筛选 -->
  39. <div class="filter-row">
  40. <!--<el-cascader-->
  41. <!--v-if="adminType == 1"-->
  42. <!--style="width: 180px"-->
  43. <!--clearable-->
  44. <!--v-model="queryParams.deptId"-->
  45. <!--:options="optionListA"-->
  46. <!--:props="{-->
  47. <!--emitPath:false,-->
  48. <!--checkStrictly: true,-->
  49. <!--value: 'deptId',-->
  50. <!--label: 'deptName',-->
  51. <!--children: 'child',-->
  52. <!--}"-->
  53. <!--:show-all-levels="false"-->
  54. <!--filterable-->
  55. <!--placeholder="筛选学院"-->
  56. <!--@change="queryParamsChange"-->
  57. <!--&gt;</el-cascader>-->
  58. <el-select v-if="adminType == 1"
  59. @change="queryParamsChange"
  60. clearable v-model="queryParams.deptId" placeholder="学院" style="width: 180px">
  61. <el-option
  62. v-for="dict in optionListA"
  63. :key="dict.deptId"
  64. :label="dict.deptName"
  65. :value="dict.deptId"
  66. />
  67. </el-select>
  68. <el-select
  69. @change="queryParamsChange"
  70. v-model="queryParams.examTypeId" clearable placeholder="考试类型" style="width: 160px">
  71. <el-option
  72. v-for="dict in optionListB"
  73. :key="dict.id"
  74. :label="dict.examTypeName"
  75. :value="dict.id"
  76. />
  77. </el-select>
  78. </div>
  79. <!-- 统计表格 -->
  80. <div class="page-content-box">
  81. <el-table class="table-box" :data="dataList" border :span-method="objectSpanMethod">
  82. <el-table-column prop="deptName" label="学院">
  83. <template slot-scope="scope">
  84. <span :style="scope.row.type == 3?'color:#184c93;font-weight:700;':''">{{scope.row.deptName}}</span>
  85. </template>
  86. </el-table-column>
  87. <el-table-column prop="examTypeName" label="考试类型" width="200">
  88. <template slot-scope="scope">
  89. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.examTypeName}}</span>
  90. </template>
  91. </el-table-column>
  92. <el-table-column prop="expectedCount" label="应考人数" width="160" align="center">
  93. <template slot-scope="scope">
  94. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.expectedCount}}</span>
  95. </template>
  96. </el-table-column>
  97. <el-table-column prop="examCount" label="实考人数" width="160" align="center">
  98. <template slot-scope="scope">
  99. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.examCount}}</span>
  100. </template>
  101. </el-table-column>
  102. <el-table-column prop="passedCount" label="通过人数" width="160" align="center">
  103. <template slot-scope="scope">
  104. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.passedCount}}</span>
  105. </template>
  106. </el-table-column>
  107. <el-table-column prop="notPassedCount" label="未通过人数" width="160" align="center">
  108. <template slot-scope="scope">
  109. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.notPassedCount}}</span>
  110. </template>
  111. </el-table-column>
  112. <el-table-column prop="absentCount" label="未考人数" width="160" align="center">
  113. <template slot-scope="scope">
  114. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.absentCount}}</span>
  115. </template>
  116. </el-table-column>
  117. <el-table-column prop="passRate" label="通过率" width="160" align="center">
  118. <template slot-scope="scope">
  119. <span :style="scope.row.type == 2?'color:#184c93;font-weight:700;':''">{{scope.row.passRate}}</span>
  120. </template>
  121. </el-table-column>
  122. <el-table-column label="操作" width="200" show-overflow-tooltip>
  123. <template slot-scope="scope">
  124. <div class="table-button-box">
  125. <p class="table-button-null"></p>
  126. <p class="table-button-p"
  127. v-if="scope.row.type != 2"
  128. @click="tableButton(1,scope.row)"
  129. >人员明细</p>
  130. <p class="table-button-null"></p>
  131. </div>
  132. </template>
  133. </el-table-column>
  134. </el-table>
  135. <pagination :page-sizes="[20, 30, 40, 50]"
  136. v-show="total>0"
  137. :total="total"
  138. :page.sync="queryParams.page"
  139. :limit.sync="queryParams.pageSize"
  140. @pagination="examElStatisticsExamGroupedList"
  141. />
  142. </div>
  143. <el-drawer
  144. size="100%"
  145. custom-class="examSituation-index-drawer"
  146. :append-to-body="true"
  147. :title="drawerTitle"
  148. ref="drawer"
  149. :visible.sync="drawer"
  150. @close="drawerReturnButton"
  151. direction="rtl">
  152. <userListPage :drawerPropsData="drawerPropsData" v-if="drawerType == 1"></userListPage>
  153. </el-drawer>
  154. </div>
  155. </template>
  156. <script>
  157. import echarts from 'echarts'
  158. import {
  159. systemUserGetPost,
  160. } from "@/api/basicsModules/index";
  161. import {
  162. examElStatisticsGetAcademicYear,examElStatisticsExamGroupedList,examElStatisticsExamGroupedChart,
  163. examElExamTypeList,systemDeptCurrentDept,
  164. } from "@/api/safetyEducationExaminationNew/index";
  165. import userListPage from "./userListPage.vue";
  166. export default {
  167. name: 'ExamSituation',
  168. components: {
  169. userListPage,
  170. },
  171. data() {
  172. return {
  173. adminType:0,
  174. chartData: {
  175. deptStats:[],
  176. barGroups: []
  177. },
  178. chartList:[],
  179. spanMap: {},
  180. optionList:[],
  181. optionListA:[],
  182. optionListB:[],
  183. valueYear:'',
  184. checkIndex:2,
  185. queryParams:{
  186. page:1,
  187. pageSize:20,
  188. deptId:'',
  189. examTypeId:'',
  190. },
  191. dataList:[],
  192. total:0,
  193. //弹窗相关
  194. drawerTitle: '',
  195. drawerType: '',
  196. drawer: false,
  197. drawerPropsData:{},
  198. }
  199. },
  200. created() {
  201. },
  202. mounted() {
  203. this.systemUserGetPost();
  204. },
  205. beforeDestroy() {
  206. if (this._barChart) this._barChart.dispose()
  207. if (this._pieChart) this._pieChart.dispose()
  208. },
  209. methods: {
  210. //操作按钮
  211. tableButton(type,row){
  212. if(type == 1){
  213. this.$set(this, 'drawerTitle', row.examTypeName+'人员明细')
  214. let obj = {
  215. adminType:this.adminType,
  216. valueYear:this.valueYear,
  217. personType:this.checkIndex,
  218. deptId:row.deptId,
  219. examTypeId:row.examTypeId,
  220. }
  221. this.$set(this, 'drawerPropsData', obj)
  222. this.$set(this, 'drawerType', 1)
  223. this.$set(this, 'drawer', true)
  224. }
  225. },
  226. //弹窗返回
  227. drawerReturnButton(){
  228. this.$set(this, 'drawerType', 0)
  229. },
  230. //查询当前登录用户身份-校级/院级
  231. systemUserGetPost(){
  232. systemUserGetPost({}).then(response => {
  233. for(let i=0;i<response.data.length;i++){
  234. if(response.data[i].postCode == 'school_level_admin'){
  235. if(response.data[i].isPost){
  236. this.$set(this,'adminType','1');
  237. }
  238. }else if(response.data[i].postCode == 'college_admin'){
  239. if(response.data[i].isPost){
  240. this.$set(this,'adminType','2');
  241. }
  242. }
  243. }
  244. this.examElExamTypeList();
  245. this.systemDeptCurrentDept();
  246. this.examElStatisticsGetAcademicYear();
  247. });
  248. },
  249. //导出
  250. exportButton(){
  251. let self = this;
  252. self.$confirm(`确认导出数据?`, "提示", {
  253. confirmButtonText: "确定",
  254. cancelButtonText: "取消",
  255. type: "warning"
  256. }).then(async () => {
  257. let obj = {
  258. academicYear:this.valueYear,
  259. personType:this.checkIndex,
  260. examTypeId:this.queryParams.examTypeId,
  261. };
  262. if(this.adminType == 1){
  263. obj.deptId = this.queryParams.deptId;
  264. }else{
  265. obj.deptId = localStorage.getItem('deptId');
  266. }
  267. self.download('/exam/elStatistics/exam/grouped/list-export', {...obj}, '考试情况统计.xlsx')
  268. }).catch(() => {})
  269. },
  270. //图表
  271. initBarChart() {
  272. const groups = this.chartData.deptStats
  273. const chart = echarts.init(this.$refs.barChart)
  274. this._barChart = chart
  275. const PAGE_SIZE = 6 // 每屏最多 6 个学院
  276. // ① 展平数据,并在每个学院的分组之间插入一个空槽位(形成组间距)
  277. const categories = []
  278. groups.forEach((g, gi) => {
  279. (g.examTypeGroup || []).forEach(t => {
  280. categories.push({
  281. deptName: g.deptName,
  282. examTypeName: t.examTypeName,
  283. passedCount: t.passedCount,
  284. notPassedCount: t.notPassedCount,
  285. absentCount: t.absentCount,
  286. isGap: false,
  287. })
  288. })
  289. // 最后一个学院后面不再插空槽
  290. if (gi < groups.length - 1) {
  291. categories.push({ isGap: true })
  292. }
  293. })
  294. // 每个学院下的考试类型数量(不写死 3)
  295. const examTypeCount = groups.length
  296. ? Math.max(...groups.map(g => (g.examTypeGroup || []).length))
  297. : 1
  298. // ② 每屏窗口:6 个学院 × (考试类型数 + 1 个空槽) - 尾部空槽
  299. const pageSpan = Math.min(PAGE_SIZE * (examTypeCount + 1) - 2, categories.length - 1)
  300. // ③ 第二根轴:学院名放在每组中间位置
  301. const middle = Math.floor(examTypeCount / 2)
  302. const groupAxisData = categories.map((c, i) => {
  303. if (c.isGap) return ''
  304. const posInGroup = i % (examTypeCount + 1)
  305. return posInGroup === middle ? c.deptName : ''
  306. })
  307. chart.setOption({
  308. legend: {
  309. data: ['通过', '未通过', '未考'],
  310. top: 10,
  311. itemWidth: 14,
  312. itemHeight: 14,
  313. textStyle: { fontSize: 12, color: '#555' },
  314. },
  315. grid: { top: 60, bottom: 90, left: 40, right: 10, containLabel: false },
  316. xAxis: [
  317. {
  318. // 柱子定位用,不显示标签
  319. type: 'category',
  320. data: categories.map(c => c.examTypeName || ''),
  321. axisLine: { show: false },
  322. axisLabel: { show: false },
  323. axisTick: { show: false },
  324. },
  325. {
  326. // 只显示学院名
  327. type: 'category',
  328. data: groupAxisData,
  329. position: 'bottom',
  330. offset: 8,
  331. axisLine: { lineStyle: { color: '#ddd' } },
  332. axisTick: { show: false },
  333. axisLabel: {
  334. fontSize: 11,
  335. color: '#666',
  336. interval: 0,
  337. rotate: 25,
  338. fontWeight: 600,
  339. },
  340. },
  341. ],
  342. yAxis: {
  343. type: 'value',
  344. max: (value) => {
  345. // value.max 是三个 series 中的最大值,向上取整到 50 的倍数
  346. return Math.ceil(value.max / 50) * 50
  347. },
  348. interval: 50,
  349. splitLine: { lineStyle: { color: '#f0f0f0' } },
  350. axisLabel: { fontSize: 11, color: '#aaa' },
  351. axisLine: { show: false },
  352. axisTick: { show: false },
  353. },
  354. dataZoom: [
  355. {
  356. type: 'slider',
  357. xAxisIndex: [0, 1],
  358. startValue: 0,
  359. endValue: pageSpan,
  360. height: 18,
  361. bottom: 8,
  362. borderColor: '#e0e0e0',
  363. fillerColor: 'rgba(79, 190, 126, 0.15)',
  364. handleStyle: { color: '#4fbe7e' },
  365. moveHandleStyle: { color: '#4fbe7e' },
  366. textStyle: { color: '#aaa', fontSize: 10 },
  367. brushSelect: false,
  368. },
  369. {
  370. type: 'inside',
  371. xAxisIndex: [0, 1],
  372. startValue: 0,
  373. endValue: pageSpan,
  374. zoomLock: true,
  375. },
  376. ],
  377. series: [
  378. {
  379. name: '通过',
  380. type: 'bar',
  381. stack: 'total',
  382. xAxisIndex: 0,
  383. barMaxWidth: 40,
  384. data: categories.map(c => (c.isGap ? null : c.passedCount)),
  385. itemStyle: { color: '#4fbe7e' },
  386. label: { show: true, position: 'inside', fontSize: 12, color: '#fff',
  387. formatter: (p) => p.value > 0 ? p.value : '' },
  388. },
  389. {
  390. name: '未通过',
  391. type: 'bar',
  392. stack: 'total',
  393. xAxisIndex: 0,
  394. barMaxWidth: 40,
  395. data: categories.map(c => (c.isGap ? null : c.notPassedCount)),
  396. itemStyle: { color: '#f56c6c' },
  397. label: { show: true, position: 'inside', fontSize: 12, color: '#fff',
  398. formatter: (p) => p.value > 0 ? p.value : '' },
  399. },
  400. {
  401. name: '未考',
  402. type: 'bar',
  403. stack: 'total',
  404. xAxisIndex: 0,
  405. barMaxWidth: 40,
  406. data: categories.map(c => (c.isGap ? null : c.absentCount)),
  407. itemStyle: { color: '#c0c4cc' },
  408. label: { show: true, position: 'inside', fontSize: 12, color: '#fff',
  409. formatter: (p) => p.value > 0 ? p.value : '' },
  410. },
  411. ],
  412. tooltip: {
  413. trigger: 'axis',
  414. axisPointer: { type: 'shadow' },
  415. formatter: (params) => {
  416. if (!params || !params.length) return ''
  417. const c = categories[params[0].dataIndex]
  418. if (!c || c.isGap) return '' // 空槽位不弹提示
  419. // let html = `<div style="font-weight:600;margin-bottom:4px">${c.deptName} · ${c.examTypeName}</div>`
  420. let html = `<div style="font-weight:600;margin-bottom:4px">${c.examTypeName}</div>`
  421. params.forEach(p => {
  422. html += `<div>${p.marker}${p.seriesName}:<b>${p.value}</b></div>`
  423. })
  424. return html
  425. },
  426. },
  427. })
  428. },
  429. //图表
  430. initPieChart() {
  431. const pass = this.chartData.totalPassed
  432. const fail = this.chartData.totalNotPassed
  433. const notExam = this.chartData.totalAbsent
  434. const chart = echarts.init(this.$refs.pieChart)
  435. this._pieChart = chart
  436. chart.setOption({
  437. legend: {
  438. orient: 'horizontal',
  439. bottom: 0,
  440. data: ['通过', '未通过', '未考'],
  441. itemWidth: 12,
  442. itemHeight: 12,
  443. textStyle: { fontSize: 12, color: '#555' },
  444. },
  445. series: [
  446. {
  447. type: 'pie',
  448. radius: ['45%', '68%'],
  449. center: ['50%', '45%'],
  450. label: {
  451. formatter: '{b}',
  452. fontSize: 12,
  453. color: '#555',
  454. },
  455. labelLine: { length: 12, length2: 8 },
  456. data: [
  457. { value: pass, name: '通过', itemStyle: { color: '#4fbe7e' } },
  458. { value: fail, name: '未通过', itemStyle: { color: '#f56c6c' } },
  459. { value: notExam, name: '未考', itemStyle: { color: '#c0c4cc' } },
  460. ],
  461. emphasis: {
  462. itemStyle: { shadowBlur: 6, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.2)' }
  463. },
  464. },
  465. ],
  466. tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
  467. })
  468. },
  469. //顶部学年切换
  470. topChange(){
  471. this.$set(this.queryParams,'page',1);
  472. this.examElStatisticsExamGroupedChart();
  473. this.examElStatisticsExamGroupedList();
  474. },
  475. //身份切换
  476. checkButton(val){
  477. if(this.checkIndex!=val){
  478. this.$set(this,'checkIndex',val);
  479. this.$set(this.queryParams,'page',1);
  480. this.examElStatisticsExamGroupedChart();
  481. this.examElStatisticsExamGroupedList();
  482. }
  483. },
  484. //条件变更
  485. queryParamsChange(){
  486. this.$set(this.queryParams,'page',1);
  487. this.examElStatisticsExamGroupedChart();
  488. this.examElStatisticsExamGroupedList();
  489. },
  490. //数据合并
  491. objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  492. // 只对第一列(学院列,columnIndex === 0)进行合并
  493. if (columnIndex === 0) {
  494. const list = this.dataList;
  495. // 如果是第一行,或者当前行的学院与上一行的学院不同,则开始合并计算
  496. if (rowIndex === 0 || row.deptName !== list[rowIndex - 1].deptName) {
  497. let rowspan = 1;
  498. // 向下遍历,统计有多少行是相同的学院
  499. for (let i = rowIndex + 1; i < list.length; i++) {
  500. if (list[i].deptName === row.deptName) {
  501. rowspan++;
  502. } else {
  503. break; // 遇到不同的学院,停止计算
  504. }
  505. }
  506. return { rowspan, colspan: 1 };
  507. } else {
  508. // 如果当前行的学院与上一行相同,则隐藏当前单元格(被合并了)
  509. return { rowspan: 0, colspan: 0 };
  510. }
  511. }
  512. // 其他列正常显示
  513. return { rowspan: 1, colspan: 1 };
  514. },
  515. //考试统计图表
  516. examElStatisticsExamGroupedChart(){
  517. let obj = {
  518. academicYear:this.valueYear,
  519. personType:this.checkIndex,
  520. }
  521. if(this.adminType == 1){
  522. obj.deptId = this.queryParams.deptId;
  523. }else if(this.adminType == 2){
  524. obj.deptId = localStorage.getItem('deptId');
  525. }
  526. examElStatisticsExamGroupedChart(obj).then(response => {
  527. this.$set(this,'chartData',response.data);
  528. this.$nextTick(() => {
  529. if(response.data.deptStats[0]){
  530. this.$nextTick(() => {
  531. this.initBarChart()
  532. this.initPieChart()
  533. })
  534. }
  535. })
  536. });
  537. },
  538. //考试统计列表
  539. examElStatisticsExamGroupedList(){
  540. let obj = {
  541. page:this.queryParams.page,
  542. pageSize:this.queryParams.pageSize,
  543. academicYear:this.valueYear,
  544. personType:this.checkIndex,
  545. examTypeId:this.queryParams.examTypeId,
  546. }
  547. if(this.adminType == 1){
  548. obj.deptId = this.queryParams.deptId;
  549. }else{
  550. obj.deptId = localStorage.getItem('deptId');
  551. }
  552. examElStatisticsExamGroupedList(obj).then(response => {
  553. // this.$set(this,'dataList',response.data.records);
  554. let list = [];
  555. for(let i=0;i<response.data.deptStats.length;i++){
  556. for(let o=0;o<response.data.deptStats[i].examTypeGroup.length;o++){
  557. list.push({
  558. deptName:response.data.deptStats[i].deptName,
  559. deptId:response.data.deptStats[i].deptId,
  560. examTypeId:response.data.deptStats[i].examTypeGroup[o].examTypeId,
  561. examTypeName:response.data.deptStats[i].examTypeGroup[o].examTypeName,
  562. expectedCount:response.data.deptStats[i].examTypeGroup[o].expectedCount,
  563. examCount:response.data.deptStats[i].examTypeGroup[o].examCount,
  564. passedCount:response.data.deptStats[i].examTypeGroup[o].passedCount,
  565. notPassedCount:response.data.deptStats[i].examTypeGroup[o].notPassedCount,
  566. absentCount:response.data.deptStats[i].examTypeGroup[o].absentCount,
  567. passRate:response.data.deptStats[i].examTypeGroup[o].passRate,
  568. type:1,
  569. })
  570. }
  571. list.push({
  572. deptName:response.data.deptStats[i].deptName,
  573. examTypeName:'汇总',
  574. expectedCount:response.data.deptStats[i].summary.expectedCount,
  575. examCount:response.data.deptStats[i].summary.examCount,
  576. passedCount:response.data.deptStats[i].summary.passedCount,
  577. notPassedCount:response.data.deptStats[i].summary.notPassedCount,
  578. absentCount:response.data.deptStats[i].summary.absentCount,
  579. passRate:response.data.deptStats[i].summary.passRate,
  580. type:2,
  581. })
  582. }
  583. if(this.adminType == 1&&!this.queryParams.deptId){
  584. for(let o=0;o<response.data.schoolStats.examTypeGroup.length;o++){
  585. list.push({
  586. deptName:response.data.schoolStats.deptName,
  587. deptId:'',
  588. examTypeId:response.data.schoolStats.examTypeGroup[o].examTypeId,
  589. examTypeName:response.data.schoolStats.examTypeGroup[o].examTypeName,
  590. expectedCount:response.data.schoolStats.examTypeGroup[o].expectedCount,
  591. examCount:response.data.schoolStats.examTypeGroup[o].examCount,
  592. passedCount:response.data.schoolStats.examTypeGroup[o].passedCount,
  593. notPassedCount:response.data.schoolStats.examTypeGroup[o].notPassedCount,
  594. absentCount:response.data.schoolStats.examTypeGroup[o].absentCount,
  595. passRate:response.data.schoolStats.examTypeGroup[o].passRate,
  596. type:3,
  597. })
  598. }
  599. list.push({
  600. deptName:response.data.schoolStats.deptName,
  601. examTypeName:'汇总',
  602. expectedCount:response.data.schoolStats.summary.expectedCount,
  603. examCount:response.data.schoolStats.summary.examCount,
  604. passedCount:response.data.schoolStats.summary.passedCount,
  605. notPassedCount:response.data.schoolStats.summary.notPassedCount,
  606. absentCount:response.data.schoolStats.summary.absentCount,
  607. passRate:response.data.schoolStats.summary.passRate,
  608. type:2,
  609. })
  610. }
  611. this.$set(this,'dataList',list);
  612. this.$set(this,'total',response.data.total);
  613. });
  614. },
  615. //查询全部考试类型
  616. examElExamTypeList(){
  617. examElExamTypeList({}).then(response => {
  618. let list = [];
  619. for(let i=0;i<response.data.length;i++){
  620. if(response.data[i].examTypeCode == 'CLASSIFIED' || response.data[i].examTypeCode == 'yzyh' || response.data[i].examTypeCode == 'STUDENT'){
  621. list.push(response.data[i]);
  622. }
  623. }
  624. this.$set(this,'optionListB',list);
  625. });
  626. },
  627. //学院列表
  628. systemDeptCurrentDept(){
  629. systemDeptCurrentDept({}).then(response => {
  630. const list = response.data || [];
  631. this.formatTreeData(list);
  632. if(list[0]){
  633. this.$set(this,'optionListA',list[0].child);
  634. }else{
  635. this.$set(this,'optionListA',[]);
  636. }
  637. });
  638. },
  639. //学年列表
  640. examElStatisticsGetAcademicYear(){
  641. examElStatisticsGetAcademicYear({}).then(response => {
  642. this.$set(this,'optionList',response.data);
  643. this.$set(this,'valueYear',response.data[0].value);
  644. this.examElStatisticsExamGroupedList();
  645. this.examElStatisticsExamGroupedChart();
  646. });
  647. },
  648. }
  649. }
  650. </script>
  651. <style scoped lang="scss">
  652. .exam-situation-card {
  653. background: #fff;
  654. /*border-radius: 6px;*/
  655. padding: 20px;
  656. margin-bottom: 12px;
  657. /*box-shadow: 0 1px 4px rgba(0,0,0,0.06);*/
  658. background: rgba(255, 255, 255, 0.95);
  659. border: 1px solid #e8edf5;
  660. border-radius: 16px;
  661. box-shadow: 0 4px 20px rgba(37, 50, 74, 0.06);
  662. .card-header {
  663. display: flex;
  664. justify-content: space-between;
  665. align-items: center;
  666. margin-bottom: 16px;
  667. .card-title { font-size: 16px; font-weight: 700; color: #222; }
  668. .header-right { width:610px;display: flex; align-items: center; gap: 20px; }
  669. }
  670. /* 分组筛选按钮 */
  671. .table-top-button-box {
  672. display: inline-block;
  673. vertical-align: top;
  674. div {
  675. display: flex;
  676. p {
  677. border: 1px solid #DCDFE6;
  678. width: 80px;
  679. text-align: center;
  680. height: 40px;
  681. line-height: 40px;
  682. cursor: pointer;
  683. font-size: 14px;
  684. &:nth-child(1) { border-top-left-radius: 4px; border-bottom-left-radius: 4px; }
  685. &:nth-child(2) { border-left: none; border-right: none; }
  686. &:nth-child(3) { border-top-right-radius: 4px; border-bottom-right-radius: 4px; }
  687. }
  688. .check-table-button{
  689. border: 1px solid #0183fa!important;
  690. background-color: #0183fa!important;;
  691. color:#fff!important;;
  692. }
  693. }
  694. }
  695. /* 导出按钮 */
  696. .export-btn {
  697. display: inline-block;
  698. padding: 0 16px;
  699. height: 40px;
  700. line-height: 40px;
  701. border-radius: 4px;
  702. font-size: 14px;
  703. cursor: pointer;
  704. background-color: #0183fa;
  705. color: #fff;
  706. border: 1px solid #0183fa;
  707. }
  708. .chart-area {
  709. display: flex;
  710. gap: 0;
  711. margin-bottom: 16px;
  712. border: 1px solid #eee;
  713. border-radius: 6px;
  714. overflow: hidden;
  715. .bar-chart-wrap {
  716. flex: 1;
  717. height: 280px;
  718. border-right: 1px solid #eee;
  719. }
  720. .pie-chart-wrap {
  721. width: 320px;
  722. height: 280px;
  723. }
  724. }
  725. .filter-row {
  726. display: flex;
  727. gap: 20px;
  728. margin-bottom: 12px;
  729. }
  730. .page-content-box{
  731. height:500px;
  732. padding:0;
  733. ::v-deep .el-table--medium td:nth-child(1){
  734. border-left:1px solid #dfe6ec!important;
  735. }
  736. ::v-deep .el-table__row:nth-child(4n){
  737. /*border-left:none!important;*/
  738. /*color:#184c93;*/
  739. /*background-color: #edf5ff;*/
  740. }
  741. }
  742. .link-blue { color: #409eff; }
  743. }
  744. </style>
  745. <style lang="scss">
  746. .examSituation-index-drawer{
  747. .el-drawer__body{
  748. padding:0;
  749. }
  750. .el-drawer__header{
  751. margin:0;
  752. }
  753. }
  754. </style>