vue3 element-plus 实现 table表格合并单元格 和 多级表头

news2024/11/17 2:44:51

多级表头

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。
只需要将el-table-column 放置于el-table-column 中,你可以实现组头。

一般可以直接用官网提供的写法,但是有可能数据会比较多的时候,就需要我们稍微改造一下,方便以后再出现合并的数据,直接可以公用。

合并行或列

多行或多列共用一个数据时,可以合并行或列。
通过给 table 传入span-method方法可以实现合并行或列, 方法的参数是一个对象,里面包含当前行 row、当前列 column、当前行号 rowIndex、当前列号 columnIndex 四个属性。 该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。

效果图如下
在这里插入图片描述
代码
表格的数据布局 index.vue

<!-- 架型匹配与拆分记录 -->
<template>
  <el-table
    :data="tableData"
    style="width: 100%"
    height="100%"
    class="record-supply"
    :row-key="getRowKeys"
    :header-cell-style="{
      background: '#fafafa',
      fontSize: '14px',
      height: '40px',
      fontWeight: 'normal',
      boxSizing: 'border-box',
      color: '#707070'
    }"
    ref="myTable"
    :span-method="spanMethod"
    @cell-mouse-enter="handleCellMouseEnter"
    @cell-mouse-leave="handleCellMouseLeave"
  >
    <el-table-column
      v-for="item in columns"
      :key="item.id"
      :label="item.label"
      :align="item.align"
      :width="item.width"
      :label-class-name="item?.labelClass"
      :class-name="item?.className"
    >
      <!-- 如果有子列,递归渲染子列 -->
      <template v-if="item.children && item.children.length > 0">
        <template v-for="child in item.children" :key="child.id">
          <el-table-column
            v-if="child?.formatValue"
            :label="child.label"
            :prop="child.prop"
            :width="child.width"
            :align="child.align"
            :label-class-name="child?.labelClass"
            :class-name="child?.className"
            :formatter="child?.formatValue"
          />

          <el-table-column
            v-else
            fixed="right"
            :label="child.label"
            :prop="child.prop"
            :width="child.width"
            :align="child.align"
            :label-class-name="child?.labelClass"
            :class-name="child?.className"
          >
            <template #default="scope">
              <div v-if="child.prop === 'projectName'">
                <div class="link">{{scope.row?.projectName}}</div>
                <div class="grey">{{scope.row?.projectNo ?? scope.row?.projectCode}}</div>
              </div>
              <div v-if="child.prop === 'matchTime'">
                <div style="word-break: break-word; white-space: normal">
                  {{ scope.row.matchTime ?? '--' }}
                </div>
              </div>
              <!-- 录入架型数据 支架型号/类型 -->
              <div v-if="child.prop === 'supplyModel'">
                <div class="link">
                  {{ scope.row.supplyModel ?? '--' }}
                </div>
                <div class="grey" v-if="scope.row.supplyFirstType || scope.row.supplySecondType">
                  {{ GET_SUPPORT_TYPE(scope.row.supplyFirstType) }} > {{ GET_SUPPORT_SECOND_TYPE_NAME(scope.row.supplySecondType) }}
                </div>
              </div>
              <!-- ERP匹配数据 支架型号/类型 --> 
              <div v-if="child.prop === 'model'">
                <div class="link">
                  {{ scope.row.model }}
                </div>
                <!-- ERP 匹配数据 -->
                <div class="grey">
                  {{ GET_SUPPORT_SECOND_TYPE_NAME(scope.row.secondDeviceType) }} 
                </div>
              </div>
            </template>
          </el-table-column>
        </template>
      </template>
    </el-table-column>
  </el-table>
</template>

<script setup lang="ts">
// import dayjs from 'dayjs'
import {
  GET_SUPPORT_TYPE,
  GET_SUPPORT_SECOND_TYPE_NAME
} from '@/views/project/device/components/config'
const props = defineProps({
  columns: { type: Array<any>, default: [] },
  tableData: { type: Array<any>, default: [] }
})
const { columns, tableData } = toRefs(props)
const getRowKeys = (row: any) => {
  return row.id
}
const megre = reactive([
  'projectNo', // 项目编码
  'expectedDeliveryTime', // 排产月
  'contractNo', // 合同号
  'matchTime', // 匹配日期
  'supplyModel', // 支架型号/类型
  'supplySingleWeight', // 单重
  'supplyDeviceCount', // 数量
  'supplyTotalWeight' // 总吨位
])
const spanArr = computed(() => {
  const spanArr: any = {}
  megre.forEach((m) => {
    spanArr[m] = { spanArr: [], pos: 0 }
  })
  tableData.value.forEach((row: any, i: any) => {
    megre.forEach((m: any) => {
      if (i == 0) {
        spanArr[m].spanArr.push(1)
        spanArr[m].pos = 0
      } else {
        // 批次号相同且项目编码相同的
        let flag = row.batchNo === tableData.value[i - 1].batchNo && row.projectNo == tableData.value[i - 1].projectNo
        //根据项目编码 合并单元格 一样则合并  为空||不同的情况不合并
        if (flag && tableData.value[i - 1].projectNo) {
          if (row[m] === tableData.value[i - 1][m]) {
            // 相等的合并+1
            spanArr[m].spanArr[spanArr[m].pos] += 1
            spanArr[m].spanArr.push(0)
          } else {
            // 不相等push 1,并且可修改下标指向
            spanArr[m].spanArr.push(1)
            spanArr[m].pos = i
          }
        } else {
          spanArr[m].spanArr.push(1)
          spanArr[m].pos = i
        }
      }
    })
  })
  return spanArr
})

const spanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
  // 合并单元格 indexOf
  const spanArr1: any = spanArr.value
  switch (columnIndex) {
    case 0:
      return {
        rowspan: spanArr1.projectNo.spanArr[rowIndex],
        colspan: spanArr1.projectNo.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 1:
      return {
        rowspan: spanArr1.projectNo.spanArr[rowIndex],
        colspan: spanArr1.projectNo.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 2:
      return {
        rowspan: spanArr1.contractNo.spanArr[rowIndex],
        colspan: spanArr1.contractNo.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 3:
      return {
        rowspan: spanArr1.matchTime.spanArr[rowIndex],
        colspan: spanArr1.matchTime.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 4:
      return {
        rowspan: spanArr1.supplyModel.spanArr[rowIndex],
        colspan: spanArr1.supplyModel.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 5:
      return {
        rowspan: spanArr1.supplySingleWeight.spanArr[rowIndex],
        colspan: spanArr1.supplySingleWeight.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 6:
      return {
        rowspan: spanArr1.supplyDeviceCount.spanArr[rowIndex],
        colspan: spanArr1.supplyDeviceCount.spanArr[rowIndex] == 0 ? 0 : 1
      }
    case 7:
      return {
        rowspan: spanArr1.supplyTotalWeight.spanArr[rowIndex],
        colspan: spanArr1.supplyTotalWeight.spanArr[rowIndex] == 0 ? 0 : 1
      }

    default:
      return {
        rowspan: 1,
        colspan: 1
      }
  }
}

let currentIndex = ref('')
let currentColumnIndex = ref('')
const handleCellMouseEnter = (row: any, column: any) => {
  //鼠标移入后赋值
  currentIndex.value = row.projectNo //row.productCode是行相同的标志
  currentColumnIndex.value = column.property //获取列的标题名
}
const handleCellMouseLeave = () => {
  //鼠标移走后置空
  currentIndex.value = ''
  currentColumnIndex.value = ''
}

// // 行的颜色设置 :row-class-name="tableRowClassName" :cell-style="cellStyle"
// const tableRowClassName = ({ row }: any) => {
//   let flag = row.projectNo == currentIndex.value && megre.includes(currentColumnIndex.value)
//   return flag ? 'quotatemplate-my-hover-row' : ''
// }

// // 鼠标移入除合并单元格的其它单元格,这时候需要单独一行展示。
// const cellStyle = ({ row, column, rowIndex, columnIndex }: any) => {
//   let flag =
//     row.projectNo == currentIndex.value &&
//     currentColumnIndex.value &&
//     megre.includes(currentColumnIndex.value)
//   return flag ? { background: '#f4f6fa' } : { '': '' }
// }
</script>

<style scoped lang="scss">
.header-nav {
  display: flex;
  align-items: center;
  height: 40px;
  border: 1px solid #ebeef5;
  background: #fafafa;
  border-bottom: none;
  border-right: none;
  & > div {
    flex: 1;
    border-right: 1px solid #ebeef5;
    text-align: center;
  }
}
:deep(.record-supply) {
  .el-table__border-left-patch {
    width: 0;
  }
  .column-border {
    border-left: 1px solid #ebeef5;
  }
  .border-none {
    border-right: none;
  }
  .border-right {
    border-right: 1px solid #ebeef5;
  }
  .column-height {
    height: 70px;
  }
  .el-table__cell {
    .cell {
      padding-left: 8px;
    }
  }
}
.edit-style {
  color: #3076fe;
  & > div {
    cursor: pointer;
  }
}
:deep(.el-table--border::before),
:deep(.el-table--border::after) {
  width: 0px;
}
.link {
  // cursor: pointer;
  color: #262626;
  overflow: hidden;
  text-overflow: ellipsis;
}
.grey {
  color: #a3a3a3;
}
</style>
<style>
/* 移除划过时表格的背景色 || 自行设置划过的背景色 || 不写下方样式将默认颜色 */
.record-supply.el-table .quotatemplate-my-hover-row {
  background: #f4f6fa !important;
}
</style>

数据的映射config.ts 页面

import dayjs from 'dayjs'
// 架型匹配与拆分记录
export const splitRecordColumns = (): any[] => [
  {
    id: 1,
    label: '录入架型数据',
    width: '',
    labelClass: 'column-border',
    className: '',
    align: 'center',
    children: [
      {
        id: 11,
        label: '项目名称/编码',
        prop: 'projectName',
        width: '172',
        align: ''
      },
      {
        id: 12,
        label: '排产月',
        prop: 'expectedDeliveryTime',
        width: '80',
        align: 'center',
        formatValue: (row: any) =>
          row.expectedDeliveryTime ? dayjs(row.expectedDeliveryTime).format('YYYY-MM') : '--'
      },
      {
        id: 13,
        label: '合同号',
        prop: 'contractNo',
        width: '160',
        labelClass: 'column-border',

        align: 'center',
        formatValue: (row: any) => row.contractNo || '--'
      },
      {
        id: 14,
        label: '匹配时间',
        prop: 'matchTime',
        width: '100',
        align: ''
      },
      {
        id: 15,
        label: '支架型号/类型',
        prop: 'supplyModel',
        width: '170',
        align: ''
      },
      {
        id: 16,
        label: '单重',
        prop: 'supplySingleWeight',
        width: '70',
        align: 'center',
        formatValue: (row: any) => (row.supplySingleWeight ? row.supplySingleWeight + '吨' : '--')
      },
      {
        id: 17,
        label: '数量',
        prop: 'supplyDeviceCount',
        width: '70',
        align: 'center',
        formatValue: (row: any) => (row.supplyDeviceCount ? row.supplyDeviceCount + '架' : '--')
      },
      {
        id: 18,
        label: '总吨位',
        prop: 'supplyTotalWeight',
        width: '90',
        align: 'center',
        formatValue: (row: any) => (row.supplyTotalWeight ? row.supplyTotalWeight + '吨' : '--')
      }
    ]
  },
  {
    id: 2,
    label: 'ERP匹配数据',
    width: '',
    labelClass: '',
    className: '',
    align: 'center',
    children: [
      {
        id: 21,
        label: '排产月',
        prop: 'planProduceMonth',
        width: '80',
        align: '',
        formatValue: (row: any) =>
          row.planProduceMonth ? dayjs(row.planProduceMonth).format('YYYY-MM') : '--'
      },
      {
        id: 22,
        label: '施工号',
        prop: 'constructionNo',
        width: '110',
        align: '',
        formatValue: (row: any) => row.constructionNo || '--'
      },
      {
        id: 23,
        label: '支架型号/类型',
        prop: 'model',
        width: '170',
        align: ''
      },
      {
        id: 24,
        label: '单重',
        prop: 'singleWeight',
        width: '70',
        align: '',
        formatValue: (row: any) => (row.singleWeight ? row.singleWeight + '吨' : '--')
      },
      {
        id: 25,
        label: '数量',
        prop: 'deviceCount',
        width: '70',
        align: '',
        formatValue: (row: any) => (row.deviceCount ? row.deviceCount + '架' : '--')
      },
      {
        id: 26,
        label: '总吨位',
        prop: 'totalWeight',
        width: '90',
        align: '',
        formatValue: (row: any) => (row.totalWeight ? row.totalWeight + '吨' : '--')
      },
      {
        id: 27,
        label: '交审日期',
        prop: 'transferDate',
        width: '90',
        align: '',
        formatValue: (row: any) =>
          row.transferDate ? dayjs(row.transferDate).format('MM月DD日') : '--'
      },
      {
        id: 28,
        label: '备注',
        prop: 'remark',
        labelClass: 'border-right',
        className: 'border-none column-height',
        width: '',
        align: '',
        formatValue: (row: any) => row.remark || '--'
      }
    ]
  }
]

注意的是,可能需求不同,但是方法是一样的。只需要把方法中的值替换即可实现公用。

如下图:
注意的项是 要和并的字段不一样,我们需要单独去设置;spanMethod 方法会根据 设定的 merge 值去合并;
spanArr 方法执行计算属性,添加我们的判断条件。需要满足需求条件才会更新数据。
在这里插入图片描述
这样就结束了。
展示最后的效果
在这里插入图片描述
在这里插入图片描述
满足条件的进行合并,不满足的则是单独一行展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1859173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unordered_set和unordered_map

用哈希结构封装map和set 哈希表的改造 节点 数据类型改为模板 迭代器 成员 一个节点的指针&#xff0c;哈希表和下标用来访问&#xff0c;哈希表需要支持修改&#xff0c;传入指针&#xff0c;const为了常迭代器可以传递哈希表 当前节点的next有内容&#xff0c;先遍历…

分布式数据库系统MyCat

MyCat简介 MyCat是一个开源的分布式数据库系统&#xff0c;是一个实现了MySQL协议的服务器&#xff0c;前端用户可以把它看作是一个数据库代理&#xff0c;用MySQL客户端工具和命令行访问&#xff0c;而其后端可以用MySQL原生协议与多个MySQL服务器通信&#xff0c;也可以用JD…

Tita的OKR:如何高效写好一个 OKR ?

OKR 是一个简单而强大的目标设定系统&#xff0c;世界各地的企业都依靠它来提高&#xff08;除其他外&#xff09;对战略、调整和参与的关注度。该系统由目标&#xff08;你想实现的目标&#xff09;和关键结果&#xff08;衡量目标实现情况的量化陈述&#xff09;组成。 目标…

参数页面设计

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 参数页面设计 {public partial class Form1 : Form{List<PMs> PMs new List<PMs>();public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){for (int …

element-ui table使用type=‘selection‘复选框全禁用-全选禁用_elementui table禁用全选

问题点&#xff1a;当条件数据全被禁用时&#xff0c;全选按钮不是禁用的状态。 复选框全被禁用时&#xff0c;全选按钮将被隐藏 问题总结&#xff1a; 当条件数据全被禁用时&#xff0c;全选按钮也变成禁用的状态&#xff0c;而不是隐藏。有会做的小伙伴希望跟帖。谢谢&#x…

PasteSpiderFile文件同步管理端使用说明(V24.6.21.1)

PasteSpider作为一款适合开发人员的部署管理工具&#xff0c;特意针对开发人员的日常情况做了一个PasteSpiderFile客户端&#xff0c;用于windows上的开发人员迅速的更新发布自己的最新代码到服务器上&#xff01; 虽然PasteSpider也支持svn/git的源码拉取&#xff0c;自动编译…

0802功放2

功放要记一般的式子&#xff0c;而非最大的式子&#xff0c;因为总不能总开到最大音量上工作&#xff0c;而是在比较合适的音量上工作 运放的最大电压也是比电源低1~2V 饱和三极管的功率&#xff0c;电流越大&#xff0c;饱和压降越大&#xff1f;&#xff1f;&#xff1f;不…

SpringBoot优点达项目实战:项目初始化(一)

SpringBoot优点达项目实战&#xff1a;项目初始化&#xff08;一&#xff09; 文章目录 SpringBoot优点达项目实战&#xff1a;项目初始化&#xff08;一&#xff09;1、项目介绍2、项目搭建3、依赖导入4、数据准备 1、项目介绍 技术框架 SpringbootmybatisPlusvueknife 2、项目…

机器学习之逻辑回归丨KNN测试

选择题 【 正确答案: A D】 A. B. C. D. 【 正确答案: B】 A. B. C. D. 【 正确答案: C, D】 A. B. C. D. 假设我们三个类别中心&#xff0c;若某测试样本为&#xff0c;它的 c ( i ) c^{(i)} c(i)是多少&#xff1f; 【 正确答案: B】 A.1 B.2 C.3 D.不确定 假设你…

跨境电商货源渠道哪里找?盘点11个拿货产业带

一、跨境货源渠道哪里找&#xff1f; 说到找货源&#xff0c;应该很多卖家都上过阿里巴巴1688“淘货”&#xff0c;阿里巴巴1688作为一个全球采购批发平台&#xff0c;在2017年上线了个跨境专供板块&#xff0c;专为跨境卖家供货&#xff0c;跨境专供板块的供货商需要经过严格…

将 MinIO 与 Keycloak OIDC 集成

Keycloak是一种单点登录解决方案。使用Keycloak&#xff0c;用户使用Keycloak而不是MinIO进行身份验证。如果没有Keycloak&#xff0c;您将不得不为每个用户创建一个单独的身份 - 从长远来看&#xff0c;这将很麻烦。您需要一个集中身份解决方案来管理 MinIO 的身份验证和授权。…

vue3 vxe-grid列中绑定vxe-switch实现数据更新

1、先上一张图&#xff1a; <template #valueSlot"{ row }"><vxe-switch :value"getV(row.svalue)" change"changeSwitch(row)" /></template>function getV(value){return value 1;};function changeSwitch(row) {console.l…

数据分析必备:一步步教你如何用matplotlib做数据可视化(11)

1、Matplotlib 三维绘图 尽管Matplotlib最初设计时只考虑了二维绘图&#xff0c;但是在后来的版本中&#xff0c;Matplotlib的二维显示器上构建了一些三维绘图实用程序&#xff0c;以提供一组三维数据可视化工具。通过导入Matplotlib包中包含的mplot3d工具包&#xff0c;可以启…

推荐免费好用的日历和浏览器,你一定要下载使用

猫眼浏览器 猫眼浏览器是一款基于Chromium内核的增强版网页浏览器&#xff0c;融合了Chrome的核心功能与Safari的优美外观。它以简约和安全为目标&#xff0c;提供了快速、流畅的网页加载和浏览体验。 猫眼浏览器内置了隐私保护和广告屏蔽功能&#xff0c;能够有效防止用户数据…

Linux tcpdump抓包必备知识

author: 放牛娃学编程 moto: 分享与热爱&#xff0c;不是大爱我不说 放牛娃每日一语: 除了你自己&#xff0c;没有人可以说你不行 别急着划开&#xff0c;这篇笔记一定能够给你带来收获 因为这里你能学到AI永远也给不了你的知识 Linux tcpdump抓包必备知识 文章目录 Linux tcp…

Vue3 头像是圆形,hover上去时头像出现黑色半透明样式,且中间显示修改两字的实现

实现效果 原头像 hover效果 实现方式 博主在实际开发过程中使用mouseover和mouseout会出现无法点击或hover频繁闪动的问题&#xff0c;故这里采用的是css中的hover&#xff0c;利用hover也能轻松实现上述效果&#xff0c;且完全不会影响点击事件的使用。 <template> &…

Mysql: 数据模型

一.关系型数据库 概念:建立在关系型基础上,由多张相互连接的二维表组成的数据库。 1.关系型数据库: 2.特点&#xff1a; 1.使用表存储数据,格式统一,便于维护。 2.使用SQL语言操作,标准统一,使用方便。 3.数据模型 通过客户端连接DBMS可以创建多个数据库,在数据库中…

TOPGP-TIPTOP调用外部Webservice

功能要求&#xff1a;ERP作业调用外部系统的webserice更新数据。 演示环境&#xff1a;ERP作业cooi002&#xff08;员工档案&#xff09;录入后更新到外部系统员工档案表。 1、外部系统的WebSerice使用.net搭建 2、在Service.cs中写一个调用方法erp_other erp_other中两个参数…

Windows 中 Chrome / Edge / Firefox 浏览器书签文件默认存储路径

1. Chrome 浏览器 按组合键 Win R&#xff0c;打开运行对话框&#xff0c;输入 %USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default或在Chrome 浏览器地址栏输入 chrome://version查看【个人资料路径】 2. Edge 浏览器 按组合键 Win R&#xff0c;打开运行对…

dockerfile文件的中的命令

# 基础镜像 FROM registry.cn-beijing.aliyuncs.com/205erp/myopenjdk:8.6 # 设置工作目录 WORKDIR /opt # 拷贝jar包到工作目录 COPY target/*.jar app.jar RUN ls # 设置暴漏的端口 EXPOSE 8080 # 启动jar包 CMD/ENTRYPOINT java ${JAVA_TOOL_OPTIONS} -jar app.jarCMD与ENT…