el-table树形表格合并相同的值

发布于:2025-03-15 ⋅ 阅读:(13) ⋅ 点赞:(0)

在这里插入图片描述

el-table树形表格合并相同的值

<style lang="scss" scoped>
.tableBox {
  /deep/ &.el-table th:first-child,
  /deep/ &.el-table td:first-child {
    padding-left: 0;
  }
}
</style>
<template>
  <div>
    <el-table
      class="tableBox"
      row-key="uniID"
      ref="refTable"
      :data="tableData"
      style="width: 100%"
      border
      :span-method="arraySpanMethod"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column prop="dateTime" label="时间" key="dateTime" min-width="140">
        <template slot-scope="{ row }">
          {{ row.groupNo ? findValue(row.groupNo, groupNoList) : row.dateTime }}
        </template>
      </el-table-column>
      <el-table-column prop="yieldConsume" label="产量(t)" key="yieldConsume" min-width="110" />
    </el-table>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

interface TableRow {
  uniID: number;
  dateTime: string;
  groupNo: number | null;
  yieldConsume: number;
  children?: TableRow[];
  parent?: TableRow | null;
}

@Component({})
export default class EnergyAnalysis extends Vue {
  private tableData: TableRow[] = [];
  private groupNoList: any = [
    {
      value: '甲',
      key: 1,
    },
    {
      value: '乙',
      key: 2,
    },
    {
      value: '丙',
      key: 3,
    },
    {
      value: '丁',
      key: 4,
    },
  ];
  private testData = {
    data: {
      everyDetail: [
        {
          dateTime: '2025-03-01',
          groupNo: null,
          yieldConsume: -30176.691,
          children: [
            {
              dateTime: '2025-03-01',
              groupNo: 1,
              yieldConsume: 100,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 1,
              yieldConsume: -18885.714,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 2,
              yieldConsume: 100,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 2,
              yieldConsume: 101,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 2,
              yieldConsume: 102,
              children: null,
            },
          ],
        },
        {
          dateTime: '2025-03-02',
          groupNo: null,
          yieldConsume: -30176.691,
          children: [
            {
              dateTime: '2025-03-02',
              groupNo: 1,
              yieldConsume: 111,
              children: null,
            },
          ],
        },
      ],
    },
  };

  created() {
    this.statisticsQuery();
  }
  private findValue(data: any, list: any) {
    const a = list.find((el: any) => el.key === data);
    return a ? a.value : '-';
  }

  private async statisticsQuery() {
    let index = 1;
    // 递归函数将原始数据转换为包含父子关系的TableRow对象数组
    const recursionList = (list: any[], parent: TableRow | null = null): TableRow[] => {
      return list?.map((v: any) => {
        const newRow: TableRow = {
          ...v,
          uniID: index++,
          parent: parent,
        };
        if (v.children) {
          newRow.children = recursionList(v.children, newRow);
        }
        return newRow;
      });
    };
    const data = this.testData;
    // 处理成表格所需的格式
    this.tableData = recursionList(data.data?.everyDetail);
    this.$nextTick(() => {
      (this.$refs as any).refTable.doLayout();
    });
  }

  /**
   * arraySpanMethod 方法用于定义表格中的单元格合并规则。
   * 此方法接收一个参数,该参数包含当前行和列的信息,包括 row、column、rowIndex 和 columnIndex。
   *
   * @param {Object} param - 包含当前行和列信息的对象。
   * @param {TableRow} param.row - 当前行的数据对象。
   * @param {VueTableColumn} param.column - 当前列的信息对象。
   * @param {number} param.rowIndex - 当前行的索引。
   * @param {number} param.columnIndex - 当前列的索引。
   *
   * 此方法特别处理了第一列(即时间列)的单元格合并逻辑:
   * 如果当前行的 `groupNo` 不为空,则检查其是否与兄弟节点有相同的 `groupNo` 值,
   * 若相同则进行单元格合并。否则返回默认的合并值(即不合并)。
   */
  private arraySpanMethod({ row, column, rowIndex, columnIndex }: any) {
    // 仅对第一列应用合并逻辑
    if (columnIndex === 0) {
      // 如果当前行有 `groupNo` 值
      if (row.groupNo != null) {
        const parent = row.parent; // 获取父级数据对象
        if (parent && parent.children) {
          // 确保存在父级及子节点列表
          const siblings = parent.children; // 子节点列表
          const currentIndex = siblings.findIndex((sib: TableRow) => sib.uniID === row.uniID); // 查找当前行在子节点列表中的位置

          // 如果找不到当前行的位置,则直接返回默认合并值
          if (currentIndex === -1) return [1, 1];

          let count = 1; // 初始化计数器,用于计算需要合并的单元格数量
          // 遍历后续的兄弟节点,查找具有相同 `groupNo` 的连续单元格
          for (let i = currentIndex + 1; i < siblings.length; i++) {
            if (siblings[i].groupNo === row.groupNo) {
              count++; // 相同 `groupNo` 则计数器加一
            } else {
              break; // 遇到不同的 `groupNo` 则停止计数
            }
          }

          // 如果当前行不是第一个具有该 `groupNo` 的行,则不显示此行
          if (currentIndex > 0 && siblings[currentIndex - 1].groupNo === row.groupNo) {
            return { rowspan: 0, colspan: 0 }; // 返回0表示不渲染该单元格
          } else {
            // 否则,根据计算出的连续相同 `groupNo` 单元格的数量返回合并值
            return { rowspan: count, colspan: 1 };
          }
        }
      } else {
        // 对于没有 `groupNo` 的行,返回默认合并值
        return { rowspan: 1, colspan: 1 };
      }
    }
    // 默认情况下,所有其他列不进行单元格合并
    return { rowspan: 1, colspan: 1 };
  }
}
</script>

让Ai进行优化后的代码

注意:以下为Ai生成,暂未测试性能内存等是否真的进行了优化

<style lang="scss" scoped>
.tableBox {
  /deep/ &.el-table th:first-child,
  /deep/ &.el-table td:first-child {
    padding-left: 0;
  }
}
</style>
<template>
  <div>
    <el-table
      class="tableBox"
      row-key="uniID"
      ref="refTable"
      :data="tableData"
      style="width: 100%"
      border
      :span-method="arraySpanMethod"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column prop="dateTime" label="时间" key="dateTime" min-width="140">
        <template slot-scope="{ row }">
          {{ row.groupNo ? findValue(row.groupNo, groupNoList) : row.dateTime }}
        </template>
      </el-table-column>
      <el-table-column prop="yieldConsume" label="产量(t)" key="yieldConsume" min-width="110" />
    </el-table>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';

interface TableRow {
  uniID: number;
  dateTime: string;
  groupNo: number | null;
  yieldConsume: number;
  children?: TableRow[];
  parent?: TableRow | null;
  // 新增预处理字段
  spanInfo?: {
    rowspan: number;
    hidden: boolean;
  };
}

@Component({})
export default class EnergyAnalysis extends Vue {
  private tableData: TableRow[] = [];
  private groupNoList: any = [
    {
      value: '甲',
      key: 1,
    },
    {
      value: '乙',
      key: 2,
    },
    {
      value: '丙',
      key: 3,
    },
    {
      value: '丁',
      key: 4,
    },
  ];
  private testData = {
    data: {
      everyDetail: [
        {
          dateTime: '2025-03-01',
          groupNo: null,
          yieldConsume: -30176.691,
          children: [
            {
              dateTime: '2025-03-01',
              groupNo: 1,
              yieldConsume: 100,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 1,
              yieldConsume: -18885.714,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 2,
              yieldConsume: 100,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 2,
              yieldConsume: 101,
              children: null,
            },
            {
              dateTime: '2025-03-01',
              groupNo: 2,
              yieldConsume: 102,
              children: null,
            },
          ],
        },
        {
          dateTime: '2025-03-02',
          groupNo: null,
          yieldConsume: -30176.691,
          children: [
            {
              dateTime: '2025-03-02',
              groupNo: 1,
              yieldConsume: 111,
              children: null,
            },
          ],
        },
      ],
    },
  };

  created() {
    this.statisticsQuery();
  }
  private findValue(data: any, list: any) {
    const a = list.find((el: any) => el.key === data);
    return a ? a.value : '-';
  }

  private async statisticsQuery() {
    let index = 1;
    const recursionList = (list: any[], parent: TableRow | null = null): TableRow[] => {
      return list?.map((v: any) => {
        const newRow: TableRow = {
          ...v,
          uniID: index++,
          parent: parent,
          spanInfo: { rowspan: 1, hidden: false }, // 初始化合并信息
        };

        // 预处理子节点的合并信息
        if (newRow.children) {
          newRow.children = recursionList(newRow.children, newRow);
          this.preCalculateSpan(newRow.children); // 关键优化点
        }

        return newRow;
      });
    };

    const data = this.testData;
    this.tableData = recursionList(data.data?.everyDetail);
    this.$nextTick(() => {
      (this.$refs as any).refTable.doLayout();
    });
  }

  /**
   * 预处理合并信息 (核心优化逻辑)
   * @param children - 子节点列表,包含需要进行合并处理的行数据。
   */
  preCalculateSpan(children: TableRow[]) {
    let pos = 0; // 当前处理的位置指针
    while (pos < children.length) {
      // 遍历所有子节点
      const current = children[pos]; // 当前处理的行
      if (current.groupNo == null) {
        // 如果当前行没有组编号,则跳过
        pos++;
        continue;
      }

      // 向后查找相同 groupNo 的数量
      let sameCount = 1; // 初始化相同组编号的数量为1(包括当前行)
      for (let i = pos + 1; i < children.length; i++) {
        // 从下一个元素开始查找
        if (children[i].groupNo === current.groupNo) {
          // 如果发现相同组编号
          sameCount++; // 增加计数
        } else {
          break; // 一旦遇到不同的组编号,停止查找
        }
      }

      // 更新合并信息
      current.spanInfo = { rowspan: sameCount, hidden: false }; // 设置当前行为合并起始行
      for (let j = pos + 1; j < pos + sameCount; j++) {
        // 对于后续的相同组编号的行
        children[j].spanInfo = { rowspan: 0, hidden: true }; // 标记这些行为隐藏状态,不需要显示
      }

      pos += sameCount; // 移动位置指针,跳过已处理的行
    }
  }

  /**
   * 合并方法直接使用预处理结果
   * @param param - 包含 row(当前行数据)、column(当前列配置)、columnIndex(当前列索引)的对象。
   * @returns 返回一个对象,指定当前单元格的 rowspan 和 colspan。
   */
  arraySpanMethod({ row, column, columnIndex }: any) {
    // 只对第一列应用合并规则
    if (columnIndex === 0 && row.spanInfo) {
      return {
        rowspan: row.spanInfo.rowspan, // 根据预处理结果设置行跨度
        colspan: row.spanInfo.hidden ? 0 : 1, // 如果该行被标记为隐藏,则设置 colspan 为 0
      };
    }
    // 默认情况下,每个单元格的 rowspan 和 colspan 都为 1
    return { rowspan: 1, colspan: 1 };
  }
}
</script>

在这里插入图片描述
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到