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