| | |
| | | |
| | | <template> |
| | | <div style="padding: 10px"> |
| | | <el-form :model="queryParam" ref="queryForm" :inline="true " style="display: flex"> |
| | | <el-form-item label="试卷名称:" > |
| | | <el-input v-model="paperName.paperName"></el-input> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="试卷题目:">--> |
| | | <!-- <el-input v-model="queryParam.paperName"></el-input>--> |
| | | <!-- </el-form-item>--> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="submitForm">查询</el-button> |
| | | </el-form-item> |
| | | <div style="padding: 10px" ref="pageContent"> |
| | | <el-form :model="queryParam" ref="queryForm" :inline="true" style="display: flex"> |
| | | <el-form-item label="试卷:"> |
| | | <el-select v-model="queryParam.examPaperId" filterable placeholder="试卷" @change="getType"> |
| | | <el-option v-for="item in examPaperList" :key="item.id" :value="item.id" :label="item.name" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="部门:" v-if="admin"> |
| | | <!-- <el-select v-model="queryParam.departmentId" collapse-tags multiple filterable placeholder="部门" clearable> |
| | | <el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value" /> |
| | | </el-select> --> |
| | | <el-cascader |
| | | clearable |
| | | filterable |
| | | v-model="queryParam.departmentId" |
| | | :options="levelEnum" |
| | | :props="{ multiple: true, emitPath: false, value: 'id', label: 'name', checkStrictly: true }" |
| | | ></el-cascader> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="submitForm">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | </el-form> |
| | | <div style="display: flex;justify-content: center;color: #0a76a4"> |
| | | <div >最低分:{{min}}</div> |
| | | <div style="margin-left: 5px">最高分:{{max}}</div> |
| | | <div style="margin-left: 5px">平均分:{{avg}}</div> |
| | | <el-row :gutter="20"> |
| | | <el-col :xl="24" class="echarts-row"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="6"> |
| | | <el-card> |
| | | <div class="data-item"> |
| | | <div class="data-icon" :style="{ 'background-color': iconList[0].color }"> |
| | | <i class="el-icon-tickets"></i> |
| | | </div> |
| | | <div class="data-info"> |
| | | <div class="data-label"> |
| | | 总考试次数 |
| | | </div> |
| | | <div class="data-num"> |
| | | {{ totalInfo.examTotal }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | </el-col> |
| | | |
| | | <el-col :span="6"> |
| | | <el-card> |
| | | <div class="data-item"> |
| | | <div class="data-icon" :style="{ 'background-color': iconList[1].color }"> |
| | | <i class="el-icon-s-claim"></i> |
| | | </div> |
| | | <div class="data-info"> |
| | | <div class="data-label"> |
| | | 参考人数 |
| | | </div> |
| | | <div class="data-num"> |
| | | {{ totalInfo.factPeopleTotal }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | </el-col> |
| | | |
| | | <el-col :span="6"> |
| | | <el-card> |
| | | <div class="data-item"> |
| | | <div class="data-icon" :style="{ 'background-color': iconList[2].color }"> |
| | | <i class="el-icon-edit"></i> |
| | | </div> |
| | | <div class="data-info"> |
| | | <div class="data-label"> |
| | | 平均分 |
| | | </div> |
| | | <div class="data-num"> |
| | | {{ totalInfo.averageScore }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | </el-col> |
| | | |
| | | <el-col :span="6"> |
| | | <el-card> |
| | | <div class="data-item"> |
| | | <div class="data-icon" :style="{ 'background-color': iconList[3].color }"> |
| | | <i class="el-icon-s-data"></i> |
| | | </div> |
| | | <div class="data-info"> |
| | | <div class="data-label"> |
| | | 参考人数百分比 |
| | | </div> |
| | | <div class="data-num"> |
| | | {{ totalInfo.referencePercentage }}% |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :xl="12" class="echarts-row"> |
| | | <el-card> |
| | | <div class="card-chart-container"> |
| | | <div id="ageChart" ref="ageChart" class="chart-style" v-loading="chartLoading1" /> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <el-col :xl="12" class="echarts-row"> |
| | | <el-card> |
| | | <div class="card-chart-container"> |
| | | <div id="scoreChart" ref="scoreChart" class="chart-style" v-loading="chartLoading2" /> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <el-row class="echarts-line"> |
| | | <div id="echarts-moth-user" style="width: 100%;height:400px;" v-loading="loading"/> |
| | | </el-row> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import examPaperAnswerApi from '@/api/examPaperAnwser' |
| | | import dashboardApi from '@/api/dashboard' |
| | | const animationDuration = 6000 |
| | | import { mapGetters, mapState } from 'vuex'; |
| | | import dashboardApi from '@/api/dashboard'; |
| | | |
| | | const colorList = ['#3498DB', '#E74C3C', '#F1C40F', '#95A5A6', '#8E44AD', '#F39C12', '#D35400']; |
| | | |
| | | |
| | | const ageLabel = { |
| | | 'age0To19': '0-19岁', |
| | | 'age20To29': '20-29岁', |
| | | 'age30To39': '30-39岁', |
| | | 'age40To49': '40-49岁', |
| | | 'ageOver50': '大于50岁', |
| | | }; |
| | | const scoreLabel = { |
| | | 'score0To59': '小于60分', |
| | | 'score60To69': '60-69分', |
| | | 'score70To79': '70-79分', |
| | | 'score80To89': '80-89分', |
| | | 'score90To100': '90-100分' |
| | | }; |
| | | const pieLabel = { |
| | | 'totalAttended': '参与考试', |
| | | 'totalAbsent': '未参与考试' |
| | | }; |
| | | |
| | | const dataKeyMap = { |
| | | 'factPeopleTotal': '参考人数', |
| | | 'averageScore': '平均分', |
| | | 'referencePercentage': '参考人数百分比', |
| | | }; |
| | | |
| | | let ageChart = null; |
| | | let scroeChart = null; |
| | | let peopleChart = null; |
| | | let observer = null; |
| | | export default { |
| | | data(){ |
| | | return{ |
| | | max:'', |
| | | min:'', |
| | | avg:'', |
| | | paperName:{ |
| | | paperName:'' |
| | | data() { |
| | | return { |
| | | totalInfo: { |
| | | examTotal: 0, |
| | | factPeopleTotal: 0, |
| | | averageScore: 0, |
| | | referencePercentage: 0 |
| | | }, |
| | | loading:false, |
| | | examPaperCount: 0, |
| | | questionCount: 0, |
| | | doExamPaperCount: 0, |
| | | doQuestionCount: 0, |
| | | echartsUserAction: null, |
| | | iconList: [ |
| | | { icon: 'el-icon-tickets', color: '#7868d9' }, |
| | | { icon: 'el-icon-s-claim', color: '#3eba45' }, |
| | | { icon: 'el-icon-edit', color: '#3da7f8' }, |
| | | { icon: 'el-icon-warning', color: '#ffbe40' }, |
| | | { icon: 'el-icon-error', color: '#fe640d' }, |
| | | ], |
| | | examPaperList: [], |
| | | chartLoading1: false, |
| | | chartLoading2: false, |
| | | queryParam: { |
| | | paperName:'', |
| | | userName:'', |
| | | subjectId: null, |
| | | pageIndex: 1, |
| | | pageSize: 10 |
| | | examPaperId: '', |
| | | departmentId: [], |
| | | examPaperType: 1 |
| | | }, |
| | | listLoading:false |
| | | admin: true |
| | | }; |
| | | }, |
| | | mounted() { |
| | | if (sessionStorage.getItem('deptAdmin') == 1) { |
| | | this.admin = false; |
| | | } |
| | | ageChart = echarts.init(this.$refs.ageChart); |
| | | scroeChart = echarts.init(this.$refs.scoreChart); |
| | | dashboardApi.examPaperList().then(res => { |
| | | this.examPaperList = res.response; |
| | | this.queryParam.examPaperId = this.examPaperList[0].id |
| | | this.queryParam.examPaperType = this.examPaperList[0].paperType |
| | | this.getChartData(); |
| | | this.observe(); |
| | | }); |
| | | }, |
| | | mounted(){ |
| | | let _this = this |
| | | dashboardApi.getData(this.paperName).then(re => { |
| | | let response = re.response |
| | | console.log(response) |
| | | _this.avg = response.avg |
| | | _this.max = response.max |
| | | _this.min = response.min |
| | | _this.examPaperCount = response.examPaperCount |
| | | _this.questionCount = response.questionCount |
| | | _this.doExamPaperCount = response.doExamPaperCount |
| | | _this.doQuestionCount = response.doQuestionCount |
| | | _this.echartsUserAction.setOption(this.option('用户活跃度', '{b}分{c}人', response.mothDayText, response)) |
| | | // _this.echartsQuestion.setOption(this.option('题目月数量', '{b}日{c}题', response.mothDayText, response.mothDayDoExamQuestionValue)) |
| | | this.loading = false |
| | | }) |
| | | this.echartsUserAction = echarts.init(document.getElementById('echarts-moth-user'), 'macarons') |
| | | }, |
| | | methods:{ |
| | | option (title, formatter, label, vaule) { |
| | | methods: { |
| | | getType(val) { |
| | | const selectedItem = this.examPaperList.find(item => item.id === val); |
| | | this.queryParam.examPaperType = selectedItem.paperType; |
| | | this.getChartData(); |
| | | }, |
| | | getChartData() { |
| | | this.chartLoading1 = true; |
| | | this.chartLoading2 = true; |
| | | dashboardApi.getData(this.queryParam).then(re => { |
| | | const { age, score, total } = re.response; |
| | | this.totalInfo = total; |
| | | const ageOption = this.barOption('年龄段统计', age, ageLabel); |
| | | const scoreOption = this.barOption('分数段统计', score, scoreLabel); |
| | | |
| | | ageChart.setOption(ageOption, true); |
| | | scroeChart.setOption(scoreOption, true); |
| | | |
| | | this.chartLoading1 = false; |
| | | this.chartLoading2 = false; |
| | | }); |
| | | }, |
| | | barOption(title, data, labelList) { |
| | | const dataKeys = data.map(item => labelList[Object.keys(item)[0]]); |
| | | const dataValues = data.map(item => Object.values(item)[0]); |
| | | return { |
| | | title: { |
| | | text: '答卷统计', |
| | | x: 'center' |
| | | text: title, |
| | | x: 'left' |
| | | }, |
| | | color: colorList, |
| | | tooltip: { |
| | | trigger: 'item', |
| | | formatter: formatter |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['0-60','60-80','80-100'] |
| | | trigger: 'item' |
| | | }, |
| | | grid: { |
| | | left: 10, |
| | | right: 10, |
| | | bottom: 20, |
| | | top: 30, |
| | | top: 40, |
| | | containLabel: true |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: dataKeys |
| | | }, |
| | | yAxis: { |
| | | type: 'value' |
| | | }, |
| | | series: [{ |
| | | data: [vaule.lowGrade,vaule.intermediate,vaule.advanced], |
| | | type: 'bar', |
| | | barMaxWidth:'10%' |
| | | }] |
| | | series: [ |
| | | { |
| | | type: 'bar', |
| | | label: { |
| | | show: true, |
| | | fontSize: 16 |
| | | }, |
| | | barMaxWidth: '40%', |
| | | data: dataValues, |
| | | } |
| | | ] |
| | | |
| | | }; |
| | | |
| | | }, |
| | | submitForm() { |
| | | this.getChartData(); |
| | | }, |
| | | |
| | | // 监听变化 |
| | | observe() { |
| | | if (!observer) { |
| | | observer = new ResizeObserver(entries => { |
| | | this.handleResize(); |
| | | }); |
| | | } |
| | | observer.observe(this.$refs.pageContent); |
| | | }, |
| | | search () { |
| | | // this.listLoading = true |
| | | let _this = this |
| | | dashboardApi.getData(this.paperName).then(re => { |
| | | console.log(re) |
| | | let response = re.response |
| | | _this.avg = response.avg |
| | | _this.max = response.max |
| | | _this.min = response.min |
| | | _this.echartsUserAction.setOption(this.option('用户活跃度', '{b}分{c}人', response.mothDayText, response)) |
| | | }) |
| | | this.echartsUserAction = echarts.init(document.getElementById('echarts-moth-user'), 'macarons') |
| | | }, |
| | | submitForm () { |
| | | this.queryParam.pageIndex = 1 |
| | | this.search() |
| | | }, |
| | | // 窗口变换 |
| | | handleResize() { |
| | | if (ageChart) { |
| | | ageChart.resize(); |
| | | } |
| | | if (scroeChart) { |
| | | scroeChart.resize(); |
| | | } |
| | | } |
| | | }, |
| | | beforeDestroy() { |
| | | observer.unobserve(this.$refs.pageContent); |
| | | }, |
| | | computed: { |
| | | ...mapGetters('enumItem', ['enumFormat']), |
| | | ...mapState('enumItem', { |
| | | levelEnum: state => state.user.levelEnum |
| | | }) |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .echarts-row { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .card-chart-container { |
| | | width: 100%; |
| | | height: 400px; |
| | | } |
| | | |
| | | .chart-style { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .data-item { |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | border-radius: 10px; |
| | | overflow: hidden; |
| | | |
| | | .data-icon { |
| | | font-size: 70px; |
| | | padding: 20px 30px; |
| | | color: #fff; |
| | | border-radius: 10px; |
| | | overflow: hidden; |
| | | margin-right: 20px; |
| | | } |
| | | |
| | | .data-info { |
| | | .data-label { |
| | | font-size: 18px; |
| | | margin-bottom: 10px; |
| | | color: #707070; |
| | | } |
| | | |
| | | .data-num { |
| | | font-size: 28px; |
| | | } |
| | | } |
| | | } |
| | | </style> |