| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="采购合同号:" prop="purchaseLedgerNo"> |
| | | <el-input v-model="form.purchaseLedgerNo" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="销售合同号:" prop="salesContractNo"> |
| | | <el-input |
| | | v-model="form.salesContractNo" |
| | | placeholder="自动填充" |
| | | clearable |
| | | disabled |
| | | /> |
| | | <el-input v-model="form.purchaseLedgerNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="发票金额(元):" prop="invoiceAmount"> |
| | | <el-input |
| | | type="number" |
| | | :step="0.01" |
| | | :min="0" |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" |
| | | v-model="form.invoiceAmount" |
| | | placeholder="自动填充" |
| | | placeholder="请输入发票金额" |
| | | clearable |
| | | :disabled="true" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | style="width: 100%" |
| | | v-model="form.entryDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="录入日期:" prop="enterDate"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.enterDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="录入日期:" prop="enterDate"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.enterDate" |
| | | type="date" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | </el-row> |
| | | <el-form-item label="产品信息:"> </el-form-item> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="form.productData" |
| | | height="auto" |
| | | <el-table |
| | | :data="form.productData" |
| | | border |
| | | show-summary |
| | | :summary-method="summarizeChildrenTable" |
| | | > |
| | | <template #ticketsNumRef="{ row }"> |
| | | <el-input-number |
| | | v-model="row.ticketsNum" |
| | | placeholder="请选择" |
| | | :min="0" |
| | | :step="0.1" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="invoiceNumBlur(row)" |
| | | /> |
| | | </template> |
| | | <template #ticketsAmountRef="{ row }"> |
| | | <el-input-number |
| | | v-model="row.ticketsAmount" |
| | | placeholder="请选择" |
| | | :min="0" |
| | | :step="0.1" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="invoiceAmountBlur(row)" |
| | | /> |
| | | </template> |
| | | </PIMTable> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column label="所属合同" prop="purchaseLedgerNo" width="200"> |
| | | <template #default="{ row }"> |
| | | <el-tag type="primary">{{ row.purchaseLedgerNo }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="产品大类" prop="productCategory" /> |
| | | <el-table-column label="规格型号" prop="specificationModel" width="150" /> |
| | | <el-table-column label="单位" prop="unit" width="70" /> |
| | | <el-table-column label="数量" prop="quantity" width="70" /> |
| | | <el-table-column label="税率(%)" prop="taxRate" width="80" /> |
| | | <el-table-column |
| | | label="含税单价(元)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column |
| | | label="含税总价(元)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column |
| | | label="不含税总价(元)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column label="本次开票数" prop="ticketsNum" width="180"> |
| | | <template #default="scope"> |
| | | <el-input-number :step="0.1" :min="0" style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsNum" |
| | | @change="invoiceNumBlur(scope.row)" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="本次开票金额(元)" |
| | | prop="ticketsAmount" |
| | | width="180" |
| | | > |
| | | <template #default="scope"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsAmount" |
| | | @change="invoiceAmountBlur(scope.row)" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="closeModal">{{ modalOptions.cancelText }}</el-button> |
| | | <el-button type="primary" :loading="modalLoading" @click="submitForm"> |
| | | {{ modalOptions.confirmText }} |
| | | </el-button> |
| | | <el-button type="primary" :loading="modalLoading" @click="submitForm"> |
| | | 确认 |
| | | </el-button> |
| | | <el-button @click="closeModal">取消</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, getCurrentInstance } from "vue"; |
| | | import { defineEmits } from 'vue'; |
| | | import { useModal } from "@/hooks/useModal"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import FileUpload from "@/components/Upload/FileUpload.vue"; |
| | |
| | | tempFileIds: [], // 文件 |
| | | }); |
| | | |
| | | const selectedContracts = ref([]); // 存储选中的合同数据 |
| | | |
| | | const rules = ref({ |
| | | invoiceNumber: [ |
| | | { required: true, message: "请输入发票号", trigger: "blur" }, |
| | |
| | | title: "来票登记", |
| | | }); |
| | | |
| | | const emit = defineEmits(['refreshList']); |
| | | |
| | | const columns = [ |
| | | { |
| | | label: "产品大类", |
| | | prop: "productCategory", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "规格型号", |
| | | prop: "specificationModel", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "单位", |
| | |
| | | { |
| | | label: "未来票数", |
| | | prop: "futureTickets", |
| | | width: 100, |
| | | }, |
| | | { |
| | | label: "未来票金额(元)", |
| | | prop: "futureTicketsAmount", |
| | | width: 200, |
| | | }, |
| | | ]; |
| | | |
| | | const getTableData = async (type, id) => { |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | if (cellValue == 0) { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | } |
| | | if (cellValue) { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | } else { |
| | | return cellValue; |
| | | } |
| | | }; |
| | | const getTableData = async (type, selectedRows) => { |
| | | if (type == "add") { |
| | | const { data } = await getPurchaseNoById({ id }); |
| | | form.purchaseLedgerNo = data.purchaseContractNumber; |
| | | form.invoiceAmount = data.invoiceAmount; |
| | | form.invoiceNumber = data.invoiceNumber; |
| | | form.entryDate = data.entryDate; |
| | | form.salesContractNoId = data.salesContractNoId; |
| | | |
| | | const { data: infoData } = await getInfo({ id }); |
| | | form.salesContractNo = infoData.salesContractNo; |
| | | form.projectName = infoData.projectName; |
| | | form.supplierName = infoData.supplierName; |
| | | form.productData = infoData.productData; |
| | | // 检查所有选择的合同是否具有相同的供应商名称 |
| | | const firstRow = selectedRows[0]; |
| | | const isSameSupplier = selectedRows.every(row => |
| | | row.supplierName === firstRow.supplierName |
| | | ); |
| | | |
| | | if (!isSameSupplier) { |
| | | proxy.$modal.msgError("请选择相同供应商名称的合同"); |
| | | return; |
| | | } |
| | | |
| | | // 允许不同的采购合同号批量处理,无需检查重复 |
| | | |
| | | // 清空表单数据 |
| | | Object.keys(form).forEach(key => { |
| | | if (key !== 'productData') { |
| | | form[key] = undefined; |
| | | } |
| | | }); |
| | | form.productData = []; |
| | | |
| | | // 加载所有选中合同的产品数据 |
| | | const promises = selectedRows.map(row => |
| | | getInfo({ id: row.id }) |
| | | ); |
| | | |
| | | Promise.all(promises).then(results => { |
| | | // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 |
| | | const allProductData = []; |
| | | results.forEach((result, index) => { |
| | | const contract = selectedRows[index]; |
| | | const contractId = contract.id; |
| | | if (result.data && result.data.productData) { |
| | | result.data.productData.forEach(item => { |
| | | allProductData.push({ |
| | | ...item, |
| | | id: contractId, // 明确设置合同ID |
| | | purchaseLedgerNo: contract.purchaseContractNumber, // 添加采购合同号 |
| | | supplierName: contract.supplierName, // 添加供应商名称 |
| | | projectName: contract.projectName // 添加项目名称 |
| | | }); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | // 设置表单数据(使用第一个合同的基本信息,采购合同号留空) |
| | | form.purchaseLedgerNo = ""; // 采购合同号留空,因为会在产品表格中分别显示 |
| | | form.invoiceAmount = 0; |
| | | form.invoiceNumber = ""; |
| | | form.entryDate = dayjs().format("YYYY-MM-DD"); |
| | | form.enterDate = dayjs().format("YYYY-MM-DD"); |
| | | form.salesContractNo = results[0].data.salesContractNo; |
| | | form.projectName = results[0].data.projectName; |
| | | form.supplierName = results[0].data.supplierName; |
| | | // 保留录入人信息 |
| | | form.issUerId = userStore.id; |
| | | form.issUer = userStore.nickName; |
| | | |
| | | form.productData = allProductData; |
| | | |
| | | // 存储选中的合同数据 |
| | | selectedContracts.value = selectedRows; |
| | | }); |
| | | } else if (type == "edit") { |
| | | const id = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; |
| | | const data = await getPurchaseById({ id, type: 2 }); |
| | | form.purchaseLedgerNo = data.purchaseContractNumber; |
| | | form.invoiceAmount = data.invoiceAmount; |
| | |
| | | form.productData = data.productData; |
| | | } |
| | | }; |
| | | |
| | | // 子表合计方法 |
| | | const summarizeChildrenTable = (param) => { |
| | | return proxy.summarizeTable(param, [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | "ticketsNum", |
| | | "ticketsAmount", |
| | | "ticketsAmountRef", |
| | | "futureTickets", |
| | | "futureTicketsAmount", |
| | | ]); |
| | | }; |
| | | //本次来票数失焦操作 |
| | | const invoiceNumBlur = (row) => { |
| | | if (!row.ticketsNum || row.ticketsNum === "") { |
| | |
| | | return; |
| | | } |
| | | // 计算本次来票金额 |
| | | row.ticketsAmount = row.ticketsNum * row.taxInclusiveUnitPrice; |
| | | row.ticketsAmount = (row.ticketsNum * row.taxInclusiveUnitPrice).toFixed(2) |
| | | // 计算未来票数 |
| | | row.futureTickets = row.tempFutureTickets - row.ticketsNum; |
| | | row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2) |
| | | // 计算未来票金额 |
| | | row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount; |
| | | row.futureTicketsAmount = (row.tempFutureTicketsAmount - row.ticketsAmount).toFixed(2) |
| | | calculateinvoiceAmount(); |
| | | }; |
| | | |
| | |
| | | (row.ticketsAmount / row.taxInclusiveUnitPrice).toFixed(2) |
| | | ); |
| | | // 计算未来票数 |
| | | row.futureTickets = row.tempFutureTickets - row.ticketsNum; |
| | | row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2) |
| | | // 计算未来票金额 |
| | | row.futureTicketsAmount = row.tempFutureTicketsAmount - row.ticketsAmount; |
| | | row.futureTicketsAmount = (row.tempFutureTicketsAmount - row.ticketsAmount).toFixed(2) |
| | | calculateinvoiceAmount(); |
| | | }; |
| | | |
| | |
| | | let invoiceAmountTotal = 0; |
| | | form.productData.forEach((item) => { |
| | | if (item.ticketsAmount) { |
| | | invoiceAmountTotal += item.ticketsAmount; |
| | | invoiceAmountTotal += Number(item.ticketsAmount); |
| | | } |
| | | }); |
| | | form.invoiceAmount = invoiceAmountTotal.toFixed(2); |
| | | }; |
| | | |
| | | const open = (type, eid) => { |
| | | openModal(); |
| | | getTableData(type, eid); |
| | | id.value = eid; |
| | | const open = async (type, selectedRows) => { |
| | | visible.value = true; |
| | | |
| | | // 如果是批量操作,设置标题 |
| | | if (Array.isArray(selectedRows) && selectedRows.length > 1) { |
| | | modalOptions.title = `批量新增 (${selectedRows.length}条)`; |
| | | } else { |
| | | modalOptions.title = type == "add" ? "新增" : "编辑"; |
| | | } |
| | | |
| | | // 如果是单个操作,获取id |
| | | if (!Array.isArray(selectedRows) || selectedRows.length === 1) { |
| | | const idValue = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; |
| | | id.value = idValue; |
| | | } |
| | | |
| | | await getTableData(type, selectedRows); |
| | | }; |
| | | |
| | | const uploadSuccess = (response) => { |
| | |
| | | form.tempFileIds = form.tempFileIds.filter((item) => item !== tempId); |
| | | }; |
| | | |
| | | const closeAndRefresh = () => { |
| | | closeModal(); |
| | | emit('refreshList'); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | formRef.value.validate(async (valid, fields) => { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | modalLoading.value = true; |
| | | const { code } = await addOrUpdateRegistration({ |
| | | purchaseLedgerId: id.value, |
| | | purchaseContractNumber: form.purchaseLedgerNo, |
| | | invoiceNumber: form.invoiceNumber, |
| | | invoiceAmount: form.invoiceAmount, |
| | | salesContractNo: form.salesContractNo, |
| | | projectName: form.projectName, |
| | | productData: form.productData, |
| | | issueDate: form.entryDate, |
| | | issUerId: form.issUerId, // 录入人id |
| | | issUer: form.issUer, // 录入人 |
| | | salesContractNoId: form.salesContractNoId, |
| | | supplierName: form.supplierName, |
| | | tempFileIds: form.tempFileIds, |
| | | enterDate: form.enterDate, |
| | | type: 4, |
| | | }); |
| | | modalLoading.value = false; |
| | | if (code == 200) { |
| | | closeModal(); |
| | | // 如果是批量操作,将所有合同的数据放在一个数组里,只调用一次接口 |
| | | if (selectedContracts.value.length > 1) { |
| | | // 创建包含所有合同数据的数组 |
| | | const batchData = selectedContracts.value.map(contract => { |
| | | // 筛选出属于当前合同的产品数据 |
| | | const contractProductData = form.productData.filter(item => |
| | | item.id === contract.id |
| | | ); |
| | | |
| | | // 为每个采购合同创建独立的对象 |
| | | return { |
| | | // 基础表单数据 |
| | | invoiceNumber: form.invoiceNumber, |
| | | invoiceAmount: form.invoiceAmount, |
| | | entryDate: form.entryDate, |
| | | enterDate: form.enterDate, |
| | | issUerId: form.issUerId, // 录入人id |
| | | issUer: form.issUer, // 录入人 |
| | | tempFileIds: form.tempFileIds, |
| | | |
| | | // 合同实际信息 |
| | | purchaseLedgerId: contract.id, // 使用id作为字段名,值为purchaseLedgerId |
| | | purchaseContractNumber: contract.purchaseContractNumber, // 使用实际的采购合同号 |
| | | salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 |
| | | supplierName: contract.supplierName, // 使用实际的供应商名称 |
| | | projectName: contract.projectName, // 使用实际的项目名称 |
| | | |
| | | // 产品数据 |
| | | productData: proxy.HaveJson(contractProductData), |
| | | |
| | | // 批量标识 |
| | | isBatch: true, |
| | | type: 4 |
| | | }; |
| | | }); |
| | | |
| | | // 只调用一次接口,传递包含所有合同数据的数组 |
| | | modalLoading.value = true; |
| | | addOrUpdateRegistration(batchData).then((res) => { |
| | | modalLoading.value = false; |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("批量登记成功"); |
| | | closeAndRefresh(); |
| | | } |
| | | }).catch(() => { |
| | | modalLoading.value = false; |
| | | proxy.$modal.msgError("批量登记失败"); |
| | | }); |
| | | } else { |
| | | // 单个合同提交逻辑 |
| | | const singleContract = selectedContracts.value[0]; |
| | | const singleForm = { |
| | | // 基础表单数据 |
| | | invoiceNumber: form.invoiceNumber, |
| | | invoiceAmount: form.invoiceAmount, |
| | | entryDate: form.entryDate, |
| | | enterDate: form.enterDate, |
| | | issUerId: form.issUerId, // 录入人id |
| | | issUer: form.issUer, // 录入人 |
| | | tempFileIds: form.tempFileIds, |
| | | |
| | | // 合同实际信息 |
| | | purchaseLedgerId: singleContract.id, // 使用id作为字段名,值为purchaseLedgerId |
| | | purchaseContractNumber: singleContract.purchaseContractNumber, // 使用实际的采购合同号 |
| | | salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 |
| | | supplierName: singleContract.supplierName, // 使用实际的供应商名称 |
| | | projectName: singleContract.projectName, // 使用实际的项目名称 |
| | | |
| | | // 产品数据 |
| | | productData: proxy.HaveJson(form.productData), |
| | | |
| | | // 批量标识 |
| | | isBatch: false, |
| | | type: 4 |
| | | }; |
| | | |
| | | modalLoading.value = true; |
| | | addOrUpdateRegistration(singleForm).then((res) => { |
| | | modalLoading.value = false; |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("登记成功"); |
| | | closeAndRefresh(); |
| | | } |
| | | }).catch(() => { |
| | | modalLoading.value = false; |
| | | proxy.$modal.msgError("登记失败"); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | |
| | | |
| | | defineExpose({ |
| | | open, |
| | | closeAndRefresh, |
| | | }); |
| | | </script> |
| | | |