| | |
| | | /> |
| | | <el-table-column label="本次开票数" prop="ticketsNum" width="180"> |
| | | <template #default="scope"> |
| | | <el-input-number :step="0.1" :min="0" :max="scope.row.tempFutureTickets || 0" style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsNum" |
| | | @change="invoiceNumBlur(scope.row)" |
| | | <el-input-number |
| | | :step="0.1" |
| | | :min="0" |
| | | :max="scope.row.tempFutureTickets || 0" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsNum" |
| | | :disabled="isProductDisabled(scope.row)" |
| | | @change="invoiceNumBlur(scope.row)" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | 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)" |
| | | <el-input-number |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | v-model="scope.row.ticketsAmount" |
| | | :disabled="isProductDisabled(scope.row)" |
| | | @change="invoiceAmountBlur(scope.row)" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | |
| | | // 设置产品数据,并初始化开票数量和金额 |
| | | allProductData.forEach(item => { |
| | | // 保存“原始未来票数/金额”(用于校验与计算) |
| | | // 保存"原始未来票数/金额"(用于校验与计算) |
| | | // 优先使用后端返回的 futureTickets/futureTicketsAmount;没有则回退到 quantity/taxInclusiveTotalPrice |
| | | item.tempFutureTickets = Number( |
| | | item.futureTickets !== undefined ? item.futureTickets : (item.quantity || 0) |
| | |
| | | item.futureTicketsAmount !== undefined ? item.futureTicketsAmount : (item.taxInclusiveTotalPrice || 0) |
| | | ); |
| | | |
| | | // 新增时:本次开票数默认 = 未来票数(且不能大于未来票数) |
| | | item.ticketsNum = Number(item.tempFutureTickets || 0); |
| | | // 联动计算本次开票金额、未来票数、未来票金额 |
| | | const unitPrice = Number(item.taxInclusiveUnitPrice || 0); |
| | | item.ticketsAmount = Number((item.ticketsNum * unitPrice).toFixed(2)); |
| | | item.futureTickets = Number((item.tempFutureTickets - item.ticketsNum).toFixed(2)); |
| | | item.futureTicketsAmount = Number( |
| | | (item.tempFutureTicketsAmount - item.ticketsAmount).toFixed(2) |
| | | ); |
| | | // 如果未来票金额为0,则本次开票数和金额都设置为0 |
| | | if (item.tempFutureTicketsAmount <= 0) { |
| | | item.ticketsNum = 0; |
| | | item.ticketsAmount = 0; |
| | | item.futureTickets = Number(item.tempFutureTickets || 0); |
| | | item.futureTicketsAmount = 0; |
| | | } else { |
| | | // 新增时:本次开票数默认 = 未来票数(且不能大于未来票数) |
| | | item.ticketsNum = Number(item.tempFutureTickets || 0); |
| | | // 联动计算本次开票金额、未来票数、未来票金额 |
| | | const unitPrice = Number(item.taxInclusiveUnitPrice || 0); |
| | | item.ticketsAmount = Number((item.ticketsNum * unitPrice).toFixed(2)); |
| | | item.futureTickets = Number((item.tempFutureTickets - item.ticketsNum).toFixed(2)); |
| | | item.futureTicketsAmount = Number( |
| | | (item.tempFutureTicketsAmount - item.ticketsAmount).toFixed(2) |
| | | ); |
| | | } |
| | | }); |
| | | |
| | | form.productData = allProductData; |
| | |
| | | }); |
| | | } else if (type == "edit") { |
| | | const id = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; |
| | | const data = await getPurchaseById({ id, type: 2 }); |
| | | form.purchaseLedgerNo = data.purchaseContractNumber; |
| | | const response = await getPurchaseById({ id, type: 2 }); |
| | | // 兼容不同的返回格式:可能是 { code, data } 或直接返回数据 |
| | | const data = response.data || response; |
| | | |
| | | // 兼容不同的字段名:purchaseContractNumber 或 purchaseLedgerNo |
| | | form.purchaseLedgerNo = data.purchaseContractNumber || data.purchaseLedgerNo || ""; |
| | | form.invoiceAmount = data.invoiceAmount; |
| | | form.invoiceNumber = data.invoiceNumber; |
| | | form.salesContractNo = data.salesContractNo; |
| | | form.projectName = data.projectName; |
| | | form.supplierName = data.supplierName; |
| | | form.entryDate = data.entryDate; |
| | | form.productData = data.productData; |
| | | form.enterDate = data.enterDate || dayjs().format("YYYY-MM-DD"); |
| | | |
| | | // 编辑时也需要初始化产品数据的 tempFutureTickets 和 tempFutureTicketsAmount |
| | | // 同时为每个产品添加合同号等信息 |
| | | const contractNumber = data.purchaseContractNumber || data.purchaseLedgerNo || ""; |
| | | if (data.productData && Array.isArray(data.productData)) { |
| | | data.productData.forEach(item => { |
| | | // 保存"原始未来票数/金额"(用于校验与计算) |
| | | // 优先使用后端返回的 futureTickets/futureTicketsAmount;没有则回退到 quantity/taxInclusiveTotalPrice |
| | | item.tempFutureTickets = Number( |
| | | item.futureTickets !== undefined ? item.futureTickets : (item.quantity || 0) |
| | | ); |
| | | item.tempFutureTicketsAmount = Number( |
| | | item.futureTicketsAmount !== undefined ? item.futureTicketsAmount : (item.taxInclusiveTotalPrice || 0) |
| | | ); |
| | | |
| | | // 确保每个产品都有合同号,用于显示在"所属合同"列 |
| | | if (!item.purchaseLedgerNo) { |
| | | item.purchaseLedgerNo = contractNumber; |
| | | } |
| | | }); |
| | | } |
| | | |
| | | form.productData = data.productData || []; |
| | | |
| | | // 编辑模式下,根据产品数据中的本次开票金额自动计算发票金额 |
| | | calculateinvoiceAmount(); |
| | | } |
| | | }; |
| | | // 子表合计方法 |
| | |
| | | form.invoiceAmount = Number(invoiceAmountTotal.toFixed(2)); |
| | | }; |
| | | |
| | | const open = async (type, selectedRows) => { |
| | | visible.value = true; |
| | | // 判断产品是否可以继续来票操作:如果未来票数和未来票金额都为0或小于等于0,则禁用 |
| | | const isProductDisabled = (row) => { |
| | | // 优先使用 tempFutureTickets(原始未来票数),如果没有则使用 futureTickets |
| | | const futureTickets = Number(row.tempFutureTickets !== undefined |
| | | ? row.tempFutureTickets |
| | | : (row.futureTickets !== undefined ? row.futureTickets : 0)); |
| | | |
| | | // 如果是批量操作,设置标题 |
| | | if (Array.isArray(selectedRows) && selectedRows.length > 1) { |
| | | modalOptions.value = { |
| | | ...(modalOptions.value || {}), |
| | | title: `批量新增 (${selectedRows.length}条)`, |
| | | }; |
| | | } else { |
| | | modalOptions.value = { |
| | | ...(modalOptions.value || {}), |
| | | title: type === "add" ? "新增" : "编辑", |
| | | }; |
| | | // 优先使用 tempFutureTicketsAmount(原始未来票金额),如果没有则使用 futureTicketsAmount |
| | | const futureAmount = Number(row.tempFutureTicketsAmount !== undefined |
| | | ? row.tempFutureTicketsAmount |
| | | : (row.futureTicketsAmount !== undefined ? row.futureTicketsAmount : 0)); |
| | | |
| | | // 只有当未来票数和未来票金额都为0或小于等于0时,才禁用 |
| | | return futureTickets <= 0 && futureAmount <= 0; |
| | | }; |
| | | |
| | | const open = async (type, selectedRows) => { |
| | | // 确保 modalOptions.value 是对象 |
| | | if (!modalOptions.value || typeof modalOptions.value !== 'object') { |
| | | modalOptions.value = {}; |
| | | } |
| | | |
| | | // 根据操作类型和选中数据设置标题 |
| | | if (Array.isArray(selectedRows) && selectedRows.length > 1) { |
| | | // 批量操作 |
| | | modalOptions.value.title = type === "add" ? `批量新增 (${selectedRows.length}条)` : `批量编辑 (${selectedRows.length}条)`; |
| | | } else { |
| | | // 单个操作 - 明确判断 type 的值 |
| | | if (type === "add" || type === "新增") { |
| | | modalOptions.value.title = "新增"; |
| | | } else if (type === "edit" || type === "编辑") { |
| | | modalOptions.value.title = "编辑"; |
| | | } else { |
| | | modalOptions.value.title = "来票登记"; // 默认标题 |
| | | } |
| | | } |
| | | |
| | | visible.value = true; |
| | | |
| | | // 如果是单个操作,获取id |
| | | if (!Array.isArray(selectedRows) || selectedRows.length === 1) { |
| | | const idValue = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; |