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