vue+element table自定义合并单元格与自定义合计栏

一、前言

在最近的实际项目开发中,有个统计报表需要对单元格进行合并,如下图:
vue+element table自定义合并单元格与自定义合计栏_第1张图片
实现功能:

  • 合并分公司相同的公司( 没有分公司的也合并到一起,但是这些没有分公司的数据可能并不是连续的,需要前端自己排序
  • 合并ETC客服中心相同的数据(不至于出现没有客服中心的数据,但在没有分公司的情况下,相同的客服中心可能不是连续的,也需要自己排序
  • 自定义累计栏,将前三列合并,自定义完成率的计算公式
  • 显示累计栏后,table横向滚动条会出现在累计栏上方(element示例也是这样的),需要修改样式;如下图
    vue+element table自定义合并单元格与自定义合计栏_第2张图片

二、功能实现

2.1 通过接口获取列表数据
getTableList() {
   this.isLoading = true;
   ticketWorkload({
     timeStart: this.formData.date[0],
     timeEnd: this.formData.date[1]
   }).then(res => {
     this.templateData = res.data.sort((a, b) => {  // 先对接口返回数据做排序
       if (a.companyId < b.companyId) {			// 按分公司id降序排序;有分公司id的数据排在前面
         return 1;
       } else if (a.companyId == b.companyId) {		// 分公司相同(包括companyId为null,即没得分公司的数据)
         return a.departmentId - b.departmentId;     // 如果companyId相同,用departmentId升序排(避免表格合并错位)
         // return 0;
       }
       return -1;
     });

     let companyList = [], centerList = [];  // 保存有哪些分公司id,哪些部门id
     let companyMerge = {}, centerMerge = {};  // 分别用分公司id,部门id作为对象的key, 对应的value是有几条相同的数据

     this.templateData.forEach(item => {
       const ixExist = companyList.find(em => String(item.companyId) === em);
       const centerExist = centerList.find(em => item.departmentId === em);
       if (!ixExist) {     // 判断同一个公司有几条数据
         companyList.push(String(item.companyId));     // item.companyId 转成字符串是容错,避免分公司id没有的时候
         companyMerge[item.companyId] = 1;
       } else {
         companyMerge[item.companyId]++;
       }

       if(!centerExist) {      // 判断同一个客服中心有几条数据
         centerList.push(item.departmentId);
         centerMerge[item.departmentId] = 1;
       } else {
         centerMerge[item.departmentId]++
       }
     });

     this.templateData.forEach((item, index) => {
       if (index === 0) {    // 第一条数据时
         // 需要合并的对象中有这个公司,并且要合并的行数大于0
         if (companyMerge[item.companyId] && companyMerge[item.companyId] > 0) {
           item.companySpan = [companyMerge[item.companyId], 1];
         }
         // 不合并公司为null的数据
         // if (item.companyId === null) {
         //   item.companySpan = [1, 1];
         // } else {
         //   if (companyMerge[item.companyId] && companyMerge[item.companyId] > 0) {
         //     item.companySpan = [companyMerge[item.companyId], 1];
         //   }
         // }

         // 合并客服中心里有数据,并且要合并的行数大于0
         if (centerMerge[item.departmentId] && centerMerge[item.departmentId] > 0) {
           item.centerSpan = [centerMerge[item.departmentId], 1];
         }
       } else {    // 不是表格第一条数据
         // 需要合并的对象中有这个公司,并且当前这条数据的公司和上一条数据的公司相同,则隐藏这一条数据
         if (companyMerge[item.companyId] && this.templateData[index].companyId === this.templateData[index-1].companyId) {
           item.companySpan = [0, 0];		// 合并0 行0列,即代表隐藏这一个单元格
         } else {
           // 如果当前这条数据和上一条数据的公司不同,则表示是一个新的公司,则合并
           item.companySpan = [companyMerge[item.companyId], 1];
         }
         // 不合并公司为null的数据
         // if (item.companyId === null) {
         //   item.companySpan = [1, 1];
         // } else {
         //   if (companyMerge[item.companyId] && this.templateData[index].companyId === this.templateData[index-1].companyId) {
         //     item.companySpan = [0, 0];
         //   } else {
         //     // 如果当前这条数据和上一条数据的公司不太,则表示是一个新的公司,则合并
         //     item.companySpan = [companyMerge[item.companyId], 1];
         //   }
         // }

         if (centerMerge[item.departmentId] && this.templateData[index].departmentId === this.templateData[index-1].departmentId) {
           item.centerSpan = [0, 0];
         } else {
           item.centerSpan = [centerMerge[item.departmentId], 1];
         }
       }
     })

     this.tableData = this.templateData;
     this.isLoading = false
   });
 }
2.2 单元格合并与自定义累计栏
// 表格合并处理
tableSpanMethod({ row, column, rowIndex, columnIndex }) {
  if (columnIndex === 1) {    // 第一列,合并分公司
    return row.companySpan
  } else if (columnIndex === 2) {   // 第二列,合并客服中心
    return row.centerSpan
  }
},
// 自定义合计栏
getSummaries(param) {
  const { columns, data } = param;
  let sums = [];
  // 遍历表格列数据
  columns.forEach((column, index) => {
    // 前四列都显示累计
    if (index === 0 || index === 1 || index === 2 || index === 3) {
      sums[index] = '累计'
    } else {
      // 取出表格数据中对应所以列的数据(column.property为对应列展示的prop)
      const values = data.map(item => Number(item[column.property]));
      if (!values.every(value => isNaN(value))) {   // 判断值不为NaN
        sums[index] = values.reduce((prev, curr) => {   // 通过reduce累加
          const value = Number(curr);
          if (!isNaN(value)) {
            return prev + curr;
          } else {
            return prev;
          }
        }, 0);
      }
    }

    if (index === 6) {    // 单独处理完成率这一列的合计数据
      // sums[index] = (sums[index] / this.tableData.length).toFixed(2) + '%'
      // 合计完成率 = 合计办结 / 合计受理
      sums[index] = (sums[5] == 0 || sums[4] == 0) ? '0%' : ((sums[5] / sums[4])*100).toFixed(2) + '%'
    }
  })

  
  // 异步将合计栏合并单元格,避免阻塞合计栏数据结构的返回
  this.timer = setTimeout(() => {
    if (this.$refs.tableRef.$el) {
      let current = this.$refs.tableRef.$el .querySelector('.el-table__footer-wrapper') .querySelector('.el-table__footer');
        
      let cell = current.rows[0].cells;
      cell[0].colSpan = '4';     // 前四行都显示累计
      cell[0].style.textAlign = 'center';     // 前四行都显示累计
      cell[1].style.display = 'none';
      cell[2].style.display = 'none';
      cell[3].style.display = 'none';
    }
  }, 50);
  // 先返回合计栏数据
  return sums;
}
}
2.3 table的template

<div class="table-box">
 <el-table ref="tableRef" :data="tableData" row-key="id" v-loading="isLoading" border 
   show-summary :summary-method="getSummaries" :span-method="tableSpanMethod">
   <el-table-column type="index" label="序号" width="50">el-table-column>
   <el-table-column prop="company" label="分公司" width="140">el-table-column>
   <el-table-column prop="department" label="ETC客服中心">el-table-column>
   <el-table-column prop="username" label="处置人员">el-table-column>
   <el-table-column prop="totalAcceptCount" label="累计受理" width="120">el-table-column>
   <el-table-column prop="totalDoneCount" label="累计办结" width="120">el-table-column>
   <el-table-column prop="completionRate" label="完成率" width="120">el-table-column>
   <el-table-column prop="totalPendingCount" label="累计待处置" width="120">el-table-column>
   <el-table-column prop="todayAcceptCount" label="当日受理" width="120">el-table-column>
   <el-table-column prop="todayDoneCount" label="当日办结" width="120">el-table-column>
   <el-table-column prop="delayCount" label="申请延期" width="120">el-table-column>
 el-table>
div>

文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出!

你可能感兴趣的:(vue,vue.js,element,单元格合并,自定义合计栏)