<template>
|
<div class="app-container">
|
<div class="search_form">
|
<el-form :model="searchForm" :inline="true">
|
<el-form-item label="合同编号:">
|
<el-input
|
v-model="searchForm.contractNo"
|
placeholder="请输入"
|
clearable
|
prefix-icon="Search"
|
@keyup.enter="handleQuery"
|
/>
|
</el-form-item>
|
<el-form-item label="签约单位简称:">
|
<el-input
|
v-model="searchForm.signingUnit"
|
placeholder="请输入"
|
clearable
|
prefix-icon="Search"
|
@keyup.enter="handleQuery"
|
/>
|
</el-form-item>
|
<el-form-item label="存档状态:">
|
<el-select
|
v-model="searchForm.archiveStatus"
|
placeholder="请选择"
|
clearable
|
style="width: 160px"
|
>
|
<el-option
|
v-for="item in archiveStatusOptions"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="签订时间:">
|
<el-date-picker
|
v-model="searchForm.signDateRange"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="daterange"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
clearable
|
@change="changeSignDateRange"
|
/>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
<el-button @click="resetSearch">重置</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
|
<div class="table_list">
|
<div class="actions">
|
<div></div>
|
<div>
|
<el-button type="primary" @click="openForm('add')">新增合同</el-button>
|
<el-button type="primary" plain @click="handleExport">导出</el-button>
|
<el-button type="danger" plain @click="handleDelete">删除</el-button>
|
</div>
|
</div>
|
<el-table
|
:data="tableData"
|
border
|
v-loading="tableLoading"
|
@selection-change="handleSelectionChange"
|
style="width: 100%"
|
height="calc(100vh - 18.5em)"
|
>
|
<el-table-column align="center" type="selection" width="55" fixed="left" />
|
<el-table-column align="center" label="序号" type="index" width="60" fixed="left" />
|
<el-table-column label="合同编号" prop="contractNo" width="160" show-overflow-tooltip />
|
<el-table-column label="签订时间" prop="signDate" width="110" show-overflow-tooltip />
|
<el-table-column label="签约单位简称" prop="signingUnit" min-width="160" show-overflow-tooltip />
|
<el-table-column label="签约周期" prop="contractPeriod" width="120" show-overflow-tooltip />
|
<el-table-column label="存档状态" prop="archiveStatus" width="120" align="center">
|
<template #default="scope">
|
<el-tag :type="getArchiveStatusType(scope.row.archiveStatus)">
|
{{ scope.row.archiveStatus || "-" }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="履约保证金(元)" prop="performanceBond" width="130" align="right" :formatter="formatAmountColumn" />
|
<el-table-column label="质保金情况" prop="warrantyDeposit" width="130" align="right" :formatter="formatAmountColumn" />
|
<el-table-column label="产值(元)" prop="outputValue" width="130" align="right" :formatter="formatAmountColumn" />
|
<el-table-column label="已回款金额(元)" prop="receivedAmount" width="130" align="right" :formatter="formatAmountColumn" />
|
<el-table-column label="结算次数" prop="settlementCount" width="90" align="center" />
|
<el-table-column label="应收金额(元)" prop="receivableAmount" width="130" align="right" :formatter="formatAmountColumn" />
|
<el-table-column label="应付比例" prop="payableRatio" width="100" align="center" />
|
<el-table-column label="最近一次开票时间" prop="lastInvoiceDate" width="130" show-overflow-tooltip />
|
<el-table-column label="已开票金额(元)" prop="invoicedAmount" width="130" align="right" :formatter="formatAmountColumn" />
|
<el-table-column label="情况说明" prop="remark" min-width="160" show-overflow-tooltip />
|
<el-table-column fixed="right" label="操作" width="150" align="center">
|
<template #default="scope">
|
<el-button link type="primary" @click="openForm('view', scope.row)">详情</el-button>
|
<el-button link type="primary" @click="openForm('edit', scope.row)">编辑</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination
|
v-show="total > 0"
|
:total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page="page.current"
|
:limit="page.size"
|
@pagination="paginationChange"
|
/>
|
</div>
|
|
<!-- 新增/编辑/详情弹窗 -->
|
<FormDialog
|
v-model="dialogVisible"
|
:title="
|
operationType === 'add'
|
? '新增合同'
|
: operationType === 'edit'
|
? '编辑合同'
|
: '合同详情'
|
"
|
:width="'78%'"
|
:operation-type="operationType"
|
@close="closeDialog"
|
@confirm="submitForm"
|
@cancel="closeDialog"
|
>
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="140px" label-position="top">
|
<el-divider content-position="left">合同基本信息</el-divider>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="合同编号:" prop="contractNo">
|
<el-input v-model="form.contractNo" placeholder="请输入合同编号" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="签订时间:" prop="signDate">
|
<el-date-picker
|
v-model="form.signDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="date"
|
placeholder="请选择"
|
clearable
|
style="width: 100%"
|
:disabled="operationType === 'view'"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="签约单位简称:" prop="signingUnit">
|
<el-input v-model="form.signingUnit" placeholder="请输入签约单位简称" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="签约周期:" prop="contractPeriod">
|
<el-input v-model="form.contractPeriod" placeholder="例如:1年 / 2024-01-01 至 2025-12-31" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="存档状态:" prop="archiveStatus">
|
<el-select v-model="form.archiveStatus" placeholder="请选择" clearable style="width: 100%" :disabled="operationType === 'view'">
|
<el-option v-for="item in archiveStatusOptions" :key="item.value" :label="item.label" :value="item.value" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="存档情况说明:" prop="archiveRemark">
|
<el-input v-model="form.archiveRemark" placeholder="请输入" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-divider content-position="left">产品信息</el-divider>
|
<div v-if="operationType !== 'view'" style="margin-bottom: 10px">
|
<el-button type="primary" plain @click="openProductForm('add')">添加产品</el-button>
|
</div>
|
<el-table :data="form.productList" border show-summary :summary-method="summarizeProducts">
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="产品大类" prop="productCategory" min-width="140" show-overflow-tooltip />
|
<el-table-column label="规格型号" prop="specificationModel" min-width="140" show-overflow-tooltip />
|
<el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" width="130" align="right">
|
<template #default="scope">{{ formatAmount(scope.row.taxInclusiveUnitPrice) }}</template>
|
</el-table-column>
|
<el-table-column label="约定/暂估用量" prop="agreedQuantity" width="130" align="right" />
|
<el-table-column label="合同计量单位" prop="contractUnit" width="120" align="center" />
|
<el-table-column label="已发货数量" prop="shippedQuantity" width="120" align="right" />
|
<el-table-column label="产值(元)" prop="outputValue" width="130" align="right">
|
<template #default="scope">{{ formatAmount(productOutputValue(scope.row)) }}</template>
|
</el-table-column>
|
<el-table-column v-if="operationType !== 'view'" label="操作" width="120" align="center">
|
<template #default="scope">
|
<el-button link type="primary" @click="openProductForm('edit', scope.row, scope.$index)">编辑</el-button>
|
<el-button link type="danger" @click="removeProduct(scope.$index)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<el-divider content-position="left">履约与质保</el-divider>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="履约保证金(元):">
|
<el-input-number v-model="form.performanceBond" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="质保金情况(元):">
|
<el-input-number v-model="form.warrantyDeposit" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="产值(元)(自动汇总):">
|
<el-input :model-value="formatAmount(computedOutputValue)" disabled />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-divider content-position="left">回款与结算</el-divider>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="已回款金额(元):">
|
<el-input-number v-model="form.receivedAmount" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="结算次数:">
|
<el-input-number v-model="form.settlementCount" :min="0" :precision="0" :step="1" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="应收金额(元):">
|
<el-input-number v-model="form.receivableAmount" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="应付比例:">
|
<el-input v-model="form.payableRatio" placeholder="例如:30% 或 0.3" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="合同节点应收(元):">
|
<el-input-number v-model="form.nodeReceivable" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="合同约定付款节点:">
|
<el-input v-model="form.paymentNodes" placeholder="请输入" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="结算记录:">
|
<el-input v-model="form.settlementRecord" type="textarea" :rows="3" placeholder="请输入" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-divider content-position="left">开票与违约</el-divider>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="开票要求:">
|
<el-input v-model="form.invoiceRequirement" placeholder="请输入" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="最近一次开票时间:">
|
<el-date-picker
|
v-model="form.lastInvoiceDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="date"
|
placeholder="请选择"
|
clearable
|
style="width: 100%"
|
:disabled="operationType === 'view'"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="已开票金额(元):">
|
<el-input-number v-model="form.invoicedAmount" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="违约金约定:">
|
<el-input v-model="form.penaltyAgreement" type="textarea" :rows="2" placeholder="请输入" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="情况说明:">
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
</FormDialog>
|
|
<!-- 添加/编辑产品弹窗 -->
|
<FormDialog
|
v-model="productDialogVisible"
|
:title="productOperationType === 'add' ? '添加产品' : '编辑产品'"
|
:width="'40%'"
|
@close="closeProductDialog"
|
@confirm="submitProduct"
|
@cancel="closeProductDialog"
|
>
|
<el-form :model="productForm" :rules="productRules" ref="productFormRef" label-width="140px" label-position="top">
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="产品大类:" prop="categoryId">
|
<el-tree-select
|
v-model="productForm.categoryId"
|
placeholder="请选择"
|
clearable
|
filterable
|
check-strictly
|
:data="productOptions"
|
:render-after-expand="false"
|
style="width: 100%"
|
@change="getModels"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="规格型号:" prop="productModelId">
|
<el-select
|
v-model="productForm.productModelId"
|
placeholder="请选择"
|
clearable
|
filterable
|
style="width: 100%"
|
@change="getProductModel"
|
>
|
<el-option
|
v-for="item in modelOptions"
|
:key="item.id"
|
:label="item.model"
|
:value="item.id"
|
/>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="合同计量单位:">
|
<el-input v-model="productForm.contractUnit" placeholder="请输入" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="含税单价(元):">
|
<el-input-number v-model="productForm.taxInclusiveUnitPrice" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="约定/暂估用量:">
|
<el-input-number v-model="productForm.agreedQuantity" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="已发货数量:">
|
<el-input-number v-model="productForm.shippedQuantity" :min="0" :precision="2" :step="0.01" controls-position="right" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
</FormDialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, computed, toRefs, getCurrentInstance, onMounted } from "vue";
|
import { ElMessageBox } from "element-plus";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import FormDialog from "@/components/Dialog/FormDialog.vue";
|
import { productTreeList, modelList } from "@/api/basicData/product.js";
|
import {
|
contractListPage,
|
getContractDetail,
|
addOrUpdateContract,
|
delContract,
|
} from "@/api/salesManagement/contractManagement.js";
|
|
const { proxy } = getCurrentInstance();
|
|
// 存档状态选项
|
const archiveStatusOptions = [
|
{ label: "已存档", value: "已存档" },
|
{ label: "已用章未寄回", value: "已用章未寄回" },
|
{ label: "未签约", value: "未签约" },
|
];
|
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
const total = ref(0);
|
const selectedRows = ref([]);
|
const page = reactive({ current: 1, size: 10 });
|
|
const searchForm = reactive({
|
contractNo: "",
|
signingUnit: "",
|
archiveStatus: "",
|
signDateRange: null,
|
signDateStart: undefined,
|
signDateEnd: undefined,
|
});
|
|
const operationType = ref("");
|
const dialogVisible = ref(false);
|
const currentId = ref("");
|
|
const formRef = ref();
|
const form = reactive({
|
contractNo: "",
|
signDate: "",
|
signingUnit: "",
|
contractPeriod: "",
|
archiveStatus: "",
|
archiveRemark: "",
|
productList: [],
|
performanceBond: undefined,
|
warrantyDeposit: undefined,
|
outputValue: 0,
|
receivedAmount: undefined,
|
settlementCount: 0,
|
receivableAmount: undefined,
|
payableRatio: "",
|
nodeReceivable: undefined,
|
paymentNodes: "",
|
settlementRecord: "",
|
invoiceRequirement: "",
|
lastInvoiceDate: "",
|
invoicedAmount: undefined,
|
penaltyAgreement: "",
|
remark: "",
|
});
|
|
const rules = {
|
contractNo: [{ required: true, message: "请输入合同编号", trigger: "blur" }],
|
signDate: [{ required: true, message: "请选择签订时间", trigger: "change" }],
|
signingUnit: [{ required: true, message: "请输入签约单位简称", trigger: "blur" }],
|
archiveStatus: [{ required: true, message: "请选择存档状态", trigger: "change" }],
|
};
|
|
// 产品弹窗相关
|
const productDialogVisible = ref(false);
|
const productOperationType = ref("");
|
const productIndex = ref(-1);
|
const productOptions = ref([]);
|
const modelOptions = ref([]);
|
const productFormRef = ref();
|
const productFormData = reactive({
|
productForm: {
|
categoryId: "",
|
productCategory: "",
|
productModelId: "",
|
specificationModel: "",
|
contractUnit: "",
|
taxInclusiveUnitPrice: undefined,
|
agreedQuantity: undefined,
|
shippedQuantity: undefined,
|
},
|
productRules: {
|
categoryId: [{ required: true, message: "请选择产品大类", trigger: "change" }],
|
productModelId: [{ required: true, message: "请选择规格型号", trigger: "change" }],
|
},
|
});
|
const { productForm, productRules } = toRefs(productFormData);
|
|
// 金额格式化
|
const formatAmount = (val) => {
|
if (val === undefined || val === null || val === "") return "0.00";
|
const num = Number(val);
|
return Number.isNaN(num) ? "0.00" : num.toFixed(2);
|
};
|
const formatAmountColumn = (row, column, cellValue) => formatAmount(cellValue);
|
|
// 单个产品产值 = 含税单价 * 已发货数量
|
const productOutputValue = (row) => {
|
const price = Number(row?.taxInclusiveUnitPrice || 0);
|
const qty = Number(row?.shippedQuantity || 0);
|
return price * qty;
|
};
|
|
// 合同产值自动汇总
|
const computedOutputValue = computed(() => {
|
return (form.productList || []).reduce((sum, row) => sum + productOutputValue(row), 0);
|
});
|
|
const getArchiveStatusType = (status) => {
|
const map = {
|
已存档: "success",
|
已用章未寄回: "warning",
|
未签约: "info",
|
};
|
return map[status] || "info";
|
};
|
|
// 产品表合计
|
const summarizeProducts = (param) => {
|
const { columns, data } = param;
|
return columns.map((col, index) => {
|
if (index === 0) return "合计";
|
if (["agreedQuantity", "shippedQuantity"].includes(col.property)) {
|
return (data || []).reduce((sum, row) => sum + Number(row[col.property] || 0), 0).toFixed(2);
|
}
|
if (col.property === "outputValue") {
|
return (data || []).reduce((sum, row) => sum + productOutputValue(row), 0).toFixed(2);
|
}
|
return "";
|
});
|
};
|
|
// 获取产品大类树
|
const getProductOptions = () => {
|
return productTreeList().then((res) => {
|
productOptions.value = convertIdToValue(res);
|
return productOptions.value;
|
});
|
};
|
|
// 选择产品大类后加载规格型号
|
const getModels = (value) => {
|
productForm.value.productCategory = findNodeById(productOptions.value, value);
|
productForm.value.productModelId = "";
|
productForm.value.specificationModel = "";
|
productForm.value.contractUnit = "";
|
modelList({ id: value }).then((res) => {
|
modelOptions.value = res;
|
});
|
};
|
|
// 选择规格型号后带出单位
|
const getProductModel = (value) => {
|
const index = modelOptions.value.findIndex((item) => item.id === value);
|
if (index !== -1) {
|
productForm.value.specificationModel = modelOptions.value[index].model;
|
productForm.value.contractUnit = modelOptions.value[index].unit;
|
} else {
|
productForm.value.specificationModel = "";
|
productForm.value.contractUnit = "";
|
}
|
};
|
|
function convertIdToValue(data) {
|
return (data || []).map((item) => {
|
const { id, children, ...rest } = item;
|
const newItem = { ...rest, value: id };
|
if (children && children.length > 0) {
|
newItem.children = convertIdToValue(children);
|
}
|
return newItem;
|
});
|
}
|
|
function findNodeById(nodes, productId) {
|
for (let i = 0; i < nodes.length; i++) {
|
if (nodes[i].value === productId) return nodes[i].label;
|
if (nodes[i].children && nodes[i].children.length > 0) {
|
const found = findNodeById(nodes[i].children, productId);
|
if (found) return found;
|
}
|
}
|
return null;
|
}
|
|
function findNodeIdByLabel(nodes, label) {
|
if (!label) return null;
|
for (let i = 0; i < nodes.length; i++) {
|
const node = nodes[i];
|
if (node.label === label) return node.value;
|
if (node.children && node.children.length > 0) {
|
const found = findNodeIdByLabel(node.children, label);
|
if (found !== null && found !== undefined) return found;
|
}
|
}
|
return null;
|
}
|
|
// 打开产品弹窗
|
const openProductForm = async (type, row, index) => {
|
productOperationType.value = type;
|
productIndex.value = index ?? -1;
|
proxy.resetForm("productFormRef");
|
Object.keys(productForm.value).forEach((key) => {
|
productForm.value[key] = key === "categoryId" || key === "productModelId" ? "" : key.includes("Price") || key.includes("Quantity") ? undefined : "";
|
});
|
if (type === "add") {
|
if (!productOptions.value.length) {
|
await getProductOptions();
|
}
|
} else {
|
productForm.value.productCategory = row.productCategory;
|
productForm.value.specificationModel = row.specificationModel;
|
productForm.value.contractUnit = row.contractUnit;
|
productForm.value.taxInclusiveUnitPrice = row.taxInclusiveUnitPrice;
|
productForm.value.agreedQuantity = row.agreedQuantity;
|
productForm.value.shippedQuantity = row.shippedQuantity;
|
try {
|
const options = productOptions.value.length ? productOptions.value : await getProductOptions();
|
const categoryId = findNodeIdByLabel(options, row.productCategory);
|
if (categoryId) {
|
productForm.value.categoryId = categoryId;
|
const models = await modelList({ id: categoryId });
|
modelOptions.value = models || [];
|
const currentModel = (modelOptions.value || []).find(
|
(m) => m.model === row.specificationModel
|
);
|
if (currentModel) productForm.value.productModelId = currentModel.id;
|
}
|
} catch (e) {
|
console.error("加载产品规格型号失败", e);
|
}
|
}
|
productDialogVisible.value = true;
|
};
|
|
const submitProduct = () => {
|
proxy.$refs["productFormRef"].validate((valid) => {
|
if (!valid) return;
|
const item = {
|
productCategory: productForm.value.productCategory,
|
specificationModel: productForm.value.specificationModel,
|
productModelId: productForm.value.productModelId,
|
contractUnit: productForm.value.contractUnit,
|
taxInclusiveUnitPrice: productForm.value.taxInclusiveUnitPrice,
|
agreedQuantity: productForm.value.agreedQuantity,
|
shippedQuantity: productForm.value.shippedQuantity,
|
};
|
if (productOperationType.value === "add") {
|
form.productList.push(item);
|
} else {
|
form.productList[productIndex.value] = item;
|
}
|
closeProductDialog();
|
});
|
};
|
|
const closeProductDialog = () => {
|
proxy.resetForm("productFormRef");
|
productDialogVisible.value = false;
|
};
|
|
const removeProduct = (index) => {
|
form.productList.splice(index, 1);
|
};
|
|
const changeSignDateRange = (value) => {
|
if (value) {
|
searchForm.signDateStart = value[0];
|
searchForm.signDateEnd = value[1];
|
} else {
|
searchForm.signDateStart = undefined;
|
searchForm.signDateEnd = undefined;
|
}
|
handleQuery();
|
};
|
|
const resetSearch = () => {
|
searchForm.contractNo = "";
|
searchForm.signingUnit = "";
|
searchForm.archiveStatus = "";
|
searchForm.signDateRange = null;
|
searchForm.signDateStart = undefined;
|
searchForm.signDateEnd = undefined;
|
page.current = 1;
|
getList();
|
};
|
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
|
const paginationChange = (obj) => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
const getList = () => {
|
tableLoading.value = true;
|
const { signDateRange, ...rest } = searchForm;
|
const params = { ...rest, current: page.current, size: page.size };
|
delete params.signDateRange;
|
return contractListPage(params)
|
.then((res) => {
|
tableLoading.value = false;
|
tableData.value = res.records || res.data?.records || [];
|
total.value = res.total ?? res.data?.total ?? 0;
|
})
|
.catch(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
const handleSelectionChange = (selection) => {
|
selectedRows.value = selection;
|
};
|
|
const resetFormData = () => {
|
Object.keys(form).forEach((key) => {
|
if (key === "productList") form[key] = [];
|
else if (key === "settlementCount") form[key] = 0;
|
else if (key === "outputValue") form[key] = 0;
|
else form[key] = "";
|
});
|
};
|
|
const openForm = (type, row) => {
|
operationType.value = type;
|
resetFormData();
|
if (type === "add") {
|
dialogVisible.value = true;
|
} else {
|
currentId.value = row.id;
|
getContractDetail({ id: row.id }).then((res) => {
|
const detail = res.data || res;
|
Object.keys(form).forEach((key) => {
|
if (key === "productList") {
|
form[key] = Array.isArray(detail[key]) ? detail[key] : [];
|
} else if (detail[key] !== undefined && detail[key] !== null) {
|
form[key] = detail[key];
|
}
|
});
|
dialogVisible.value = true;
|
});
|
}
|
};
|
|
const submitForm = () => {
|
proxy.$refs["formRef"].validate((valid) => {
|
if (!valid) return;
|
if (!form.productList || form.productList.length === 0) {
|
proxy.$modal.msgWarning("请至少添加一条产品信息");
|
return;
|
}
|
form.outputValue = Number(computedOutputValue.value.toFixed(2));
|
addOrUpdateContract(form).then(() => {
|
proxy.$modal.msgSuccess("保存成功");
|
closeDialog();
|
getList();
|
});
|
});
|
};
|
|
const closeDialog = () => {
|
proxy.resetForm("formRef");
|
dialogVisible.value = false;
|
};
|
|
const handleDelete = () => {
|
if (selectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
const ids = selectedRows.value.map((item) => item.id);
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
delContract(ids).then(() => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
});
|
})
|
.catch(() => {});
|
};
|
|
const handleExport = () => {
|
proxy.download("/sales/contract/export", { ...searchForm }, "合同管理.xlsx");
|
};
|
|
onMounted(() => {
|
getList();
|
getProductOptions();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.search_form {
|
margin-bottom: 10px;
|
}
|
|
.actions {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 10px;
|
}
|
</style>
|