StudyHourStats.vue 13 KB

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