zxl
2025-10-23 5a80a60227011398c8fe306d4adcdd09297d21e2
manager/src/views/statistics/order.vue
@@ -5,6 +5,7 @@
        <affixTime @selected="clickBreadcrumb" />
      </Card>
    </Affix>
    <Card class="card">
        <div class="chart-wrapper">
          <div class="chart-header">
@@ -17,7 +18,7 @@
      <div class="my-chart-container">
        <div class="chart-wrapper" style="height: 800px">
          <div class="chart-header">
            <h2>商品/视频浏览量完播率 趋势图</h2>
            <h2>商品/视频浏览量完播率 排名图</h2>
          </div>
          <div class="button-group-wrapper">
            <!-- 第一组:商品/视频(靠左) -->
@@ -72,7 +73,6 @@
        </div>
      </div>
    </Card>
    <Card class="card">
      <div class="my-chart-container">
        <div class="chart-wrapper">
@@ -82,7 +82,40 @@
          <div ref="orderTimePeriodChartDom" class="chart-container"></div>
        </div>
      </div>
    </Card>
    <Card class="card">
      <div class="my-chart-container">
        <div class="chart-wrapper" style="height: 800px">
          <div class="chart-header">
            <h2>商品复购率 排名图</h2>
          </div>
          <div class="button-group-wrapper">
            <!-- 页面样式需要 -->
            <div></div>
            <ButtonGroup>
              <Button
                :type="repurchaseCurrentLimit === 10 ? 'success' : 'default'"
                @click="handleRepurchaseLimitChange(10)"
              >
                前10
              </Button>
              <Button
                :type="repurchaseCurrentLimit === 20 ? 'success' : 'default'"
                @click="handleRepurchaseLimitChange(20)"
              >
                前20
              </Button>
              <Button
                :type="repurchaseCurrentLimit === 30 ? 'success' : 'default'"
                @click="handleRepurchaseLimitChange(30)"
              >
                前30
              </Button>
            </ButtonGroup>
          </div>
          <div ref="productRepurchaseRateChartDom" class="repurchase-chart-container"></div>
        </div>
      </div>
    </Card>
@@ -284,7 +317,7 @@
import refundRow from "./order/refundOrder";
import affixTime from "@/components/affix-time";
import * as echarts from 'echarts';
import {pvUvData,getOrderCount,getViewAndCompletionRateCount,getOrderTimePeriod} from "../../api/orderStatistics";
import {pvUvData,getOrderCount,getViewAndCompletionRateCount,getOrderTimePeriod,gerProductRepurchase} from "../../api/orderStatistics";
export default {
  components: { orderRow, refundRow, affixTime },
@@ -294,11 +327,16 @@
      // 图表实例
      chart: null, //pvuv
      orderCountChart:null, //订单日趋势
      viewPrintChart:null,
      orderTimePeriodChart:null,
      viewPrintChart:null, //完播率
      orderTimePeriodChart:null, //订单/浏览时间
      productRepurchaseRateChart:null,//商品复购率
      currentType:"goods",
      currentLimit:10,
      repurchaseCurrentLimit:10,
      // 统计数据
      orderOrRefund: 1, // 订单还是退单
@@ -621,8 +659,6 @@
     const dates = [];
     const today = new Date();
     let days = 1;
     console.log(param.year)
     console.log(param.month)
     if(param.year !== null && param.year !== undefined && param.month !== null && param.month !== undefined && param.month !=='' ){
       // 当传入年份和月份时,生成该月份的所有日期
       const year = parseInt(param.year);
@@ -672,28 +708,34 @@
      if (this.orderTimePeriodChart){
        this.orderTimePeriodChart.resize();
      }
      if (this.productRepurchaseRateChart){
        this.productRepurchaseRateChart.resize();
      }
    },
    initChart(){
      this.chart = echarts.init(this.$refs.chartDom)
      this.viewPrintChart = echarts.init(this.$refs.viewPrintChartDom)
      this.orderCountChart = echarts.init(this.$refs.orderCountChartDom)
      this.orderTimePeriodChart = echarts.init(this.$refs.orderTimePeriodChartDom)
      this.productRepurchaseRateChart = echarts.init(this.$refs.productRepurchaseRateChartDom)
      this.updateChartData(this.orderParams)
      this.updateOrderCountChartDate(this.orderParams)
      this.updateChartData(this.orderParams)//更新 pvuv
      let form = {...this.orderParams};
      console.log(this.currentType)
      console.log(this.currentLimit)
      form.currentType = this.currentType;
      form.currentLimit = this.currentLimit;
      console.log(form)
      this.updateViewAndCompletionRateData(form)
      this.updateOrderCountChartDate(this.orderParams)//更新日订单
      this.updateOrderTimePeriodData(this.orderParams)
      let viewForm = {...this.orderParams};
      viewForm.currentType = this.currentType;
      viewForm.currentLimit = this.currentLimit;
      this.updateViewAndCompletionRateData(viewForm)//更新完播率
      this.updateOrderTimePeriodData(this.orderParams)//更新浏览数据,下订单日期时间段分析
      let productRepurchaseDataForm ={...this.orderParams};
      productRepurchaseDataForm.currentLimit = this.repurchaseCurrentLimit
      this.updateProductRepurchaseData(productRepurchaseDataForm)//
    },
    // 更新图表数据
    //------------更新图表数据pvuv start
    async updateChartData(param) {
      // 生成日期和PV数据
      const { pvData ,uvData} = await this.generateChartData(param)
@@ -851,8 +893,8 @@
      // 3. 此时pvData和uvData已被接口数据填充,再返回
      return { pvData, uvData };
    },
    //-------------
    //-------------订单日趋势
    //-------------end
    //-------------订单日趋势start
    async updateOrderCountChartDate(param){
     const { orderCountData } = await this.generateOrderCountChartData(param)
      this.orderCountChart.setOption(this.getOrderCountChartOption(this.getDates(param),orderCountData))
@@ -954,9 +996,9 @@
        animationEasing: 'cubicOut' // 缓动效果,优化动画流畅度
      };
    },
    //-------------
    //-------------end
    //-------------浏览量,完播率,
    //-------------浏览量,完播率,start
    handleLimitChange(limit) {
      if (this.currentLimit !== limit) {
        this.currentLimit = limit
@@ -1028,7 +1070,7 @@
        grid: {
          left: '4%', // 视频类型左移,给完播率标签留空间
          right: '12%',
          bottom: '0',
          bottom: '2%',
          top: '5%',
          containLabel: true
        },
@@ -1043,6 +1085,7 @@
          min: 0
        },
        yAxis: {
          inverse: true,
          type: 'category',
          data: yData,
          axisLine: { lineStyle: { color: '#ddd' } },
@@ -1090,8 +1133,8 @@
        ]
      };
    },
    //-------------
    //-------------浏览数据,下订单日期时间段分析
    //-------------end
    //-------------浏览数据,下订单日期时间段分析start
    async updateOrderTimePeriodData(param){
     const { viewData,countData,dateData} = await this.generateOrderTimePeriodChartData(param);
      this.orderTimePeriodChart.setOption(this.getOrderTimePeriodChartOption(viewData,countData,dateData));
@@ -1243,7 +1286,141 @@
        animationEasing: 'cubicOut'
      };
    },
    //--------------ebd
    //-------------复购率 start
    handleRepurchaseLimitChange(limit) {
      if (this.repurchaseCurrentLimit !== limit) {
        this.repurchaseCurrentLimit = limit
        let form = {...this.orderParams}
        form.currentLimit = this.repurchaseCurrentLimit;
        this.updateProductRepurchaseData(form) // 重新加载数据
      }
    },
    async updateProductRepurchaseData(param){
      const { rateData,goodsData} = await this.generateProductRepurchaseChartData(param);
      this.productRepurchaseRateChart.setOption(this.getProductRepurchaseChartOption(this.getDates(param),rateData,goodsData));
    },
    async generateProductRepurchaseChartData(param){
      let rateData = [];
      let goodsData = [];
      try{
        const res =  await gerProductRepurchase(param);
        if (res.code === 200){
          rateData = res.data.rateData;
          goodsData = res.data.goodsData;
        }
      }catch (error){
        console.error("接口调用失败", error);
      }
      return {rateData,goodsData}
    },
    getProductRepurchaseChartOption(dates, rateData, goodsData) {
      // 工具函数:判断数值是否为整数(避免100.00显示为100.00%)
      const isInteger = (num) => {
        return Math.abs(num - Math.round(num)) < Number.EPSILON;
      };
      return {
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(255, 255, 255, 0.9)',
          borderColor: '#eee',
          borderWidth: 1,
          textStyle: { color: '#333' },
          axisPointer: {
            type: 'shadow'
          },
          formatter: (params) => {
            const goodsName = params[0].name;
            const rate = params[0].value;
            // 整数显示无小数,非整数保留两位小数
            const displayRate = isInteger(rate) ? rate : rate.toFixed(2);
            return `<div class="font-medium">${goodsName}</div>
            <div>复购率: <span style="color: #722ED1; font-weight: bold">${displayRate}%</span></div>`;
          },
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          top: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'value',
          axisLine: { show: false },
          axisTick: { show: false },
          axisLabel: {
            color: '#86909C',
            // 坐标轴标签:整数显示无小数,非整数保留0位(取整)
            formatter: (value) => {
              return isInteger(value) ? `${value}%` : `${Math.round(value)}%`;
            }
          },
          splitLine: {
            lineStyle: {
              color: '#f2f3f5',
              type: 'dashed'
            }
          },
          min: 0,
          max: (value) => {
            // 限制最大值不超过100(复购率最高100%),同时保留1.2倍的间距
            const calculatedMax = value.max * 1.2;
            return Math.min(calculatedMax, 100);
          }
        },
        yAxis: {
          type: 'category',
          data: goodsData,
          axisLine: { lineStyle: { color: '#eee' } },
          axisTick: { show: false },
          axisLabel: {
            color: '#86909C',
            interval: 0,
            formatter: (value) => {
              return value.length > 10 ? value.substring(0, 10) + '...' : value;
            }
          },
          splitLine: { show: false },
          inverse: true
        },
        series: [
          {
            name: '商品复购率',
            type: 'bar',
            data: rateData,
            barWidth: '60%',
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                { offset: 0, color: '#722ED1' },
                { offset: 1, color: '#EB2F96' }
              ]),
              borderRadius: [0, 4, 4, 0]
            },
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowColor: 'rgba(114, 46, 209, 0.5)'
              }
            },
            label: {
              show: true,
              position: 'right',
              // 柱状图标签:整数显示无小数,非整数保留1位
              formatter: (params) => {
                const value = params.value;
                return isInteger(value) ? `${value}%` : value.toFixed(1) + '%';
              },
              color: '#722ED1',
              fontWeight: 'bold'
            }
          }
        ],
      };
    },
    //-------------end
    formatDate(date) {
      const month = date.getMonth() + 1; // 月份从0开始,需+1
      const day = date.getDate();
@@ -1310,6 +1487,7 @@
      this.refundParams.pageSize = 10
      //更新表格
      this.updateChartData(this.orderParams)
      this.updateOrderCountChartDate(this.orderParams)
@@ -1319,6 +1497,11 @@
      this.updateViewAndCompletionRateData(form)
      this.updateOrderTimePeriodData(this.orderParams)
      let productRepurchaseDataForm ={...this.orderParams};
      productRepurchaseDataForm.currentLimit = this.repurchaseCurrentLimit
      this.updateProductRepurchaseData(productRepurchaseDataForm)//
    },
    // 实例化订单概览
@@ -1723,6 +1906,10 @@
  width: 100%;
  height: 662px;
}
.repurchase-chart-container{
  width: 100%;
  height: 662px;
}
.chart-container {
  width: 100%;
  height: 400px;