<template>
|
<div class="app-container">
|
<div class="search_form">
|
<el-form :model="searchForm"
|
:inline="true">
|
<el-form-item label="客户名称:">
|
<el-select v-model="searchForm.customerId"
|
filterable
|
placeholder="请选择客户名称"
|
clearable
|
style="width: 220px"
|
@change="handleQuery">
|
<el-option v-for="item in customerOption"
|
:key="item.id"
|
:label="item.customerName"
|
:value="item.id">
|
{{ item.customerName + "——" + item.taxpayerIdentificationNumber }}
|
</el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="销售合同号:">
|
<el-input v-model="searchForm.salesContractNo"
|
placeholder="请输入"
|
clearable
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="项目名称:">
|
<el-input v-model="searchForm.projectName"
|
placeholder="请输入"
|
clearable
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="录入日期:">
|
<el-date-picker v-model="searchForm.entryDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="daterange"
|
placeholder="请选择"
|
clearable
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary"
|
@click="handleQuery">搜索</el-button>
|
<el-button @click="resetQuery">重置</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="table_list">
|
<el-table :data="tableData"
|
border
|
v-loading="loading">
|
<el-table-column label="序号"
|
type="index"
|
width="60"
|
align="center" />
|
<el-table-column label="反审时间"
|
prop="counterReviewTime"
|
align="center">
|
<template #default="scope">
|
{{ formatTime(scope.row.counterReviewTime) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="反审人"
|
prop="counterReviewPerson"
|
align="center" />
|
<el-table-column label="销售合同号"
|
prop="salesContractNo" />
|
<el-table-column label="客户名称"
|
prop="customerName"
|
show-overflow-tooltip />
|
<el-table-column label="项目名称"
|
prop="projectName"
|
show-overflow-tooltip />
|
<el-table-column label="合同金额(元)"
|
prop="contractAmount"
|
align="right">
|
<template #default="scope">
|
{{ formattedNumber(null, null, scope.row.contractAmount) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="操作"
|
width="100"
|
align="center"
|
fixed="right">
|
<template #default="scope">
|
<el-button link
|
type="primary"
|
@click="handleView(scope.row)">查看快照</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination v-show="total > 0"
|
:total="total"
|
:page="page.current"
|
:limit="page.size"
|
@pagination="paginationChange" />
|
</div>
|
<!-- 快照详情对话框 -->
|
<el-dialog v-model="dialogVisible"
|
title="反审数据快照详情"
|
width="85%">
|
<div class="snapshot-detail">
|
<el-divider content-position="left">基本信息</el-divider>
|
<el-descriptions border
|
:column="3">
|
<el-descriptions-item label="销售合同号">{{ currentSnapshot.salesContractNo }}</el-descriptions-item>
|
<el-descriptions-item label="业务员">{{ currentSnapshot.salesman }}</el-descriptions-item>
|
<el-descriptions-item label="客户名称">{{ currentSnapshot.customerName }}</el-descriptions-item>
|
<el-descriptions-item label="项目名称">{{ currentSnapshot.projectName }}</el-descriptions-item>
|
<el-descriptions-item label="签订日期">{{ currentSnapshot.executionDate }}</el-descriptions-item>
|
<el-descriptions-item label="交货日期">{{ currentSnapshot.deliveryDate }}</el-descriptions-item>
|
<el-descriptions-item label="录入人">{{ currentSnapshot.entryPersonName || currentSnapshot.entryPerson }}</el-descriptions-item>
|
<el-descriptions-item label="录入日期">{{ currentSnapshot.entryDate }}</el-descriptions-item>
|
<el-descriptions-item label="合同金额(元)">{{ formattedNumber(null, null, currentSnapshot.contractAmount) }}</el-descriptions-item>
|
<el-descriptions-item label="反审时间">{{ formatTime(currentSnapshot.counterReviewTime) }}</el-descriptions-item>
|
<el-descriptions-item label="反审人">{{ currentSnapshot.counterReviewPerson }}</el-descriptions-item>
|
</el-descriptions>
|
<el-divider content-position="left"
|
style="margin-top: 30px;">产品信息</el-divider>
|
<el-table :data="currentSnapshot.productData"
|
border
|
stripe
|
show-summary
|
:summary-method="summarizeMainTable">
|
<el-table-column align="center"
|
label="序号"
|
type="index"
|
width="60" />
|
<el-table-column label="产品大类"
|
prop="productCategory"
|
min-width="120"
|
show-overflow-tooltip />
|
<el-table-column label="规格型号"
|
prop="specificationModel"
|
min-width="150"
|
show-overflow-tooltip />
|
<el-table-column label="厚度(mm)"
|
prop="thickness"
|
width="90"
|
align="center" />
|
<el-table-column label="楼层编号"
|
prop="floorCode"
|
min-width="120"
|
show-overflow-tooltip />
|
<el-table-column label="含税单价(元)"
|
prop="taxInclusiveUnitPrice"
|
width="110"
|
align="right">
|
<template #default="scope">
|
{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="宽(mm)"
|
prop="width"
|
width="80"
|
align="center" />
|
<el-table-column label="高(mm)"
|
prop="height"
|
width="80"
|
align="center" />
|
<el-table-column label="数量"
|
prop="quantity"
|
width="80"
|
align="center" />
|
<el-table-column label="结算单片面积(㎡)"
|
prop="settlePieceArea"
|
width="130"
|
align="center">
|
<template #default="scope">
|
{{ scope.row.settlePieceArea ? Number(scope.row.settlePieceArea).toFixed(4) : "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="面积(m²)"
|
prop="actualTotalArea"
|
width="110"
|
align="center">
|
<template #default="scope">
|
{{ scope.row.actualTotalArea ? Number(scope.row.actualTotalArea).toFixed(4) : "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="税率(%)"
|
prop="taxRate"
|
width="80"
|
align="center" />
|
<el-table-column label="含税总价(元)"
|
prop="taxInclusiveTotalPrice"
|
width="110"
|
align="right">
|
<template #default="scope">
|
{{ formattedNumber(null, null, scope.row.taxInclusiveTotalPrice) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="不含税总价(元)"
|
prop="taxExclusiveTotalPrice"
|
width="110"
|
align="right">
|
<template #default="scope">
|
{{ formattedNumber(null, null, scope.row.taxExclusiveTotalPrice) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="加工要求"
|
prop="processRequirement"
|
min-width="150"
|
show-overflow-tooltip />
|
<el-table-column label="发票类型"
|
prop="invoiceType"
|
width="100"
|
align="center" />
|
<el-table-column label="额外加工"
|
min-width="180">
|
<template #default="scope">
|
<div v-if="scope.row.salesProductProcessList && scope.row.salesProductProcessList.length > 0">
|
<el-tag v-for="(item, idx) in scope.row.salesProductProcessList"
|
:key="idx"
|
size="small"
|
type="info"
|
style="margin: 2px;">
|
{{ item.processName }} ({{ item.quantity }})
|
</el-tag>
|
</div>
|
</template>
|
</el-table-column>
|
<el-table-column label="备注"
|
prop="remark"
|
min-width="120"
|
show-overflow-tooltip />
|
<el-table-column label="重箱"
|
prop="heavyBox"
|
width="100"
|
show-overflow-tooltip />
|
</el-table>
|
<el-row :gutter="30"
|
style="margin-top: 20px;">
|
<el-col :span="12">
|
<div class="remark-section">
|
<div class="label">备注:</div>
|
<div class="content">{{ currentSnapshot.remarks || "无" }}</div>
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="remark-section">
|
<div class="label">客户备注:</div>
|
<div class="content">{{ currentSnapshot.customerRemarks || "无" }}</div>
|
</div>
|
</el-col>
|
</el-row>
|
</div>
|
<template #footer>
|
<el-button @click="dialogVisible = false">关闭</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted, getCurrentInstance } from "vue";
|
import {
|
customerList,
|
ledgerListPage,
|
getSalesLedgerWithProducts,
|
} from "@/api/salesManagement/salesLedger.js";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import dayjs from "dayjs";
|
|
const { proxy } = getCurrentInstance();
|
const loading = ref(false);
|
const tableData = ref([]);
|
const total = ref(0);
|
const dialogVisible = ref(false);
|
const currentSnapshot = ref({});
|
const customerOption = ref([]);
|
|
const searchForm = reactive({
|
customerId: undefined,
|
salesContractNo: "",
|
projectName: "",
|
width: undefined,
|
height: undefined,
|
entryDate: [],
|
deliveryStatus: undefined,
|
stockStatus: undefined,
|
reverseAuditDate: [],
|
});
|
|
const page = reactive({
|
current: 1,
|
size: 10,
|
});
|
|
const getList = () => {
|
loading.value = true;
|
|
const params = {
|
...page,
|
salesContractNo: searchForm.salesContractNo,
|
projectName: searchForm.projectName,
|
width: searchForm.width,
|
height: searchForm.height,
|
deliveryStatus: searchForm.deliveryStatus,
|
stockStatus: searchForm.stockStatus,
|
reviewStatus: 2, // 固定传2
|
beginTime: searchForm.reverseAuditDate?.[0],
|
endTime: searchForm.reverseAuditDate?.[1],
|
entryDateStart: searchForm.entryDate?.[0],
|
entryDateEnd: searchForm.entryDate?.[1],
|
};
|
|
// 查询客户名称与台账保持一致:先选 customerId,再映射为 customerName 查询
|
const selectedCustomer = (customerOption.value || []).find(
|
item => String(item?.id ?? "") === String(searchForm.customerId ?? "")
|
);
|
if (selectedCustomer?.customerName) {
|
params.customerName = String(selectedCustomer.customerName).trim();
|
}
|
|
ledgerListPage(params)
|
.then(res => {
|
tableData.value = res.records || [];
|
total.value = res.total || 0;
|
})
|
.catch(err => {
|
console.error("获取反审历史失败:", err);
|
tableData.value = [];
|
total.value = 0;
|
})
|
.finally(() => {
|
loading.value = false;
|
});
|
};
|
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
|
const paginationChange = obj => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
const resetQuery = () => {
|
searchForm.customerId = undefined;
|
searchForm.salesContractNo = "";
|
searchForm.projectName = "";
|
searchForm.width = undefined;
|
searchForm.height = undefined;
|
searchForm.entryDate = [];
|
searchForm.deliveryStatus = undefined;
|
searchForm.stockStatus = undefined;
|
searchForm.reverseAuditDate = [];
|
page.current = 1;
|
handleQuery();
|
};
|
|
const getCustomerOption = () => {
|
customerList().then(res => {
|
customerOption.value = res || [];
|
});
|
};
|
|
const handleView = row => {
|
getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
|
currentSnapshot.value = { ...res };
|
// 字段名兼容处理,与销售台账保持一致
|
currentSnapshot.value.customerRemarks =
|
res?.customerRemarks ?? res?.customer_remarks ?? "";
|
dialogVisible.value = true;
|
});
|
};
|
|
const formattedNumber = (row, column, cellValue) => {
|
if (cellValue == null || cellValue === "") return "0.00";
|
return Number(cellValue).toLocaleString("zh-CN", {
|
minimumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
});
|
};
|
|
const formatTime = time => {
|
if (!time) return "";
|
return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
|
};
|
|
const summarizeMainTable = param => {
|
const { columns, data } = param;
|
const sums = [];
|
columns.forEach((column, index) => {
|
if (index === 0) {
|
sums[index] = "合计";
|
return;
|
}
|
const prop = column.property;
|
if (
|
[
|
"quantity",
|
"actualTotalArea",
|
"taxInclusiveTotalPrice",
|
"taxExclusiveTotalPrice",
|
].includes(prop)
|
) {
|
const values = data.map(item => Number(item[prop]));
|
if (!values.every(value => isNaN(value))) {
|
const sum = values.reduce((prev, curr) => {
|
const value = Number(curr);
|
if (!isNaN(value)) {
|
return prev + curr;
|
} else {
|
return prev;
|
}
|
}, 0);
|
if (prop === "quantity") {
|
sums[index] = sum;
|
} else if (prop === "actualTotalArea") {
|
sums[index] = sum.toFixed(4);
|
} else {
|
sums[index] = sum.toLocaleString("zh-CN", {
|
minimumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
});
|
}
|
} else {
|
sums[index] = "";
|
}
|
} else {
|
sums[index] = "";
|
}
|
});
|
return sums;
|
};
|
|
onMounted(() => {
|
getCustomerOption();
|
getList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.app-container {
|
padding: 20px;
|
}
|
.search_form {
|
margin-bottom: 20px;
|
}
|
.table_list {
|
background: #fff;
|
padding: 20px;
|
border-radius: 4px;
|
}
|
.snapshot-detail {
|
max-height: 70vh;
|
overflow-y: auto;
|
padding-right: 10px;
|
|
.remark-section {
|
margin-bottom: 15px;
|
.label {
|
font-weight: bold;
|
color: #606266;
|
margin-bottom: 8px;
|
}
|
.content {
|
padding: 10px;
|
background-color: #f5f7fa;
|
border-radius: 4px;
|
min-height: 40px;
|
white-space: pre-wrap;
|
}
|
}
|
}
|
</style>
|