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

多级表头

数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。
只需要将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.mfbz.cn/a/739990.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

江门电子行业实施MES系统前后对比

在江门电子行业实施MES系统之前和之后的对比可以涉及以下几个方面&#xff1a; 生产效率提升&#xff1a;实施MES系统后&#xff0c;江门电子行业可以实现生产过程的实时监控和优化&#xff0c;减少生产中的浪费和停机时间&#xff0c;提高生产效率。 质量控制改善&#xff1a;…

【稀疏三维重建】Flash3D:单张图像重建场景的GaussianSplitting

项目主页&#xff1a;https://www.robots.ox.ac.uk/~vgg/research/flash3d/ 来源&#xff1a;牛津、澳大利亚国立 文章目录 摘要1.引言2.相关工作3.方法3.1 背景&#xff1a;从单个图像中重建场景3.2 单目前向的多个高斯 4.实验4.14.2 跨域新视角合成4.3 域内新视图合成 摘要 F…

ONLYOFFICE 桌面编辑器8.1最新版本强势来袭!

文章目录 软件介绍一、安装与界面安装过程用户界面 二、性能与稳定性启动速度与响应时间稳定性 三、兼容性与集成文件格式兼容性第三方集成 四、可支持多人协作五、功能齐全的PDF编辑器六、PDF表单七、文档编辑器中的新增功能八、总结九、自己的建议 软件介绍 在现代办公环境中…

Cell2Sentence:为LLM传输生物语言

像GPT这样的LLM在自然语言任务上表现出了令人印象深刻的性能。这里介绍一种新的方法&#xff0c;通过将基因表达数据表示为文本&#xff0c;让这些预训练的模型直接适应生物背景&#xff0c;特别是单细胞转录组学。具体来说&#xff0c;Cell2Sentence将每个细胞的基因表达谱转换…

解决Windows打开Excel时正在访问打印机问题、复制Word文档卡死的问题

Excel打开打印机问题 取消让windows管理默认打印机 把所有打印机删除&#xff08;粗暴&#xff09; 把windows虚拟打印机设置了默认打印机 控制面板》程序》启用或关闭windows功能》安装“MicrosoftXPS文档写入程序” 把默认打印机改成MicrosoftXPSDocumentWriter 复制W…

如何统计每天新增好友删除好友跟收款

自动统计功能可以了解每天员工添加了多少人&#xff0c;删除了哪些好友&#xff0c;并查看已被删除好友的聊天记录&#xff0c;避免有的员工私下走私单或者转移客户。统计转账是为了避免员工收多报少&#xff0c;或者瞒报。 ​​​

0620所学——环境变量、CMake等

https://www.cnblogs.com/bravesunforever/p/10939078.html CMake&#xff1a; https://zhuanlan.zhihu.com/p/659412062 0621: 学会了在Github里创建组织&#xff0c;把本地仓库“同步”&#xff0c;就可以上传到Github&#xff0c;然后学会了把自己的Repos转移到组织里。G…

Unity的ScrollView滚动视图复用

发现问题 在游戏开发中有一个常见的需求&#xff0c;就是需要在屏幕显示多个&#xff08;多达上百&#xff09;显示item&#xff0c;然后用户用手指滚动视图可以选择需要查看的item。 现在的情况是在100个data的时候&#xff0c;Unity引擎是直接创建出对应的100个显示item。 …

Nest系列 - 4. 连接Mysql数据库以及typeOrm介绍

前面我们使用nest g res xxx 自动生成CRUD的代码&#xff0c;不仅简单&#xff0c;而且只能在本地玩。今天我们就来看nest 如何连接数据库&#xff0c;数据库有很多种&#xff0c;我们今天来看连接最常用mysql 数据库&#xff0c;并且使用typeOrm 进行数据库操作 mysql 安装 …

原装GUVCL-T21GH 韩国Genicom紫外线传感器光电二极管原厂代理商

深圳市宏南科技有限公司是韩国GenUV公司的原厂代理商&#xff0c;所售紫外线传感器均来自于原始生产厂商直接供货&#xff0c;非第三方转售。 韩国GENICOM 紫外线传感器 GUVCL-T21GH 特征&#xff1a; 单供电电压工作 电压输出 高灵敏度和良好的日盲性 尺寸小巧紧凑 韩国GENIC…

如何确保每颗螺丝都是合格品质

螺丝&#xff0c;一种用来连接和固定物体的金属件&#xff0c;通常是长有螺纹的金属棒。螺丝有不同种类和尺寸&#xff0c;常见的用途包括组装家具、机械设备和其他结构。连接和固定物体&#xff0c;通过螺丝的螺纹结构&#xff0c;将两个或多个物体牢固地连接在一起。提供调节…

研究上百个小时,高手总结了这份 DALL-E 3 人物连续性公式(上)

上篇 Dall-E 3 讲了常见的 20 个公式&#xff0c;今天单独来讲一下人物连续性公式&#xff0c;这个公式来自 AshutoshShrivastava。 上篇回顾&#xff1a; 效果超好&#xff01;全新 DALL-E 3 必须掌握的 20 种公式使用方法上周末&#xff0c;DALL-E 3 正式加入 ChatGpt&…

playwright vscode 插件源码解析

Playwright vscode插件主要功能 Playwright是微软开发的一款主要用于UI自动化测试的工具&#xff0c;在vscode中上安装playwright vscode插件&#xff0c;可以运行&#xff0c;录制UI自动化测试。 playwright vscode插件主要包括两块功能&#xff0c;功能一是在Test Explorer中…

excel字符串列的文本分列合并

excel表有两列&#xff0c;第一列是“姓名”&#xff0c;第二列是“诊断”&#xff0c;有高血压、糖尿病等。我想出一个统计表&#xff0c;将每个人的诊断分为1-N列&#xff0c;比如张三&#xff0c;第一诊断高血压&#xff0c;第二诊断糖尿病&#xff0c;分列显示。我们可以用…

七人团购新体验:解锁数字时代购物新篇章

在数字化浪潮的推动下&#xff0c;购物体验正迈向新的里程碑。其中&#xff0c;七人团购模式以其独特的魅力和创新性&#xff0c;为消费者带来了前所未有的实惠与便利。现在&#xff0c;让我们一同探索这一新兴购物模式的运作机制与潜在价值&#xff0c;特别是针对一款标价599元…

Excel如果将一个表格拆分为多个表格,文末另赠彩蛋!

前期分享如何用数据透视表将一个表格拆分成多个工作薄Excel一个表格拆分多个表格&#xff0c;你学会了吗&#xff1f; 今天刘小生分享另外一种&#xff0c;如果拆分成多个工作表格文件&#xff01; 如何将一个表格根据部门进行拆分成多个表格&#xff0c;再点对点发送给各部门…

MacBook Pro 忘记root用户密码,重置密码步骤

一、以普通用户名登录系统&#xff0c;并打开terminal终端&#xff0c; 输入&#xff1a;sudo bash sudo bash Password:*****&#xff08;输入当前用户的密码&#xff09; 成功后进入bash-3.2#的命令模式 二、在bash-3.2#命令模式下 输入&#xff1a;sudo passwd root sud…

代码随想录算法训练营第三十三天|452. 用最少数量的箭引爆气球、 435. 无重叠区间、 763.划分字母区间

452. 用最少数量的箭引爆气球 题目链接&#xff1a;452. 用最少数量的箭引爆气球 文档讲解&#xff1a;代码随想录 状态&#xff1a;没想出来 思路&#xff1a;对气球终点位置排序&#xff0c;从第一个气球终点位置射出箭&#xff0c;看这支箭可以尽可能穿过几个气球&#xff0…

一文搞懂Linux多线程【上】

目录 &#x1f6a9;引言 &#x1f6a9;再次理解页表 &#x1f6a9;初识线程 &#x1f6a9;线程和pthread库 &#x1f680;线程创建 &#x1f6a9;线程的资源共享问题 &#x1f6a9;线程的优缺点 &#x1f6a9;引言 今天&#xff0c;我们开始学习Linux中的线程部分。Lin…

中国车牌检测数据集VOC+YOLO格式2001张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2001 标注数量(xml文件个数)&#xff1a;2001 标注数量(txt文件个数)&#xff1a;2001 标注…