antd-表格行合并那些事儿

840 阅读1分钟

效果图:

image.png 后端返回数据:

image.png 实现步骤:

  1. 将数据平铺处理成效果图展示的格式
handleData(data) {
  return data.flatMap(item => {
    if (item.tpList.length > 0) {
      return item.tpList.map(tp => {
        return {
          ...item,
          updateTime: this.$moment(item.updateTime).format('YYYY-MM-DD'),
          postLevelList: tp.postLevelList,
          tpList: [tp]
        };
      });
    }
    return {...item}
  });
},
  • 处理好的数据格式

image.png

  1. 开始合并单元格(在不需要额外的样式需求及事件时,可以在配置列时直接调用此函数。有其他需求可参考下方配置的操作列对比修改)
//传入的name表示要根据哪个字段进行合并,tableData是处理好的表格数据
mergeCell(value, row, index, name, tableData) {
   // 满足要求需要合并的行中的第一行
   const temp_Index = tableData.findIndex(record => record[name] === row[name] && row[name] !== null && row[name] !== '');
   // 需要合并的行数
   const rowSpan = tableData.filter(record => record[name] === row[name] && row[name] !== null && row[name] !== '').length;
   if (rowSpan > 1) {
      // 要合并的行中的第一个(从这一行合并)
      if (temp_Index === index) {
         return {
            children: value,
            attrs: { rowSpan }
         };
      }
      // 其他要合并的行都设rowSpan=0
      return {
         children: value,
         attrs: { rowSpan: 0 }
      };
   }
   return value;
}
  • 这里根据name进行合并,columns配置如下:
columns: [
  {
    title: '岗位系列',
    dataIndex: 'name',
    key: 'name',
    width: 300,
    align: 'left',
    customRender: (value, row, index) => {
      return mergeCell(value, row, index, 'name', this.tableData);
    }
  },
  {
    title: '岗位类别',
    dataIndex: 'postTypeList',
    key: 'postTypeList',
    width: 300,
    align: 'left',
    scopedSlots: {customRender: 'postTypeList'},
    customRender: (value, row, index) => {
      // 满足要求需要合并的行中的第一行
      const temp_Index = this.tableData.findIndex(record => record.name === row.name && row.name !== null);
      // 需要合并的行数
      const rowSpan = this.tableData.filter(record => record.name === row.name && row.name !== null).length;
      let tag = this.$createElement('tb-table-tags', {
        props: {
          list: value
        }
      });
      if (rowSpan > 1) {
        // 要合并的行中的第一个(从这一行合并)
        if (temp_Index === index) {
          return {
            children: value ? tag : '',
            attrs: {rowSpan}
          };
        }
        // 其他要合并的行都设rowSpan=0
        return {
          children: value ? tag : '',
          attrs: {rowSpan: 0}
        };
      }
      return value ? tag : '';
    }
  },
  {
    title: '专业技术职务',
    dataIndex: 'tpList',
    key: 'tpList',
    width: 300,
    align: 'left',
    scopedSlots: {customRender: 'tpList'},
  },
  {
    title: '字典值',
    dataIndex: 'postLevelList',
    key: 'postLevelList',
    width: 300,
    align: 'left',
    scopedSlots: {customRender: 'postLevelList'},
  },
  {
    title: '最新修改日期',
    dataIndex: 'updateTime',
    key: 'updateTime',
    width: 300,
    align: 'left',
    customRender: (value, row, index) => {
      return mergeCell(value, row, index, 'name', this.tableData);
    }
  },
  {
    title: '状态',
    dataIndex: 'state',
    key: 'state',
    width: 200,
    align: 'center',
    customRender: (value, row, index) => {
      // 满足要求需要合并的行中的第一行
      const temp_Index = this.tableData.findIndex(record => record.name === row.name && row.name !== null);
      // 需要合并的行数
      const rowSpan = this.tableData.filter(record => record.name === row.name && row.name !== null).length;
      let tag = this.$createElement('string-table-tag', {
        props: {
          type: value ? 'primary' : 'danger'
        }
      }, value ? '启用' : '禁用');
      if (rowSpan > 1) {
        // 要合并的行中的第一个(从这一行合并)
        if (temp_Index === index) {
          return {
            children: tag,
            attrs: {rowSpan}
          };
        }
        // 其他要合并的行都设rowSpan=0
        return {
          children: tag,
          attrs: {rowSpan: 0}
        };
      }
      return tag;
    }
  },
  {
    title: '操作',
    dataIndex: 'operation',
    key: 'operation',
    width: 200,
    customRender: (value, row, index) => {
      const temp_Index = this.tableData.findIndex(record => record.name === row.name && row.name !== null);
      const rowSpan = this.tableData.filter(record => record.name === row.name && row.name !== null).length;
      let div = this.$createElement(
          'div',
          [
            this.$createElement('string-text-button', {
              on: {click: () => this.updateState(row)},
              props: {
                type: row.state === 0 ? 'primary' : 'delete'
              }
            }, row.state ? '禁用' : '启用'),
            this.$createElement('a-divider', {props: {type: 'vertical'}}),
            this.$createElement('string-text-button', {
              on: {click: () => this.onEdit(row)},
              props: {
                type: 'edit'
              }
            }, '编辑'),
            this.$createElement('a-divider', {props: {type: 'vertical'}}),
            this.$createElement('string-text-button', {
              on: {click: () => this.onDelete(row)},
              props: {
                type: 'delete',
                content: `确认删除【${row.name}】,是否继续?`
              }
            }, '删除')
          ]
      );
      if (rowSpan > 1) {
        if (temp_Index === index) {
          return {
            children: div,
            attrs: {rowSpan}
          };
        }
        return {
          children: div,
          attrs: {rowSpan: 0}
        };
      }
      return div;
    }
  }
],
  • 这样我们的表格就合并好了,可以按照我们想要的样子渲染啦。html部分如下:
 <a-table
     id="myTable"
     :columns="columns"
     :data-source="tableData"
     :loading="loading"
     :pagination="false"
     :rowKey="record => record.id"
     bordered
 >
   <template slot="tpList" slot-scope="text, record">
     <tb-table-tags :list="record.tpList"></tb-table-tags>
   </template>
   <template slot="postLevelList" slot-scope="text, record">
     <tb-table-tags :list="record.postLevelList"></tb-table-tags>
   </template>
 </a-table>