浏览代码

首页统计

xdd 1 月之前
父节点
当前提交
f9565543b3
共有 2 个文件被更改,包括 308 次插入81 次删除
  1. 57 0
      src/api/statistics/statistics.js
  2. 251 81
      src/views/statistics/index.vue

+ 57 - 0
src/api/statistics/statistics.js

@@ -203,3 +203,60 @@ export function watchCourseTopTen(param){
     data: safeParam
   })
 }
+
+
+/**
+ * 答题红包金额TOP10
+ * @returns {*}
+ */
+export function rewardMoneyTopTen(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/rewardMoneyTopTen',
+    method: 'post',
+    data: safeParam
+  })
+}
+
+/**
+ * 答题红包金额趋势
+ * @returns {*}
+ * @param param
+ * @returns {*}
+ */
+export function rewardMoneyTrend(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/rewardMoneyTrend',
+    method: 'post',
+    data: safeParam
+  })
+}

+ 251 - 81
src/views/statistics/index.vue

@@ -209,44 +209,48 @@
     </div>
 
     <!-- 图表区域 (Charts Area) -->
-    <el-row :gutter="20" class="charts-section">
-      <el-col :span="12">
-        <el-card shadow="never">
-          <div slot="header" class="chart-header">
-            <span>会员观看、完播人数趋势图</span>
-            <div class="legend">
-              <div class="legend-item">
-                <span class="dot viewer-dot"></span>
-                <span>观看人数</span>
-              </div>
-              <div class="legend-item">
-                <span class="dot complete-dot"></span>
-                <span>完播人数</span>
+    <transition name="fade">
+      <el-row :gutter="20" class="charts-section" v-show="selectedDiv===0">
+        <el-col :span="12">
+          <el-card shadow="never">
+            <div slot="header" class="chart-header">
+              <span>会员观看、完播人数趋势图</span>
+              <div class="legend">
+                <div class="legend-item">
+                  <span class="dot viewer-dot"></span>
+                  <span>观看人数</span>
+                </div>
+                <div class="legend-item">
+                  <span class="dot complete-dot"></span>
+                  <span>完播人数</span>
+                </div>
               </div>
+              <el-button size="small" plain class="view-more">平台每日统计 <i class="el-icon-arrow-right"></i></el-button>
             </div>
-            <el-button size="small" plain class="view-more">平台每日统计 <i class="el-icon-arrow-right"></i></el-button>
-          </div>
-          <div ref="viewerChart" class="chart-container"></div>
-        </el-card>
-      </el-col>
+            <div ref="viewerChart" class="chart-container"></div>
+          </el-card>
+        </el-col>
 
-      <el-col :span="12">
-        <el-card shadow="never">
-          <div slot="header" class="chart-header">
-            <span>经销商会员观看TOP10</span>
-            <div class="legend">
-              <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>
+        <el-col :span="12">
+          <el-card shadow="never">
+            <div slot="header" class="chart-header">
+              <span>经销商会员观看TOP10</span>
+              <div class="legend">
+                <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>
             </div>
-            <el-button size="small" plain class="view-more">经销商统计 <i class="el-icon-arrow-right"></i></el-button>
-          </div>
-          <div ref="dealerChart" class="chart-container"></div>
-        </el-card>
-      </el-col>
-    </el-row>
-    <el-card shadow="never">
+            <div ref="dealerChart" class="chart-container"></div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </transition>
+    <transition name="fade">
+    <el-row>
+    <el-card shadow="never"  v-show="selectedDiv===1">
       <div slot="header" class="chart-header">
         <span>经销商会员观看TOP10</span>
         <div class="legend">
@@ -285,14 +289,17 @@
       </div>
       <div ref="courseWatchChart" class="chart-container"></div>
     </el-card>
+    </el-row>
+    </transition>
 
-    <el-row :gutter="20" class="charts-section">
+    <transition name="fade">
+    <el-row :gutter="20" class="charts-section" v-show="selectedDiv===2">
       <el-col :span="12">
         <el-card shadow="never">
           <div slot="header" class="chart-header">
             <span>答题红包金额TOP10</span>
             <div class="legend">
-              <el-radio-group v-model="viewerType" size="small" @change="handleDealerChartData">
+              <el-radio-group v-model="dataType" size="small" @change="handleAnswerRedPackViewerChart">
                 <el-radio-button label="0">按经销商排行</el-radio-button>
                 <el-radio-button label="1">按课程排行</el-radio-button>
               </el-radio-group>
@@ -302,7 +309,6 @@
           <div ref="answerRedPackViewerChart" class="chart-container"></div>
         </el-card>
       </el-col>
-
       <el-col :span="12">
         <el-card shadow="never">
           <div slot="header" class="chart-header">
@@ -312,13 +318,14 @@
                 <span class="dot viewer-dot"></span>
                 <span>答题红包金额</span>
               </div>
+          </div>
             <el-button size="small" plain class="view-more">红包记录 <i class="el-icon-arrow-right"></i></el-button>
           </div>
           <div ref="answerRedPackMoneyViewerChart" class="chart-container"></div>
-          </div>
         </el-card>
       </el-col>
     </el-row>
+    </transition>
   </div>
 </template>
 
@@ -327,13 +334,11 @@ import * as echarts from 'echarts'
 import {
   analysisPreview,
   authorizationInfo,
-  dealerAggregated, deaMemberTopTen,
+  dealerAggregated, deaMemberTopTen, rewardMoneyTopTen, rewardMoneyTrend,
   smsBalance,
   watchCourseTopTen, watchEndPlayTrend
 } from "@/api/statistics/statistics";
 import dayjs from 'dayjs';
-import parallelModel from "echarts/src/coord/parallel/ParallelModel";
-
 
 
 const viewCharOption = {
@@ -475,10 +480,136 @@ const courseWatchOption = {
     }
   ]
 }
+
+const lineChartOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross' // 改为 'cross' 更适合折线图
+    }
+    // 你可能想要自定义 tooltip 的 formatter 来显示时间和金额
+    // formatter: function (params) {
+    //   const point = params[0];
+    //   const date = new Date(point.value[0]);
+    //   // 自定义时间格式
+    //   const formattedTime = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
+    //   return `${point.seriesName}<br/>${formattedTime} : ${point.value[1]} 元`;
+    // }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '8%', // 如果x轴标签旋转,可能需要更大的 bottom
+    top: '5%',    // 增加一点顶部空间给可能的 Y 轴名称
+    containLabel: true
+  },
+  xAxis: {
+    type: 'time', // X轴类型改为 'time'
+    // data: [], // 时间轴不需要单独设置 data,数据在 series 中提供
+    axisLabel: {
+      // interval: 0, // 时间轴通常自动处理间隔,可以先移除或注释掉
+      rotate: 30,   // 保留旋转,如果标签可能重叠
+      fontSize: 10,
+      // width: 100, // width 和 overflow 对于时间轴可能行为不同,按需调整
+      // overflow: 'truncate',
+      formatter: null // ECharts 会自动格式化时间,如需特定格式可用 function 或字符串模板
+      // 例如: formatter: '{yyyy}-{MM}-{dd}\n{HH}:{mm}'
+    }
+  },
+  yAxis: {
+    type: 'value',
+    name: '金额 (元)', // 添加 Y 轴名称
+    nameLocation: 'end', // 名称位置
+    nameTextStyle: {
+      align: 'right',
+      padding: [0, 10, 0, 0] // 调整名称与轴线的距离
+    },
+    splitLine: {
+      lineStyle: {
+        type: 'dashed'
+      }
+    },
+    axisLabel: {
+      formatter: '{value} 元' // 可选:给 Y 轴刻度添加单位
+    }
+  },
+  series: [
+    {
+      name: '答题红包金额',
+      type: 'line', // 系列类型改为 'line'
+      // data: [],  // 数据格式需要是 [[时间1, 金额1], [时间2, 金额2], ...]
+      // 时间可以是时间戳 (毫秒), 'YYYY-MM-DD HH:mm:ss' 格式字符串, 或者 Date 对象
+      // 例如: [['2023-10-26 08:00:00', 120], ['2023-10-26 09:00:00', 200]]
+      data: [
+        // 示例数据,你需要用实际数据替换
+        // ['2024-01-01 10:00:00', 5.5],
+        // ['2024-01-01 11:00:00', 8.2],
+        // ['2024-01-02 09:30:00', 6.0],
+        // ['2024-01-03 14:00:00', 10.8],
+      ],
+      itemStyle: { // 控制数据点(标记)的样式
+        color: '#409EFF'
+      },
+      lineStyle: { // 控制线的样式
+        color: '#409EFF'
+      },
+      smooth: false, // 是否平滑曲线,可设为 true
+      symbol: 'circle', // 数据点标记形状,'emptyCircle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
+      symbolSize: 4   // 数据点标记大小
+    }
+  ]
+};
+
+
+const redPackageOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '8%',
+    top: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: [],
+    axisLabel: {
+      interval: 0,
+      rotate: 30,
+      fontSize: 10,
+      width: 100,
+      overflow: 'truncate'
+    }
+  },
+  yAxis: {
+    type: 'value',
+    splitLine: {
+      lineStyle: {
+        type: 'dashed'
+      }
+    }
+  },
+  series: [
+    {
+      name: '答题红包金额',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    }
+  ]
+}
 export default {
   name: 'StatisticsDashboard',
   data() {
     return {
+      dataType: '0',
       delerSort: 'DESC',
       smsRemainCount: 0,
       viewerType: '0',
@@ -520,8 +651,9 @@ export default {
       versionLimit: 0,
       /// 选中的分析概览
       selectedDiv: 0,
-      filterType: 0
-
+      filterType: 0,
+      answerRedPackViewerChart: null,
+      answerRedPackMoneyViewerChart: null
     }
   },
   mounted() {
@@ -529,6 +661,8 @@ export default {
       this.initViewerChart()
       this.initDealerChart()
       this.initCourseWatchChart();
+      this.initAnswerRedPackViewerChart();
+      this.initAnswerRedPackMoneyViewerChart();
 
       // 监听窗口大小变化,重新渲染图表
       window.addEventListener('resize', () => {
@@ -580,31 +714,41 @@ 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();
-        this.handleCourseWatchChart(res.data)
-      }
-    })
-    watchEndPlayTrend({...param,type: 0,statisticalType: 0,startTime: startTime,endTime: endTime}).then(res=>{
-      if(res.code === 200){
-        this.handleViewChartData(res.data)
-      }
-    })
+
+    this.handleCourseWatchChart()
+    this.handleViewChartData()
 
     // 经销商会员观看TOP10
-    deaMemberTopTen({...param,type: 0,statisticalType: 0,startTime: startTime,endTime: endTime}).then(res=>{
-      if(res.code === 200){
-        this.handleDealerChartData(res.data)
-      }
-    })
+    this.handleDealerChartData()
+
+    this.handleAnswerRedPackViewerChart()
+
+    this.handleAnswerRedPackMoneyViewerChart()
 
   },
   methods: {
     handleToggleDiv(selected){
       this.selectedDiv = selected;
+
+      if (selected === 1) {
+        this.$nextTick(() => {
+          if (this.courseWatchChart) {
+            this.courseWatchChart.resize();
+          } else {
+          }
+        });
+      }
+      else if (selected === 0) {
+        this.$nextTick(() => {
+          if (this.viewerChart) this.viewerChart.resize();
+          if (this.dealerChart) this.dealerChart.resize();
+        });
+      } else if (selected === 2) {
+        this.$nextTick(() => {
+          if (this.answerRedPackViewerChart) this.answerRedPackViewerChart.resize();
+          if (this.answerRedPackMoneyViewerChart) this.answerRedPackMoneyViewerChart.resize();
+        });
+      }
     },
     formatDate(date) {
       return dayjs(date).format('YYYY-MM-DD');
@@ -651,7 +795,7 @@ export default {
       return param;
     },
     // 分析概览
-    handleAnalysis(){
+    handleAnalysis(e){
 
       let param = this.getParam();
       analysisPreview(param).then(res=>{
@@ -669,30 +813,46 @@ export default {
         }
       })
 
-      this.handleViewChartData()
-
-      this.handleDealerChartData()
-
-      this.handleCourseWatchChart()
-
+      if(this.selectedDiv === 0){
+        this.handleViewChartData()
+        this.handleDealerChartData()
+      } else if(this.selectedDiv === 1) {
+        this.handleCourseWatchChart()
+      } else if(this.selectedDiv === 2) {
+        this.handleAnswerRedPackViewerChart()
+        this.handleAnswerRedPackMoneyViewerChart()
+      }
     },
     handleAnswerRedPackViewerChart(){
       let param = this.getParam();
-      param = {...param,statisticalType:this.viewerType};
-      watchCourseTopTen(param).then(res=>{
+      param = {...param,statisticalType:this.viewerType,dataType: this.dataType};
+      rewardMoneyTopTen(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 answerUserCountList = data.map(e=>e.answerUserCount);
-          let correctUserCountList = data.map(e=>e.correctUserCount);
-          let courseNameList = data.map(e=>e.courseName);
-          courseWatchOption.xAxis.data = courseNameList;
-          courseWatchOption.series[0].data = watchUserCountList;
-          courseWatchOption.series[1].data = completedUserCountList;
-          courseWatchOption.series[2].data = answerUserCountList;
-          courseWatchOption.series[3].data = correctUserCountList;
-          this.courseWatchChart.setOption(courseWatchOption)
+          let companyNameList = data.map(e=>e.companyName)
+          let courseNameList = data.map(e=>e.courseName)
+          let rewardMoneyList = data.map(e=>e.rewardMoney)
+          if(this.dataType === '0'){
+            redPackageOption.xAxis.data = companyNameList;
+          }else{
+            redPackageOption.xAxis.data = courseNameList;
+          }
+          redPackageOption.series[0].data = rewardMoneyList;
+
+          this.answerRedPackViewerChart.setOption(redPackageOption)
+        }
+      })
+    },
+    handleAnswerRedPackMoneyViewerChart(){
+      let param = this.getParam();
+      param = {...param,statisticalType:this.viewerType,dataType: this.dataType};
+      rewardMoneyTrend(param).then(res=>{
+        if(res.code === 200){
+          let data = res.data;
+          let option = data.map(e=>[e.x,e.rewardMoney])
+          lineChartOption.series[0].data = option;
+
+          this.answerRedPackMoneyViewerChart.setOption(lineChartOption)
         }
       })
     },
@@ -765,6 +925,16 @@ export default {
 
       this.courseWatchChart.setOption(courseWatchOption)
     },
+    initAnswerRedPackViewerChart(){
+      this.answerRedPackViewerChart = echarts.init(this.$refs.answerRedPackViewerChart)
+
+      this.answerRedPackViewerChart.setOption(redPackageOption)
+    },
+    initAnswerRedPackMoneyViewerChart(){
+      this.answerRedPackMoneyViewerChart = echarts.init(this.$refs.answerRedPackMoneyViewerChart)
+
+      this.answerRedPackMoneyViewerChart.setOption(lineChartOption)
+    }
   },
 
   beforeDestroy() {