el-table实现日期表头+二级表头+嵌套echarts

先上效果图
在这里插入图片描述
在这里插入图片描述

表头的时间首个是搜索项的endTime,后面的时间则是startTime到endTime-1的正序排列,折线图则是时间的正序排列
1、先实现月份表头,用的是项目封装后的el-table,但是跟直接在页面上实现没有啥区别

//数据结构
{"status":200,"message":"SUCCESS","data":{"records":
[{
"customerName":"客户A",
"applicationId":"11111111",
"statisticNum":
{"2024-01_stock":0,
"2023-09_incr":1,
"2023-10_stock":3,
"2023-09_stock":1,
"2023-12_stock":2,
"2024-02_incr":0,
"2023-12_incr":2,
"2023-11_incr":1,
"2023-11_stock":1,
"2024-01_incr":0,
"2024-02_stock":0,
"2023-10_incr":3}
},],"total":"xxx","size":"xxx","current":"xxx","searchCount":true,"pages":"xxxx"}}
//存量&增量下拉框值v-model="incrOrstock"
<el-option value="6" label="存量&增量"></el-option>
<el-option value="2" label="存量"></el-option>
<el-option value="3" label="增量"></el-option>
//methods
//在调取列表接口前调用获取头部方法
   getList(){
     const params = {
       aa:xxx,
       bb:xxx
     };
      this.generateCols();//调用表头方法
      tableApi(params).then((res)=>{
      //处理完下面的表头数据这的this.tableDefs里就有了cols属性,页面上展示的数据用的也是cols里的
       this.tableDefs.data = res.data.records; //给el-table赋值
       //从这是后面设置eacharts时用的
          if (res.data.records.length) {
            this.incrArr = [];//增量
            this.stockArr = [];//存量
            this.statisticNum = [];//总的数据
            res.data.records.forEach((ele) => {
              this.statisticNum.push(ele.statisticNum);
            });
          }
       //调用处理echarts
       this.initData(); 
     })
  },
  //处理时间数据,将endTime放在第一个,其余的正序排
    getMonthDifference(start_date, end_date) {
      const start = new Date(start_date);
      const end = new Date(end_date);
      const difference = [];
      difference.push(end_date);//先将endTime放进去
      while (start < end) {
        const currentMonth = `${start.getFullYear()}-${(start.getMonth() + 1)
          .toString()
          .padStart(2, "0")}`; //补零
        difference.push(currentMonth);
        //时间小于endTime-1时结束循环
        start.setMonth(start.getMonth() + 1);
      }
      //difference就是除endTime的其余时间正序排列
      return difference;
    },
   generateCols() {
  
      const months = this.getMonthDifference(
        this.dateRange[0],//搜索项的startTime
        this.dateRange[1]//搜索项的endTime
      );
      const cols = [];
      //第一列表头
      this.$set(cols, cols.length, {
        name: "客户名称",
        field: "customerName",//field就是el-table-column上的prop
        align: "center",
      });

      const chartItem = {
        name: "统计图",
        align: "center",
        cols: [],
      };
      //将第一块的二级表头放在统计图下
      if (this.incrOrstock % 3 === 0) {//下拉框值能整除3就是增量
        this.$set(chartItem.cols, chartItem.cols.length, {
          name: "增量",
          field: "chartIncr",
          //图表插槽
        });
      }
      if (this.incrOrstock % 2 === 0) {//下拉框值能整除2就是存量
        this.$set(chartItem.cols, chartItem.cols.length, {
          name: "存量",
          field: "chartStock",
        });
      }
      this.$set(cols, cols.length, chartItem);
     //跟上面一样,将二级表头放在时间一级表头下
      months.forEach((month) => {
        const newItem = {
          name: month,
          field: "month",
          align: "center",
          cols: [],
        };
        if (this.incrOrstock % 3 === 0) {
          this.$set(newItem.cols, newItem.cols.length, {
            name: "增量",
            field: "statisticNum." + month + "_incr",
            align: "center",
          });
        }
        if (this.incrOrstock % 2 === 0) {
          this.$set(newItem.cols, newItem.cols.length, {
            name: "存量",
            field: "statisticNum." + month + "_stock",
            align: "center",
          });
        }
        this.$set(cols, cols.length, newItem);
      });
      this.tableDefs.cols = cols;//放到el-table-column上
    },

2、实现将charts放到el-table中(主要就是想办法给你要放图标的元素指定id,因为echarts需要获取到指定元素才能初始化)

//这是在el-table中,因为我这是公共table组件,需要加一些判断来防止影响到其他页面
//html
         <div v-if="item.hasOwnProperty('cols')">
            <el-table-column
              v-for="(item2, index2) in item.cols" //item就是遍历的tableData
              :key="index2"
              :type="item2.type"
              :label="item2.name"
              :prop="item2.field"
              :align="item.align || 'center'"
            >
              <template slot-scope="scope">
                <div
                  v-if="item2.field == 'chartStock'"
                  class="chart_box"
                  :id="
                    item2.field == 'chartStock'//重要的就是给id这,想办法给到你要展示图表的元素唯一id值
                      ? 'chart_stock_' + scope.$index
                      : ''
                  "
                ></div>
                <div
                  v-if="item2.field == 'chartIncr'"
                  class="chart_box"
                  :id="
                    item2.field == 'chartIncr'
                      ? 'chart_incr_' + scope.$index
                      : ''
                  "
                ></div>
                //这下面的判断是为了防止切换单个存量or增量时数据展示错误
                <div v-if="item2.field.split('_')[1] == 'stock'">
                  {{
                    item.cols.length == 2
                      ? scope.row.statisticNum[item.cols[1].field.split(".")[1]]
                      : scope.row.statisticNum[item.cols[0].field.split(".")[1]]
                  }}
                </div>
                <div v-if="item2.field.split('_')[1] == 'incr' && item.cols">
                  {{ scope.row.statisticNum[item.cols[0].field.split(".")[1]] }}
                </div>
              </template>
            </el-table-column>
          </div>
 //methods
     initData() {
      this.$nextTick(() => {
      //判断是否下拉选项带着存量
        if (this.incrOrstock == 6 || this.incrOrstock == 2) {
        //this.tableDefs.pages.size就是当前table展示几条数据,我这默认是一页十条
          for (let i = 0; i < this.tableDefs.pages.size; i++) {
            let stockArr = this.statisticNum[i];
            let sortArr = [];
            //归类数组并按时间排序
            for (let [key, value] of Object.entries(stockArr)) {
              if (key.split("_")[1] == "stock") {//截取判断一下是否是存量的数据
                //将存量数据归类按照时间前后排序
                sortArr.push({ key: key, value: value });
              }
            }
            sortArr.sort((a, b) => {
              const dateA = new Date(a.key.split("_")[0]);
              const dateB = new Date(b.key.split("_")[0]);
              return dateA - dateB;
            });
            let dataArr = [];
            //排序完不需要key值了
            sortArr.forEach((ele) => {
              dataArr.push(ele.value); //图标需要的数据
            });
            //在el-table-column中已经定义好的id直接获取初始图标就行
            let myChart = echarts.init(
              document.getElementById("chart_stock_" + i)
            );
            // 绘制图表
            myChart.setOption({
              xAxis: {
                type: "category",
                boundaryGap: false,
                data: [],
              },
              yAxis: {
                type: "value",
                axisLabel: {
                  show: false, // 不显示坐标轴上的文字
                },
                splitLine: {
                  show: false, // 不显示网格线
                },
                axisTick: {
                  show: false, // 不显示坐标轴刻度线
                },
              },
              series: [
                {
                  data: dataArr,
                  type: "line",
                  areaStyle: {},
                },
              ],
            });
            //监听容器大小发生变化重绘图表
            const element = document.getElementById("chart_stock_" + i);
            const resizeObserver = new ResizeObserver((entries) => {
              myChart.resize();
            });
            resizeObserver.observe(element);
          }
        }
        //增量处理方式相同
        if (this.incrOrstock == 6 || this.incrOrstock == 3) {
             ........
        }
      });
    },
  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值