Vue使用el-table给每一行数据上面增加一行自定义合并行

news2025/4/15 22:16:05
// template
<template>
	<el-table
	     :data="flattenedData"
	     :span-method="objectSpanMethod"
	     border
	     class="custom-header-table"
	     style="width: 100%"
	     ref="myTable"
	     :height="'60vh'"
	 >
	     <!-- 订单详情列 -->
	     <el-table-column label="订单详情" width="300">
	         <template #default="{ row }">
	             <!-- 额外行 -->
	             <div v-if="row.isExtraRow" class="extra-row">
	                 <div class="content">
	                     <span class="row_text">
	                         订单号:{{ row.orderNo }}
	                     </span>
	                     <el-button
	                         type="text"
	                         size="mini"
	                         @click="
	                             copyOrderNo(row.orderNo, '订单号')
	                         "
	                         class="copy-btn"
	                     >
	                         复制
	                     </el-button>
	                     <span class="row_text"
	                         >下单时间:{{ row.createTime }}
	                     </span>
	                     <span class="row_text">
	                         企业名称:{{ row.contact }}
	                     </span>
	                     <span class="row_text">
	                         报告单位:{{ row.reportUnitAddress }}
	                     </span>
	                 </div>
	                 <span class="statistic">
	                     <el-statistic
	                         v-if="row.tradeStatus == 11"
	                         format="HH:mm:ss"
	                         :value="row.remainingTime"
	                         time-indices
	                     >
	                         <template slot="suffix">
	                             <span class="color"
	                                 >后自动关闭</span
	                             >
	                         </template>
	                     </el-statistic>
	                 </span>
	             </div>
	             <!-- 商品行 -->
	             <div v-else class="cell_box">
	                 <div class="flex">
	                     <el-image
	                         class="avatar"
	                         :src="row.serveImageUrl"
	                         :preview-src-list="[row.serveImageUrl]"
	                     ></el-image>
	                     <div class="name">
	                         <div class="flex">
	                             <el-tag
	                                 type="danger"
	                                 size="small"
	                                 v-if="row.isUrgent == 1"
	                             >
	                                 加急
	                             </el-tag>
	                             <el-tooltip
	                                 effect="dark"
	                                 :content="row.serveName"
	                                 placement="top"
	                             >
	                                 <span
	                                     class="name-text"
	                                     :class="
	                                         row.isUrgent == 1
	                                             ? 'title'
	                                             : 'title2'
	                                     "
	                                 >
	                                     {{ row.serveName }}
	                                 </span>
	                             </el-tooltip>
	                         </div>
	                         <div class="name-desc title2">
	                             检测用途:{{ row.testUse }}
	                         </div>
	                     </div>
	                 </div>
	             </div>
	         </template>
	     </el-table-column>
	     <!-- 下单数量列 -->
	     <el-table-column label="下单数量" width="200">
	         <template #default="{ row }">
	             <div class="cell_box txt" v-if="!row.isExtraRow">
	                 {{ row.orderNumber || '-' }}
	             </div>
	         </template>
	     </el-table-column>
	
	     <!-- 实付金额列 -->
	     <el-table-column label="实付金额" width="200">
	         <template #default="{ row }">
	             <div class="cell_box txt" v-if="!row.isExtraRow">
	                 ¥{{ row.totalPrice || '0.00' }}
	             </div>
	         </template>
	     </el-table-column>
	
	     <!-- 订单状态列 -->
	     <el-table-column label="订单状态">
	         <template #default="{ row }">
	             <div class="cell_box" v-if="!row.isExtraRow">
	                 <!-- 待付款 -->
	                 <template v-if="row.tradeStatus == 11">
	                     <el-tag size="small" type="danger">
	                         待付款
	                     </el-tag>
	                 </template>
	                 <template
	                     v-if="
	                         row.tradeStatus == 20 &&
	                         row.acceptStatus == 0
	                     "
	                 >
	                     <el-tag size="small" type="warning">
	                         受理中
	                     </el-tag>
	                 </template>
	                 <template
	                     v-if="
	                         row.tradeStatus == 20 &&
	                         row.acceptStatus == 1
	                     "
	                 >
	                     <el-tag size="small" type="success">
	                         服务中
	                     </el-tag>
	                 </template>
	                 <template v-if="row.tradeStatus == 40">
	                     <el-tag size="small"> 已完成 </el-tag>
	                 </template>
	                 <template
	                     v-if="
	                         row.tradeStatus == -1 ||
	                         row.tradeStatus == -2
	                     "
	                 >
	                     <el-tag size="small" type="info">
	                         已关闭
	                     </el-tag>
	                 </template>
	             </div>
	         </template>
	     </el-table-column>
	
	     <!-- 操作列 -->
	     <el-table-column label="操作" width="150px">
	         <template #default="{ row }">
	             <div
	                 class="cell_box operations"
	                 v-if="!row.isExtraRow"
	             >
	                 <el-button
	                     @click="handlePayment(row)"
	                     type="text"
	                     size="small"
	                     class="payBtn"
	                     v-if="row.tradeStatus == 11"
	                 >
	                     扫码付款
	                 </el-button>
	                 <el-button
	                     class="btns"
	                     type="text"
	                     size="small"
	                     @click="handleDetails(row)"
	                     >订单详情</el-button
	                 >
	                 <el-button
	                     class="btns"
	                     type="text"
	                     size="small"
	                     @click="handleClose(row)"
	                     v-if="row.tradeStatus == 11"
	                     >关闭订单</el-button
	                 >
	             </div>
	         </template>
	     </el-table-column>
	 </el-table>
 </template>
// data
 data() {
    return {
        // 原始数据
        tableData: [],
        showCheckboxes: false
    }
}
// computed
computed: {
	// 实际数据
    flattenedData() {
        let result = []
        this.tableData.forEach((order) => {
            // 计算剩余时间
            const remainingTime = (() => {
                const currentTime = new Date(order.systemTime).getTime()
                const deadline = new Date(order.deadlineCloseTime).getTime()
                return currentTime >= deadline
                    ? 0
                    : deadline - currentTime + new Date().getTime() // 加上当前时间
            })()
            // 1. 额外行(订单信息)
            result.push({
                isExtraRow: true,
                orderNo: order.orderNo, // 使用实际订单号
                createTime: order.createTime,
                contact: order.contact,
                tradeStatus: order.tradeStatus,
                reportUnitAddress: order.reportUnitAddress,
                remainingTime: remainingTime
                // orderData: order,      // 存储完整订单数据(可选)
            })

            // 2. 商品行(从 orderServeList 解析)
            try {
                const serveList = JSON.parse(order.orderServeList || '[]')
                serveList.forEach((serveItem) => {
                    result.push({
                        ...serveItem, // 商品信息
                        isExtraRow: false,
                        orderId: order.id, // 关联订单ID
                        tradeStatus: order.tradeStatus,
                        acceptStatus: order.acceptStatus
                        // orderData: order // 关联订单数据(可选)
                    })
                })
            } catch (e) {
                console.error('解析 orderServeList 失败:', e)
            }
        })
        console.log(result, 'result')

        return result
    }
}
// methods
methods: {
	objectSpanMethod({ row, column, rowIndex, columnIndex }) {
	     if (row.isExtraRow) {
	         // 动态计算列数(需确保 el-table 已渲染)
	         const columns = this.$refs.myTable?.columns?.length
	         if (columnIndex === 0) {
	             return {
	                 rowspan: 1,
	                 colspan: columns // 动态跨所有列
	             }
	         } else {
	             return {
	                 rowspan: 0,
	                 colspan: 0
	             }
	         }
	     }
	     return { rowspan: 1, colspan: 1 }
	 },
	 copyOrderNo(content, title) {
	     const textArea = document.createElement('textarea')
	     textArea.value = content
	     // 隐藏 textarea,并防止它影响页面布局
	     textArea.style.position = 'fixed'
	     textArea.style.opacity = '0'
	     textArea.style.left = '-9999px'
	     textArea.style.top = '0'
	     document.body.appendChild(textArea)
	     textArea.select()
	
	     try {
	         const successful = document.execCommand('copy')
	         if (successful) {
	             this.$message.success(title + '已复制!')
	         } else {
	             this.$message.error('复制失败,请手动复制')
	         }
	     } catch (err) {
	         this.$message.error('复制失败,请手动复制')
	     }
	     document.body.removeChild(textArea)
	 }
 }
// style
<style lang="scss" scoped>
	/deep/ .custom-header-table {
	    .el-table__header {
	        th {
	            background: #f6f6f6 !important;
	            height: 20px;
	            font-family: PingFangSC, PingFang SC;
	            font-weight: 500;
	            font-size: 14px;
	            color: #515a6e;
	            line-height: 20px;
	            text-align: left;
	            font-style: normal;
	            padding-left: 10px !important;
	        }
	    }
	}
	
	/* 额外行样式 */
	.extra-row {
	    background-color: #e2ebfe;
	    padding: 10px;
	    font-weight: bold;
	    display: flex;
	    justify-content: space-between;
	    align-items: center;
	    gap: 20px;
	
	    .content {
	        flex: 1;
	        white-space: nowrap; // 使文本不换行显示
	        overflow: hidden;
	        text-overflow: ellipsis; // 显示省略号
	    }
	
	    .statistic {
	        width: 170px;
	        /deep/ .number {
	            color: #ff4131 !important;
	        }
	    }
	}
	
	/* 不影响正常行 */
	/deep/ .el-table__body tr:not(.extra-row) td {
	    padding: 0; /* 正常行的 padding 保持不变 */
	}
	
	/deep/ .el-table .cell {
	    padding: 0; /* 正常行的 padding 保持不变 */
	}
	
	/deep/ .cell {
	    padding-left: 0 !important;
	}
	.copy-btn {
	    font-size: 14px;
	    margin-left: 10px;
	    margin-left: -5px;
	    color: #1464df;
	}
	
	.btns {
	    color: #1464df;
	}
	
	.cell_box {
	    padding: 10px;
	}
	
	.flex {
	    display: flex;
	
	    .avatar {
	        width: 92px;
	        height: 91px;
	        margin-left: 10px;
	    }
	
	    /deep/ .el-tag {
	        margin-right: 5px;
	    }
	
	    .name {
	        display: flex;
	        flex-direction: column;
	        justify-content: space-around;
	        margin-left: 10px;
	
	        &-text {
	            height: 22px;
	            font-family: PingFangSC, PingFang SC;
	            font-weight: 500;
	            font-size: 16px;
	            color: #262626;
	            line-height: 22px;
	            text-align: left;
	            font-style: normal;
	        }
	        &-desc {
	            height: 20px;
	            font-family: PingFangSC, PingFang SC;
	            font-weight: 400;
	            font-size: 14px;
	            color: #999999;
	            line-height: 20px;
	            text-align: left;
	            font-style: normal;
	        }
	    }
	}
	
	.title {
	    max-width: 150px;
	    white-space: nowrap; // 使文本不换行显示
	    overflow: hidden;
	    text-overflow: ellipsis; // 显示省略号
	}
	
	.title2 {
	    max-width: 180px;
	    white-space: nowrap; // 使文本不换行显示
	    overflow: hidden;
	    text-overflow: ellipsis; // 显示省略号
	}
	
	.row_text {
	    margin: 0 8px;
	}
	
	.color {
	    color: #ff4131;
	}
	
	.payBtn {
	    color: orange;
	}
	
	.txt {
	    font-family: PingFangSC, PingFang SC;
	    font-weight: 400;
	    font-size: 14px;
	    color: #3c3c3c;
	    text-align: left;
	    font-style: normal;
	}
	
	.operations {
	    display: flex;
	    flex-direction: column;
	
	    /deep/ .el-button + .el-button,
	    .el-checkbox.is-bordered + .el-checkbox.is-bordered {
	        margin-left: 0 !important;
	    }
	}
</style>

如何需要合并同一个订单下的数据的操作列

methods: {
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (row.isExtraRow) {
        // 处理额外行(订单信息行)
        const columns = this.$refs.myTable?.columns?.length;
        if (columnIndex === 0) {
          return {
            rowspan: 1,
            colspan: columns // 动态跨所有列
          };
        } else {
          return {
            rowspan: 0,
            colspan: 0
          };
        }
      } else {
        // 处理商品行
        if (columnIndex === 4) { // 操作列是第5列(从0开始计数)
          // 找到当前订单的所有商品行
          const orderRows = this.getOrderRows(row.orderId);
          const firstRowIndex = this.findFirstRowIndex(row.orderId);
          
          // 如果是当前订单的第一个商品行,则合并行数
          if (rowIndex === firstRowIndex) {
            return {
              rowspan: orderRows.length,
              colspan: 1
            };
          } else {
            return {
              rowspan: 0,
              colspan: 0
            };
          }
        }
      }
      return { rowspan: 1, colspan: 1 };
    },
    
    // 获取指定订单的所有商品行
    getOrderRows(orderId) {
      return this.flattenedData.filter(item => 
        !item.isExtraRow && item.orderId === orderId
      );
    },
    
    // 找到指定订单的第一个商品行的索引
    findFirstRowIndex(orderId) {
      return this.flattenedData.findIndex(item => 
        !item.isExtraRow && item.orderId === orderId
      );
    }
}

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

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

相关文章

ChromeOS 135 版本更新

ChromeOS 135 版本更新 一、ChromeOS 135 更新内容 1. ChromeOS 电池寿命优化策略 为了延长 Chromebook 的使用寿命&#xff0c;ChromeOS 135 引入了一项全新的电池充电限制策略 —— DevicePowerBatteryChargingOptimization&#xff0c;可提供更多充电优化选项&#xff0c…

javaSE.Lambda表达式

如果一个接口中有且只有一个待实现的抽象方法&#xff0c;那么我们可以将匿名内部类简写为Lambda表达式。 简写规则 标准格式&#xff1a; &#xff08;【参数类型 参数名称&#xff0c;】...&#xff09; -> {代码语句&#xff0c; 包括返回值} 只有一行花括号{}可以省略。…

【随身wifi】青龙面板保姆级教程

0.操作前必看 本教程基于Debian系统&#xff0c;从Docker环境。面板安装&#xff0c;到最后拉取脚本的使用。 可以拉库跑狗东京豆&#xff0c;elm红包等等&#xff0c;也可以跑写自己写的脚本&#xff0c;自行探索 重要的号别搞&#xff0c;容易黑号&#xff0c;黑号自己负责…

Android 之美国关税问题导致 GitHub 403 无法正常访问,责任在谁?

这几天各国关税问题导致世界动荡不安&#xff0c;如今GitHub又无法正常访问&#xff0c;是不是Google到时候也无法正常使用了。

4月13日星期日早报简报微语报早读

4月13日星期日&#xff0c;农历三月十六&#xff0c;早报#微语早读。 1、北京处置倒伏树木843棵&#xff0c;已全部处置完毕&#xff1b; 2、山西大同“订婚强奸案”本月16日二审宣判&#xff0c;一审男方被判3年刑&#xff1b; 3、今年我国快递业务量已突破500亿件&#xf…

动态路由, RIP路由协议,RIPv1,RIPv2

动态路由 1、回顾 路由&#xff1a;从源主机到目标主机的过程 源主机发送数据给目标主机&#xff0c;源主机会查看自身的路由信息 如果目标主机是自己同网段&#xff0c;源主机查看的是直连路由 如果目标主机和自己不同网段&#xff0c;源主机查看的是静态路由、动态路由、默…

【已更新完毕】2025泰迪杯数据挖掘竞赛B题数学建模思路代码文章教学:基于穿戴装备的身体活动监测

基于穿戴装备的身体活动监测 摘要 本研究基于加速度计采集的活动数据&#xff0c;旨在分析和统计100名志愿者在不同身体活动类别下的时长分布。通过对加速度数据的处理&#xff0c;活动被划分为睡眠、静态活动、低强度、中等强度和高强度五类&#xff0c;进而计算每个志愿者在…

212、【图论】字符串接龙(Python)

题目描述 题目链接&#xff1a;110. 字符串接龙 代码实现 import collectionsn int(input()) beginStr, endStr input().split() strList [input() for _ in range(n)]deque collections.deque() # 使用队列遍历结点 deque.append([beginStr, 1]) # 存储当前字符串和遍…

【UE5】RTS游戏的框选功能+行军线效果实现

目录 效果 步骤 一、项目准备 二、框选NPC并移动到指定地点 三、框选效果 四、行军线效果 效果 步骤 一、项目准备 1. 新建一个俯视角游戏工程 2. 新建一个pawn、玩家控制器和游戏模式,这里分别命名为“MyPawn”、“MyController”和“MyGameMode” 3. 打开“MyGam…

设计模式 四、行为设计模式(2)

五、状态模式 1、概述 状态设计模式是一种行为型设计模式&#xff0c;它允许对象在其内部状态发生时改变其行为&#xff0c;这种模式可以消除大量的条件语句&#xff0c;并将每个状态的行为封装到单独的类中。 状态模式的主要组成部分如下&#xff1a; 1&#xff09;上…

FEA 仿真助力高速连接器设计中的信号完整性

各行各业高速信号软件和硬件的快速发展&#xff0c;带来了更高的频率和带宽。因此&#xff0c;对连接器组件的整体性能要求也更加严格。同时&#xff0c;器件和封装形式、互连以及系统内其他设备的小型化也带来了额外的设计挑战。所有这些都对信号传输完整性产生重大影响。 高速…

yum的基本操作和vim指令

在我们的手机端或者Windows上下载软件&#xff0c;可以在相应的应用商店或者官网进行下载&#xff0c;这样对于用户来说十分的方便和便捷。而在Linux上&#xff0c;也有类似的安装方式&#xff0c;我们来一一了解一下。 Linux安装软件的3种方法 源代码安装 在Linux下安装软件…

Qt触摸屏隐藏鼠标指针

Qt触摸屏隐藏鼠标指针 Chapter1 Qt触摸屏隐藏鼠标指针 Chapter1 Qt触摸屏隐藏鼠标指针 使用Qt开发的屏幕软件HMI不需要显示鼠标&#xff0c;qt设置&#xff0c;可以在只启动HMI的时候隐藏光标&#xff0c;退出时再显示。 1.如果只希望在某个 widget 中不显示鼠标指针&#xf…

LangGraph——Agent AI的持久化状态

LangGraph 内置了一个持久化层&#xff0c;通过检查点(checkpointer)机制实现。当你使用检查点器编译图时&#xff0c;它会在每个超级步骤(super-step)自动保存图状态的检查点。这些检查点被存储在一个线程(thread)中&#xff0c;可在图执行后随时访问。由于线程允许在执行后访…

【双指针】专题:LeetCode 1089题解——复写零

复写零 一、题目链接二、题目三、算法原理1、先找到最后一个要复写的数——双指针算法1.5、处理一下边界情况2、“从后向前”完成复写操作 四、编写代码五、时间复杂度和空间复杂度 一、题目链接 复写零 二、题目 三、算法原理 解法&#xff1a;双指针算法 先根据“异地”操…

【C++初学】C++核心编程(一):内存管理和引用

前言 在C的世界里&#xff0c;面向对象编程&#xff08;OOP&#xff09;是核心中的核心。它不仅是一种编程范式&#xff0c;更是一种思考问题的方式。本文将带你从C的内存分区模型出发&#xff0c;深入探讨引用、函数、类和对象、继承、多态以及文件操作等核心概念。通过丰富的…

(PC+WAP)大气滚屏网站模板 电气电力设备网站源码下载

源码介绍 (PCWAP)大气滚屏网站模板 电气电力设备网站源码下载。PbootCMS内核开发的网站模板&#xff0c;该模板适用于滚屏网站模板、电气电力设备网站源码等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b;PCWAP&#xff0c…

笔试专题(九)

文章目录 十字爆破&#xff08;暴力&#xff09;题解代码 比那名居的桃子&#xff08;滑动窗口/前缀和&#xff09;题解代码 分组&#xff08;暴力枚举 优化二分&#xff09;题解代码 十字爆破&#xff08;暴力&#xff09; 题目链接 题解 1. 暴力 预处理 2. 如果单纯的暴…

3 VS Code 配置优化与实用插件推荐:settings.json 详解、CodeGeeX 智能编程助手及插件离线安装方法

1 优化 settings.json 文件 1.1 settings.json 简介 settings.json 是 VS Code 的核心配置文件&#xff0c;用于存储用户的个性化设置和偏好。通过该文件&#xff0c;用户可以自定义和覆盖 VS Code 的默认行为&#xff0c;包括但不限于以下方面&#xff1a; 编辑器外观&#…

TA学习之路——1.6 PC手机图形API介绍

1前言 电脑的工作原理&#xff1a;电脑是由各种不同的硬件组成&#xff0c;由驱动软件驱使硬件进行工作。所有的软件工程师都会直接或者间接的使用到驱动。 定义&#xff1a;是一个图形库&#xff0c;用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序接口&#xff08;API)。…