教程:使用 Vue 3 和 arco 实现表格合并

news2025/2/19 12:51:09
1. 功能概述

本教程将介绍如何使用 Vue 3 和 arco 组件库实现表格合并功能。具体来说,我们会根据表格数据中的某个字段(如 type)对表格的某一列(如入库类型列)进行合并,同时将质检说明列合并为一列。

2. 数据准备

首先,我们需要准备一份数据示例:

import { ref, computed } from 'vue';

const storageGoodsVosdata = ref([
  {
    id: 1,
    workOrderId: 'WO001',
    goodsNo: 'G001',
    goodsName: 'Test Product 1',
    skuCode: 'SKU001',
    skuInfo: 'Color: White; Style: Simple',
    quantity: 1,
    type: 0,
    typeName: 'Defective Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image1.jpg',
      'https://example.com/image2.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image3.jpg',
      'https://example.com/image4.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image5.jpg',
      'https://example.com/image6.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
  {
    id: 2,
    workOrderId: 'WO001',
    goodsNo: 'G001',
    goodsName: 'Test Product 1',
    skuCode: 'SKU001',
    skuInfo: 'Color: White; Style: Simple',
    quantity: 1,
    type: 0,
    typeName: 'Defective Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image1.jpg',
      'https://example.com/image2.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image3.jpg',
      'https://example.com/image4.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image5.jpg',
      'https://example.com/image6.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
  {
    id: 3,
    workOrderId: 'WO001',
    goodsNo: 'G002',
    goodsName: 'Test Product 2',
    skuCode: 'SKU002',
    skuInfo: 'Color: Black; Style: Modern',
    quantity: 1,
    type: 1,
    typeName: 'Goods Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image7.jpg',
      'https://example.com/image8.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image9.jpg',
      'https://example.com/image10.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image11.jpg',
      'https://example.com/image12.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
  {
    id: 4,
    workOrderId: 'WO001',
    goodsNo: 'G002',
    goodsName: 'Test Product 2',
    skuCode: 'SKU002',
    skuInfo: 'Color: Black; Style: Modern',
    quantity: 1,
    type: 1,
    typeName: 'Goods Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image7.jpg',
      'https://example.com/image8.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image9.jpg',
      'https://example.com/image10.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image11.jpg',
      'https://example.com/image12.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
]);

const sortedStorageData = computed(() => {
  return [...storageGoodsVosdata.value].sort((a, b) => a.type - b.type);
});
3. 表格合并方法

接下来,我们定义一个 spanMethod 函数来处理表格合并逻辑:

function spanMethod({ rowIndex, columnIndex }) {
  if (columnIndex === 0) { // 只处理第一列(入库类型列)
    const arr = sortedStorageData.value;
    const item = arr[rowIndex];

    // 如果是第一行,或者当前行的类型与前一行不同
    if (rowIndex === 0 || arr[rowIndex - 1].type !== item.type) {
      // 计算当前类型的连续行数
      const count = arr.slice(rowIndex).findIndex(row => row.type !== item.type);
      return {
        rowspan: count === -1 ? arr.length - rowIndex : count,
        colspan: 1,
      };
    }

    // 其他行不显示
    return {
      rowspan: 0,
      colspan: 0,
    };
  }

  // 处理质检说明列(最后一列)
  if (columnIndex === 8) { // 质检说明列的索引
    if (rowIndex === 0) {
      return {
        rowspan: sortedStorageData.value.length,
        colspan: 1,
      };
    }
    return {
      rowspan: 0,
      colspan: 0,
    };
  }
}
模板部分

最后,我们在模板中使用 a-table 组件来渲染表格,并绑定数据和合并方法:

<template>
  <a-table
    :data="sortedStorageData"
    :bordered="{ cell: true }"
    :pagination="false"
    :span-method="spanMethod"
  >
    <template #columns>
      <a-table-column title="Incoming Type" data-index="typeName" align="center" :min-width="180">
        <template #cell="{ record }">
          {{ record.type === 1 ? 'Goods Incoming' : 'Defective Incoming' }}
        </template>
      </a-table-column>

      <a-table-column
        title="Product SKU Number"
        data-index="salary"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          {{ record.goodsNo }}
        </template>
      </a-table-column>
      <a-table-column
        cell-class="custom-col"
        title="Product Name"
        data-index="goodsNo"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            {{ record.goodsName }}
          </div>
        </template>
      </a-table-column>
      <a-table-column
        cell-class="custom-col"
        title="Quantity"
        data-index="goodsName"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            ×{{ record.quantity }}
          </div>
        </template>
      </a-table-column>
      <a-table-column cell-class="custom-col" title="Defective Reason" data-index="spec" align="center" :min-width="180">
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            {{ record.type === 1 ? '--' : record.reasonCodeStr }}
          </div>
        </template>
      </a-table-column>
      <a-table-column
        cell-class="custom-col"
        title="Logistic Receipts"
        data-index="quantity"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            <div v-show="record.type === 1">
              --
            </div>
            <div style="display: flex; gap: 5px;">
              <a-image
                v-for="item in record.logisticReceiptsUrls"
                v-show="record.type === 0"
                :key="item"
                width="30"
                :src="item"
              />
            </div>
          </div>
        </template>
      </a-table-column>
      <a-table-column
        cell-class="custom-col"
        title="Outer Packaging"
        data-index="quantity"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            <div v-show="record.type === 1">
              --
            </div>
            <div style="display: flex; gap: 5px;">
              <a-image
                v-for="item in record.outerPackagingUrls"
                v-show="record.type === 0"
                :key="item"
                width="30"
                :src="item"
              />
            </div>
          </div>
        </template>
      </a-table-column>
      <a-table-column
        cell-class="custom-col"
        title="Housekeeping Diagram"
        data-index="quantity"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            <div v-show="record.type === 1">
              --
            </div>
            <div style="display: flex; gap: 5px;">
              <a-image
                v-for="item in record.housekeepingDiagramUrls"
                v-show="record.type === 0"
                :key="item"
                width="30"
                :src="item"
              />
            </div>
          </div>
        </template>
      </a-table-column>
      <a-table-column
        cell-class="custom-col"
        title="Quality Inspection Note"
        data-index="quantity"
        align="center"
        :min-width="180"
      >
        <template #cell="{ record }">
          <div class="good-item-wrapper">
            <!-- 这里可以替换为实际的质检说明数据 -->
            质检说明
          </div>
        </template>
      </a-table-column>
    </template>
  </a-table>
</template>

<script setup>
import { ref, computed } from 'vue';
import { ATable, ATableColumn, AImage } from 'ant-design-vue';

const storageGoodsVosdata = ref([
  {
    id: 1,
    workOrderId: 'WO001',
    goodsNo: 'G001',
    goodsName: 'Test Product 1',
    skuCode: 'SKU001',
    skuInfo: 'Color: White; Style: Simple',
    quantity: 1,
    type: 0,
    typeName: 'Defective Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image1.jpg',
      'https://example.com/image2.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image3.jpg',
      'https://example.com/image4.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image5.jpg',
      'https://example.com/image6.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
  {
    id: 2,
    workOrderId: 'WO001',
    goodsNo: 'G001',
    goodsName: 'Test Product 1',
    skuCode: 'SKU001',
    skuInfo: 'Color: White; Style: Simple',
    quantity: 1,
    type: 0,
    typeName: 'Defective Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image1.jpg',
      'https://example.com/image2.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image3.jpg',
      'https://example.com/image4.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image5.jpg',
      'https://example.com/image6.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
  {
    id: 3,
    workOrderId: 'WO001',
    goodsNo: 'G002',
    goodsName: 'Test Product 2',
    skuCode: 'SKU002',
    skuInfo: 'Color: Black; Style: Modern',
    quantity: 1,
    type: 1,
    typeName: 'Goods Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image7.jpg',
      'https://example.com/image8.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image9.jpg',
      'https://example.com/image10.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image11.jpg',
      'https://example.com/image12.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
  {
    id: 4,
    workOrderId: 'WO001',
    goodsNo: 'G002',
    goodsName: 'Test Product 2',
    skuCode: 'SKU002',
    skuInfo: 'Color: Black; Style: Modern',
    quantity: 1,
    type: 1,
    typeName: 'Goods Incoming',
    reasonCode: 'R01',
    reasonCodeStr: 'Label/Certificate/Manual/Missing or Damaged',
    logisticReceiptsUrls: [
      'https://example.com/image7.jpg',
      'https://example.com/image8.jpg',
    ],
    outerPackagingUrls: [
      'https://example.com/image9.jpg',
      'https://example.com/image10.jpg',
    ],
    housekeepingDiagramUrls: [
      'https://example.com/image11.jpg',
      'https://example.com/image12.jpg',
    ],
    createTime: '2025-02-12 09:43:31',
  },
]);

const sortedStorageData = computed(() => {
  return [...storageGoodsVosdata.value].sort((a, b) => a.type - b.type);
});
function spanMethod({ rowIndex, columnIndex }) {
  if (columnIndex === 0) { // 只处理第一列(入库类型列)
    const arr = sortedStorageData.value;
    const item = arr[rowIndex];

    // 如果是第一行,或者当前行的类型与前一行不同
    if (rowIndex === 0 || arr[rowIndex - 1].type !== item.type) {
      // 计算当前类型的连续行数
      const count = arr.slice(rowIndex).findIndex(row => row.type !== item.type);
      return {
        rowspan: count === -1 ? arr.length - rowIndex : count,
        colspan: 1,
      };
    }

    // 其他行不显示
    return {
      rowspan: 0,
      colspan: 0,
    };
  }

  // 处理质检说明列(最后一列)
  if (columnIndex === 8) { // 质检说明列的索引
    if (rowIndex === 0) {
      return {
        rowspan: sortedStorageData.value.length,
        colspan: 1,
      };
    }
    return {
      rowspan: 0,
      colspan: 0,
    };
  }
}
</script>

<style scoped>
.custom-col {
  /* 可以添加自定义样式 */
}

.good-item-wrapper {
  /* 可以添加自定义样式 */
}
</style>
5. 解释
  • 数据排序:使用 computed 计算属性对数据进行排序,确保相同类型的数据相邻。
  • 表格合并逻辑spanMethod 函数根据列索引和行索引来决定哪些单元格需要合并。对于入库类型列,根据 type 字段合并相同类型的行;对于质检说明列,将所有行合并为一列。
  • 模板渲染:使用 a-table 组件渲染表格,并通过 #columns 插槽定义表格列。每个列可以通过 #cell 插槽自定义单元格内容。

通过以上步骤,你就可以实现一个带有合并单元格功能的表格。

6. 效果

在这里插入图片描述

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

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

相关文章

uniapp - iconfont下载本地并且运用至项目上

1、项目中创建一个文件夹放置iconfont相关文件&#xff0c;例如src/assets/iconfont&#xff08;名称自己定义&#xff09; 2、在iconfont下载项目至本地 3、解压后把文件复制进1的文件夹中 4、修改src/assets/iconfont - iconfont.css里的font-face的src地址&#xff0c;修…

【前端】自己从头实现一个gpt聊天页面

预览 最小化功能点 主界面&#xff1a;侧边栏会话历史、聊天窗口发送和断开。侧边栏&#xff1a;展示会话列表&#xff0c;每个会话包含多条聊天记录&#xff0c; 通过localstorage本地储存和恢复&#xff0c;会话需要重命名和删除。聊天框&#xff1a;区分一下发送者和回答者…

数据结构——二叉树(2025.2.12)

目录 一、树 1.定义 &#xff08;1&#xff09;树的构成 &#xff08;2&#xff09;度 2.二叉树 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;二叉树的遍历 &#xff08;3&#xff09;遍历特性 二、练习 1.二叉树 &#xff08;1&#xff09;创建二叉树…

Vulhub靶机 ActiveMQ任意 文件写入(CVE-2016-3088)(渗透测试详解)

一、开启vulhub环境 docker-compose up -d 启动 docker ps 查看开放的端口 漏洞版本&#xff1a;ActiveMQ在5.14.0之前的版本&#xff08;不包括5.14.0&#xff09; 二、访问靶机IP 8161端口 默认账户密码都是admin 1、利用bp抓包&#xff0c;修改为PUT方法并在fileserver…

跟着李沐老师学习深度学习(十一)

经典的卷积神经网络 在本次笔记中主要介绍一些经典的卷积神经网络模型&#xff0c;主要包含以下&#xff1a; LeNet&#xff1a;最早发布的卷积神经网络之一&#xff0c;目的是识别图像中的手写数字&#xff1b;AlexNet&#xff1a; 是第一个在大规模视觉竞赛中击败传统计算机…

【微软- Entra ID】Microsoft Entra ID

Microsoft Entra ID是微软提供的基于云的身份和访问管理服务。Microsoft Entra ID是一个全面的解决方案,用于管理身份、执行访问策略以及在云和本地保护您的应用程序和数据。 目录 一、查看 Microsoft Entra ID 微软Entra租户 微软Entra模式 二、比较Microsoft Entra ID与…

Halcon相机标定

1&#xff0c;前言。 相机的成像过程实质上是坐标系的转换。首先空间中的点由“世界坐标系”转换到“相机坐标系”&#xff0c;然后再将其投影到成像平面&#xff08;图像物理坐标系&#xff09;&#xff0c;最后再将成像的平面上的数据转换为图像像素坐标系。但是由于透镜的制…

Linux 配置 MySQL 定时自动备份到另一台服务器

Linux 配置 MySQL 定时自动备份到另一台服务器 前言1、配置服务器通信1.1&#xff1a;配置过程 2、编写自动备份sh脚本文件3&#xff1a;设置定时自动执行 前言 此方案可使一台服务器上的 MySQL 中的所有数据库每天 0 点自动转储为 .sql 文件&#xff0c;然后将文件同步到另一…

《安富莱嵌入式周报》第350期:Google开源Pebble智能手表,开源模块化机器人平台,开源万用表,支持10GHz HRTIM的单片机,开源CNC控制器

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1YPKEeyEeM/ 《安富莱嵌入式周报》第350期&#xff1a;Google开…

LabVIEW与小众设备集成

在LabVIEW开发中&#xff0c;当面临控制如布鲁克OPUS红外光谱仪这类小众专业设备的需求&#xff0c;而厂家虽然提供了配套软件&#xff0c;但由于系统中还需要控制其他设备且不能使用厂商的软件时&#xff0c;必须依赖特定方法通过LabVIEW实现设备的控制。开发过程中&#xff0…

无人机之无线传输技术!

一、Lightbridge和OcuSync图传技术 Lightbridge技术&#xff1a;这是大疆自主研发的一种专用通信链路技术&#xff0c;使用单向图像数据传输&#xff0c;类似于电视广播塔的数据传输形式。它主要采用2.4GHz频段进行传输&#xff0c;并且可以实现几乎“零延时”的720p高清图像传…

移远通信边缘计算模组成功运行DeepSeek模型,以领先的工程能力加速端侧AI落地

近日&#xff0c;国产大模型DeepSeek凭借其“开源开放、高效推理、端侧友好”的核心优势&#xff0c;迅速风靡全球。移远通信基于边缘计算模组SG885G&#xff0c;已成功实现DeepSeek模型的稳定运行&#xff0c;并完成了针对性微调。 目前&#xff0c;该模型正在多款智能终端上进…

rust学习一、入门之搭建简单开发环境

1、搭建开发环境(windows11&#xff09; a.登录官网 一看就明白&#xff0c;此处略。 b.安装rustup 一看就明白&#xff0c;此处略。 c.安装 cargo script 或者 rust-script script cargo install cargo-script 完成后 注意&#xff1a;时间有一点点久。 测试 cargo s…

FANUC机器人示教器中如何显示或关闭寄存器或IO的注释信息?

FANUC机器人示教器中如何显示或关闭寄存器或IO的注释信息? 如下图所示,我们打开一个子程序,可以看到程序中的寄存器和IO是显示注释信息的, 如果想关闭注释显示的话,怎么设置? 如下图所示,按下下一页的箭头(NEXT键), 如下图所示,点击“编辑”,在弹出的窗口中,选择“…

在springboot加vue项目中加入图形验证码

后端 首先先要创建一个CaptchaController的类&#xff0c;可以在下面的代码中看到 在getCaptcha的方法里面写好了生成随机的4位小写字母或数字的验证码&#xff0c;然后通过BufferedImage类变为图片&#xff0c;顺便加上了干扰线。之后把图片转为Base64编码方便传给前端 为了…

23. AI-大语言模型

文章目录 前言一、LLM1. 简介2. 工作原理和结构3. 应用场景4. 最新研究进展5. 比较 二、Transformer架构1. 简介2. 基本原理和结构3. 应用场景4. 最新进展 三、开源1. 开源概念2. 开源模式3. 模型权重 四、再谈DeepSeek 前言 AI‌ 一、LLM LLM&#xff08;Large Language Mod…

Spring Cloud-Sentinel

Sentinel服务熔断与限流 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量控制、流量路由、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。 官网地址&#xff1a;home | Sentinelhttps://sen…

Java中使用EasyExcel

Java中使用EasyExcel 文章目录 Java中使用EasyExcel一&#xff1a;EasyExcel介绍1.1、核心函数导入数据导出数据 1.2、项目实际应用导入数据导出数据 1.3、相关注解ExcelProperty作用示例 二&#xff1a;EasyExcel使用2.1、导入功能2.2、导出功能 三&#xff1a;EasyExcel完整代…

建筑兔零基础自学python记录18|实战人脸识别项目——视频检测07

本次要学视频检测&#xff0c;我们先回顾一下图片的人脸检测建筑兔零基础自学python记录16|实战人脸识别项目——人脸检测05-CSDN博客 我们先把上文中代码复制出来&#xff0c;保留红框的部分。 ​ 然后我们来看一下源代码&#xff1a; import cv2 as cvdef face_detect_demo(…

自定义基座实时采集uniapp日志

自定义基座实时采集uniapp日志 打测试包给远端现场(测试/客户)实际测试时也能实时看到日志了&#xff0c;也有代码行数显示。 流程设计 #mermaid-svg-1I5W9r1DU4xUsaTF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid…