// template
<template><el-table:data="flattenedData":span-method="objectSpanMethod"borderclass="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-buttontype="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-statisticv-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-imageclass="avatar":src="row.serveImageUrl":preview-src-list="[row.serveImageUrl]"></el-image><div class="name"><div class="flex"><el-tagtype="danger"size="small"v-if="row.isUrgent == 1">加急</el-tag><el-tooltipeffect="dark":content="row.serveName"placement="top"><spanclass="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><templatev-if="row.tradeStatus == 20 &&row.acceptStatus == 0"><el-tag size="small" type="warning">受理中</el-tag></template><templatev-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><templatev-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 }"><divclass="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-buttonclass="btns"type="text"size="small"@click="handleDetails(row)">订单详情</el-button><el-buttonclass="btns"type="text"size="small"@click="handleClose(row)"v-if="row.tradeStatus == 11">关闭订单</el-button></div></template></el-table-column></el-table></template>
// datadata() {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, // 关联订单IDtradeStatus: 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?.lengthif (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);}
}