Files
klp-oa/klp-ui/src/views/crm/report/SalesReportOrderDetail.vue
砂糖 20cefe115d feat(金额显示): 统一金额单位为万元并优化产品内容处理
refactor(产品内容): 提取产品内容处理逻辑到独立工具类
style(合同表单): 调整技术附件和商务附件顺序
2026-05-11 10:38:29 +08:00

399 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="order-detail-container" v-loading="loading">
<div class="table-toolbar">
<el-button
type="success"
icon="el-icon-download"
@click="handleExport"
>
导出订单明细
</el-button>
</div>
<!-- 三个Tab页切换 -->
<el-tabs v-model="activeTab" class="order-tabs" tab-position="top">
<!-- Tab1: 订单维度订单主表信息 -->
<el-tab-pane label="订单维度" name="mainOrder">
<el-table
:data="orderDetailList"
border
style="width: 100%;"
@selection-change="handleSelectionChange"
>
<el-table-column prop="orderCode" label="订单编号" min-width="120"></el-table-column>
<el-table-column prop="customerCode" label="客户编码" min-width="100"></el-table-column>
<el-table-column prop="companyName" label="公司名称" min-width="150"></el-table-column>
<el-table-column prop="contactPerson" label="联系人" min-width="80"></el-table-column>
<el-table-column prop="customerLevel" label="客户等级" min-width="100"></el-table-column>
<el-table-column prop="industry" label="所属行业" min-width="120"></el-table-column>
<el-table-column prop="orderAmount" label="订单金额(万元)">
<template #default="scope">
{{ formatAmount(scope.row.orderAmount) }}
</template>
</el-table-column>
<el-table-column prop="salesman" label="销售员" min-width="80"></el-table-column>
<el-table-column prop="deliveryDate" label="交货日期" min-width="100">
<template #default="scope">
{{ scope.row.deliveryDate ? formatDate(scope.row.deliveryDate) : '-' }}
</template>
</el-table-column>
<el-table-column prop="orderStatus" label="订单状态" min-width="100">
<template #default="scope">
<el-tag v-if="scope.row.orderStatus === 1" type="success">已完成</el-tag>
<el-tag v-else-if="scope.row.orderStatus === 0" type="warning">待处理</el-tag>
<el-tag v-else type="danger">已取消</el-tag>
</template>
</el-table-column>
<el-table-column prop="financeStatus" label="财务状态" min-width="100">
<template #default="scope">
<el-tag v-if="scope.row.financeStatus === 1" type="success">已结款</el-tag>
<el-tag v-else type="danger">未结款</el-tag>
</template>
</el-table-column>
<el-table-column prop="unpaidAmount" label="未结金额(万元)" min-width="100">
<template #default="scope">
{{ formatAmount(scope.row.unpaidAmount) }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="160">
<template #default="scope">
{{ scope.row.createTime }}
</template>
</el-table-column>
<el-table-column prop="itemCount" label="明细数量" min-width="80"></el-table-column>
<el-table-column prop="objectionCount" label="异议数量" min-width="80"></el-table-column>
</el-table>
</el-tab-pane>
<!-- Tab2: 明细维度订单产品明细扁平展示 -->
<el-tab-pane label="明细维度" name="itemDetail">
<el-table
:data="flatOrderItemList"
border
style="width: 100%;"
stripe
>
<el-table-column prop="orderCode" label="关联订单编号" min-width="120"></el-table-column>
<el-table-column prop="companyName" label="客户公司" min-width="150"></el-table-column>
<el-table-column prop="productCode" label="产品编码" min-width="120"></el-table-column>
<el-table-column prop="productName" label="产品名称" min-width="150"></el-table-column>
<el-table-column prop="specification" label="产品规格" min-width="120"></el-table-column>
<el-table-column prop="productCount" label="产品数量" min-width="80"></el-table-column>
<el-table-column prop="unitPrice" label="单价(元 / 吨)" min-width="100">
<template #default="scope">
{{ formatAmount(scope.row.unitPrice) }}
</template>
</el-table-column>
<el-table-column prop="itemAmount" label="明细金额(元)" min-width="120">
<template #default="scope">
{{ formatAmount(scope.row.itemAmount) }}
</template>
</el-table-column>
<el-table-column prop="remark" label="明细备注" min-width="150"></el-table-column>
</el-table>
</el-tab-pane>
<!-- Tab3: 客户分组折叠面板 + 展开后独立订单表格替代树表 -->
<el-tab-pane label="客户分组" name="customerGroup">
<!-- 无客户数据提示 -->
<div v-if="customerGroupedList.length === 0" class="empty-tip">
暂无客户分组数据
</div>
<!-- 折叠面板每个面板对应一个客户展开显示该客户的订单表格 -->
<el-collapse v-else class="customer-collapse" accordion>
<!-- 循环渲染客户折叠项 -->
<el-collapse-item
v-for="customer in customerGroupedList"
:key="customer.customerKey"
:name="customer.customerKey"
>
<!-- 折叠面板标题展示客户核心信息 + 汇总数据 -->
<template #title>
<div class="collapse-title">
<span class="company-name">{{ customer.companyName }}</span>
<span class="customer-info">客户编码{{ customer.customerCode }}</span>
<span class="customer-info">客户等级{{ customer.customerLevel }}</span>
<span class="customer-info">所属行业{{ customer.industry }}</span>
<span class="summary-info">总订单金额{{ formatAmount(customer.totalOrderAmount) }} 万元</span>
<span class="summary-info">订单数量{{ customer.orderCount }} </span>
</div>
</template>
<!-- 展开后该客户的独立订单表格 -->
<div class="customer-order-table">
<el-table
:data="customer.orderList"
border
style="width: 100%;"
stripe
empty-text="该客户暂无订单数据"
>
<el-table-column prop="orderCode" label="订单编号" min-width="120"></el-table-column>
<el-table-column prop="orderAmount" label="订单金额(万元)" min-width="120">
<template #default="scope">
{{ formatAmount(scope.row.orderAmount) }}
</template>
</el-table-column>
<el-table-column prop="salesman" label="销售员" min-width="80"></el-table-column>
<el-table-column prop="deliveryDate" label="交货日期" min-width="100">
<template #default="scope">
{{ scope.row.deliveryDate ? formatDate(scope.row.deliveryDate) : '-' }}
</template>
</el-table-column>
<el-table-column prop="orderStatus" label="订单状态" min-width="100">
<template #default="scope">
<el-tag v-if="scope.row.orderStatus === 1" type="success">已完成</el-tag>
<el-tag v-else-if="scope.row.orderStatus === 0" type="warning">待处理</el-tag>
<el-tag v-else type="danger">已取消</el-tag>
</template>
</el-table-column>
<el-table-column prop="financeStatus" label="财务状态" min-width="100">
<template #default="scope">
<el-tag v-if="scope.row.financeStatus === 1" type="success">已结款</el-tag>
<el-tag v-else type="danger">未结款</el-tag>
</template>
</el-table-column>
<el-table-column prop="unpaidAmount" label="未结金额(万元)" min-width="120">
<template #default="scope">
{{ formatAmount(scope.row.unpaidAmount) }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="160">
<template #default="scope">
{{ scope.row.createTime }}
</template>
</el-table-column>
</el-table>
</div>
</el-collapse-item>
</el-collapse>
</el-tab-pane>
</el-tabs>
<!-- 分页组件针对主订单列表全局生效 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageParams.pageNum"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageParams.pageSize"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
style="margin-top: 20px; text-align: right;"
></el-pagination>
</div>
</template>
<script>
export default {
name: "SalesReportOrderDetail",
props: {
// 订单明细列表(主表)
orderDetailList: {
type: Array,
default: () => []
},
// 分页参数
pageParams: {
type: Object,
required: true,
default: () => ({ pageNum: 1, pageSize: 10 })
},
// 总条数
total: {
type: Number,
default: 0
},
// 加载状态
loading: {
type: Boolean,
default: false
},
// 金额格式化方法
formatAmount: {
type: Function,
required: true
},
// 日期格式化方法(年月日)
formatDate: {
type: Function,
required: true
},
},
data() {
return {
// 激活的Tab页
activeTab: "mainOrder"
};
},
computed: {
// 扁平后的订单产品明细Tab2使用
flatOrderItemList() {
const flatList = [];
if (!this.orderDetailList || this.orderDetailList.length === 0) {
return flatList;
}
this.orderDetailList.forEach(order => {
// 过滤空明细
if (!order.orderItemList || order.orderItemList.length === 0) return;
// 给每个明细添加主表关联信息
order.orderItemList.forEach(item => {
flatList.push({
...item,
orderCode: order.orderCode || '',
companyName: order.companyName || '',
customerCode: order.customerCode || ''
});
});
});
return flatList;
},
// 按客户分组的数据(复用原有逻辑,仅修改渲染方式)
customerGroupedList() {
if (!this.orderDetailList || this.orderDetailList.length === 0) {
return [];
}
const customerMap = new Map();
// 遍历订单,按客户分组
this.orderDetailList.forEach(order => {
// 跳过无效订单
if (!order.customerCode && !order.companyName) {
return;
}
// 生成唯一客户Key
const customerKey = `${order.customerCode || 'unknown_code'}_${order.companyName || 'unknown_company'}`;
// 转换订单金额为数字
const orderAmountNum = Number(order.orderAmount) || 0;
// 初始化客户信息
if (!customerMap.has(customerKey)) {
customerMap.set(customerKey, {
customerKey,
companyName: order.companyName || '未知公司',
customerCode: order.customerCode || '未知编码',
customerLevel: order.customerLevel || '未知等级',
industry: order.industry || '未知行业',
totalOrderAmount: 0,
orderCount: 0,
orderList: []
});
}
// 更新客户统计数据和订单列表
const customerItem = customerMap.get(customerKey);
customerItem.orderCount += 1;
customerItem.totalOrderAmount += orderAmountNum;
if (order.orderCode) {
customerItem.orderList.push({ ...order });
}
});
// 转换为数组返回
return Array.from(customerMap.values());
}
},
methods: {
// 分页大小改变,通知父组件
handleSizeChange(val) {
this.$emit("size-change", val);
},
// 当前页改变,通知父组件
handleCurrentChange(val) {
this.$emit("current-change", val);
},
// 表格勾选,通知父组件
handleSelectionChange(val) {
this.$emit("selection-change", val);
},
// 导出订单,通知父组件
handleExport() {
this.$emit("export-order");
}
}
};
</script>
<style scoped>
.order-detail-container {
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.04);
padding-bottom: 20px;
}
.table-toolbar {
padding: 15px 20px;
background-color: #fafafa;
border-bottom: 1px solid #ebeef5;
text-align: right;
}
.order-tabs {
margin: 20px;
}
/* 无数据提示样式 */
.empty-tip {
text-align: center;
padding: 30px 0;
color: #999;
font-size: 14px;
}
/* 客户分组折叠面板样式 */
.customer-collapse {
--el-collapse-item-content-padding: 0;
--el-collapse-item-border-width: 1px 0 0 0;
--el-collapse-border-color: #ebeef5;
}
/* 折叠面板标题样式 */
.collapse-title {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 15px;
font-size: 14px;
}
.collapse-title .company-name {
font-weight: bold;
color: #1f2d3d;
min-width: 150px;
}
.collapse-title .customer-info {
color: #606266;
min-width: 120px;
}
.collapse-title .summary-info {
color: #e6a23c;
font-weight: 500;
min-width: 180px;
}
/* 客户订单表格样式 */
.customer-order-table {
margin-top: 10px;
padding-bottom: 15px;
}
/* 优化折叠面板和表格样式 */
:deep(.el-collapse-item__header) {
padding: 12px 20px;
background-color: #fafafa;
}
:deep(.el-collapse-item__content) {
padding: 15px 20px;
border-top: 1px solid #ebeef5 !important;
}
:deep(.el-table__empty-block) {
min-height: 80px;
}
</style>