当前位置: 首页 > news >正文

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

// 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
      );
    }
}

相关文章:

  • C++算法(1):stringstream详解,高效字符串处理与类型转换的利器
  • 【NLP 55、强化学习与NLP】
  • OpenHarmony Camera开发指导(二):相机设备管理(ArkTS)
  • ALOPS智能化运维管理平台
  • 浅析Centos7安装Oracle12数据库
  • 详解正则表达式中的?:、?= 、 ?! 、?<=、?<!
  • 火语言RPA--增加减少时间
  • EN控制同步整流WD1020 ,3.0V-21V 的宽 VIN 输入范围,0.9V-20V 的宽输出电压范围
  • Android activity属性taskAffinity的作用
  • call、bind、apply
  • MySQL Error Log
  • 【第16届】蓝桥杯C++b组--记录一次被薄纱的心情
  • 艾伦·图灵:计算机科学与人工智能之父
  • 08-JVM 面试题-mk
  • KWDB创作者计划—KWDB认知引擎:数据流动架构与时空感知计算的范式突破
  • 20250412_代码笔记_CVRProblemDef
  • js 颜色转换分析
  • 【Flink运行时架构】核心组件
  • 优化方法介绍(一)
  • PCIe 5.0光学SSD原型问世!
  • 海南做网站的网络公司/it培训机构口碑排名
  • wordpress置顶不重复/aso优化是什么意思
  • 用html5做的静态网站网站/免费发广告帖子的网站
  • 惠州网站推广排名/手机版怎么用百度快照
  • 男人女人做羞羞事网站/网络营销师怎么考
  • 我不想找之前做网站的续费/关键词排名怎么做上去