| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- <template>
- <div class="page-container">
- <div class="page-header">
- <h2 class="page-title">数据统计</h2>
- <div class="page-filters">
- <el-select v-model="classId" placeholder="选择班级" clearable style="width:160px">
- <el-option label="全部班级" value="" />
- <el-option v-for="c in classes" :key="c.id" :label="c.name" :value="String(c.id)" />
- </el-select>
- </div>
- </div>
- <el-row :gutter="16" style="margin-bottom:16px">
- <el-col :span="12">
- <el-card shadow="hover">
- <div slot="header"><strong>组间积分对比</strong></div>
- <div ref="groupChart" style="height:350px"></div>
- </el-card>
- </el-col>
- <el-col :span="12">
- <el-card shadow="hover">
- <div slot="header"><strong>学员积分排行</strong></div>
- <div ref="userChart" style="height:350px"></div>
- </el-card>
- </el-col>
- </el-row>
- </div>
- </template>
- <script>
- import * as echarts from 'echarts'
- import { statsScoreboard, statsUserScoreboard } from '@/api/stats'
- import { classList } from '@/api/class'
- export default {
- name: 'Stats',
- data: function () {
- return {
- classes: [],
- classId: '',
- groupChart: null,
- userChart: null
- }
- },
- watch: {
- classId: function () {
- this.fetchAll()
- }
- },
- mounted: function () {
- this.fetchClasses()
- this.fetchAll()
- this.initCharts()
- window.addEventListener('resize', this.handleResize)
- },
- beforeDestroy: function () {
- window.removeEventListener('resize', this.handleResize)
- if (this.groupChart) this.groupChart.dispose()
- if (this.userChart) this.userChart.dispose()
- },
- methods: {
- fetchClasses: function () {
- var self = this
- classList().then(function (res) {
- self.classes = res.data || []
- }).catch(function () {})
- },
- fetchAll: function () {
- var self = this
- var params = {}
- if (self.classId) params.classId = self.classId
- Promise.all([
- statsScoreboard(params),
- statsUserScoreboard(params)
- ]).then(function (results) {
- self.renderGroupChart(results[0].data || [])
- self.renderUserChart(results[1].data || [])
- }).catch(function () {
- self.$message.error('获取统计数据失败')
- })
- },
- initCharts: function () {
- var self = this
- self.$nextTick(function () {
- self.groupChart = echarts.init(self.$refs.groupChart)
- self.userChart = echarts.init(self.$refs.userChart)
- })
- },
- renderGroupChart: function (data) {
- if (!this.groupChart) return
- var names = data.map(function (item) { return item.groupName })
- var scores = data.map(function (item) { return item.groupTotal })
- this.groupChart.setOption({
- tooltip: { trigger: 'axis' },
- xAxis: { type: 'category', data: names },
- yAxis: { type: 'value', name: '积分' },
- series: [{
- type: 'bar',
- data: scores,
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: '#FC7A57' },
- { offset: 1, color: '#818CF8' }
- ])
- },
- barMaxWidth: 40
- }],
- grid: { left: 50, right: 20, bottom: 40, top: 30 }
- })
- },
- renderUserChart: function (data) {
- if (!this.userChart) return
- var top10 = data.slice(0, 10)
- var names = top10.map(function (item) { return item.name })
- var scores = top10.map(function (item) { return item.total })
- this.userChart.setOption({
- tooltip: { trigger: 'axis' },
- xAxis: { type: 'category', data: names },
- yAxis: { type: 'value', name: '积分' },
- series: [{
- type: 'bar',
- data: scores,
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: '#10B981' },
- { offset: 1, color: '#34D399' }
- ])
- },
- barMaxWidth: 40
- }],
- grid: { left: 50, right: 20, bottom: 60, top: 30 }
- })
- },
- handleResize: function () {
- if (this.groupChart) this.groupChart.resize()
- if (this.userChart) this.userChart.resize()
- }
- }
- }
- </script>
- <style scoped>
- .page-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- flex-wrap: wrap;
- gap: 8px;
- }
- .page-title {
- margin: 0;
- font-size: 18px;
- font-weight: 600;
- }
- .page-filters {
- display: flex;
- align-items: center;
- }
- </style>
|