StudyHourStats.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. <!-- 学时统计 -->
  2. <template>
  3. <div class="study-hour-card">
  4. <div class="card-header">
  5. <span class="card-title">学时统计</span>
  6. <p class="export-btn" @click="exportButton()">
  7. <i class="el-icon-download"></i> 导出数据
  8. </p>
  9. </div>
  10. <!-- 分组柱状图 -->
  11. <p class="chart-wrap" v-if="!chartData[0]" style="color:#999;font-size:14px;line-height:260px;text-align: center;">暂无数据</p>
  12. <div class="chart-wrap" v-if="chartData[0]" id="chart-wrap-bar-chart" ref="barChart"></div>
  13. <!-- 筛选 -->
  14. <div class="filter-row">
  15. <el-select v-model="queryParams.personType" placeholder="用户类型" style="width:220px">
  16. <el-option label="研究生" value="2" />
  17. <el-option label="本科生" value="3" />
  18. <el-option label="教职工" value="1" />
  19. <el-option label="博士" value="4" />
  20. </el-select>
  21. <!--<el-cascader-->
  22. <!--v-if="adminType == 1"-->
  23. <!--style="width: 180px"-->
  24. <!--v-model="queryParams.deptId"-->
  25. <!--:options="optionListA"-->
  26. <!--:props="{-->
  27. <!--emitPath:false,-->
  28. <!--checkStrictly: true,-->
  29. <!--value: 'deptId',-->
  30. <!--label: 'deptName',-->
  31. <!--children: 'child',-->
  32. <!--}"-->
  33. <!--:show-all-levels="false"-->
  34. <!--filterable-->
  35. <!--placeholder="学院"-->
  36. <!--&gt;</el-cascader>-->
  37. <el-select v-if="adminType == 1" v-model="queryParams.deptId" placeholder="学院" style="width: 180px">
  38. <el-option
  39. v-for="dict in optionListA"
  40. :key="dict.deptId"
  41. :label="dict.deptName"
  42. :value="dict.deptId"
  43. />
  44. </el-select>
  45. <el-select v-model="queryParams.gradeNumber" placeholder="学年" style="width: 140px">
  46. <el-option
  47. v-for="dict in optionListB"
  48. :key="dict.gradeNumber"
  49. :label="dict.gradeNumber"
  50. :value="dict.gradeNumber"
  51. />
  52. </el-select>
  53. <el-input v-model="queryParams.searchValue" placeholder="学号/姓名" size="small" prefix-icon="el-icon-search" style="width:210px" clearable />
  54. <p class="page-inquire-common-style-button" @click="handleQuery">查询</p>
  55. <p class="page-reset-common-style-button" @click="resetQuery">重置</p>
  56. </div>
  57. <!-- 表格 -->
  58. <div class="page-content-box">
  59. <el-table class="table-box" :data="tableData" border>
  60. <el-table-column prop="userName" label="姓名" width="200" />
  61. <el-table-column prop="account" label="学工号" width="140" />
  62. <el-table-column prop="gradeNumber" label="学年" width="140" />
  63. <el-table-column prop="deptName" label="所属学院" show-overflow-tooltip />
  64. <el-table-column prop="year1CreditHours" label="第一年" width="140" align="center" />
  65. <el-table-column prop="year2CreditHours" label="第二年" width="140" align="center" />
  66. <el-table-column prop="year3CreditHours" label="第三年" width="140" align="center" />
  67. <el-table-column prop="year4CreditHours" label="第四年" width="140" align="center" />
  68. <el-table-column prop="totalCreditHours" label="总时长" width="140" align="center" />
  69. </el-table>
  70. <pagination :page-sizes="[20, 30, 40, 50]"
  71. v-show="total>0"
  72. :total="total"
  73. :page.sync="queryParams.page"
  74. :limit.sync="queryParams.pageSize"
  75. @pagination="examElStatisticsCreditHourList"
  76. />
  77. </div>
  78. </div>
  79. </template>
  80. <script>
  81. import echarts from 'echarts'
  82. import {
  83. systemUserGetPost,
  84. } from "@/api/basicsModules/index";
  85. import {
  86. examElStatisticsCreditHourChart,examElStatisticsCreditHourList,
  87. systemUserGetAcademicYear,systemDeptCurrentDept,
  88. } from "@/api/safetyEducationExaminationNew/index";
  89. export default {
  90. name: 'StudyHourStats',
  91. data() {
  92. return {
  93. adminType:0,
  94. filterData: {
  95. personType: '',
  96. college: '',
  97. grade: '',
  98. keyword: '',
  99. page: 1,
  100. colleges: ['化学与化工学院','生命科学学院','物理学院','电气工程学院','材料科学学院','机械工程学院','自动化学院','资源环境学院'],
  101. grades: ['2017级','2018级','2019级','2020级','2021级','2022级'],
  102. },
  103. chartData: [
  104. // { label: '化学与化工', graduate: 320, undergrad: 180, staff: 95 },
  105. // { label: '生命科学', graduate: 280, undergrad: 160, staff: 72 },
  106. // { label: '物理', graduate: 240, undergrad: 145, staff: 68 },
  107. // { label: '电气工程', graduate: 300, undergrad: 195, staff: 85 },
  108. // { label: '材料科学', graduate: 220, undergrad: 135, staff: 60 },
  109. // { label: '机械工程', graduate: 195, undergrad: 170, staff: 55 },
  110. // { label: '自动化', graduate: 180, undergrad: 120, staff: 48 },
  111. // { label: '资源环境', graduate: 165, undergrad: 110, staff: 52 },
  112. ],
  113. tableData: [],
  114. optionListA:[],
  115. optionListB:[],
  116. queryParams:{
  117. page:1,
  118. pageSize:20,
  119. personType:'',
  120. deptId:'',
  121. gradeNumber:'',
  122. searchValue:'',
  123. },
  124. total:0,
  125. }
  126. },
  127. mounted() {
  128. this.systemUserGetPost();
  129. },
  130. beforeDestroy() {
  131. if (this._barChart) this._barChart.dispose()
  132. },
  133. methods: {
  134. //查询当前登录用户身份-校级/院级
  135. systemUserGetPost(){
  136. systemUserGetPost({}).then(response => {
  137. for(let i=0;i<response.data.length;i++){
  138. if(response.data[i].postCode == 'school_level_admin'){
  139. if(response.data[i].isPost){
  140. this.$set(this,'adminType','1');
  141. }
  142. }else if(response.data[i].postCode == 'college_admin'){
  143. if(response.data[i].isPost){
  144. this.$set(this,'adminType','2');
  145. }
  146. }
  147. }
  148. this.systemUserGetAcademicYear();
  149. this.systemDeptCurrentDept();
  150. this.examElStatisticsCreditHourChart();
  151. this.examElStatisticsCreditHourList();
  152. });
  153. },
  154. //导出
  155. exportButton(){
  156. let self = this;
  157. self.$confirm(`确认导出数据?`, "提示", {
  158. confirmButtonText: "确定",
  159. cancelButtonText: "取消",
  160. type: "warning"
  161. }).then(async () => {
  162. let obj = {
  163. academicYear:this.valueYear,
  164. gradeNumber:this.queryParams.gradeNumber,
  165. searchValue:this.queryParams.searchValue,
  166. };
  167. if(this.adminType == 1){
  168. obj.deptId = this.queryParams.deptId;
  169. }else{
  170. obj.deptId = localStorage.getItem('deptId');
  171. }
  172. self.download('/exam/elStatistics/creditHour/export', {...obj}, '学时统计.xlsx')
  173. }).catch(() => {})
  174. },
  175. initBarChart() {
  176. const chart = echarts.init(this.$refs.barChart)
  177. this._barChart = chart
  178. const data = this.chartData
  179. const pageSize = 6
  180. const total = data.length
  181. const endPercent = total > pageSize ? (pageSize / total) * 100 : 100
  182. chart.setOption({
  183. legend: {
  184. data: ['研究生', '本科生', '教职工', '博士'],
  185. top: 10,
  186. right: 'center',
  187. itemWidth: 14,
  188. itemHeight: 14,
  189. textStyle: { fontSize: 12, color: '#555' },
  190. },
  191. // bottom 加大,给滚动条留空间
  192. grid: { top: 50, bottom: 76, left: 56, right: 20, containLabel: false },
  193. xAxis: {
  194. type: 'category',
  195. data: data.map(d => d.deptName),
  196. axisLine: { lineStyle: { color: '#ddd' } },
  197. axisTick: { show: false },
  198. axisLabel: { fontSize: 12, color: '#666', rotate: 30 },
  199. },
  200. yAxis: {
  201. type: 'value',
  202. name: '学时',
  203. nameTextStyle: { fontSize: 11, color: '#aaa', padding: [0, 30, 0, 0] },
  204. max: (value) => {
  205. return Math.ceil(value.max / 50) * 50
  206. },
  207. splitNumber:5,
  208. splitLine: { lineStyle: { color: '#f0f0f0' } },
  209. axisLabel: { fontSize: 11, color: '#aaa' },
  210. axisLine: { show: false },
  211. axisTick: { show: false },
  212. },
  213. dataZoom: [
  214. {
  215. type: 'slider',
  216. show: true,
  217. xAxisIndex: [0],
  218. bottom: 10,
  219. start: 0,
  220. end: endPercent,
  221. height: 14,
  222. handleSize: '80%',
  223. showDetail: false,
  224. },
  225. {
  226. type: 'inside',
  227. xAxisIndex: [0],
  228. start: 0,
  229. end: endPercent,
  230. zoomOnMouseWheel: false,
  231. moveOnMouseMove: true,
  232. },
  233. ],
  234. series: [
  235. {
  236. name: '研究生',
  237. type: 'bar',
  238. barGap: '10%',
  239. barCategoryGap: '40%',
  240. data: data.map(d => d.graduateCreditHours),
  241. itemStyle: { color: '#5b9cf6' },
  242. label: {
  243. show: true,
  244. position: 'top',
  245. fontSize: 11,
  246. color: '#555',
  247. formatter: '{c}',
  248. },
  249. },
  250. {
  251. name: '本科生',
  252. type: 'bar',
  253. data: data.map(d => d.undergraduateCreditHours),
  254. itemStyle: { color: '#4fbe7e' },
  255. label: {
  256. show: true,
  257. position: 'top',
  258. fontSize: 11,
  259. color: '#555',
  260. formatter: '{c}',
  261. },
  262. },
  263. {
  264. name: '教职工',
  265. type: 'bar',
  266. data: data.map(d => d.staffCreditHours),
  267. itemStyle: { color: '#f59e42' },
  268. label: {
  269. show: true,
  270. position: 'top',
  271. fontSize: 11,
  272. color: '#555',
  273. formatter: '{c}',
  274. },
  275. },
  276. {
  277. name: '博士',
  278. type: 'bar',
  279. data: data.map(d => d.doctoralCreditsHours),
  280. itemStyle: { color: '#00CED1' },
  281. label: {
  282. show: true,
  283. position: 'top',
  284. fontSize: 11,
  285. color: '#555',
  286. formatter: '{c}',
  287. },
  288. },
  289. ],
  290. tooltip: {
  291. trigger: 'axis',
  292. axisPointer: { type: 'shadow' },
  293. },
  294. })
  295. },
  296. //学时统计图表
  297. examElStatisticsCreditHourChart(){
  298. let obj = {};
  299. if(this.adminType == 1){
  300. obj.deptId = this.queryParams.deptId;
  301. }else{
  302. obj.deptId = localStorage.getItem('deptId');
  303. }
  304. examElStatisticsCreditHourChart(obj).then(response => {
  305. this.$set(this,'chartData',response.data.deptStats);
  306. if(response.data.deptStats[0]){
  307. this.$nextTick(() => {
  308. this.initBarChart()
  309. })
  310. }
  311. });
  312. },
  313. //学时统计列表
  314. examElStatisticsCreditHourList(){
  315. let obj = JSON.parse(JSON.stringify(this.queryParams))
  316. if(this.adminType == 1){
  317. obj.deptId = this.queryParams.deptId;
  318. }else{
  319. obj.deptId = localStorage.getItem('deptId');
  320. }
  321. examElStatisticsCreditHourList(obj).then(response => {
  322. this.$set(this,'tableData',response.data.records);
  323. this.$set(this,'total',response.data.total);
  324. });
  325. },
  326. //学年下拉列表
  327. systemUserGetAcademicYear(){
  328. systemUserGetAcademicYear({}).then(response => {
  329. this.$set(this,'optionListB',response.data);
  330. });
  331. },
  332. //学院列表
  333. systemDeptCurrentDept(){
  334. systemDeptCurrentDept({}).then(response => {
  335. const list = response.data || [];
  336. this.formatTreeData(list);
  337. if(list[0]){
  338. this.$set(this,'optionListA',list[0].child);
  339. }else{
  340. this.$set(this,'optionListA',[]);
  341. }
  342. });
  343. },
  344. //查询按钮
  345. handleQuery(){
  346. this.$set(this.queryParams,'page',1);
  347. this.examElStatisticsCreditHourList();
  348. },
  349. //重置按钮
  350. resetQuery(){
  351. this.$set(this,'dateRange',[])
  352. this.$set(this,'queryParams',{
  353. page:1,
  354. pageSize:20,
  355. personType:'',
  356. deptId:'',
  357. gradeNumber:'',
  358. searchValue:'',
  359. });
  360. this.examElStatisticsCreditHourList();
  361. },
  362. }
  363. }
  364. </script>
  365. <style scoped lang="scss">
  366. .study-hour-card {
  367. background: #fff;
  368. /*border-radius: 6px;*/
  369. padding: 16px 20px;
  370. margin-bottom: 12px;
  371. /*box-shadow: 0 1px 4px rgba(0,0,0,0.06);*/
  372. background: rgba(255, 255, 255, 0.95);
  373. border: 1px solid #e8edf5;
  374. border-radius: 16px;
  375. box-shadow: 0 4px 20px rgba(37, 50, 74, 0.06);
  376. .card-header {
  377. display: flex;
  378. justify-content: space-between;
  379. align-items: center;
  380. margin-bottom: 16px;
  381. .card-title { font-size: 16px; font-weight: 700; color: #222; }
  382. }
  383. .export-btn {
  384. display: inline-block;
  385. padding: 0 16px;
  386. height: 40px;
  387. line-height: 40px;
  388. border-radius: 4px;
  389. font-size: 14px;
  390. cursor: pointer;
  391. background-color: #0183fa;
  392. color: #fff;
  393. border: 1px solid #0183fa;
  394. }
  395. .chart-wrap {
  396. border: 1px solid #eee;
  397. border-radius: 6px;
  398. margin-bottom: 16px;
  399. height: 300px;
  400. }
  401. .filter-row {
  402. display: flex;
  403. gap: 20px;
  404. margin-bottom: 12px;
  405. flex-wrap: wrap;
  406. }
  407. .page-content-box{
  408. height:500px;
  409. padding:0;
  410. }
  411. .link-blue { color: #409eff; }
  412. .pagination-wrap {
  413. display: flex;
  414. justify-content: center;
  415. margin-top: 14px;
  416. }
  417. }
  418. </style>