Stats.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <div class="page-container">
  3. <div class="page-header">
  4. <h2 class="page-title">数据统计</h2>
  5. <div class="page-filters">
  6. <el-select v-model="classId" placeholder="选择班级" clearable style="width:160px">
  7. <el-option label="全部班级" value="" />
  8. <el-option v-for="c in classes" :key="c.id" :label="c.name" :value="String(c.id)" />
  9. </el-select>
  10. </div>
  11. </div>
  12. <el-row :gutter="16" style="margin-bottom:16px">
  13. <el-col :span="12">
  14. <el-card shadow="hover">
  15. <div slot="header"><strong>组间积分对比</strong></div>
  16. <div ref="groupChart" style="height:350px"></div>
  17. </el-card>
  18. </el-col>
  19. <el-col :span="12">
  20. <el-card shadow="hover">
  21. <div slot="header"><strong>学员积分排行</strong></div>
  22. <div ref="userChart" style="height:350px"></div>
  23. </el-card>
  24. </el-col>
  25. </el-row>
  26. </div>
  27. </template>
  28. <script>
  29. import * as echarts from 'echarts'
  30. import { statsScoreboard, statsUserScoreboard } from '@/api/stats'
  31. import { classList } from '@/api/class'
  32. export default {
  33. name: 'Stats',
  34. data: function () {
  35. return {
  36. classes: [],
  37. classId: '',
  38. groupChart: null,
  39. userChart: null
  40. }
  41. },
  42. watch: {
  43. classId: function () {
  44. this.fetchAll()
  45. }
  46. },
  47. mounted: function () {
  48. this.fetchClasses()
  49. this.fetchAll()
  50. this.initCharts()
  51. window.addEventListener('resize', this.handleResize)
  52. },
  53. beforeDestroy: function () {
  54. window.removeEventListener('resize', this.handleResize)
  55. if (this.groupChart) this.groupChart.dispose()
  56. if (this.userChart) this.userChart.dispose()
  57. },
  58. methods: {
  59. fetchClasses: function () {
  60. var self = this
  61. classList().then(function (res) {
  62. self.classes = res.data || []
  63. }).catch(function () {})
  64. },
  65. fetchAll: function () {
  66. var self = this
  67. var params = {}
  68. if (self.classId) params.classId = self.classId
  69. Promise.all([
  70. statsScoreboard(params),
  71. statsUserScoreboard(params)
  72. ]).then(function (results) {
  73. self.renderGroupChart(results[0].data || [])
  74. self.renderUserChart(results[1].data || [])
  75. }).catch(function () {
  76. self.$message.error('获取统计数据失败')
  77. })
  78. },
  79. initCharts: function () {
  80. var self = this
  81. self.$nextTick(function () {
  82. self.groupChart = echarts.init(self.$refs.groupChart)
  83. self.userChart = echarts.init(self.$refs.userChart)
  84. })
  85. },
  86. renderGroupChart: function (data) {
  87. if (!this.groupChart) return
  88. var names = data.map(function (item) { return item.groupName })
  89. var scores = data.map(function (item) { return item.groupTotal })
  90. this.groupChart.setOption({
  91. tooltip: { trigger: 'axis' },
  92. xAxis: { type: 'category', data: names },
  93. yAxis: { type: 'value', name: '积分' },
  94. series: [{
  95. type: 'bar',
  96. data: scores,
  97. itemStyle: {
  98. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  99. { offset: 0, color: '#FC7A57' },
  100. { offset: 1, color: '#818CF8' }
  101. ])
  102. },
  103. barMaxWidth: 40
  104. }],
  105. grid: { left: 50, right: 20, bottom: 40, top: 30 }
  106. })
  107. },
  108. renderUserChart: function (data) {
  109. if (!this.userChart) return
  110. var top10 = data.slice(0, 10)
  111. var names = top10.map(function (item) { return item.name })
  112. var scores = top10.map(function (item) { return item.total })
  113. this.userChart.setOption({
  114. tooltip: { trigger: 'axis' },
  115. xAxis: { type: 'category', data: names },
  116. yAxis: { type: 'value', name: '积分' },
  117. series: [{
  118. type: 'bar',
  119. data: scores,
  120. itemStyle: {
  121. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  122. { offset: 0, color: '#10B981' },
  123. { offset: 1, color: '#34D399' }
  124. ])
  125. },
  126. barMaxWidth: 40
  127. }],
  128. grid: { left: 50, right: 20, bottom: 60, top: 30 }
  129. })
  130. },
  131. handleResize: function () {
  132. if (this.groupChart) this.groupChart.resize()
  133. if (this.userChart) this.userChart.resize()
  134. }
  135. }
  136. }
  137. </script>
  138. <style scoped>
  139. .page-header {
  140. display: flex;
  141. justify-content: space-between;
  142. align-items: center;
  143. margin-bottom: 16px;
  144. flex-wrap: wrap;
  145. gap: 8px;
  146. }
  147. .page-title {
  148. margin: 0;
  149. font-size: 18px;
  150. font-weight: 600;
  151. }
  152. .page-filters {
  153. display: flex;
  154. align-items: center;
  155. }
  156. </style>