8fde755dd2a8b2fcd99483a5b603974c9df95fe5..18f2f183b1b50f36e810dad2c8c7aebd69366bcb
6 小时以前 zxl
会员二维码跳转绑定,列表显示
18f2f1 对比 | 目录
12 小时以前 zxl
订单页面统计图
292ee9 对比 | 目录
14 小时以前 zxl
订单页面统计图
3827a9 对比 | 目录
4个文件已修改
755 ■■■■ 已修改文件
manager/src/api/orderStatistics.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/member/list/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/seller/shop/shopList.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/views/statistics/order.vue 659 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manager/src/api/orderStatistics.jsx
@@ -7,3 +7,25 @@
    params: param
  })
}
export const getOrderCount = (param) =>{
  return service({
    url:"/lmk/statistics/orderCount",
    method: "GET",
    params: param
  })
}
export const getViewAndCompletionRateCount = (param) =>{
  return service({
    url:"/lmk/statistics/viewAndCompletionRateCount",
    method: "GET",
    params: param
  })
}
export const getOrderTimePeriod = (param) =>{
  return service({
    url:"/lmk/statistics/orderTimePeriod",
    method: "GET",
    params: param
  })
}
manager/src/views/member/list/index.vue
@@ -212,6 +212,11 @@
          },
        },
        {
          title: "绑定店铺",
          key: "bindStoreName",
          tooltip: true,
        },
        {
          title: "操作",
          key: "action",
          align: "center",
manager/src/views/seller/shop/shopList.vue
@@ -42,6 +42,27 @@
        <Page :current="searchForm.pageNumber" :total="total" :page-size="searchForm.pageSize" @on-change="changePage" @on-page-size-change="changePageSize" :page-size-opts="[10, 20, 50]"
          size="small" show-total show-elevator show-sizer></Page>
      </Row>
      <Modal
        v-model="showGeneralQrCode"
        title="二维码"
        width="800"
        :mask-closable="false"
        :loading="codeLoading"
      >
        <vue-qr
          :text="QRCodeUrl"
          :margin="0"
          colorDark="#000"
          colorLight="#fff"
          :size="150"
        ></vue-qr>
        <div slot="footer">
          <Button type="text" @click="closeGeneralQrCode">关闭</Button>
          <!--          <Button type="primary" @click="generalQrCode">确认</Button>-->
        </div>
      </Modal>
    </Card>
  </div>
</template>
@@ -53,10 +74,20 @@
  enableBrand,
  shopAudit,
} from "@/api/shops";
import vueQr from "vue-qr";
export default {
  components:{
    "vue-qr": vueQr,
  },
  name: "shop",
  data() {
    return {
      QRCodeUrl:"",
      showGeneralQrCode:false,
      codeLoading:false,
      codeUrl: this.QRcodeBaseUrl+ '/scanpage/my',
      loading: true, // 表单加载状态
      searchForm: {
        // 搜索框初始化对象
@@ -148,6 +179,7 @@
          fixed: "right",
          render: (h, params) => {
            let enableOrDisable = "";
            let qrCodeButton = "";
            if (params.row.storeDisable == "OPEN") {
              enableOrDisable = h(
                "Button",
@@ -165,8 +197,28 @@
                    },
                  },
                },
                "关闭"
                "关闭",
              );
              qrCodeButton = h(
                "Button",
                {
                  props: {
                    type: "warning",
                    size: "small",
                    ghost: true
                  },
                  style: {
                    marginRight: "5px",
                  },
                  on: {
                    click: () => {
                      this.generalQrCode(params.row);
                    },
                  },
                },
                "二维码"
              );
            } else if (params.row.storeDisable == "CLOSED") {
              enableOrDisable = h(
                "Button",
@@ -224,6 +276,7 @@
                  },
                  "修改"
                ),
              ]);
            }
@@ -284,7 +337,9 @@
                },
                "修改"
              ),
              enableOrDisable,
              qrCodeButton,
            ]);
          },
        },
@@ -296,6 +351,18 @@
  },
  methods: {
    closeGeneralQrCode(){
      this.showGeneralQrCode = false;
      this.QRCodeUrl = '';
    },
    generalQrCode(row){
      this.QRCodeUrl = '';
      this.showGeneralQrCode = true
      this.codeLoading = true;
      this.QRCodeUrl = this.codeUrl + "?shareStoreId="+ row.id;
    },
    // 回调给父级
    callback(val) {
      this.$emit("callback", val);
manager/src/views/statistics/order.vue
@@ -5,66 +5,87 @@
        <affixTime @selected="clickBreadcrumb" />
      </Card>
    </Affix>
<!--    <Card class="card">-->
<!--      <div class="my-chart-container">-->
<!--        &lt;!&ndash; 数据概览卡片 &ndash;&gt;-->
<!--&lt;!&ndash;        <div class="stats-cards">&ndash;&gt;-->
<!--&lt;!&ndash;          <div class="stat-card">&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-header">&ndash;&gt;-->
<!--&lt;!&ndash;              <span class="stat-title">总浏览量</span>&ndash;&gt;-->
<!--&lt;!&ndash;              <i class="fa fa-eye stat-icon"></i>&ndash;&gt;-->
<!--&lt;!&ndash;            </div>&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-value">{{ totalPv }}</div>&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-trend positive">&ndash;&gt;-->
<!--&lt;!&ndash;              <i class="fa fa-arrow-up"></i> 12.5% 较上月&ndash;&gt;-->
<!--&lt;!&ndash;            </div>&ndash;&gt;-->
<!--&lt;!&ndash;          </div>&ndash;&gt;-->
    <Card class="card">
        <div class="chart-wrapper">
          <div class="chart-header">
            <h2>PV/UV 趋势图</h2>
          </div>
          <div ref="chartDom" class="chart-container"></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">
            <!-- 第一组:商品/视频(靠左) -->
            <ButtonGroup>
              <Button
                :type="currentType === 'goods' ? 'primary' : 'default'"
                @click="handleTypeChange('goods')"
              >
                商品
              </Button>
              <Button
                :type="currentType === 'video' ? 'primary' : 'default'"
                @click="handleTypeChange('video')"
              >
                视频
              </Button>
            </ButtonGroup>
<!--&lt;!&ndash;          <div class="stat-card">&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-header">&ndash;&gt;-->
<!--&lt;!&ndash;              <span class="stat-title">平均日浏览量</span>&ndash;&gt;-->
<!--&lt;!&ndash;              <i class="fa fa-calendar stat-icon"></i>&ndash;&gt;-->
<!--&lt;!&ndash;            </div>&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-value">{{ avgDailyPv }}</div>&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-trend positive">&ndash;&gt;-->
<!--&lt;!&ndash;              <i class="fa fa-arrow-up"></i> 8.3% 较上月&ndash;&gt;-->
<!--&lt;!&ndash;            </div>&ndash;&gt;-->
<!--&lt;!&ndash;          </div>&ndash;&gt;-->
            <!-- 第二组:前10/前20/前30(靠右) -->
            <ButtonGroup>
              <Button
                :type="currentLimit === 10 ? 'success' : 'default'"
                @click="handleLimitChange(10)"
              >
                前10
              </Button>
              <Button
                :type="currentLimit === 20 ? 'success' : 'default'"
                @click="handleLimitChange(20)"
              >
                前20
              </Button>
              <Button
                :type="currentLimit === 30 ? 'success' : 'default'"
                @click="handleLimitChange(30)"
              >
                前30
              </Button>
            </ButtonGroup>
          </div>
          <div ref="viewPrintChartDom" class="view-chart-container"></div>
        </div>
      </div>
    </Card>
    <Card class="card">
      <div class="my-chart-container">
        <div class="chart-wrapper">
          <div class="chart-header">
            <h2>订单增长 趋势图</h2>
          </div>
          <div ref="orderCountChartDom" class="chart-container"></div>
        </div>
      </div>
    </Card>
<!--&lt;!&ndash;          <div class="stat-card">&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-header">&ndash;&gt;-->
<!--&lt;!&ndash;              <span class="stat-title">最高单日浏览量</span>&ndash;&gt;-->
<!--&lt;!&ndash;              <i class="fa fa-trophy stat-icon"></i>&ndash;&gt;-->
<!--&lt;!&ndash;            </div>&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-value">{{ maxDailyPv }}</div>&ndash;&gt;-->
<!--&lt;!&ndash;            <div class="stat-trend">{{ maxPvDate }}</div>&ndash;&gt;-->
<!--&lt;!&ndash;          </div>&ndash;&gt;-->
<!--&lt;!&ndash;        </div>&ndash;&gt;-->
    <Card class="card">
      <div class="my-chart-container">
        <div class="chart-wrapper">
          <div class="chart-header">
            <h2>浏览数据/订单时间段 趋势图</h2>
          </div>
          <div ref="orderTimePeriodChartDom" class="chart-container"></div>
        </div>
      </div>
<!--        &lt;!&ndash; 图表区域 &ndash;&gt;-->
<!--        <div class="chart-wrapper">-->
<!--          <div class="chart-header">-->
<!--            <h2>PV/UV 趋势图</h2>-->
<!--          </div>-->
<!--          <div ref="chartDom" class="chart-container"></div>-->
<!--        </div>-->
    </Card>
<!--        &lt;!&ndash; 数据更新时间 &ndash;&gt;-->
<!--&lt;!&ndash;        <div class="update-time">&ndash;&gt;-->
<!--&lt;!&ndash;          数据更新时间: {{ updateTime }}&ndash;&gt;-->
<!--&lt;!&ndash;        </div>&ndash;&gt;-->
<!--      </div>-->
<!--    </Card>-->
<!--    <Card class="card">-->
<!--      <div class="my-chart-container">-->
<!--        <div class="chart-wrapper">-->
<!--          <div class="chart-header">-->
<!--            <h2>订单增长 趋势图</h2>-->
<!--          </div>-->
<!--          <div ref="orderCount-chartDom" class="chart-container"></div>-->
<!--        </div>-->
<!--      </div>-->
<!--    </Card>-->
    <Card class="card">
      <div>
        <h4>交易概况</h4>
@@ -263,7 +284,7 @@
import refundRow from "./order/refundOrder";
import affixTime from "@/components/affix-time";
import * as echarts from 'echarts';
import {pvUvData} from "../../api/orderStatistics";
import {pvUvData,getOrderCount,getViewAndCompletionRateCount,getOrderTimePeriod} from "../../api/orderStatistics";
export default {
  components: { orderRow, refundRow, affixTime },
@@ -273,7 +294,11 @@
      // 图表实例
      chart: null, //pvuv
      orderCountChart:null, //订单日趋势
      viewPrintChart:null,
      orderTimePeriodChart:null,
      currentType:"goods",
      currentLimit:10,
      // 统计数据
      orderOrRefund: 1, // 订单还是退单
@@ -592,28 +617,90 @@
    },
  },
  methods: {
   getDates(param){
     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);
       const month = parseInt(param.month);
       // 获取该月的天数
       const daysInMonth = new Date(year, month, 0).getDate();
       // 生成该月所有日期
       for (let day = 1; day <= daysInMonth; day++) {
         const date = new Date(year, month - 1, day); // 月份从0开始,所以要减1
         dates.push(this.formatDate(date, 'MM-dd'));
       }
     }else{
       // 确定天数逻辑不变
       if (param.searchType === "TODAY") {
         days = 1;
       } else if (param.searchType === "YESTERDAY") {
         days = 1;
       } else if (param.searchType === "LAST_SEVEN") {
         days = 7;
       } else if (param.searchType === "LAST_THIRTY") {
         days = 30;
       }
       for (let i = days - 1; i >= 0; i--) {
         const date = new Date(today);
         date.setDate(today.getDate() - i);
         dates.push(this.formatDate(date, 'MM-dd'));
       }
     }
     // 生成日期数组逻辑不变
     return dates;
   },
    //------------- puvu
    handleResize() {
      if (this.chart) {
        this.chart.resize()
      }
      if(this.viewPrintChart){
        this.viewPrintChart.resize()
      }
      if (this.orderCountChart){
        this.orderCountChart.resize()
      }
      if (this.orderTimePeriodChart){
        this.orderTimePeriodChart.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.updateChartData(this.orderParams)
      this.updateOrderCountChartDate(this.orderParams)
      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.updateOrderTimePeriodData(this.orderParams)
    },
    // 更新图表数据
    async updateChartData(param) {
      // 生成日期和PV数据
      const { dates, pvData ,uvData} = await this.generateChartData(param)
      console.log(dates, pvData ,uvData)
      // 更新统计数据
      const { pvData ,uvData} = await this.generateChartData(param)
      // 设置图表配置
      this.chart.setOption(this.getChartOption(dates, pvData, uvData))
      this.chart.setOption(this.getChartOption(this.getDates(param), pvData, uvData))
    },
// 获取图表配置项
    // 获取图表配置项
    // 图表配置项(恢复原始颜色)
    getChartOption(dates, pvData, uvData) {
      return {
@@ -744,30 +831,9 @@
        animationEasing: 'cubicOut'
      };
    },
// 生成pv/uv图表数据
    async generateChartData(param) { // 1. 声明为async函数
      const dates = [];
      const today = new Date();
      let days = 1;
      // 确定天数逻辑不变
      if (param.searchType === "TODAY") {
        days = 1;
      } else if (param.searchType === "YESTERDAY") {
        days = 1;
      } else if (param.searchType === "LAST_SEVEN") {
        days = 7;
      } else if (param.searchType === "LAST_THIRTY") {
        days = 30;
      }
      // 生成日期数组逻辑不变
      for (let i = days - 1; i >= 0; i--) {
        const date = new Date(today);
        date.setDate(today.getDate() - i);
        dates.push(this.formatDate(date, 'MM-dd'));
      }
    // 生成pv/uv图表数据
    async generateChartData(param) {
     // 1. 声明为async函数
      // 2. 使用await等待接口返回,确保数据获取后再继续
      let pvData = [];
      let uvData = [];
@@ -783,18 +849,400 @@
      }
      // 3. 此时pvData和uvData已被接口数据填充,再返回
      return { dates, pvData, uvData };
      return { pvData, uvData };
    },
    //-------------
    //-------------订单日趋势
    async updateOrderCountChartDate(param){
     const { orderCountData } = await this.generateOrderCountChartData(param)
      this.orderCountChart.setOption(this.getOrderCountChartOption(this.getDates(param),orderCountData))
    },
    async generateOrderCountChartData(param){
      let orderCountData = [];
      try {
        const res = await getOrderCount(param);
        if (res.code === 200) {
          orderCountData = res.data;
        }
      } catch (error) {
        console.error("接口调用失败", error);
      }
      return { orderCountData };
    },
    getOrderCountChartOption(dates, orderCountDate) {
      return {
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(255, 255, 255, 0.9)',
          borderColor: '#eee',
          borderWidth: 1,
          textStyle: { color: '#333' },
          // 修正1:Tooltip 内容与“订单量”主题匹配,简化逻辑
          formatter: (params) => {
            const date = params[0].name;
            const orderCount = params[0].value || 0; // 直接取唯一系列数据
            return `<div class="font-medium">${date}</div>
                <div>订单量: <span style="color: #00b42a; font-weight: bold">${orderCount.toLocaleString()}</span></div>`;
          },
        },
        legend: {
          data: ['订单量'],
          top: 0,
          textStyle: { color: '#666' }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true,
          top: '20%' // 优化1:增加顶部间距,避免与legend重叠
        },
        xAxis: {
          type: 'category',
          data: dates,
          axisLine: { lineStyle: { color: '#eee' } },
          axisTick: { show: false },
          axisLabel: { interval: 'auto', rotate: 0, color: '#86909C' },
          splitLine: { show: false }
        },
        yAxis: {
          type: 'value',
          axisLine: { show: false },
          axisTick: { show: false },
          axisLabel: { color: '#86909C', formatter: '{value}' },
          splitLine: { lineStyle: { color: '#f2f3f5' } },
          min: 0 // 正确:订单量不能为负,固定最小值为0
        },
        series: [
          {
            name: '订单量',
            type: 'line',
            data: orderCountDate,
            symbol: 'circle',
            symbolSize: 6,
            emphasis: {
              symbolSize: 8,
              showSymbol: true
            },
            lineStyle: {
              width: 3,
              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                { offset: 0, color: '#00b42a' },
                { offset: 1, color: '#72c140' }
              ]),
              cap: 'round', // 端点圆角,优化视觉
              join: 'round', // 拐角圆角,优化视觉
              miterLimit: 3
            },
            itemStyle: {
              color: '#00b42a',
              borderColor: '#fff',
              borderWidth: 0 // 修正2:与注释一致,显示白色边框(避免点与背景融合)
            },
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: 'rgba(0, 180, 42, 0.2)' },
                { offset: 1, color: 'rgba(0, 180, 42, 0)' }
              ])
            },
            smooth: true,
            showSymbol: true // 显示所有数据点,便于查看具体数值
          }
        ],
        animation: true,
        animationDuration: 1500,
        animationEasing: 'cubicOut' // 缓动效果,优化动画流畅度
      };
    },
    //-------------
    //-------------浏览量,完播率,
    handleLimitChange(limit) {
      if (this.currentLimit !== limit) {
        this.currentLimit = limit
        let form = {...this.orderParams}
        form.currentLimit = this.currentLimit;
        form.currentType = this.currentType;
        this.updateViewAndCompletionRateData(form) // 重新加载数据
      }
    },
    handleTypeChange(type) {
      if (this.currentType !== type){// 避免重复点击
        this.currentType = type // 更新当前类型
        let form = {...this.orderParams}
        form.currentLimit = this.currentLimit;
        form.currentType = this.currentType;
        this.updateViewAndCompletionRateData(form) // 重新加载数据
      }
    },
    async updateViewAndCompletionRateData(param) {
      // 生成日期和每日订单量数据
      const { xData,yData ,rateData} = await this.generateViewAndCompletionRateChartData(param)
      // 更新统计数据
      // 设置图表配置(
      this.viewPrintChart.setOption(this.getViewAndCompletionRateChartOption( xData,yData,rateData));
    },
    async generateViewAndCompletionRateChartData(param){
      let xData = [];
      let yData = [];
      let rateData =[];
      try {
        const res = await getViewAndCompletionRateCount(param); // 等待接口响应
        if (res.code === 200) {
          xData = res.data.xData;
          yData = res.data.yData
          rateData = res.data.rateData;
        }
      } catch (error) {
        console.error("接口调用失败", error);
      }
      return { xData,yData,rateData}
    },
    getViewAndCompletionRateChartOption(xData, yData, rateData) {
      // 兼容ECharts实例引用(根据项目环境选择this.$echarts或全局echarts)
      let isVideoType = this.currentType === "video"
      const tooltipFormatter = (params) => {
        let content = `${params[0].name}<br/>浏览次数: ${params[0].value} 次`;
        if (this.currentType === 'video') {
          const rate = rateData?.[params[0].dataIndex] ?? 0;
          content += `<br/>完播率: ${rate}%`;
        }
        return content;
      };
      return {
        title: {
          text: isVideoType ? '视频浏览量&完播率统计' : '商品浏览量统计', // 视频标题加“完播率”
          left: 'center',
          textStyle: { fontSize: 16, fontWeight: 'normal', color: '#333' },
          subtext: `按${isVideoType ? '视频' : '商品'}分类(Top${this.currentLimit})`,
          subtextStyle: { fontSize: 12, color: '#666' }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: { type: 'shadow' },
          formatter:tooltipFormatter
        },
        grid: {
          left: '5%', // 视频类型左移,给完播率标签留空间
          right: '10%',
          bottom: '0',
          top: '5%',
          containLabel: true
        },
        xAxis: {
          type: 'value',
          name: '浏览次数',
          nameGap:100,
          nameTextStyle: { color: '#666', fontSize: 12 },
          axisLine: { show: false },
          axisLabel: { formatter: '{value}', color: '#666', fontSize: 12 },
          splitLine: { lineStyle: { color: '#f5f5f5' } },
          min: 0
        },
        yAxis: {
          type: 'category',
          data: yData,
          axisLine: { lineStyle: { color: '#ddd' } },
          axisLabel: { color: '#666', fontSize: 12, interval: 0 }, // 强制显示所有标签
          splitLine: { show: false }
        },
        series: [
          {
            name: isVideoType ? '浏览量&完播率' : '浏览量',
            type: 'bar',
            data: xData,
            itemStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                { offset: 0, color: '#409eff' },
                { offset: 1, color: '#69b1ff' }
              ]),
              borderRadius: [0, 4, 4, 0] // 横向柱子右侧圆角
            },
            barWidth: isVideoType ? '30%' : '40%', // 视频类型柱子变窄,避免标签拥挤
            label: {
              show: true,
              position: 'right', // 标签在柱子右侧
              color: '#333',
              fontSize: 12,
              // 标签内容:视频类型显示“浏览量+完播率”,商品类型只显示浏览量
              formatter: function(params) {
                const viewCount = params.value;
                if (isVideoType) {
                  const rate = rateData[params.dataIndex] || 0; // 兜底空值
                  // 换行显示,避免横向拥挤
                  return `${viewCount} 次\n完播率: ${rate}%`;
                }
                return `${viewCount} 次`;
              }.bind(this) // 绑定this,确保能访问到 isVideoType 和 rateData
            },
            emphasis: {
              itemStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                  { offset: 0, color: '#3a86ff' },
                  { offset: 1, color: '#5a9dff' }
                ])
              }
            }
          }
        ]
      };
    },
    //-------------
    //-------------浏览数据,下订单日期时间段分析
    async updateOrderTimePeriodData(param){
     const { viewData,countData,dateData} = await this.generateOrderTimePeriodChartData(param);
      this.orderTimePeriodChart.setOption(this.getOrderTimePeriodChartOption(viewData,countData,dateData));
    },
    async generateOrderTimePeriodChartData(param){
      let viewData= [];
      let countData =[];
      let dateData = [];
      try {
        const res = await getOrderTimePeriod(param); // 等待接口响应
        if (res.code === 200) {
          viewData = res.data.viewData;
          countData = res.data.countData
          dateData = res.data.dateData;
        }
      } catch (error) {
        console.error("接口调用失败", error);
      }
      return { viewData,countData,dateData}
    },
    getOrderTimePeriodChartOption(viewData,countData,dateData){
      return {
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(255, 255, 255, 0.9)',
          borderColor: '#eee',
          borderWidth: 1,
          textStyle: { color: '#333' },
          formatter: (params) => {
            const date = params[0].name;
            const view = params.find(item => item.seriesName === '浏览数据')?.value || 0;
            const count= params.find(item => item.seriesName === '订单时间段')?.value || 0;
            // 优化:添加换行符转义,避免潜在格式问题(可选,不影响功能)
            return `<div class="font-medium">${date}</div>
                <div>浏览数据: <span style="color: #165DFF; font-weight: bold">${view.toLocaleString()}</span></div>
                <div>订单时间段: <span style="color: #00b42a; font-weight: bold">${count.toLocaleString()}</span></div>`;
          },
        },
        legend: {
          data: ['浏览数据', '订单时间段'],
          top: 0,
          textStyle: { color: '#666' }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true,
          top: '15%'
        },
        xAxis: {
          type: 'category',
          data: dateData,
          axisLine: { lineStyle: { color: '#eee' } },
          axisTick: { show: false },
          axisLabel: { interval: 'auto', rotate: 0, color: '#86909C' },
          splitLine: { show: false }
        },
        yAxis: {
          type: 'value',
          axisLine: { show: false },
          axisTick: { show: false },
          axisLabel: { color: '#86909C', formatter: '{value}' },
          splitLine: { lineStyle: { color: '#f2f3f5' } },
          min: 0
        },
        series: [
          // PV折线(保留原始蓝色系,优化点线衔接)
          {
            name: '浏览数据',
            type: 'line',
            data: viewData,
            symbol: 'circle',
            symbolSize: 6, // 保留原有点大小
            emphasis: {
              symbolSize: 8,
              showSymbol: true
            },
            lineStyle: {
              width: 3, // 保留原有线宽
              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                { offset: 0, color: '#165DFF' }, // 原始PV主色
                { offset: 1, color: '#36CFC9' }  // 原始渐变辅助色
              ]),
              // 关键优化1:线条端点设为圆角,避免“切口”空白
              cap: 'round',
              // 关键优化2:线条拐角设为圆角,避免衔接间隙
              join: 'round',
              // 辅助:控制拐角圆角大小(与线宽匹配,避免溢出)
              miterLimit: 3
            },
            itemStyle: {
              color: '#165DFF', // 原始点颜色
              borderColor: '#fff', // 保留白色边框(增强层次感)
              // 关键优化3:减小边框宽度,避免遮挡线条导致断层
              borderWidth: 0 // 从2调整为1.5
            },
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: 'rgba(22, 93, 255, 0.2)' }, // 原始填充色
                { offset: 1, color: 'rgba(22, 93, 255, 0)' }
              ])
            },
            smooth: true,
            showSymbol: true, // 保留你设置的“默认显示所有点”
          },
          // UV折线(保留原始绿色系,同PV优化逻辑)
          {
            name: '订单时间段',
            type: 'line',
            data: countData,
            symbol: 'circle',
            symbolSize: 6, // 保留原有点大小
            emphasis: {
              symbolSize: 8,
              showSymbol: true
            },
            lineStyle: {
              width: 3, // 保留原有线宽
              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
                { offset: 0, color: '#00b42a' }, // 原始UV主色
                { offset: 1, color: '#72c140' }  // 原始渐变辅助色
              ]),
              // 同PV优化:端点圆角+拐角圆角
              cap: 'round',
              join: 'round',
              miterLimit: 3
            },
            itemStyle: {
              color: '#00b42a', // 原始点颜色
              borderColor: '#fff', // 保留白色边框
              // 同PV优化:减小边框宽度
              borderWidth: 0 // 从2调整为1.5
            },
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: 'rgba(0, 180, 42, 0.2)' }, // 原始填充色
                { offset: 1, color: 'rgba(0, 180, 42, 0)' }
              ])
            },
            smooth: true,
            showSymbol: true, // 保留“默认显示所有点”
          }
        ],
        animation: true,
        animationDuration: 1500,
        animationEasing: 'cubicOut'
      };
    },
    formatDate(date) {
      const month = date.getMonth() + 1; // 月份从0开始,需+1
@@ -863,6 +1311,14 @@
      //更新表格
      this.updateChartData(this.orderParams)
      this.updateOrderCountChartDate(this.orderParams)
      let form = {...this.orderParams};
      form.currentType = this.currentType;
      form.currentLimit = this.currentLimit;
      this.updateViewAndCompletionRateData(form)
      this.updateOrderTimePeriodData(this.orderParams)
    },
    // 实例化订单概览
@@ -928,6 +1384,21 @@
};
</script>
<style scoped lang="scss">
.button-group-wrapper {
  display: flex;
  justify-content: space-between; /* 左右两端对齐 */
  align-items: center; /* 垂直居中(避免按钮高度不一致导致错位) */
  width: 100%; /* 必须撑满父容器,否则 justify-content: space-between 无效 */
  margin-bottom: 20px; /* 与图表保持间距 */
  flex-wrap: wrap; /* 小屏幕自动换行(避免按钮挤压) */
  gap: 12px; /* 换行时两组按钮的上下间距 */
}
/* 图表容器:保持固定高度 */
.chart-wrapper {
  width: 100%;
  height: 500px;
}
.active {
  color: $theme_color;
  position: relative;
@@ -1248,6 +1719,10 @@
//  color: #fff;
//}
.view-chart-container {
  width: 100%;
  height: 662px;
}
.chart-container {
  width: 100%;
  height: 400px;