|
@@ -0,0 +1,132 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="data-stat">
|
|
|
|
+ <div class="data-stat-header">
|
|
|
|
+ <div class="stat-summary">
|
|
|
|
+ <div class="stat-summary-item">
|
|
|
|
+ <h4>当前在线人数</h4>
|
|
|
|
+ <p>
|
|
|
|
+ <animate-number :value="summary.onlineCount"></animate-number>
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="stat-summary-item">
|
|
|
|
+ <h4>当前考试中人数</h4>
|
|
|
|
+ <p>
|
|
|
|
+ <animate-number :value="summary.examingCount"></animate-number>
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="stat-summary-item">
|
|
|
|
+ <h4>累计考试科次</h4>
|
|
|
|
+ <p>
|
|
|
|
+ <animate-number :value="summary.stdExamCount"></animate-number>
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="stat-summary-item">
|
|
|
|
+ <h4>累计服务考生</h4>
|
|
|
|
+ <p><animate-number :value="summary.studentCount"></animate-number></p>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="data-stat-body">
|
|
|
|
+ <div class="data-stat-table">
|
|
|
|
+ <div class="data-stat-table-title">机构考生分布</div>
|
|
|
|
+ <el-table :data="tableData" stripe>
|
|
|
|
+ <el-table-column label="机构名称"></el-table-column>
|
|
|
|
+ <el-table-column width="80" label="在线人数"></el-table-column>
|
|
|
|
+ <el-table-column width="80" label="在考人数"></el-table-column>
|
|
|
|
+ </el-table>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="data-stat-chart">
|
|
|
|
+ <div class="data-stat-chart-title">在线考生地域分布</div>
|
|
|
|
+ <vue-charts
|
|
|
|
+ v-if="areaChartOption"
|
|
|
|
+ :options="areaChartOption"
|
|
|
|
+ autoresize
|
|
|
|
+ ></vue-charts>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import {
|
|
|
|
+ statSummary,
|
|
|
|
+ statOrgStudent,
|
|
|
|
+ statAreaStudent,
|
|
|
|
+} from "../../../api/system";
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ name: "DataStatistics",
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ summary: {
|
|
|
|
+ onlineCount: 0,
|
|
|
|
+ examingCount: 0,
|
|
|
|
+ stdExamCount: 0,
|
|
|
|
+ studentCount: 0,
|
|
|
|
+ },
|
|
|
|
+ tableData: [],
|
|
|
|
+ areaChartOption: null,
|
|
|
|
+ // setTs
|
|
|
|
+ setTsMap: {
|
|
|
|
+ summary: [],
|
|
|
|
+ areaMap: [],
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ // this.initData();
|
|
|
|
+ },
|
|
|
|
+ beforeDestroy() {
|
|
|
|
+ this.clearSetTs();
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ addSetTime(typeName, action, time = 1 * 1000) {
|
|
|
|
+ this.setTsMap[typeName].push(setTimeout(action, time));
|
|
|
|
+ },
|
|
|
|
+ clearSetTs(typeName) {
|
|
|
|
+ if (typeName) {
|
|
|
|
+ if (!this.setTsMap[typeName] || !this.setTsMap[typeName].length) return;
|
|
|
|
+ this.setTsMap[typeName].forEach((t) => clearTimeout(t));
|
|
|
|
+ this.setTsMap[typeName] = [];
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ Object.keys(this.setTsMap).forEach((k) => {
|
|
|
|
+ this.setTsMap[k].forEach((t) => clearTimeout(t));
|
|
|
|
+ this.setTsMap[k] = [];
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ initData() {
|
|
|
|
+ this.intervalSummary();
|
|
|
|
+ this.intervalStudent();
|
|
|
|
+ },
|
|
|
|
+ async getSummary() {
|
|
|
|
+ const res = await statSummary();
|
|
|
|
+ this.summary = res.data;
|
|
|
|
+ },
|
|
|
|
+ async getStatOrgStudent() {
|
|
|
|
+ const res = await statOrgStudent();
|
|
|
|
+ this.tableData = res.data;
|
|
|
|
+ },
|
|
|
|
+ async getStatAreaStudent() {
|
|
|
|
+ const res = await statAreaStudent();
|
|
|
|
+ // todo:
|
|
|
|
+ this.areaChartOption = res.data;
|
|
|
|
+ },
|
|
|
|
+ async intervalSummary() {
|
|
|
|
+ const typeName = "summary";
|
|
|
|
+ this.clearSetTs(typeName);
|
|
|
|
+
|
|
|
|
+ await this.getSummary();
|
|
|
|
+ this.addSetTime(typeName, this.intervalSummary, 5 * 1000);
|
|
|
|
+ },
|
|
|
|
+ async intervalStudent() {
|
|
|
|
+ const typeName = "areaMap";
|
|
|
|
+ this.clearSetTs(typeName);
|
|
|
|
+
|
|
|
|
+ await this.getStatOrgStudent();
|
|
|
|
+ await this.getStatAreaStudent();
|
|
|
|
+ this.addSetTime(typeName, this.intervalStudent, 10 * 1000);
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+</script>
|