瀏覽代碼

首页统计

xdd 1 月之前
父節點
當前提交
fe46f9b9c2
共有 2 個文件被更改,包括 430 次插入173 次删除
  1. 127 3
      src/api/statistics/statistics.js
  2. 303 170
      src/views/statistics/index.vue

+ 127 - 3
src/api/statistics/statistics.js

@@ -2,14 +2,29 @@ import request from "@/utils/request";
 
 /**
  * 分析概览
- * @param query
+ * @param param
  * @returns {AxiosPromise}
  */
-export function analysisPreview(query) {
+export function analysisPreview(param) {
+  const safeParam = JSON.parse(JSON.stringify(param));
+
+  if (safeParam.startTime) {
+    const startDate = new Date(safeParam.startTime);
+    if (!isNaN(startDate.getTime())) {
+      safeParam.startTime = `${safeParam.startTime.trim()} 00:00:00`;
+    }
+  }
+
+  if (safeParam.endTime) {
+    const endDate = new Date(safeParam.endTime);
+    if (!isNaN(endDate.getTime())) {
+      safeParam.endTime = `${safeParam.endTime.trim()} 23:59:59`;
+    }
+  }
   return request({
     url: '/index/statistics/analysisPreview',
     method: 'post',
-    data: query
+    data: safeParam
   })
 }
 
@@ -51,3 +66,112 @@ export function authorizationInfo() {
     params: {}
   })
 }
+
+/**
+ * 课程观看top10
+ * @returns {*}
+ */
+export function watchCourseTopTen(param){
+  const safeParam = JSON.parse(JSON.stringify(param));
+
+  if (safeParam.startTime) {
+    const startDate = new Date(safeParam.startTime);
+    if (!isNaN(startDate.getTime())) {
+      safeParam.startTime = `${safeParam.startTime.trim()} 00:00:00`;
+    }
+  }
+
+  if (safeParam.endTime) {
+    const endDate = new Date(safeParam.endTime);
+    if (!isNaN(endDate.getTime())) {
+      safeParam.endTime = `${safeParam.endTime.trim()} 23:59:59`;
+    }
+  }
+  return request({
+    url: '/index/statistics/watchCourseTopTen',
+    method: 'post',
+    data: safeParam
+  })
+}
+
+/**
+ * 课程观看趋势
+ * @returns {*}
+ */
+export function watchCourseTrend(param){
+  const safeParam = JSON.parse(JSON.stringify(param));
+
+  if (safeParam.startTime) {
+    const startDate = new Date(safeParam.startTime);
+    if (!isNaN(startDate.getTime())) {
+      safeParam.startTime = `${safeParam.startTime.trim()} 00:00:00`;
+    }
+  }
+
+  if (safeParam.endTime) {
+    const endDate = new Date(safeParam.endTime);
+    if (!isNaN(endDate.getTime())) {
+      safeParam.endTime = `${safeParam.endTime.trim()} 23:59:59`;
+    }
+  }
+  return request({
+    url: '/index/statistics/watchCourseTrend',
+    method: 'post',
+    data: safeParam
+  })
+}
+
+/**
+ * 课程观看趋势
+ * @returns {*}
+ */
+export function watchEndPlayTrend(param){
+  const safeParam = JSON.parse(JSON.stringify(param));
+
+  if (safeParam.startTime) {
+    const startDate = new Date(safeParam.startTime);
+    if (!isNaN(startDate.getTime())) {
+      safeParam.startTime = `${safeParam.startTime.trim()} 00:00:00`;
+    }
+  }
+
+  if (safeParam.endTime) {
+    const endDate = new Date(safeParam.endTime);
+    if (!isNaN(endDate.getTime())) {
+      safeParam.endTime = `${safeParam.endTime.trim()} 23:59:59`;
+    }
+  }
+  return request({
+    url: '/index/statistics/watchEndPlayTrend',
+    method: 'post',
+    data: safeParam
+  })
+}
+
+/**
+ * 经销商会员观看
+ * @param param
+ * @returns {*}
+ */
+export function deaMemberTopTen(param){
+  const safeParam = JSON.parse(JSON.stringify(param));
+
+  if (safeParam.startTime) {
+    const startDate = new Date(safeParam.startTime);
+    if (!isNaN(startDate.getTime())) {
+      safeParam.startTime = `${safeParam.startTime.trim()} 00:00:00`;
+    }
+  }
+
+  if (safeParam.endTime) {
+    const endDate = new Date(safeParam.endTime);
+    if (!isNaN(endDate.getTime())) {
+      safeParam.endTime = `${safeParam.endTime.trim()} 23:59:59`;
+    }
+  }
+  return request({
+    url: '/index/statistics/deaMemberTopTen',
+    method: 'post',
+    data: safeParam
+  })
+}

+ 303 - 170
src/views/statistics/index.vue

@@ -45,7 +45,6 @@
             </div>
             <div class="card-value highlight">{{memberCount}}</div>
             <div class="card-badge">
-              <i class="el-icon-camera"></i>
             </div>
           </div>
         </el-col>
@@ -116,7 +115,7 @@
     </el-card>
 
     <!-- 分析概览 (Analysis Overview) -->
-    <el-card class="analysis-section" shadow="never">
+    <div class="analysis-section" shadow="never">
       <div slot="header" class="header">
         <span>分析概览</span>
         <div class="tab-group">
@@ -135,85 +134,89 @@
           <el-button size="small" type="primary">刷新</el-button>
         </div>
       </div>
-
+    </div>
+    <div>
       <el-row :gutter="20">
-        <el-col :span="6">
-          <div class="analysis-card">
-            <div class="card-icon"><i class="el-icon-monitor"></i></div>
-            <div class="card-content">
-              <div class="card-row">
-                <span>观看人数</span>
-                <span class="highlight">{{watchUserCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>完播人数</span>
-                <span class="highlight">{{completedUserCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>完播率</span>
-                <span class="highlight">{{completedRate}}%</span>
+        <el-col :span="12" style="position: relative">
+          <div class="analysis-card-check" :class="selectedDiv===0?'analysis-card-check-selected color':''" @click="handleToggleDiv(0)">
+            <div class="analysis-card">
+              <div class="card-icon"><i class="el-icon-monitor"></i></div>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>观看人数</span>
+                  <span class="highlight">{{watchUserCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>完播人数</span>
+                  <span class="highlight">{{completedUserCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>完播率</span>
+                  <span class="highlight">{{completedRate}}%</span>
+                </div>
               </div>
             </div>
-          </div>
-        </el-col>
-
-        <el-col :span="6">
-          <div class="analysis-card">
-            <div class="card-icon"><i class="el-icon-video-play"></i></div>
-            <div class="card-content">
-              <div class="card-row">
-                <span>观看次数</span>
-                <span class="highlight">{{watchCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>完播次数</span>
-                <span class="highlight">{{completedCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>视频完播率</span>
-                <span class="highlight">{{watchRate}}</span>
+            <div class="analysis-card">
+              <div class="card-icon"><i class="el-icon-video-play"></i></div>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>观看次数</span>
+                  <span class="highlight">{{watchCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>完播次数</span>
+                  <span class="highlight">{{completedCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>视频完播率</span>
+                  <span class="highlight">{{watchRate}}</span>
+                </div>
               </div>
             </div>
           </div>
         </el-col>
 
-        <el-col :span="6">
-          <div class="analysis-card">
-            <div class="card-icon"><i class="el-icon-headset"></i></div>
-            <div class="card-content">
-              <div class="card-row">
-                <span>答题人数</span>
-                <span class="highlight">{{answerMemberCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>正确人数</span>
-                <span class="highlight">{{correctUserCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>正确率</span>
-                <span class="highlight">{{correctRate}}%</span>
+        <el-col :span="6" style="position: relative">
+          <div class="analysis-card-check" :class="selectedDiv===1?'analysis-card-check-selected color':''"  @click="handleToggleDiv(1)">
+            <div class="analysis-card">
+              <div class="card-icon"><i class="el-icon-headset"></i></div>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>答题人数</span>
+                  <span class="highlight">{{answerMemberCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>正确人数</span>
+                  <span class="highlight">{{correctUserCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>正确率</span>
+                  <span class="highlight">{{correctRate}}%</span>
+                </div>
               </div>
             </div>
           </div>
         </el-col>
 
-        <el-col :span="6">
-          <div class="analysis-card">
-            <div class="card-icon"><i class="el-icon-present"></i></div>
-            <div class="card-content">
-              <div class="card-row">
-                <span>答题红包个数</span>
-                <span class="highlight">{{rewardCount}}</span>
-              </div>
-              <div class="card-row">
-                <span>答题红包金额(元)</span>
-                <span class="highlight">{{rewardMoney}}</span>
+        <el-col :span="6" style="position: relative">
+          <div class="analysis-card-check" :class="selectedDiv===2?'analysis-card-check-selected color':''"  @click="handleToggleDiv(2)">
+            <div class="analysis-card">
+              <div class="card-icon"><i class="el-icon-present"></i></div>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>答题红包个数</span>
+                  <span class="highlight">{{rewardCount}}</span>
+                </div>
+                <div class="card-row">
+                  <span>答题红包金额(元)</span>
+                  <span class="highlight">{{rewardMoney}}</span>
+                </div>
               </div>
             </div>
           </div>
         </el-col>
       </el-row>
-    </el-card>
+    </div>
 
     <!-- 图表区域 (Charts Area) -->
     <el-row :gutter="20" class="charts-section">
@@ -242,9 +245,9 @@
           <div slot="header" class="chart-header">
             <span>经销商会员观看TOP10</span>
             <div class="legend">
-              <el-radio-group v-model="viewerType" size="small">
-                <el-radio-button label="viewers">按观看人数</el-radio-button>
-                <el-radio-button label="completed">按完播人数</el-radio-button>
+              <el-radio-group v-model="viewerType" size="small" @change="handleDealerChartData">
+                <el-radio-button label="0">按观看人数</el-radio-button>
+                <el-radio-button label="1">按完播人数</el-radio-button>
               </el-radio-group>
             </div>
             <el-button size="small" plain class="view-more">经销商统计 <i class="el-icon-arrow-right"></i></el-button>
@@ -258,15 +261,94 @@
 
 <script>
 import * as echarts from 'echarts'
-import {analysisPreview, authorizationInfo, dealerAggregated, smsBalance} from "@/api/statistics/statistics";
+import {
+  analysisPreview,
+  authorizationInfo,
+  dealerAggregated, deaMemberTopTen,
+  smsBalance,
+  watchCourseTopTen, watchEndPlayTrend
+} from "@/api/statistics/statistics";
 import dayjs from 'dayjs';
+import parallelModel from "echarts/src/coord/parallel/ParallelModel";
+
+
 
+const viewCharOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: '观看人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    },
+    {
+      name: '完播人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#67C23A'
+      }
+    }
+  ]
+}
+const dealerOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'value'
+  },
+  yAxis: {
+    type: 'category',
+    data: []
+  },
+  series: [
+    {
+      name: '观看人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    }
+  ]
+}
 export default {
   name: 'StatisticsDashboard',
   data() {
     return {
       smsRemainCount: 0,
-      viewerType: 'viewers',
+      viewerType: '0',
       viewerChart: null,
       dealerChart: null,
       // 分公司数量
@@ -302,7 +384,10 @@ export default {
       rewardMoney: 0.0,
       queryTime: '今日',
       todayWatchUserCount: 0,
-      versionLimit: 0
+      versionLimit: 0,
+      /// 选中的分析概览
+      selectedDiv: 0
+
     }
   },
   mounted() {
@@ -360,13 +445,35 @@ export default {
         this.versionLimit = res.data.versionLimit;
       }
     })
+    let startTime = this.formatDate(today);
+    let endTime = this.formatDate(today);
+    watchCourseTopTen({...param,type: 0,statisticalType: 0,startTime: startTime,endTime: endTime}).then(res=>{
+      if(res.code === 200){
+        // this.handleAnalysis();
+      }
+    })
+    watchEndPlayTrend({...param,type: 0,statisticalType: 0,startTime: startTime,endTime: endTime}).then(res=>{
+      if(res.code === 200){
+        this.handleViewChartData(res.data)
+      }
+    })
+
+    // 经销商会员观看TOP10
+    deaMemberTopTen({...param,type: 0,statisticalType: 0,startTime: startTime,endTime: endTime}).then(res=>{
+      if(res.code === 200){
+        this.handleDealerChartData(res.data)
+      }
+    })
   },
   methods: {
+    handleToggleDiv(selected){
+      this.selectedDiv = selected;
+    },
     formatDate(date) {
       return dayjs(date).format('YYYY-MM-DD');
     },
-    // 分析概览
-    handleAnalysis(){
+
+    getParam(){
       let param = {
         startTime: '',
         endTime: ''
@@ -374,30 +481,41 @@ export default {
       // 获取当前日期时间
       const today = dayjs();
 
+      let type = 0;
       if (this.queryTime === '今日') {
         param.startTime = this.formatDate(today);
         param.endTime = this.formatDate(today);
+        type = 0;
       } else if (this.queryTime === '昨日') {
         const yesterday = today.subtract(1, 'day');
         param.startTime = this.formatDate(yesterday);
         param.endTime = this.formatDate(yesterday);
+        type = 1;
       } else if (this.queryTime === '本周') {
         param.startTime = this.formatDate(today.startOf('week'));
         param.endTime = this.formatDate(today.endOf('week'));
+        type = 2;
       } else if (this.queryTime === '本月') {
         param.startTime = this.formatDate(today.startOf('month'));
         param.endTime = this.formatDate(today.endOf('month'));
+        type = 3;
       } else if (this.queryTime === '上月') {
         const lastMonth = today.subtract(1, 'month');
         param.startTime = this.formatDate(lastMonth.startOf('month'));
         param.endTime = this.formatDate(lastMonth.endOf('month'));
+        type = 4;
       } else {
-        // 可以添加一个默认处理或错误提示
         console.warn(`未知的 queryTime: ${this.queryTime}, 默认使用今日`);
         param.startTime = this.formatDate(today);
         param.endTime = this.formatDate(today);
       }
+      param.type = type;
+      return param;
+    },
+    // 分析概览
+    handleAnalysis(){
 
+      let param = this.getParam();
       analysisPreview(param).then(res=>{
         if(res.code === 200){
           this.watchUserCount = res.data.watchUserCount;
@@ -412,108 +530,58 @@ export default {
           this.rewardMoney = res.data.rewardMoney;
         }
       })
+
+      this.handleViewChartData()
+
+      this.handleDealerChartData()
+
     },
-    initViewerChart() {
-      this.viewerChart = echarts.init(this.$refs.viewerChart)
+    handleDealerChartData(){
+      let param = this.getParam();
 
-      const option = {
-        tooltip: {
-          trigger: 'axis',
-          axisPointer: {
-            type: 'shadow'
-          }
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true
-        },
-        xAxis: {
-          type: 'category',
-          data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
-        },
-        yAxis: {
-          type: 'value'
-        },
-        series: [
-          {
-            name: '观看人数',
-            type: 'bar',
-            data: [50, 20, 40, 120, 700, 800, 900, 780, 700, 700, 680, 580, 550, 450, 400, 320, 170, 0, 0, 0, 0, 0, 0, 0],
-            itemStyle: {
-              color: '#409EFF'
-            }
-          },
-          {
-            name: '完播人数',
-            type: 'bar',
-            data: [30, 10, 20, 300, 600, 700, 780, 700, 650, 650, 650, 520, 450, 400, 330, 120, 100, 0, 0, 0, 0, 0, 0, 0],
-            itemStyle: {
-              color: '#67C23A'
-            }
-          }
-        ]
-      }
+      // 经销商会员观看TOP10
+      deaMemberTopTen({...param,statisticalType: this.viewerType}).then(res=>{
+        if(res.code === 200){
+          let data = res.data;
+          let companyNameList = data.map(e=>e.companyName);
+          let watchUserList = data.map(e=>e.watchUserCount);
+          dealerOption.yAxis.data = companyNameList;
+          dealerOption.series[0].data = watchUserList;
+
+          this.dealerChart.setOption(dealerOption)
+        }
+      })
 
-      this.viewerChart.setOption(option)
+    },
+    handleViewChartData(){
+      let param = this.getParam();
+
+      watchEndPlayTrend({...param}).then(res=>{
+        if(res.code === 200){
+          let data = res.data;
+          let watchUserCountList = data.map(e=>e.watchUserCount);
+          let completedUserCountList = data.map(e=>e.completedUserCount);
+          let xAxis = data.map(e=>e.x);
+          viewCharOption.series[0].data = watchUserCountList;
+          viewCharOption.series[1].data = completedUserCountList;
+          viewCharOption.xAxis.data = xAxis;
+
+          this.viewerChart.setOption(viewCharOption);
+        }
+      })
+
+    },
+    initViewerChart() {
+      this.viewerChart = echarts.init(this.$refs.viewerChart)
+      this.viewerChart.setOption(viewCharOption)
     },
     initDealerChart() {
       this.dealerChart = echarts.init(this.$refs.dealerChart)
 
-      const option = {
-        tooltip: {
-          trigger: 'axis',
-          axisPointer: {
-            type: 'shadow'
-          }
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true
-        },
-        xAxis: {
-          type: 'value'
-        },
-        yAxis: {
-          type: 'category',
-          data: ['七彩公司', '二级经销商A', '内蒙七彩', '呼和浩特分公司', '呼和浩特经销商', '海南经销', '重庆市分公司', '东方分销商', '银田分公司', '重庆一分销']
-        },
-        series: [
-          {
-            name: '观看人数',
-            type: 'bar',
-            data: [2780, 1050, 650, 600, 500, 350, 260, 230, 180, 120],
-            itemStyle: {
-              color: '#409EFF'
-            }
-          }
-        ]
-      }
-
-      this.dealerChart.setOption(option)
-    }
-  },
-  watch: {
-    viewerType(newVal) {
-      if (newVal === 'viewers') {
-        this.dealerChart.setOption({
-          series: [{
-            data: [2780, 1050, 650, 600, 500, 350, 260, 230, 180, 120]
-          }]
-        })
-      } else {
-        this.dealerChart.setOption({
-          series: [{
-            name: '完播人数',
-            data: [2500, 980, 620, 580, 480, 320, 240, 210, 160, 100]
-          }]
-        })
-      }
+      this.dealerChart.setOption(dealerOption)
     }
   },
+
   beforeDestroy() {
     window.removeEventListener('resize', this.resizeHandler)
     this.viewerChart && this.viewerChart.dispose()
@@ -632,11 +700,9 @@ export default {
 }
 
 .analysis-card {
-  background-color: #fff;
   border-radius: 4px;
   padding: 20px;
   display: flex;
-  box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
 }
 
 .card-icon {
@@ -653,13 +719,29 @@ export default {
 }
 
 .card-content {
-  flex: 1;
+  display: flex;
 }
 
 .card-row {
   display: flex;
-  justify-content: space-between;
-  margin-bottom: 10px;
+  justify-content: center;
+  justify-items: center;
+  flex-direction: column;
+  padding: 10px;
+  .highlight{
+    text-align: center;
+    margin-top: 1em;
+
+    font-family: BebasNeue;
+    color: #1677ff;
+    font-size: 26px;
+    line-height: 42px;
+    font-weight: 400;
+    margin-top: 8px;
+  }
+  font-size: 15px;
+  color: #000;
+
 }
 
 .charts-section {
@@ -706,4 +788,55 @@ export default {
   height: 350px;
   width: 100%;
 }
+.analysis-card-check{
+  display: flex;
+  flex-direction: row;
+  border: 1px solid transparent;
+  background-color: #fff;
+  border-radius: 4px;
+}
+.analysis-card-check:hover{
+  cursor: pointer;
+}
+.analysis-card-check-selected:after{
+  content: "";
+  display: block;
+  border-width: 15px;
+  position: absolute;
+  bottom: -30px;
+  left: 50%;
+  margin-left: -32px;
+  border-style: solid dashed dashed solid;
+  border-color: #4592FF transparent transparent transparent;
+  font-size: 0;
+  line-height: 0;
+  z-index:1;
+}
+.analysis-card-check-selected:before{
+  content: "";
+  display: block;
+  border-width: 15px;
+  position: absolute;
+  bottom: -30px;
+  left: 50%;
+  margin-left: -32px;
+  border-style: solid dashed dashed solid;
+  border-color: #4592FF transparent transparent transparent;
+  font-size: 0;
+  line-height: 0;
+  z-index:1;
+}
+.analysis-card-check-selected{
+  border: 1px solid #4592FF;
+  background-color: #e7f1ff;
+}
+.color{
+  position: relative;
+  border: 1px solid #4592FF;
+  background-color: #e7f1ff;
+}
+.color:after {
+  bottom: -27px;
+  border-color: #E7F1FF transparent transparent transparent;
+}
 </style>